C++调试技术
目标文件信息查看
检查目标文件的段信息是否包含调试数据:
readelf -S test | grep debug
确认文件是否存在调试信息:
file test
删除文件中的调试信息:
strip test
gdb调试方法
1. 调试可执行文件
编译时添加-g选项以生成调试信息,然后使用gdb加载程序:
gcc -g test.c -o test
gdb test
在gdb中设置运行参数并启动程序:
(gdb) set args
(gdb) run
2. 调试正在运行的进程
通过ps命令查找目标进程的PID:
ps -ef | grep pname
附加到指定PID的进程进行调试:
gdb attach <pid>
或者直接在gdb中执行:
(gdb) attach <pid>
如果需要调试一个未带调试信息的运行程序,可以先编译出带调试信息的版本,再通过以下命令加载:
(gdb) file <executable_with_debug_info>
3. 核心转储文件(core dump)调试
检查核心转储文件是否启用:
ulimit -c
启用不限制大小的核心转储文件:
ulimit -c unlimited
设置核心文件名格式和路径:
echo "/home/ubuntu/corefile/core-%e-%p" > /proc/sys/kernel/core_pattern
调试核心文件时,使用以下命令加载:
gdb <exefile> <corefile>
获取调用栈信息
方法一:addr2line工具
将地址转换为对应的文件名、函数名和代码行号:
addr2line <address> -e <executable_file>
例如,反汇编目标文件后查询地址与代码的关系:
objdump -d -l -C -S test.elf > test.elf.asm
方法二:使用C库函数实现堆栈跟踪
以下是通过backtrace()和backtrace_symbols()实现的自定义堆栈打印功能:
#include <signal.h>
#include <execinfo.h>
#include <stdio.h>
#define MAX_FRAMES 100
void signal_handler(int sig) {
void* buffer[MAX_FRAMES];
int frames = backtrace(buffer, MAX_FRAMES);
printf("Backtrace: %d frames captured\n", frames);
char** symbols = backtrace_symbols(buffer, frames);
if (symbols == nullptr) {
printf("Failed to capture backtrace symbols\n");
return;
}
for (int i = 0; i < frames; ++i) {
printf("%s\n", symbols[i]);
}
free(symbols);
exit(1); // 终止程序避免无限循环
}
void bad_function() {
void* ptr = malloc(1024 * 1024 * 256);
free(ptr);
free(ptr); // 触发错误
}
void parent_function() {
bad_function();
}
int main() {
signal(SIGSEGV, signal_handler);
parent_function();
return 0;
}
编译并运行程序:
gcc -rdynamic -o test test.c
./test
输出示例:
Backtrace: 9 frames captured
./a.out(CallbackSignal+0x6b) [0x5acf3e1b22d4]
/lib/x86_64-linux-gnu/libc.so.6(+0x42520) [0x7cbb21a42520]
/lib/x86_64-linux-gnu/libc.so.6(free+0x1e) [0x7cbb21aa53fe]
./a.out(FuncBadBoy+0x32) [0x5acf3e1b2417]
./a.out(FuncBadFather+0x12) [0x5acf3e1b242c]
./a.out(main+0x31) [0x5acf3e1b2460]
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90) [0x7cbb21a29d90]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x7cbb21a29e40]
./a.out(_start+0x25) [0x5acf3e1b21a5]