将 gdb on 与 execl、wait 和 ptrace 一起使用
using gdb on with execl, wait, and ptrace
我正在尝试调试调用另一个程序并使用 ptrace 的程序。
我可以运行,就好了;然而,当试图用 gdb 调试它时,程序在 wait(&status) 处挂起。我想做的是调试主进程,可能来回切换。
我认为显示代码和 gdb 输出会更容易:
switch(pid = fork())
{
case -1: /*error*/
{
perror("fork()");
exit(-1);
}
case 0:/*child process*/
{
ptrace(PTRACE_TRACEME, NULL, NULL); /*allow child process to be traced*/
execl(path, name, NULL); /*child will be stopped here*/
perror("execl()");
exit(-1);
}
/*parent continues execution*/
}
wait(&status);
while(true)
{
if(WIFEXITED(status) || (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL))
{
cout << "process " << child << "terminated\n";
exit(0);
}
get_and_handle_input();
当使用 gdb 时,它停止在 wait(&status):
gdb ./prog
GNU gdb (GDB; openSUSE 13.2) 7.8
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-suse-linux".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://bugs.opensuse.org/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
warning: /etc/gdbinit.d/gdb-heap.py: No such file or directory
Reading symbols from ./prog...done.
(gdb) r ../tests/function_test
Starting program: /home/user/dev/src/prog ../tests/function_test
[New process 7930]
^C
Program received signal SIGINT, Interrupt.
0x00007ffff68479d2 in __libc_wait (stat_loc=0x7fffffffdc7c) at ../sysdeps/unix/sysv/linux/wait.c:30
30 return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
(gdb) bt
#0 0x00007ffff68479d2 in __libc_wait (stat_loc=0x7fffffffdc7c) at ../sysdeps/unix/sysv/linux/wait.c:30
#1 0x00000000004059bc in main (argc=<optimized out>, argv=<optimized out>) at shell.cpp:44
(gdb) info inferiors
Num Description Executable
2 process 7930 /home/user/dev/src/prog
* 1 process 7926 /home/user/dev/src/prog
(gdb) continue
Continuing.
如果我切换到进程 2 并使用继续,则进程 2 运行s;但是,这对我没有任何好处(即使我在过程 1 中设置了一个断点)。
希望这是有道理的。如果我需要清理任何东西,请告诉我。
如果可以,gdb 会尝试获取目标进程中的 fork 事件通知。
在 Linux,gdb 调用 ptrace(PTRACE_SETOPTIONS,...,TRACEFORK|TRACECLONE|TRACEEXEC)
。 TRACECLONE
确保在 fork 之后,自动跟踪子进程。当目标进程分叉时,gdb 会查看 follow-fork-mode and detach-on-fork 的设置,并且要么保持附加到两个进程(但只允许一个到 运行),要么从一个进程中删除所有断点(如果有的话)并且与它分离(因此允许两个进程 运行,一个被追踪,一个不被追踪)。
因为您已将 detach-on-fork
设置为 off
,gdb 仍然附加到两个进程,运行 一个进程并保持另一个挂起。如果 follow-fork-mode
是 parent
,默认情况下,父 运行 和 waitpid
只是挂起。如果 follow-fork-mode
是 child
,您的 ptrace(PTRACE_TRACEME, ...)
调用将失败,因为一个进程一次只能有一个 Tracer。所以最好的做法似乎是将 detach-on-fork
设置为 on
,这样 gdb 将只跟踪父进程。
我在 gdb 8.2.1 中遇到了同样的问题。
它似乎已在 gdb 8.3.1 中修复。
我正在尝试调试调用另一个程序并使用 ptrace 的程序。
我可以运行,就好了;然而,当试图用 gdb 调试它时,程序在 wait(&status) 处挂起。我想做的是调试主进程,可能来回切换。
我认为显示代码和 gdb 输出会更容易:
switch(pid = fork())
{
case -1: /*error*/
{
perror("fork()");
exit(-1);
}
case 0:/*child process*/
{
ptrace(PTRACE_TRACEME, NULL, NULL); /*allow child process to be traced*/
execl(path, name, NULL); /*child will be stopped here*/
perror("execl()");
exit(-1);
}
/*parent continues execution*/
}
wait(&status);
while(true)
{
if(WIFEXITED(status) || (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL))
{
cout << "process " << child << "terminated\n";
exit(0);
}
get_and_handle_input();
当使用 gdb 时,它停止在 wait(&status):
gdb ./prog
GNU gdb (GDB; openSUSE 13.2) 7.8
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-suse-linux".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://bugs.opensuse.org/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
warning: /etc/gdbinit.d/gdb-heap.py: No such file or directory
Reading symbols from ./prog...done.
(gdb) r ../tests/function_test
Starting program: /home/user/dev/src/prog ../tests/function_test
[New process 7930]
^C
Program received signal SIGINT, Interrupt.
0x00007ffff68479d2 in __libc_wait (stat_loc=0x7fffffffdc7c) at ../sysdeps/unix/sysv/linux/wait.c:30
30 return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0,
(gdb) bt
#0 0x00007ffff68479d2 in __libc_wait (stat_loc=0x7fffffffdc7c) at ../sysdeps/unix/sysv/linux/wait.c:30
#1 0x00000000004059bc in main (argc=<optimized out>, argv=<optimized out>) at shell.cpp:44
(gdb) info inferiors
Num Description Executable
2 process 7930 /home/user/dev/src/prog
* 1 process 7926 /home/user/dev/src/prog
(gdb) continue
Continuing.
如果我切换到进程 2 并使用继续,则进程 2 运行s;但是,这对我没有任何好处(即使我在过程 1 中设置了一个断点)。
希望这是有道理的。如果我需要清理任何东西,请告诉我。
如果可以,gdb 会尝试获取目标进程中的 fork 事件通知。
在 Linux,gdb 调用 ptrace(PTRACE_SETOPTIONS,...,TRACEFORK|TRACECLONE|TRACEEXEC)
。 TRACECLONE
确保在 fork 之后,自动跟踪子进程。当目标进程分叉时,gdb 会查看 follow-fork-mode and detach-on-fork 的设置,并且要么保持附加到两个进程(但只允许一个到 运行),要么从一个进程中删除所有断点(如果有的话)并且与它分离(因此允许两个进程 运行,一个被追踪,一个不被追踪)。
因为您已将 detach-on-fork
设置为 off
,gdb 仍然附加到两个进程,运行 一个进程并保持另一个挂起。如果 follow-fork-mode
是 parent
,默认情况下,父 运行 和 waitpid
只是挂起。如果 follow-fork-mode
是 child
,您的 ptrace(PTRACE_TRACEME, ...)
调用将失败,因为一个进程一次只能有一个 Tracer。所以最好的做法似乎是将 detach-on-fork
设置为 on
,这样 gdb 将只跟踪父进程。
我在 gdb 8.2.1 中遇到了同样的问题。 它似乎已在 gdb 8.3.1 中修复。