在 Linux 上对 C++程序 debug 技巧方法总结
定位 segmentation fault
当出现 segmentation fault 报错时程序会直接挂掉,看不到程序崩溃的堆栈信息,不方便定位问题原因。这里总结了下几次遇到这个问题的解决流程,做下记录。
首先需要明确下 segmentation fault 通常是由于 内存泄漏或者溢出:进程执行中遇到了一个无效的内存地址/引用,或者段错误,都会触发 SIGSEGV 信号,内核接收到 SIGSEGV 信号后,默认终止了该进程。
因此,需要查看新增代码段中,是否存在可能的非法指针,
- 比如访问 nullptr 指针;
- 比如使用指针访问已经释放的内存(指针的拷贝是浅拷贝,只拷贝指向的内存,内容没有拷贝,虽然指针地址不同,但是指向的地址相同);
- 比如程序对多线程并不支持,两个线程访问的内存错乱。
如果本地可以快速编译并执行程序,可以通过增加指针判断,限制进程数量,打印指针地址和值等方式进一步定位问题原因。也不失为一个方法。
打印指针信息
char *p="abcde";
// 此处是输出指针变量的地址
cout << hex << &p << endl;
// 此处是输出指针变量的值,即指针所指向内存的地址
cout << hex << static_cast<void*>p << endl;
使用 gdb 查看信息
比较通用的方法是:通过 gdb 查看堆栈信息。
方法一
首先通过 top 等命令找到报错程序所对应的进程号。
查看进程信息
top -u username 查看 username 的所有进程
pidof mysqlid 可以查看程序 mysqlid 的进程号
top -p pid 可以查看进程号为 pid 的进程
gdb attach xxx
可以查看 pid 为 xxx 的进程,并进入 gdb 查看信息。
gdb 中通过 bt
命令列出线程的函数调用堆栈信息。
方法二
使用 core 文件, linux 默认会为 SIGSEGV 故障生成 一个 core 文件,该文件记录了出错时的堆栈信息,通过gdb 程序 core 可以快速追踪到问题代码。不过我们在编译的时候,需要加上编译参数 -g,例如,gcc -g a.c -o test
。
gdb ./test core
后同样使用 bt 和 where 命令可以查看堆栈信息。
但是,core 文件并不总是存在的,可能 linux 内核限制,也可能当前程序的目录下面没有写权限。
ulimit -a
可以查看是否有限制 core 文件,如果 core file size 过小,可以通过ulimit -c 2048
来设置 core file size 为 2048;- 如果程序在当前目录下没有写权限,则需要通过用户权限修改,通常此时是不能修改的,不可以使用此方法。
Linux 反汇编 debug
.so 文件是 Linux 系统中常见的文件类型之一,是用于动态连接的共享对象文件。.so 文件是二进制文件,包含的信息被编译成二进制代码。有时候我们需要对 so 文件进行分析,例如检查其代码,查看其库依赖关系,或了解其服务对Linux操作系统的影响。这时候,反汇编SO文件是必不可少的技术之一。
反汇编工具简介
在 Linux 上,反汇编工具非常丰富,其中最常见的是 GNU Binary Utilities(binutils)。binutils提供了很多工具,其中最常用的是disassemble工具(也称为objdump)。 disassemble工具可以从目标文件中提取反汇编指令,帮助我们分析SO文件的代码。
我们可以使用以下命令来查找Linux操作系统上是否存在disassemble工具:
man objdump
我们可以使用以下命令来查找Linux操作系统上是否存在disassemble工具:
sudo apt-get install binutils
反汇编SO文件
在反汇编之前,我们需要了解这个SO文件的信息。我们可以使用文件命令来获取文件的信息:
查看 so 文件
file libexample.so
这个命令将输出SO文件的系统信息(例如,系统体系结构,编译时间和编译器信息等)和字符串表信息等。
运行SO文件需要一些库支持,这些库可能会是其他SO文件或系统提供的库。因此,在反汇编SO文件之前,我们需要查看依赖哪些库。以下命令可以显示SO文件使用的库:
查看库
ldd libexample.so
objdump是分析SO文件的核心工具。以下是分析SO文件的命令:
分析命令
objdump -d libexample.so
// 重定向文件
objdump -d libexample.so > disass.txt
该命令输出反汇编SO文件的指令。每个指令都对应着SO文件中的一段代码。在这里,我们可以查看SO文件中的代码。例如,我们可以使用以下命令查看其中的一段代码:
添加筛选
objdump -d libexample.so | grep "function name"
这个命令将输出SO文件中与“function name”匹配的代码(其中“function name”是我们要查看的函数名称)。
反汇编代码比较复杂,但我们可以使用以下命令来处理和分析它:
处理反汇编代码
objdump -d libexample.so | c++filt | les
该命令将使用名字过滤器来处理反汇编指令,并使用 less 工具滚动显示。名字过滤器可以将反汇编的指令转化为更易读的形式,帮助我们进行分析。
此外,还是使用 c++filt 还原变量和函数名称,定位到具体问题函数和变量。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现