从 gdb 调用远程 (OpenOCD) 目标中的函数

逆向工程 数据库 标签
2021-07-07 03:49:05

有没有办法在通过 JTAG 连接的远程目标上调用函数?目前,我已将 OpenOCD 连接到一个目标,并附加了 gdb,并且我知道要调用的函数的地址及其签名。

使用普通的二进制文件和 gdb,以下(有点令人惊讶)有效。假设我有一个类似的功能:

static int f(int x) {
    printf("The value of x is %d\n", x);
    return x*2;
}

我可以在 gdb 下运行该函数,即使是在剥离的二进制文件中,只要我知道它的地址:

cosimo:~ moyix$ gdb -q --args ./hello 
Reading symbols from ./hello...(no debugging symbols found)...done.
(gdb) break *0x100000ee0
Breakpoint 1 at 0x100000ee0
(gdb) r
Starting program: /Users/moyix/hello 

Breakpoint 1, 0x0000000100000ee0 in _mh_execute_header ()
(gdb) call (0x100000f20)(10)
The value of x is 10
$1 = 20

但是尝试对连接到 OpenOCD 的 gdb 做类似的事情给了我:

moyix@dev:~/git/openocd-code$ arm-none-eabi-gdb -q
(gdb) target remote localhost:3333
Remote debugging using localhost:3333
0x8006b06c in ?? ()
(gdb) call (0xC0066E08)(0x10000, 4, 0, 0, 0)
Entry point address is not known.
(gdb) 

我从谷歌搜索中收集到,这是因为gdb 想要在某个地方放置它的虚拟堆栈帧,并且由于它没有符号信息,甚至没有二进制文件的入口点,它不知道将它放在哪里。有什么方法可以手动为其虚拟框架指定一个位置(希望它在函数执行后将事情恢复原状......)?

2个回答

这不是最干净的解决方案,我仍然不知道如何让 gdb 正确执行。我的解决方案是通过以下方式简单地手动“调用”该函数:

  1. 保存当前的寄存器集(info reg=> 日志文件)。
  2. 通过手动修改寄存器、将内容压入堆栈等来设置参数,小心确保不要覆盖高于当前堆栈指针的任何内容。
  3. 在我要调用的函数的每个返回上放置一个断点。(注意:可能在将来,将返回地址设置为某个任意点然后在该点上设置断点会更好。)
  4. 将程序计数器设置为我要调用的函数的地址。
  5. 一旦断点命中,检查返回值等。
  6. 手动恢复寄存器值(包括堆栈指针)。

这并不完美,因为它在开始和结束时需要大量的手动工作,但对于偶尔使用来说效果很好。

我在不同的用例中遇到了相同问题的这个问题:调试 ELF 二进制文件qemu-arm,尝试从附加进程调用代码。

我可以提供gdb它错过的信息,将目标二进制文件指定为符号文件(使用symbol-file命令)。

https://sourceware.org/gdb/onlinedocs/gdb/Files.html

当然,您的情况可能会更复杂。使用实时设备内地址链接二进制文件可能会奏效,尽管它可能并非微不足道。