一、 发生段错误情况分类
- 访问不存在的内存
- 访问系统保护的内存
- 指针操作越界(包括数组)
二、GDB调试出现Core dump 出现的汇编代码
GDB 显示汇编
GDB 如何通过 layout asm/src
显示汇编、源代码窗口
vscode配置gdb显示汇编
vscode 虽然集成了,但是不能显示汇编窗口那么方便, 需要在调试控制台使用 -exec 指令执行查看汇编, -exec disassemble /m
三、 三种场景,三种用法
- 在编写过程中,程序启动就出现
core dump
, 直接使用 gdb 调试即可 - 代码写完之后运行一段时间之后, 或者是一些不确定条件导致的
core dump
, 编译加-g
- 同2, 生产环境 不加
-g
, 特定条件触发core dump
四、 测试代码如下
#include <stdio.h>
void test(int *ptr, int val) {
//对空指针指向的内存区域写,会发生段错误
ptr[10] = val;
}
int main()
{
int *null_ptr = NULL;
//*null_ptr = 10;
int val = 10;
test(null_ptr, val);
return 0;
}
gdb 调试 core 文件
代码写完之后运行一段时间之后, 或者是一些不确定条件导致的 core dump
# 1. 首先, 在编译代码的时候需要加上 `-g` 参数;
# 2. ulimit -c #查看是否开启core文件, 0则不会生成core文件
# 3. ulimit -c [size] #生成限制core文件大小
ulimit -c unlimited #生成core文件不受大小限制, 临时设置, 永久设置在 /etc/security/limits.conf 填写以下两行
@root soft core unlimited
@root hard core unlimited
# 4. 指定core文件保存位置和文件命名方式
`echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern`
# 5. 指定core文件生成是否添加pid作为扩展
`echo 1 > /proc/sys/kernel/core_uses_pid`
# 6. mkdir /corefile 目录
# 7. gcc -g xx.c && a.out
# 8. 会在/corefile 下看生成的 .core 文件
# 9. gdb -core /corefile/xxx.core
# 10 进入gdb之后, 执行 file a.out
# 11. where/bt
# 10. 分析, 可以查看到对应的栈, 参数传递信息等
objdump 排查 core dump
在 报错core dump
的时候, 内核中会提示如下错误
[ 6629.248711] a.out[2891]: segfault at 28 ip 000000000040054c sp 00007fffd1e9ee20 error 6 in a.out[400000+1000]
[ 6629.248716] Code: 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 f3 0f 1e fa eb 8a 55 48 89 e5 48 89 7d f8 89 75 f4 48 8b 45 f8 48 8d 50 28 8b 45 f4 <89> 02 90 5d c3 55 48 89 e5 48 83 ec 10 48 c7 45 f8 00 00 00 00 c7
其中 打印出来的二进制code就是 编译过后的 二进制执行文件, 即a.out中的内容, objdump 就是将 a.out 二进制文件反汇编成汇编语言, 然后通过汇编语言定位问题
X86汇编代码说明链接:https://www.cnblogs.com/han-guang-xue/p/16525292.html
# 1. 生成汇编, objdump -d a.out > a.outDump
# 2. 查看发生的错误位置 grep -n -A 10 -B 10 "40054c" a.outDump
# 3. 根据以下代码能很明确的定位到代码出现的位置:40054c, 就是 *ptr[10] = 10; 报错
# 4. 问题1: 无法查看参数传递
# 5. 问题2: 如果优化编译的话,看汇编对比源码会比较困难
97-0000000000400536 <test>:
98- 400536: 55 push %rbp ; 将地址 0x400536 压栈并记录到寄存器 rbp 中
99- 400537: 48 89 e5 mov %rsp,%rbp
100- 40053a: 48 89 7d f8 mov %rdi,-0x8(%rbp) ; 将 0x400536 - 0x08 地址指向 rdi寄存器中的值 *ptr = NULL;
101- 40053e: 89 75 f4 mov %esi,-0xc(%rbp) ; 将 0x400536 - 0x0c 地址指向 esi寄存器中的值 val = 10;
102- 400541: 48 8b 45 f8 mov -0x8(%rbp),%rax ; 设置rax地址指向 rdi寄存器地址指向的值
103- 400545: 48 8d 50 28 lea 0x28(%rax),%rdx ; 计算器偏移地址, 就是 0x28 = 40 = 10*4; 也就是 rdx = rax+40, 既ptr[10];
104- 400549: 8b 45 f4 mov -0xc(%rbp),%eax ; 将esi寄存器地址指向的值,10,保存到寄存器eax中
105: 40054c: 89 02 mov %eax,(%rdx) ; 设置 rdx 寄存器的地址指向值 eax, 既 ptr[10] = val;
106- 40054e: 90 nop ; 无操作
107- 40054f: 5d pop %rbp ; 将rbp 出栈
108- 400550: c3 retq ; 将方法test推出栈, 并跳回原来执行的地方
109-
110-0000000000400551 <main>:
111- 400551: 55 push %rbp ; 将地址 0x400551 压栈并记录到寄存器 rbp 中
112- 400552: 48 89 e5 mov %rsp,%rbp ; 将 0x400551 记录到 rsp(用于堆栈指针) 中
113- 400555: 48 83 ec 10 sub $0x10,%rsp ; 暂时没搞明白
114- 400559: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp) ; 设置 0x400551 - 0x08 值为 0x0, *null_ptr = NULL;
115- 400560: 00
116- 400561: c7 45 f4 0a 00 00 00 movl $0xa,-0xc(%rbp) ; 设置 0x400551 - 0x0c 值为 0xa, val = 10;
117- 400568: 8b 55 f4 mov -0xc(%rbp),%edx ; 设置 edx 指向地址 0x400551 - 0x0c, 该地址指向值 10
118- 40056b: 48 8b 45 f8 mov -0x8(%rbp),%rax ; 设置 rax 指向地址 0x400551 - 0x08, 该地址指向值 0
119- 40056f: 89 d6 mov %edx,%esi ; 将edx地址保存到esi中
120- 400571: 48 89 c7 mov %rax,%rdi ; 将rax地址保存到rdi中
121- 400574: e8 bd ff ff ff callq 400536 <test> ; callq 跳到指定地址执行
https://blog.csdn.net/qq_29350001/article/details/53780697
标签:10,00,针对,48,错误,core,mov,rbp,排查 From: https://www.cnblogs.com/han-guang-xue/p/16932168.html