
腾讯一面:生产环境如何使用gdb调试Release发行版本的程序?
这篇文章写不行,重写一次。
一句话描述:

问:如果使用gdb解决core问题
下面是我的回答
假如产生core下面是我解决步骤
假如 一台服务器上20个服务,
我怎么清楚那个服务出现问题
必须明确清楚。
进入 /var/log/core 或者 /var/crash 目录
file <core文件名>
hello: ELF 64-bit LSB executable, x86-64, , stripped
关键字段:not stripped 包含调试符号和调试信息。
关键字段:stripped表示符号表和调试信息已被移除
一般生产Release版本都无调试符号,需要加载
直接找管理员 寻找rpm debug按照包 直接安装,
这个事情让管理员执行,你时间宝贵 外派别人执行。 你只负责定位问题,但是明确告诉管理员 cpu类型
lscpu
lscpu | grep 'Model name' Model name: Intel(R) Xeon(R) Platinum 8255C CPU @ 2.50GHz
Model name: Hygon C86 7285
名称 | 在海光CPU系统中的典型值或特征 | 解释说明 |
|---|---|---|
架构 (Architecture) | x86_64 | 这表明海光CPU采用x86_64指令集,兼容主流的64位操作系统和软件 |
厂商 ID (Vendor ID) | HygonGenuine | 这是识别海光处理器最直接的标志 |
CPU 系列 (CPU family) | 具体数值(如24) | 海光CPU特定的家族编号。 |
型号 (Model) / 型号名称 | 具体数值 / Hygon C86 XXX | 指明CPU的具体型号,例如Hygon C86 7185或7285等 |
疑问 没有调试符号怎么办?
查看所有线程 (gdb) info threads Id Target Id Frame 1 Thread 0x7ffff7fdb740 (LWP 1234) "main" 0x00007ffff7fab4f3 in __libc_start_main () 2 Thread 0x7ffff7fda700 (LWP 1235) "worker" 0x00007ffff7fc1e2d in nanosleep ()
切换到线程2并查看寄存器 (gdb) thread 2 (gdb) info registers
一次性查看所有线程的寄存器状态 (gdb) thread apply all info registers
Thread 1 (Thread 0x7ffff7fdb740 (LWP 1234)): rax 0x0 0 rbx 0x7fffffffe0a8 140737488347304 ...
Thread 2 (Thread 0x7ffff7fda700 (LWP 1235)): rax 0xfffffffffffffdfc -516 rbx 0x7ffff7fda700 140737353928448 ...
问题来了:只有寄存器 怎么和变量结合起来?什么请看使用寄存器呢
隐藏知识:对cpu 而言 每个变量存储寄存器上,寄存器存储变量地址
变量名本质是程序员给某块内存或寄存器起的易记名字
info args | 打印函数参数 |
|---|---|
info locals | 打印当前栈帧的局部变量 |
print variable_name | 打印变量值 |
为什么反汇编(无调试信息)
disassemble → 分析变量对应的寄存器 → 通过寄存器获取值
举例:
通过反汇编分析变量-寄存器关系
# 分析上面的反汇编输出:
# - 变量 a: 存储在 [rbp-4],加载到 edx 寄存器
# - 变量 b: 存储在 [rbp-8],加载到 eax 寄存器
# - 变量 c: 计算结果存储在 eax,然后保存到 [rbp-12]
# 2. 查看当前寄存器值
(gdb) info registers rbp eax edx
rbp 0x7fffffffe0e0 0x7fffffffe0e0
eax 0x1e 30
edx 0xa 10
# 3. 通过寄存器获取变量值
(gdb) print $eax
$1 = 30
(gdb) print $edx
$2 = 10
# 4. 通过内存地址查看变量
(gdb) x/wd $rbp-4 # 查看变量 a (4字节整数)
0x7fffffffe0dc: 10
(gdb) x/wd $rbp-8 # 查看变量 b
0x7fffffffe0d8: 20
(gdb) x/wd $rbp-12 # 查看变量 c
0x7fffffffe0d4: 30
上面操作太复杂了 相关插件
gdb.gdbinit
# 保存到 ~/.gdbinit
define simple
info registers
info locals
info args
where
end
# 使用
(gdb) simple
前面说过 通过core 不能解决问题,
只能发现问题, 必须拿出足够证据证明 为什么core
gdb bt 基本查看core的位置。
请一定相信 当前位置core位置,不考虑多线程是否其他堆栈上。
其实没有那么容易
空指针:
疑问:gdb print 变量 只查看简单变量,遇到复杂的 查看stl 链表,红黑树 复杂结构?
GDB如何优化显示c++ STL数据结构的值 gdb配置打印STL容器脚本pretty printer 参考https://zhuanlan.zhihu.com/p/662099267
引用技术断言错误:
请相信 gdb core 位置一定正确的,但是如何解决 需要业务十分了解
本文重点:变量---地址--寄存器 是隐藏基本知识
为什么这么说 如果gdb 产生10G文件 被禁止后
怎么产生一个文件 记录这些信息呢
Core文件本质上是程序崩溃瞬间的完整内存镜像,包含:
历史文章:
序号 | 知识地图 | 题目 |
|---|---|---|
1 | 网络 | 判断一个端口是否可用 |
2 | 网络 | epoll不支持文件IO,kqueue怎么做到的 |
3 | 并发 | Redis 单线程为什这么快 |
4 | 数据结构 | 什么是跳表(Skip List) |
5 | 数据库 | 如何把一个文件系统目录树存储到数据库 |
6 | 并发 | 从一道面试题谈linux下fork的运行机制 |
7 | 并发 | close-on-exec机制 |
8 | 数据结构 | LRU缓存 |
9 | 分布式 | 什是线性一致性 |