在 Linux 上对 C++程序 debug 技巧方法总结

定位 segmentation fault

当出现 segmentation fault 报错时程序会直接挂掉,看不到程序崩溃的堆栈信息,不方便定位问题原因。这里总结了下几次遇到这个问题的解决流程,做下记录。

首先需要明确下 segmentation fault 通常是由于 内存泄漏或者溢出:进程执行中遇到了一个无效的内存地址/引用,或者段错误,都会触发 SIGSEGV 信号,内核接收到 SIGSEGV 信号后,默认终止了该进程。
因此,需要查看新增代码段中,是否存在可能的非法指针,

  1. 比如访问 nullptr 指针;
  2. 比如使用指针访问已经释放的内存(指针的拷贝是浅拷贝,只拷贝指向的内存,内容没有拷贝,虽然指针地址不同,但是指向的地址相同);
  3. 比如程序对多线程并不支持,两个线程访问的内存错乱。

如果本地可以快速编译并执行程序,可以通过增加指针判断,限制进程数量,打印指针地址和值等方式进一步定位问题原因。也不失为一个方法。

打印指针信息
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 内核限制,也可能当前程序的目录下面没有写权限。

  1. ulimit -a 可以查看是否有限制 core 文件,如果 core file size 过小,可以通过 ulimit -c 2048 来设置 core file size 为 2048;
  2. 如果程序在当前目录下没有写权限,则需要通过用户权限修改,通常此时是不能修改的,不可以使用此方法。

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 还原变量和函数名称,定位到具体问题函数和变量。

posted @   周一上线  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示