第二章 调试前的必会知识
4. 获取内核的进程转储
4.1 举例
ulimit -c 1073741824
#设置内核转储文件上限- 新建测试文件
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *a=NULL;
*a=0x1;
return 0;
}
- 编译:
gcc 14_a.c -g
#注意加上-g选项保存调试信息 ./a.out
#运行,,正常应该报错file *core
:在当前目录下查看生成的内核转储文件gdb -c core ./a.out
:用GDB调试生成的内核转储文件,出现如下信息
[New LWP 3096]
Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00000000004004e6 in main () at 14_a.c:7
7 *a=0x1;
(gdb) q
上述信息指示第7行在访问a地址的时候出现错误
4.2 启用整个系统的内核转储功能
- 修改会添加 /etc/profie:
ulimit -S -c unlimited > /dev/null 2>&1
DAEMON_COREFILEFILE='unlimited'
- 在文件/etc/sysctl.conf中添加:
fs.suid_dumpable=1
- 重启系统
4.3 利用内核转储掩码排除共享内存
- 见书本
5. 调试器(GDB)的基本使用方法(之一)
gcc -wall -02 -werror -g 源文件
- -g:保存调试信息
- -werror:在警告发生时当做错误来处理
./a.out ;ls *core
#运行并查看内核转储文件gdb -c core ./a.out
:用GDB调试生成的内核转储文件,出现如下信息b main
:在main函数出设置断点info braek
:查看断点run -a
:运行程序start
:同上backtrace full -N
:在端点处显示最后的N个栈帧print
:显示局部变量info reg
:显示寄存器值p/c $eax
:ASCII显示寄存器的值
- u:无符号十进制
- o:八进制
- t:二进制
- d:十进制
x/10i $pc
:显示地址pc处的10条汇编代码
- x:16进制显示pc处的值
- 同上
disassemble
:反汇编当前的整个函数disassemble 程序计数器
:反汇编程序计数器所在函数的整个函数disassemble 开始地址 结束地址
:反汇编从开始地址到结束地址之间的部分next
:执行下一步step
:执行到函数内部nexti
:逐条执行汇编指令continue
:继续执行,加数字如 c 5表遇到5次断点不停止watch <表达式>
:常量或变量发生变化时暂停运行awatch <表达式>
:被访问、改变时暂停访问rwatch <表达式>
:被访问时暂停运行
awatch short_output
:short_output被访问时暂停运行
delete b
:删除断点和监视点set variable <变量>=<表达式>
:如set variable a=1,把a的值改为1generate-core-file
:生成内核转储文件gcore 'pidof emacs'
:在命令行直接生成内核转储文件
6. 调试器(GDB)的基本使用方法(之二)
attach pid
:attach到进程ID为pid的进程上break 断点 if 条件
:条件断点ignore 断点编号 条件
:反复执行step/stepi/next/netxi/continue 次数
:指定命令执行的次数finish
:执行完当前函数后暂停until <地址>
:执行完当前代码块后跳出循环,常用于跳出循环disable/enable 断点
:临时删除/启用断点
_7. 调试器(GDB)的基本使用方法(之三)
p $
:显示最后一次print输出的值show walue
:显示历史中print的最后十条值 +