gdb命令

gdb 命令 #

gdb(GNU 调试器)是一个功能强大的调试工具,用于调试 C、C++和其他编程语言编写的程序。它允许开发者检查程序在运行时的内部状态,设置断点,查看变量值,以及逐步执行代码。

语法 #

gdb [选项] [程序 [核心文件/进程ID]]

常用选项 #

选项 描述
-h, --help 显示帮助信息
-v, --version 显示版本信息
-q, --quiet 不显示介绍和版权信息
-s 文件 从指定文件读取符号表
-e 程序 指定要执行的程序
-c 文件 指定核心转储文件
-p PID 附加到指定进程 ID
-x 文件 从文件执行 GDB 命令
-d 目录 添加源文件搜索路径
-n, --nx 不执行初始化文件(.gdbinit)
-batch 批处理模式,执行完命令后退出
-cd 目录 将工作目录更改为指定目录
-f, --fullname 输出完整文件名和行号
-b 波特率 设置串行线路的波特率
-tty 设备 使用设备作为程序的标准输入和输出

基本 GDB 命令 #

1. 启动和退出 #

命令 描述
gdb 程序 启动 GDB 并加载程序
gdb -c core 程序 使用核心转储文件启动 GDB
gdb --pid=PID 附加到正在运行的进程
quitq 退出 GDB
kill 终止正在调试的程序

2. 运行和停止 #

命令 描述
runr [参数] 开始执行程序,可选传递命令行参数
start 运行程序,在 main 函数处停止
continuec 继续执行程序
steps 单步执行,进入函数调用
nextn 单步执行,不进入函数调用
finish 执行到当前函数返回
untilu [位置] 执行到指定位置
advance [位置] 继续执行到指定位置
attach 进程ID 附加到正在运行的进程
detach 从当前附加的进程分离

3. 断点和观察点 #

命令 描述
breakb [位置] 在指定位置设置断点
tbreak [位置] 设置临时断点(触发一次后删除)
watch 表达式 设置观察点,当表达式的值改变时停止
rwatch 表达式 设置读观察点,当表达式被读取时停止
awatch 表达式 设置访问观察点,当表达式被读取或写入时停止
catch 事件 在指定事件发生时停止(如异常)
info breakpoints 列出所有断点和观察点
deleted [编号] 删除指定编号的断点或观察点
disable [编号] 禁用指定编号的断点或观察点
enable [编号] 启用指定编号的断点或观察点
clear [位置] 删除指定位置的断点
condition 编号 表达式 为断点添加条件
ignore 编号 次数 忽略断点指定次数

4. 检查程序状态 #

命令 描述
backtracebt 显示所有栈帧
framef [编号] 选择栈帧
info frame 显示当前栈帧的详细信息
up 选择上一层栈帧
down 选择下一层栈帧
info locals 显示当前栈帧的局部变量
info args 显示当前函数的参数
info registers 显示寄存器的值
disassemble 反汇编当前函数
listl [位置] 显示源代码
printp 表达式 显示表达式的值
display 表达式 每次停止时显示表达式的值
undisplay [编号] 取消自动显示
whatis 表达式 显示表达式的类型
ptype 表达式 显示表达式的详细类型信息
info threads 显示所有线程
thread 编号 切换到指定线程

5. 修改程序状态 #

命令 描述
set variable 变量=值 修改变量的值
set 表达式=值 修改表达式的值
return [表达式] 强制从当前函数返回
jump 位置 跳转到指定位置执行
signal 信号 向程序发送信号
call 函数(参数) 调用函数

6. 其他命令 #

命令 描述
shell 命令 执行 shell 命令
source 文件 从文件执行 GDB 命令
define 命令名 定义新的 GDB 命令
document 命令名 为自定义命令添加文档
set 参数 值 设置 GDB 参数
show 参数 显示 GDB 参数的值
help [命令] 显示帮助信息
apropos 关键字 搜索相关命令
save breakpoints 文件 保存断点到文件
save history 文件 保存命令历史到文件

位置指定方式 #

在 GDB 中,可以通过多种方式指定位置:

  1. 函数名break main
  2. 行号break 42
  3. 文件:行号break file.c:42
  4. 文件:函数break file.c:main
  5. +偏移break +1(当前行之后的第一行)
  6. -偏移break -1(当前行之前的第一行)
  7. 地址break *0x12345678
  8. 偏移量break *main+20

高级用法 #

1. 条件断点 #

break 位置 if 条件

例如:

break 42 if i == 100

2. 命令列表 #

可以为断点指定一系列命令,当断点触发时自动执行:

break 位置
commands
命令1
命令2
...
end

例如:

break 42
commands
print i
print j
continue
end

3. 捕获异常 #

catch throw        # 捕获所有C++异常
catch catch        # 捕获C++异常处理
catch assert       # 捕获失败的断言
catch syscall      # 捕获系统调用

4. 打印设置 #

set print array on           # 漂亮地打印数组
set print pretty on          # 漂亮地打印结构
set print object on          # 显示对象的派生类型
set print static-members off # 不显示静态成员
set print elements 100       # 限制显示的数组元素数量

5. 自定义 GDB 命令 #

define 命令名
  命令1
  命令2
  ...
end

例如:

define plist
  set $n = $arg0->next
  while $n != 0
    print *$n
    set $n = $n->next
  end
end

6. 调试多线程程序 #

info threads                # 显示所有线程
thread 编号                  # 切换到指定线程
set scheduler-locking on    # 只运行当前线程
set scheduler-locking off   # 允许所有线程运行
set scheduler-locking step  # 在单步执行时只运行当前线程
thread apply all 命令        # 对所有线程应用命令

7. 调试共享库 #

info sharedlibrary          # 显示已加载的共享库
set auto-solib-add on       # 自动加载共享库符号
sharedlibrary 正则表达式      # 加载匹配的共享库符号

8. 调试核心转储 #

gdb 程序 core               # 使用核心转储文件启动GDB
generate-core-file         # 为当前程序生成核心转储

9. 远程调试 #

target remote 主机:端口      # 连接到远程GDB服务器

10. 反向调试 #

record                     # 开始记录执行历史
record stop                # 停止记录
reverse-continue           # 反向继续执行
reverse-step               # 反向单步执行
reverse-next               # 反向单步执行(不进入函数)
reverse-finish             # 反向执行到函数调用点

实用示例 #

1. 基本调试会话 #

$ gdb ./myprogram
(gdb) break main
(gdb) run
(gdb) next
(gdb) print variable
(gdb) continue
(gdb) quit

2. 调试段错误 #

$ gdb ./myprogram
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
(gdb) backtrace
(gdb) frame 2
(gdb) list
(gdb) print *ptr

3. 条件断点 #

(gdb) break 42 if i == 100
(gdb) run

4. 观察变量 #

(gdb) watch global_var
(gdb) run
Hardware watchpoint 1: global_var
Old value = 0
New value = 42

5. 检查数据结构 #

(gdb) print *node
(gdb) print node->next->data
(gdb) ptype struct Node

6. 调试多线程程序 #

(gdb) info threads
(gdb) thread 2
(gdb) bt
(gdb) thread apply all bt

7. 使用断点命令 #

(gdb) break 42
(gdb) commands
> silent
> print i
> print j
> continue
> end
(gdb) run

8. 调试内存问题 #

(gdb) set environment MALLOC_CHECK_=2
(gdb) run

9. 保存和恢复断点 #

(gdb) save breakpoints breakpoints.txt
(gdb) source breakpoints.txt

10. 使用 GDB 脚本 #

创建script.gdb文件:

set pagination off
break main
run
next 5
print variable
continue
quit

然后运行:

$ gdb -x script.gdb ./myprogram

调试 C++特性 #

1. 设置断点在重载函数 #

(gdb) break 'MyClass::method(int)'
(gdb) break 'MyClass::method(std::string)'

2. 查看 STL 容器 #

(gdb) print myvector
(gdb) print myvector._M_impl._M_start[0]
(gdb) print mymap['key']

3. 调试模板 #

(gdb) break 'MyTemplate<int>::method'

4. 查看虚函数表 #

(gdb) p *((void ***)obj)[0]@10

调试内存问题 #

1. 检查内存泄漏 #

GDB 本身不是内存泄漏检测工具,但可以与 Valgrind 等工具结合使用:

$ valgrind --leak-check=full --vgdb=yes --vgdb-error=0 ./myprogram
$ gdb ./myprogram
(gdb) target remote | /usr/lib/valgrind/../../bin/vgdb

2. 检查野指针 #

(gdb) watch *pointer
(gdb) run

3. 检查缓冲区溢出 #

(gdb) break function
(gdb) run
(gdb) print buffer
(gdb) x/20x buffer

常见问题排查 #

1. 没有调试信息 #

错误:

No debugging symbols found in ./myprogram

解决方案:

# 使用-g编译程序
gcc -g -o myprogram myprogram.c

2. 源代码找不到 #

错误:

No such file or directory.

解决方案:

(gdb) directory /path/to/source

3. 优化代码调试困难 #

问题:变量值不正确或行号混乱

解决方案:

# 编译时禁用优化
gcc -g -O0 -o myprogram myprogram.c

4. 无法设置断点 #

错误:

Function "function" not defined.

解决方案:

# 确保函数名正确,对于C++可能需要使用完整的名称
(gdb) break Namespace::Class::function

5. 调试共享库 #

问题:无法看到共享库中的符号

解决方案:

(gdb) set auto-solib-add on
(gdb) sharedlibrary

GDB 图形界面 #

1. GDB TUI 模式 #

GDB 内置的文本用户界面:

(gdb) tui enable

或启动时使用:

gdb -tui ./myprogram

TUI 常用命令:

(gdb) layout src      # 显示源代码窗口
(gdb) layout asm      # 显示汇编窗口
(gdb) layout split    # 同时显示源代码和汇编
(gdb) layout regs     # 显示寄存器窗口
(gdb) focus cmd       # 焦点切换到命令窗口
(gdb) focus src       # 焦点切换到源代码窗口
(gdb) refresh         # 刷新显示

2. 外部前端 #

  • DDD:数据显示调试器,提供数据结构可视化
  • Eclipse:通过 CDT 插件提供 GDB 集成
  • Visual Studio Code:通过扩展提供 GDB 支持
  • Emacs:通过 GUD 模式集成 GDB
  • gdbgui:基于浏览器的 GDB 前端

GDB 配置文件 #

GDB 启动时会读取以下配置文件:

  1. /etc/gdb/gdbinit:系统范围的初始化文件
  2. ~/.gdbinit:用户主目录中的初始化文件
  3. ./.gdbinit:当前目录中的初始化文件

常用的.gdbinit配置:

# 启用漂亮打印
set print pretty on
set print array on
set print array-indexes on

# 禁用分页
set pagination off

# 保存历史命令
set history save on
set history filename ~/.gdb_history
set history size 10000

# 自动反汇编
define hook-stop
  disassemble $pc-8, $pc+16
end

# 自定义命令
define phead
  print *(void **)($arg0)
end

与其他调试工具的比较 #

工具 优点 缺点 适用场景
GDB 功能强大、灵活、支持多种语言 命令行界面学习曲线陡峭 C/C++程序、系统级调试
LLDB 现代设计、C++API、与 Clang 集成 某些平台支持不如 GDB macOS/iOS 开发、使用 LLVM 工具链
Visual Studio 调试器 图形界面、易用性高 仅限 Windows 平台 Windows 应用程序开发
Valgrind 内存错误检测、性能分析 运行速度慢 内存泄漏和访问错误检测
strace/ltrace 轻量级、跟踪系统调用和库调用 功能有限 快速诊断系统交互问题

提示和技巧 #

1. 使用简写命令 #

大多数 GDB 命令都有简写形式:

  • b 代替 break
  • c 代替 continue
  • n 代替 next
  • s 代替 step
  • p 代替 print
  • bt 代替 backtrace

2. 使用命令历史 #

  • 上下箭头键浏览历史命令
  • Ctrl+R 搜索历史命令

3. 使用 Python 扩展 #

GDB 支持 Python 脚本,可以扩展功能:

# 在.gdbinit中
python
def print_list(val):
    result = []
    node = val
    while node != 0:
        result.append(node['data'])
        node = node['next']
    return result

class LinkedListPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        return "LinkedList with elements: " + str(print_list(self.val))

def lookup_type(val):
    if str(val.type) == 'LinkedList *':
        return LinkedListPrinter(val)
    return None

gdb.pretty_printers.append(lookup_type)
end

4. 使用断点条件和命令 #

(gdb) break file.c:123 if i > 100
(gdb) commands
> silent
> print i
> print j
> continue
> end

5. 使用宏 #

(gdb) macro expand MACRO(arg)

6. 使用反向调试 #

(gdb) record
(gdb) continue
# 程序崩溃
(gdb) reverse-stepi
(gdb) reverse-next

7. 保存调试会话 #

(gdb) save breakpoints bp.txt
(gdb) save history history.txt

8. 使用 GDB 仪表板 #

安装 GDB 仪表板(一个增强的 GDB 界面):

wget -P ~ https://git.io/.gdbinit

9. 调试优化代码 #

(gdb) set debug-file-directory /path/to/debug/files
(gdb) set substitute-path /build/path /local/path

10. 使用 GDB 脚本自动化调试 #

gdb -batch -ex "run" -ex "bt" -ex "quit" ./myprogram

扩展阅读 #