Gdb¶
- 打开编译选项
makefile:g++ -g -O0 cmake:set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0")
- 常用命令
使用GDB打印/查看大型代码库文件中的变量,可以按照以下步骤进行: 首先,确保已经安装了GDB调试器,并且代码库已经编译为可调试的可执行文件。 打开终端,进入代码库所在的目录,并运行可执行文件的命令。 在终端中输入gdb 可执行文件名,进入GDB调试环境。 在GDB命令行中,可以使用以下命令来打印/查看变量: 使用break 行号或break 函数名设置断点,以便在特定位置停下来查看变量。 使用run命令运行程序,直到遇到断点位置。 使用print 变量名命令打印变量的值。 使用display 变量名命令持续打印变量的值,每次程序停下来都会显示。 使用info locals命令查看当前作用域内的所有局部变量。 使用info globals命令查看全局变量。 使用info variables命令查看当前作用域内的所有变量。 使用backtrace命令查看函数调用栈,可以查看函数调用关系。 使用step命令逐行执行代码,并进入函数内部。 使用next命令逐行执行代码,但不进入函数内部。 使用continue命令继续执行代码,直到下一个断点或程序结束。 在GDB调试环境中,可以根据需要重复执行上述命令,以查看和调试代码库中的变量。
- 进阶命令
(gdb) info proc mappings (gdb) disassemble 0x7e9f476000 (gdb) info symbol 0x7e9f476000 (gdb) x/32x 0x7e9f476000 # gdb -p pid # detach # 查看局部变量 info locals # 查看全局变量 info variables # 查看当前位置 where # 查看当前代码 list # 设置断点 break test.cpp:11 break main break test.cpp:main # 运行到断点 continue(如果没有断点则程序一直运行,停止运行用ctrl+c) # 打印断点处变量值 print i # 查看断点 info breakpoints info break 1 # 删除断点 delete 1 delete(取消所有断点) # 下一语句 next # 下一步 step # 列出所有函数 info functions # 列出指定类的所有函数 info functions MyClass # run 1. 新实例启动:当你在 GDB 中使用 run 命令时,GDB 会创建一个新的进程来运行你指定的程序。这意味着原来的程序(如果它是通过 gdb -p <pid> 附加的)将不再运行,因为 GDB 现在控制的是一个新的进程。 2. 附加与运行的区别: 附加:使用 gdb -p <pid> 附加到一个正在运行的程序时,GDB 会暂停该程序并允许你进行调试。此时,程序的状态保持不变。 运行:使用 run 命令时,GDB 启动一个新的程序实例,原来的程序(如果是通过 gdb 附加的)将被终止。 调试会话:如果你希望调试一个已经在运行的程序,应该使用 gdb -p <pid> 来附加到该进程,而不是使用 run 命令。 # set print frame-arguments all 用于设置调试器在打印栈帧信息时显示所有函数参数的值。 具体来说,这个命令的作用如下: 打印所有参数:当你在 GDB 中查看当前栈帧或调用栈时,使用这个命令可以让 GDB 显示当前函数的所有参数,而不仅仅是某些特定的参数。 调试便利:这对于调试复杂的函数调用非常有用,尤其是在函数参数较多或参数类型较复杂的情况下,可以帮助开发者更好地理解程序的状态。 使用这个命令后,当你使用 backtrace 或 frame 命令查看栈帧时,GDB 会显示所有参数的值,帮助你更好地分析程序的执行情况。 # g++ -g -o0 *.cpp -o test_thread -pthread 不使用-g在gdb调试时没有文件源码信息 # g++ -fsanitize=address -g your_program.cpp -o your_program 是一个编译器选项,用于启用地址消毒器(AddressSanitizer),这是一个用于检测内存错误的工具。它可以帮助开发者发现以下几种常见的内存问题: 1. 越界访问:检测数组或缓冲区的越界读写。 使用后释放:检测对已经释放的内存的访问。 3. 内存泄漏:检测未释放的内存,帮助识别内存泄漏问题。 双重释放:检测对同一内存块的多次释放。 使用 -fsanitize=address 编译程序时,编译器会插入额外的检查代码,以便在运行时捕获这些错误。这样可以在开发和测试阶段更早地发现潜在的内存问题,从而提高代码的稳定性和安全性。
- 查看是否包含调试信息
1)如果输出中有 .debug_* 段,表示包含调试符号 readelf -S /path/to/executable | grep debug objdump -h /path/to/executable | grep debug 2)如果输出中有未被剥离的符号(即没有 "U" 标记的符号),则可能包含调试信息 nm /path/to/executable 注: objdump: 用于显示二进制文件的汇编代码、符号表、段信息等。 可以反汇编可执行文件,查看其机器代码对应的汇编指令。 示例用法:objdump -d <filename> 可以反汇编指定的可执行文件。 nm: 用于列出目标文件中的符号(函数、变量等)。 可以显示符号的地址、类型和名称,帮助开发者了解程序中使用了哪些符号。 示例用法:nm <filename> 可以列出指定文件中的所有符号。 readelf: 用于显示 ELF 文件的结构和内容,包括头信息、节区、段、符号表等。 提供了比 objdump 更详细的 ELF 文件信息。 示例用法:readelf -a <filename> 可以显示指定 ELF 文件的所有信息。
- bt命令
bt 是 "backtrace" 的缩写。它用于显示当前程序的调用栈(call stack),即程序在崩溃时的函数调用顺序。 (gdb) bt
- 调试core文件
gdb 程序 core文件 (gdb) bt 注意: 1)ulimit -c unlimited 2)cat /proc/sys/kernel/core_pattern |/usr/share/apport/apport %p %s %c %d %P %E 核心转储的生成模式被设置为通过 apport 处理。这意味着当程序崩溃时,核心转储不会直接生成为文件,而是由 apport 收集并处理,通常用于报告崩溃。 systemctl stop apport停止,或者 echo "core" | sudo tee /proc/sys/kernel/core_pattern 将核心转储的生成模式更改为默认设置 echo "core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern kernel.core_pattern = core.%e.%p(/etc/sysctl.conf) 核心转储文件格式 1. 基本格式: core:生成的核心文件将命名为 core,并存储在当前工作目录中。 core.%e:生成的核心文件将命名为 core.<程序名>,其中 <程序名> 是崩溃程序的名称。 core.%p:生成的核心文件将命名为 core.<进程ID>,其中 <进程ID> 是崩溃程序的进程ID。 2. 组合格式: core.%e.%p:生成的核心文件将命名为 core.<程序名>.<进程ID>。 core.%e.%p.%h.%t:生成的核心文件将命名为 core.<程序名>.<进程ID>.<主机名>.<时间戳>,其中时间戳是崩溃发生的时间。 3. 自定义路径: /tmp/core.%e.%p:将核心文件存储在 /tmp 目录下,命名为 core.<程序名>.<进程ID>。
- 其它
# 清除页面缓存 sh -c "echo 1 > /proc/sys/vm/drop_caches" # 清除目录项缓存(dentries)和 inode 缓存 sh -c "echo 2 > /proc/sys/vm/drop_caches" # 清除页面缓存、目录项缓存(dentries)和 inode 缓存 sh -c "echo 3 > /proc/sys/vm/drop_caches" valgrind --tool=massif ./your_program ms_print massif.out.<pid> heaptrack ./your_program heaptrack_gui heaptrack.<pid>.gz
- 参考
https://www.cnblogs.com/lvdongjie/p/8994092.html https://blog.bruceding.me/464.html