linux下段错误调试
# 段错误
一般来说,段错误就是指访问的内存超出了系统所给这个程序的内存空间。
通常这个值是由 gdtr
来保存的,他是一个 48 位的寄存器,其中的 32 位是保存由它指向的 gdt表
,后 13 位保存相应于 gdt
的下标,最后 3 位包括了程序是否在内存中以及程序的在 cpu 中的运行级别。指向的 gdt
是由以 64 位为一个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。
一旦程序发生了越界访问,cpu 就会产生相应的异常保护,于是 segmentation fault
就出现了。
简而言之,产生段错误就是访问了错误的内存段,一般是你没有权限,或者根本就不存在对应的物理内存,尤其常见的是访问 0 地址。
# gdb查找段错误
使用 gdb
调试需要带有调试信息的可执行程序,编译的时候需要加上 -g -rdynamic
参数。
- 控制台 gdb 启动应用,
gdb ./app
,然后run
跑起来 - 查看出现段错错误时打印的信息进行分析
- 使用
nm
命令列出二进制文件中的符号表,包括符号地址、符号类型、符号名等,这样可以帮助定位在哪里发生了段错误 - 使用
ldd
命令查看二进制程序的共享链接库依赖,包括库的名称、起始地址,这样可以确定段错误到底是发生在了自己的程序中还是依赖的共享库中 - 使用
dmesg
命令可以查看发生段错误的程序名称、引起段错误发生的内存地址、指令指针地址、堆栈指针地址、错误代码、错误原因等 - 使用
addr2line
打印出发生错误的文件和行号
# addr2line -e '可执行文件名' 'dmesg打印的地址'
addr2line -e a.out 0x8043db
1
2
2
- 终极大法
printf
。。。
# core file
想让系统在信号中断造成的错误时转储 core
文件,需要使用 ulimit
进行设置
# 查看 core file size
ulimit -c
# 开启无限制转储
ulimit -c unlimited
# 关闭转储
ulimit -c 0
# num 为最多转储的core文件数
ulimit -c num
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
开始 core
文件转储之后,应用程序运行出现 segmentation fault
时就会产生 core
文件,名字一般是 core.进程号
或者 core
,保存在该应用程序对应的目录下。
注:
/proc/sys/kernel/core_uses_pid
可以控制产生的core
文件的名字是否添加pid
作为扩展,如果添加则文件的内容为1
,否则为0
。
gdb -c core.pid ./app_name
1
进入 gdb 调试模式后,输入 where
或者 bt
查看出错的信息
一般的解决思路如下:
- 进入 GDB 运行程序直到程序出错
- 查看出错的代码段的行数
- 对出现问题行的前一行设置断点(
break [行数]
)并监视该代码段涉及的变量(watch [变量名]
) - 如果涉及递归调用,在运行过程中需要经常查看堆栈列表 (
bt/backtrace
) 避免堆栈溢出 - 然后就可以开始运行,当到达断点行或监视变量发生改变时就会停下来,这时可以展示被监视的变量 (
dispaly [变量名]
) ,这样然后再单步执行(step
),查看变量是否按照预期在变化
关于GDB调试工具的更多使用方式可以参照: GDB使用教程 (opens new window)
编辑此页 (opens new window)
上次更新: 2023/01/12, 13:48:14