GDB(十) 调试正在运行的进程

本文介绍如何使用GDB调试器附加到正在运行的循环进程上,并演示了如何查看栈跟踪、修改变量值及分离进程等操作。同时,还讨论了当被调试进程缺少调试信息时的情形。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我编写了一个循环:


把它编译成a.out,并在后台执行它:./a.out &

[1] 2570

然后用命令gdb ./a.out 2570可以附加到这个进程上。被时进程会中断。

或者在GDB里输入attach 2570同样可以附加到进程。

输入bt来查看栈

(gdb) bt
#0  0x008e9416 in __kernel_vsyscall ()
#1  0x003bb900 in nanosleep () from /lib/i386-linux-gnu/libc.so.6
#2  0x003bb71f in sleep () from /lib/i386-linux-gnu/libc.so.6
#3  0x0804845d in main () at ptype_struct.c:22
可以看到程序正中断在系统调用vsyscall上。用frame 3进入main函数的栈框架并打印i的值,

(gdb) frame 3
#3  0x0804845d in main () at ptype_struct.c:22
22            sleep(1);
(gdb) p i
$1 = 153
next可以执行下一行。

(gdb) next
Single stepping until exit from function __kernel_vsyscall,
which has no line number information.
0x003bb900 in nanosleep () from /lib/i386-linux-gnu/libc.so.6

设置i的值。

(gdb) p i = 999999
$3 = 999999

detach可以分离进程。
(gdb) detach
Detaching from program: /home/tommy/tmp/a.out, process 2570
(gdb) q
[1]+  完成                  ./a.out

如果被调试的进程没有调试信息:

$ strip ./a.out
$ ./a.out &
[1] 2603
tommy:~/tmp$ gdb
gdb> attach 2603

(gdb) bt
#0  0x00b0f416 in __kernel_vsyscall ()
#1  0x00721900 in nanosleep () from /lib/i386-linux-gnu/libc.so.6
#2  0x0072171f in sleep () from /lib/i386-linux-gnu/libc.so.6
#3  0x0804845d in ?? ()
#4  0x0069e113 in __libc_start_main () from /lib/i386-linux-gnu/libc.so.6
#5  0x08048351 in ?? ()
函数名没有被打印。

注意GDB其实可以看作是ptrace系统调用的前端。ptrace专门用来观察和控制另一个进程的执行。观察别的进程可能需要恰当的权限,比如超级用户。不要去调试init进程,不然可能会很伤。我不小心把它杀掉,电脑直接黑屏。

<think>我们正在讨论如何使用GDB调试正在运行进程。根据引用内容,我们可以总结出基本步骤: 1. 找到要调试进程的PID(进程ID)。 2. 使用GDB的`attach`命令附加到该进程。 3. 使用GDB命令进行调试(如设置断点、继续执行、单步执行等)。 4. 调试完成后,可以使用`detach`命令分离进程,然后退出GDB。 参考引用[1]中提到了`attach process-id`命令,引用[2]和[3]则提供了如何获取进程ID以及附加的示例。 具体步骤: 步骤1:获取进程ID 可以通过`ps`命令或`top`命令来查找进程的PID。例如,使用`ps aux | grep 进程名`。 步骤2:启动GDB并附加到进程 在终端输入:`gdb -p PID` 或者先启动gdb,然后在gdb中执行`attach PID`。 步骤3:开始调试GDB中,你可以设置断点、查看变量、单步执行等。常用的命令包括: - `break`(或`b`):设置断点 - `continue`(或`c`):继续运行 - `next`(或`n`):单步执行(不进入函数) - `step`(或`s`):单步执行(进入函数) - `print`(或`p`):打印变量值 - `backtrace`(或`bt`):查看调用栈 - `info threads`:查看线程信息(如果是多线程程序) - `thread <ID>`:切换到指定线程 步骤4:分离和退出 调试完成后,使用`detach`命令将GDB进程分离,这样进程可以继续运行。然后使用`quit`退出GDB。 注意:在调试过程中,程序会暂停执行,所以请谨慎操作,特别是在生产环境中。 另外,引用[2]提供了一个示例程序,我们可以用它来演示。假设我们有一个每秒打印一个数字的程序(如示例中的程序),现在它正在运行,我们想用GDB调试它。 示例演示: 1. 编译程序:gcc -g test.c -o test (注意:编译时需要加-g选项,以便调试) 2. 运行程序:./test 3. 使用`ps aux | grep test`找到该进程的PID(假设为1234)。 4. 启动GDB并附加:gdb -p 1234 5. 在GDB中设置断点:例如,在main函数设置断点:`break main` 或者在循环内设置:`break 6`(第6行) 6. 使用`continue`让程序继续运行,当断点命中时,程序会暂停。 7. 使用`next`或`step`单步执行,使用`print i`查看变量i的值。 8. 调试完成后,使用`detach`分离,然后`quit`退出。 注意:在调试过程中,程序会暂停,所以如果你在循环中设置断点,每次循环都会暂停,直到你继续。 引用[1]提供了更多GDB命令的详细说明,例如`until`、`finish`、`return`等,这些在调试过程中也很有用。 特别提醒:在调试生产环境中的进程时,一定要小心,因为暂停进程可能会影响服务。建议在测试环境中进行。 现在,我们来生成相关问题。</think>### 如何使用 GDB 调试正在运行进程 #### 核心步骤: 1. **获取进程 PID** 使用 `ps` 或 `pgrep` 命令查找目标进程的 PID: ```bash ps aux | grep <进程名> # 例如:ps aux | grep myapp pgrep <进程名> # 例如:pgrep nginx ``` 2. **附加到运行进程** 通过 PID 附加 GDB 调试器: ```bash gdb -p <PID> # 直接附加(推荐) #gdb # 启动 GDB (gdb) attach <PID> #GDB 内附加 ``` **注意**:附加后目标进程会暂停执行[^1]。 3. **设置断点与调试** 常用调试命令: ```bash (gdb) break main.c:20 # 在文件第 20 行设断点 (gdb) continue # 继续运行(缩写 c) (gdb) next # 单步跳过(缩写 n) (gdb) step # 单步进入(缩写 s) (gdb) print variable # 打印变量值(缩写 p) (gdb) backtrace # 查看调用栈(缩写 bt) ``` 4. **分离与退出** ```bash (gdb) detach # 分离进程进程继续运行(gdb) quit # 退出 GDB(缩写 q) ``` #### 调试示例: 假设调试一个每秒输出数字的 C 程序(源码见引用[^2]): ```bash # 1. 获取 PID(假设 PID=12345) ps aux | grep print_num # 2. 附加调试gdb -p 12345 # 3. 设置断点并调试 (gdb) break 6 # 在循环内设断点 (gdb) continue # 继续执行 (gdb) print i # 查看计数器值 (gdb) next # 单步执行 ``` #### 注意事项: 1. **编译要求**:程序需用 `-g` 选项编译(如 `gcc -g program.c`),否则无法查看源码和变量。 2. **权限要求**:需具有目标进程的操作权限(通常需 root 或进程所有者权限)。 3. **多线程调试**: - `info threads` 查看所有线程 - `thread <ID>` 切换线程[^1] 4. **生产环境谨慎操作**:调试会导致进程暂停,可能影响线上服务。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值