目录
引言
曾经在stackoverflow看到过一篇求助帖子《Is there any way to tell GDB to wait for a process to start and attach to it?》,大体问题:工具链上调用关系很长,父进程调用子进程,子进程调用孙进程,如此下去,最后有一个进程崩溃了,提问者期望在崩溃之前用GDB attach上去调试调试,好找到崩溃原因。
问题是崩溃进程可能崩溃的很快,以至于没有时间attach。
本文将对strace源代码做轻微改动,以赋予它遇到execve系统调用时(真正执行前)可以回调shell脚本的能力。我会先preview下改造的效果,然后简单讲下Stack Overflow上给出的两个解决方案,最后讲述如何修改strace源码。
新strace效果preview
[root@strace]# ./src/strace -f --syscall_callback_script=./test.sh ./exe1
[pid 2218037] execve("./exe2", ["./exe2"], 0x7ffe32765268 /* 61 vars */./src/strace: Process 2218037 detached
<detached ...>
[root@strace]# ps -ef|grep exe2
root 2218037 2218029 0 05:23 pts/1 00:00:00 ./exe2
root 2218041 2201850 0 05:23 pts/1 00:00:00 grep --color=auto exe2
[root@strace]# gdb -p 2218037
Attaching to process 2218037
Reading symbols from /min/strace/exe2...done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...done.
0x00007fb0944dacb0 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) where
#0 0x00007fb0944dacb0 in _start () from /lib64/ld-linux-x86-64.so.2
#1 0x0000000000000001 in ?? ()
#2 0x00007ffcde850947 in ?? ()
#3 0x0000000000000000 in ?? ()
(gdb) b main
Breakpoint 1 at 0x40058a: file exe2.c, line 5.
(gdb) c
Continuing.
Program received signal SIGSTOP, Stopped (signal).
0x00007fb0944dacb0 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) where
#0 0x00007fb0944dacb0 in _start () from /lib64/ld-linux-x86-64.so.2
#1 0x0000000000000001 in ?? ()
#2 0x00007ffcde850947 in ?? ()
#3 0x0000000000000000 in ?? ()
(gdb) c
Continuing.
Breakpoint 1, main () at exe2.c:5
5 printf("I am exe2\n");
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-236.el8.7.x86_64
(gdb) where
#0 main () at exe2.c:5
已有解决方案
帖子上给出了几种解决方案,列出其中两种
解决方案一:循环检测
写一个shell脚本,不停的检测目标(按进程名字)存在不存在,一旦存在就attach上去。
#!/bin/sh
progstr=$1
progpid=`pgrep -o $progstr`
while [ "$progpid" = "" ]; do
progpid=`pgrep -o $progstr`
done
gdb -ex continue -p $progpid
Usage:
gdbwait my_program
问题:这个脚本不能100%保证能抓住目标,特别是目标转瞬即逝的情况。我们下面给出的exe2就几乎抓不到。
解决方案二:gdb-helpers
有人在Github上有个repo:gdb-helpers ,里面有个工具叫preattach.
问题:不过它依赖systemtap,没安装systemtap 是用不了的。
改造strace
基本想法是strace既然能检测到系统调用,而Linux是用fork-execv*(syscall execve)来发起子进程的,那能不能在execve时让目标暂停然后给GDB时间去attach哪?
简单的fork程序
先写一个简单的fork程序,便于测试
<