Project

General

Profile

Gdb

  1. 打开编译选项
    makefile:g++ -g -O0
    cmake:set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0")
    
  2. 常用命令
    使用GDB打印/查看大型代码库文件中的变量,可以按照以下步骤进行:
    
        首先,确保已经安装了GDB调试器,并且代码库已经编译为可调试的可执行文件。
        打开终端,进入代码库所在的目录,并运行可执行文件的命令。
        在终端中输入gdb 可执行文件名,进入GDB调试环境。
        在GDB命令行中,可以使用以下命令来打印/查看变量:
            使用break 行号或break 函数名设置断点,以便在特定位置停下来查看变量。
            使用run命令运行程序,直到遇到断点位置。
            使用print 变量名命令打印变量的值。
            使用display 变量名命令持续打印变量的值,每次程序停下来都会显示。
            使用info locals命令查看当前作用域内的所有局部变量。
            使用info globals命令查看全局变量。
            使用info variables命令查看当前作用域内的所有变量。
            使用backtrace命令查看函数调用栈,可以查看函数调用关系。
            使用step命令逐行执行代码,并进入函数内部。
            使用next命令逐行执行代码,但不进入函数内部。
            使用continue命令继续执行代码,直到下一个断点或程序结束。
    
        在GDB调试环境中,可以根据需要重复执行上述命令,以查看和调试代码库中的变量。
    
  3. 进阶命令
    (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 编译程序时,编译器会插入额外的检查代码,以便在运行时捕获这些错误。这样可以在开发和测试阶段更早地发现潜在的内存问题,从而提高代码的稳定性和安全性。
    
  4. 查看是否包含调试信息
    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 文件的所有信息。
    
  5. bt命令
    bt 是 "backtrace" 的缩写。它用于显示当前程序的调用栈(call stack),即程序在崩溃时的函数调用顺序。
    (gdb) bt
    
  6. 调试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>。
    
  7. 其它
    # 清除页面缓存
    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
    
  8. 参考
    https://www.cnblogs.com/lvdongjie/p/8994092.html
    https://blog.bruceding.me/464.html