x命令是GDB中查看内存内容的唯一可靠方式,它可直接解析指针所指地址的数据,如x/16xb p从p指向位置读16字节;而print等命令仅显示指针值本身,不展开内存。

x 命令是唯一可靠的方式,其他命令(如 print)只显示指针值本身,不展开内存内容。
用 x 查看指针指向的起始地址及周边
核心思路是:把指针变量当作地址传给 x,而不是解引用它。比如有 char *p = "hello",直接执行 x/16xb p 就能从 p 指向的位置开始读 16 字节。
- 别写
x/16xb *p—— 这会尝试把*p(即第一个字符'h')当地址用,大概率触发Cannot access memory at address 0x68 - 正确写法是
x/16xb p或更明确地x/16xb &p(查看指针变量自身存储位置)或x/16xb p(查看指针所指内容) - 如果想看指针「前面」的内容(比如怀疑栈溢出覆盖了前几个字),可手动减偏移:
x/8xb p-8
x/ 参数组合怎么选才不翻车
常见误判是单位(u)和格式(f)混用,导致输出长度错乱或数据被错误拼接。
-
x/8xb p:8 个独立字节,最安全,适合观察原始内存布局(如字符串、结构体填充) -
x/4xw p:4 个 4 字节整数,适合看数组或结构体字段(但要注意大小端) -
x/16xc p:16 个字符,含不可见控制符,适合确认字符串边界 - 避免用
x/8xh p查 char 数组——2 字节一组会把相邻字符强行合并成一个值,容易误解
快速定位指针上下文:栈/堆/全局区判断
光看内存不够,得知道这块内存在哪分配的,否则无法判断是否越界或已释放。
- 查指针值本身:
p p,看地址落在哪个段(例如0x7fffffffe000是栈,0x555555559000是堆,0x555555554000附近通常是代码/只读数据) - 查分配来源:
info proc mappings配合地址范围比对,或用bt看调用栈里有没有malloc/strdup等 - 检查是否悬垂:
x/4xb p能读通 ≠ 内存有效;若程序已free(p),GDB 仍可能读出旧数据,需结合watch *p或 ASan 验证
按回车连续查看下一段内存的坑
GDB 的「回车复用上条 x 命令」功能很方便,但默认延续的是「地址+数量+格式+单位」四要素,容易忽略地址没变。
- 执行
x/8xb p后按回车,GDB 实际执行的是x/8xb 0x7fffffffe010(假设上次结束地址是这个),不是x/8xb p+8 - 若想真正「往下走」,必须显式写
x/8xb p+8,或先用set $p = p + 8更新寄存器再x/8xb $p - 状态延续(sticky)只记格式和单位,不记地址——这点很多人栽在调试多级指针时
真正难的不是命令怎么敲,而是每次看到一串十六进制,得立刻反应出:这是字符串尾部?是结构体 padding?还是刚被 memset 覆盖过的残留?这需要结合变量定义、编译选项(比如 -fstack-protector 插入的 Canary)和内存布局反复交叉验证。











