繁体   English   中英

无法在我的迷你调试器中为linux创建一个断点

[英]Cannot make a breakpoint in my mini debugger for linux

我致力于将迷你调试器作为个人项目。 调试器适用于GNU / Linux环境下的x86处理器。

我在调试程序的特定地址设置断点的方法是第一次我的调试器午餐。 如果我再试一次就失败了。

我想确保我是否以正确的方式做到这一点。

假设我有一个helloworld程序要调试如下:

#include <iostream>
int main()
{
    std::cerr << "hello,World\n";
return 0;
}

它用objdump -d解释如下

0000000000400907 <main>:
400907: 55                      push   %rbp
  400908:   48 89 e5                mov    %rsp,%rbp
  40090b:   be 04 0a 40 00          mov    $0x400a04,%esi
  400910:   bf 60 10 60 00          mov    $0x601060,%edi
  400915:   e8 06 ff ff ff          callq  400820 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
  40091a:   b8 00 00 00 00          mov    $0x0,%eax
  40091f:   5d                      pop    %rbp
  400920:   c3                      retq 

而且我肯定用-g选项编译了我的helloworld。

对于第一次试验,我设置的断点为0x4009150x40091a 所以我期待的是,当我继续 (像GDB这样的命令)我的调试器时,它将停在0x400915 ,当我再次继续它将打印“helloworld”但不发生这种情况。 它只是回归,因为没有任何断点。

所以作为另一个试验,当我的调试器启动我的helloworld程序时。 我看到helloworld程序的pid并在/ proc / [helloworld pid] / maps打开它的地图文件,看起来像

00400000-00401000 r-xp 00000000 08:07 1578540                            /home/yahia/mytinydebugger/tdbg/build/debugging-examples/helloworld
00600000-00602000 rw-p 00000000 08:07 1578540                            /home/yahia/mytinydebugger/tdbg/build/debugging-examples/helloworld
7f9483434000-7f9483457000 r-xp 00000000 08:06 529041                     /lib/x86_64-linux-gnu/ld-2.19.so
7f9483656000-7f9483658000 rw-p 00022000 08:06 529041                     /lib/x86_64-linux-gnu/ld-2.19.so
7f9483658000-7f9483659000 rw-p 00000000 00:00 0 
7fff5a314000-7fff5a335000 rw-p 00000000 00:00 0                          [stack]
7fff5a335000-7fff5a337000 r--p 00000000 00:00 0                          [vvar]
7fff5a337000-7fff5a339000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

然后专注于堆栈的第一个地址

7fff5a314000-7fff5a335000 rw-p 00000000 00:00 0                          [stack

并添加0x7fff5a314000 + 0x400915 = 0x7FFF5A714915和0x40091a相同。 它按照我的预期第一次工作但是当我再次尝试它时它不起作用。 我甚至自动在代码中通过从/ proc / [helloworld pid] / maps中自动获取这个十六进制数学。 它似乎第一次正常工作,无论我再试一次,它都没有。

我不知道为什么它总是不起作用。

我通过二次试验设置断点的方法是对的吗?

我知道我应该把INT3的intel指令放在我希望有断点的地址上。 这是我用来设置断点的代码。

void breakpoint::enable() {
    // Fetch the program instruction at the desired address of a specific process.
    auto data = ptrace(PTRACE_PEEKDATA, m_pid, m_addr, nullptr);
    // Save the lower byte which will be replaced with INT3 instruction.
    m_saved_data = static_cast<uint8_t>(data & 0xff);
    uint64_t int3 = 0xcc;
    // Set the lower byte to INT3 instruction
    uint64_t data_with_int3 = ((data & ~0xff) | int3);
    // Push the modified instruction with the breakpoint to the same address it was fetched.
    ptrace(PTRACE_POKEDATA, m_pid, m_addr, data_with_int3);
    // Enable that (this) object of the class has a breakpoint at [m_addr] of [m_pid] process.
    m_enabled = true;
}

调试器的完整代码在这里 它并不大。 它很简单,提交很少,因为它处于早期阶段。

我的操作系统是ubuntu 14.04 ,调试器和helloworld示例都是用g ++ 7.2.0编译的

首先,您应该使用ADDR_NO_RANDOMIZE personality来获取可预测的地址,就像GDB默认情况一样。 这将帮助您弄清楚发生了什么。 但是,您尚未启用PIE,因此ASLR不会导致您在主程序中设置断点的困难。

然后,您需要检查ptrace函数的结果是否有错误。 您需要在调用之前将errno为零,然后检查它是否已更改。 这将告诉你(在合理范围内)你是否通过了一个完全虚假的地址。

另请注意,使用PTRACE_PEEKDATAPTRACE_POKEDATA ptrace始终会修补完整的单词。 为了修补单个字节,您需要使用移位和屏蔽操作将断点指令放入字中的右侧字节。

我通过恢复INT3指令损坏的指令以及我的存储库中的合并请求中显示的其他更改来修复此问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM