GDB 符号检视三件套:`ptype` / `info variables` / `info functions`

调试 NuttX/Vela 这类嵌入式系统时,光会 btprint 远远不够。真正能让你在陌生代码里快速定位、看清结构、批量布点的,是 GDB 的符号检视命令。本文整理三件最常用的:

  • ptype ------ 看类型长什么样
  • info variables ------ 找全局/静态变量在哪
  • info functions ------ 找函数在哪

它们都不打印运行时值,而是从符号表里捞元数据,速度快、不依赖程序运行状态,特别适合 coredump 离线分析。


一、ptype ------ 查看类型定义

ptype(print type)只打印类型的结构,不打印变量的值。

常见用法

命令 作用
ptype <var> 查看变量的类型定义
ptype <type> 直接查看某个类型(struct/union/enum/typedef)
ptype/o <struct> 显示 offset 和 size(调试内存布局神器
ptype/m <class> 只显示成员,不展开继承(C++)
ptype <expr> 查看任意表达式的类型,如 ptype foo->bar[2].baz

它能干什么

  1. 看 struct 字段布局

    复制代码
    (gdb) ptype/o struct task_struct
    /* offset    |  size */  type = struct task_struct {
    /*    0      |     8 */    long state;
    /*    8      |     8 */    void *stack;
    ...

    排查内存对齐、padding、字段偏移问题时,比 offsetof 直观得多。

  2. typedef 穿透ptype size_t 告诉你它实际是 unsigned long,避免猜类型。

  3. enum 取值ptype enum state_e 一次性列出所有枚举值。

  4. 函数签名ptype my_func 显示返回值和参数类型,特别适合调试函数指针。

  5. C++ 类层次ptype 完整展开(含虚函数表、继承),ptype/m 只看自身成员。

  6. 判断指针 vs 数组 :源码里 int a[10]int *a 看着像,ptype 一眼分清。

与近邻命令对比

  • print x / p x → 看
  • ptype x → 看类型
  • whatis x → 类型简版(不展开 struct 成员,一行输出)
  • info types <regex> → 在符号表里搜类型名

排查 crash 看 coredump 时,ptype/o 配合 p *(struct foo *)0xaddr 是定位「字段偏移踩错 / 结构体版本不一致」的常用组合。


二、info variables ------ 查找全局/静态变量

info variables符号表 里捞全局和静态变量,不打印值,只告诉你叫什么、在哪、什么类型

基本用法

命令 作用
info variables 列出所有全局和静态变量(通常很长)
info variables <regex> 用正则过滤,最常用
info variables -n 只看非调试符号(minimal symbols)

典型场景

  1. 找变量定义在哪

    复制代码
    (gdb) info variables ^g_task_list$
    File kernel/sched/task.c:
    42:  struct list_head g_task_list;

    直接告诉你文件:行号 + 类型,比翻代码快。

  2. 模糊搜索 :忘了变量全名,info variables uart.*config 一搜就出。

  3. 看驱动注册了哪些静态结构info variables _ops$ 找所有以 _ops 结尾的(file_operationsuart_ops 之类)。

  4. 核对链接产物 :某个 static 变量是否真的进了最终镜像。

与近邻命令对比

命令 看什么
info variables <re> 全局/静态变量符号
info functions <re> 函数符号
info types <re> 类型名(struct/typedef/enum)
info address <sym> 单个符号的地址
info symbol <addr> 反查:这个地址属于哪个符号
print &var 拿到变量地址(要先知道名字)
ptype var 看类型定义

⚠️ 局部变量不会 出现在 info variables 里 ------ 那是栈上的,要用 info locals / info args 看当前帧。


三、info functions ------ 查找函数符号

info functionsinfo variables 是一对,专门搜函数

基本用法

命令 作用
info functions 列出所有函数(通常爆屏,慎用)
info functions <regex> 正则过滤,最常用
info functions -n 只看非调试符号
info functions -q <re> quiet 模式,不打印文件分组头
info functions -t <type> <re> 按返回类型过滤(较新 GDB)

典型场景

  1. 找函数定义在哪

    复制代码
    (gdb) info functions ^uart_open$
    File drivers/serial/uart.c:
    128:  int uart_open(struct file *filep);

    直接给文件:行号 + 完整签名

  2. 模糊搜索info functions .*_init$ 列出所有 _init 结尾的初始化函数。

  3. 看某模块对外接口info functions ^uart_ 列出 uart 子系统所有函数。

  4. C++ 重载/模板:所有重载版本一并列出,签名各异,方便挑你要打断点的那个。

  5. 静态函数也能找到(只要带调试符号),不像 grep 还要管作用域。

调试组合拳

复制代码
(gdb) info functions probe          # 模糊找入口
(gdb) b *uart_probe                 # 在函数入口下断点
(gdb) info address uart_probe       # 拿函数地址(用于函数指针比对)
(gdb) disas uart_probe              # 反汇编
(gdb) ptype uart_probe              # 看签名
(gdb) rbreak ^uart_                 # 给所有 uart_ 开头函数下断点(批量)

与近邻命令对比

命令 用途
info functions <re> 列出匹配的函数符号
rbreak <re> 给匹配的函数批量下断点(破坏性,会真下断)
disas <func> 反汇编整个函数体
info line <func> 看函数起始行号 → 地址映射
ptype <func> 看函数类型签名(返回值/参数)

四、三件套联动:crash 离线分析的标准流程

假设 coredump 里看到一个陌生符号 uart_priv 出现在栈上:

复制代码
(gdb) info variables ^uart_priv$       # 1. 在哪定义?
File drivers/serial/uart.c:
89:  static struct uart_priv_s uart_priv;

(gdb) ptype uart_priv                  # 2. 类型长啥样?
type = struct uart_priv_s {
    int state;
    struct circbuf rx;
    ...
}

(gdb) ptype/o struct uart_priv_s       # 3. 字段偏移确认
/* offset | size */ ...

(gdb) p uart_priv                      # 4. 当前值是什么
$1 = {state = 2, rx = {...}, ...}

(gdb) info address uart_priv           # 5. 物理地址(对比 dump)
Symbol "uart_priv" is static at address 0x20001234.

再配合 info functions ^uart_ 把整套接口列出来,整个驱动的轮廓 5 分钟内就能摸清。


五、要点回顾

你想知道... 用什么
这个类型长什么样?字段偏移多少? ptype / ptype/o
这个全局变量定义在哪个文件? info variables <regex>
这个函数定义在哪?签名是什么? info functions <regex>
这个地址是哪个符号? info symbol <addr>
这个符号的地址是多少? info address <sym>

三件套的共性:只读符号表,不依赖运行时。哪怕程序根本没跑起来,只要 ELF 带调试信息,就能用。这是它们在 coredump 分析里特别趁手的原因。


References

相关推荐
CC城子5 天前
嵌入式Linux宕机问题GDB调试(一)
gdb·嵌入式软件
CC城子5 天前
嵌入式Linux宕机问题GDB调试(二)
linux·gdb
故事还在继续吗17 天前
常见的导致 coredump 的原因
开发语言·gdb
C咖咖21 天前
Linux 下使用 GDB 调试 C++ 的全面总结
linux·gdb·调试
lightqjx1 个月前
【Linux】Linux工具(yum、vim、gcc/g++、make/makefile、gdb)的详细介绍
linux·vim·gdb·yum·gcc/g++·linux工具·make/makefile
爱凤的小光1 个月前
GDB调试技巧与指令完全指南---个人学习篇
shell·gdb
kali-Myon1 个月前
CTFshow-Pwn142-Off-by-One(堆块重叠)
c语言·数据结构·安全·gdb·pwn·ctf·
花花少年2 个月前
在嵌入式设备中快速体验gdb调试
gdb
Qt程序员2 个月前
深入理解:GDB调试器的工作原理
linux·c++·gdb·调试器