如何在C语言主函数中调试外部程序?VS Code+GDB调试system调用外部程序的问题及替代方案
我之前也碰到过和你一模一样的情况:在hello.c里用system("/path/to/world")调用外部程序,在这行设断点后点Step Into,结果弹出Could not load source './stdlib/../sysdeps/posix/system.c': 'SourceRequest' not supported.的错误,根本进不去world的代码里。
为什么用system()没法直接调试外部程序?
原因很简单:system()函数本质是调用系统shell(比如bash)来执行你的world程序,相当于中间多了一个shell进程。GDB默认只会跟踪父进程(也就是hello进程),就算你想跟进,也会先进入shell的代码,而不是直接跳到world的main函数——而且系统libc的源码你大概率没装,所以才会弹出找不到system.c的错误。
替代方案:用fork()+exec系列函数配合GDB的多进程调试
要直接调试被调用的外部程序,我们需要跳过shell这一层,直接创建子进程执行world,同时让GDB跟踪子进程。具体步骤如下:
1. 修改hello.c的代码,替换system()
把原来的system()调用换成fork()+execv()的组合,这样可以直接启动world进程,不需要经过shell:
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main(int argc, char **argv) { pid_t pid = fork(); if (pid == 0) { // 子进程:执行world程序 char *args[] = {"/path/to/world", NULL}; execv("/path/to/world", args); // 如果execv执行失败才会走到这里 perror("execv failed"); return 1; } else if (pid > 0) { // 父进程:等待子进程结束 wait(NULL); } else { perror("fork failed"); return 1; } return 0; }
2. 配置VS Code的launch.json,让GDB跟踪子进程
打开VS Code的调试面板,编辑launch.json,添加follow-fork-mode和detach-on-fork这两个配置项,告诉GDB跟着子进程走:
{ "version": "0.2.0", "configurations": [ { "name": "Debug Hello", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/hello", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true }, // 关键配置:跟踪子进程,不分离父进程 { "text": "set follow-fork-mode child", "description": "Make GDB follow the child process" }, { "text": "set detach-on-fork off", "description": "Keep parent process attached" } ], "preLaunchTask": "C/C++: gcc build active file" } ] }
3. 编译时添加调试信息
不管是hello.c还是world.c,编译的时候一定要加-g参数,保留调试符号:
gcc -g /path/to/hello.c -o /path/to/hello gcc -g /path/to/world.c -o /path/to/world
4. 设置断点并调试
- 直接在
world.c的main函数行设置断点,或者在hello.c的execv那行设置断点 - 启动调试,当程序走到
execv时点击Step Into,就能直接进入world的main函数开始调试了
额外说明
如果只是临时想调试world程序,其实也可以直接在VS Code里配置调试world本身,但如果必须通过hello来触发world的执行,上面的方法就是最靠谱的解决方案。
内容的提问来源于stack exchange,提问作者stackbiz




