为什么当我使用 exec-wrapper 脚本来执行我的目标二进制文件时 gdb 不会中断。
这是我的小测试。
我使用没有饼图选项的二进制文件来使用可预测的地址。
$ gcc -no-pie main.c
我有这个小小的 gdb exec 包装脚本。
$ cat wrapper.sh
#!/bin/bash
env -i ./a.out
然后我像这样调试我的程序,通过在 *main 处设置 exec-wrapper 变量和调试断点,断点不起作用:
$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) b *main
Breakpoint 1 at 0x401126
(gdb) set exec-wrapper ./wrapper.sh
(gdb) r
Starting program: /home/snake/gdb-test/a.out
boum !
During startup program exited normally.
(gdb)
这里是没有设置 exec-wrapper 变量和在 *main 处的调试断点的相同示例,断点有效:
$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) b *main
Breakpoint 1 at 0x401126
(gdb) r
Starting program: /home/snake/gdb-test/a.out
Breakpoint 1, 0x0000000000401126 in main ()
(gdb)
为什么在第一种情况下断点不起作用?
也许 gdb 没有附加到我的 exec 包装脚本运行的进程中。
谢谢你的帮助。
更新:
谢谢@ws,你的提醒和观点很有趣。
我使用env -i
为了在空环境中启动程序,以便在非随机地址空间、gdb 输入/输出和任何路径中具有可预测的堆栈。但是 GDB 缺少使用相对路径来配置二进制名称以传递给 argv[0] 的选项,而其他压入堆栈的变量将根据执行上下文的目录位置导致堆栈偏移。
所以我构建了这个小包装来克服这个问题。也许脏,但工作得很好。
#include <unistd.h>
int main()
{
int e;
char *envp[] = { NULL };
char *argv[] = { "./a.out", NULL };
e = execve("./a.out", argv, envp);
}
然后
$ gcc exec_wrapper.c -o exec_wrapper
最后
$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) set exec-wrapper ./exec_wrapper
(gdb) b *main
Breakpoint 1 at 0x1149
(gdb) r
Starting program: /home/snake/gdb-test/a.out
Breakpoint 1, 0x0000555555555149 in main ()
(gdb)
所以我不太明白你的答案@ws,我的可执行文件名称直接编码在二进制文件中,并且运行良好。如果我了解 gdb 的行为,通常 GDB 会监视第一个进程陷阱 execve() 由 shell 启动以跟随它。在 exec-wrapper 被配置的情况下,它跟在第二个 execve() 之后。(感谢一位朋友向我展示这种行为)。
gdb/nat/fork-inferior.h
/* Number of traps that happen between exec'ing the shell to run an
inferior and when we finally get to the inferior code, not counting
the exec for the shell. This is 1 on all supported
implementations. */
#define START_INFERIOR_TRAPS_EXPECTED 1
gdb/nat/fork-inferior.c
/* The process was started by the fork that created it, but it will
have stopped one instruction after execing the shell. Here we
must get it up to actual execution of the real program. */
if (get_exec_wrapper () != NULL)
pending_execs++;
也许我不明白你的回答@ws。对不起。您的意思是说 gdb 将二进制名称与完整路径与 execve() 调用的 argv[0] 进行字符串比较?