##调试基础
获取core dump(内核转储)文件,保存了问题发生时的状态。
大多数Linux发行版默认情况下关闭了内核转储的功能。通过使用ulimit命令可以查看当前的内核转储功能是否有效。
ulimit -c
0
-c表示内核转储文件的大小限制,为0表示内核转储无效。可以使用ulimit -c ulimited,设为无限制之后,发生问题时进程的内存就可以全部转储到内核转储文件中。
通过file core*文件我们可以查看core文件的相关信息。
例如:
core.7561: ELF 64-bit LSB core file x86-64,version 1(SYSV),SVR4-style,from './a.out'
通过使用gdb ./a.out core.7561启动core文件的调试。
##在专用目录中生成内核储存
在生成core文件时,我们希望指定core文件的所在目录,以及相关的core文件格式,我们可通过sysctl变量kernel.core_pattern设置。假设在/etc/sysctl.conf中这样设置。
cat /etc/sysctl.conf
kernel.core_pattern = /var/core/%t-%e-%p-%c.core
kernel.core_uses_pid = 0
sysctl -p
在这种情况下,就会在/var/core/下生成内核转储文件。
格式说明
|-----%% ----|--------------字符本身----------|
|-----%p ----|--------被转储的进程ID----------|
|-----%u ----|----被转储进程的真实用户ID-------|
|-----%g ----|----被转储进程的真实组ID---------|
|-----%s ----|----引发转储的信号编号-----------|
|-----%t ----|----------转储时刻--------------|
|-----%h ----|-------------主机名-------------|
|-----%e ----|-------------可执行文件名--------|
|-----%c ----|------转储文件的大小上限----------|
##GDB的基本使用方法
1.准备
通过gcc的-g选项生成调试信息。如果使用makefile构建,一般要在CFLAGS中指定-g选项。
2.启动
gdb
3.设置断点
b,断点可以通过函数名,当前文件内的行号来设置,也可以先指定文件名在指定行号,还可以指定与暂停位置的偏移量,或者用地址来设置。
格式:
break 函数名
break 行号
break 文件名:行号
break 文件名:函数名
break +偏移量
break -偏移量
break *地址
例子:
break main
break main.c:10
break +3
break *0x12345678
如果不指定断点位置,默认会在下一行代码上设置断点。通过info break命令可以查看设置好的断点。
4.运行:
run 参数
5.显示栈帧:
bt(backtrace)显示所有的栈帧
bt -N只显示开头N个栈帧
bt full -N只显示最后的N个栈帧
5.显示变量:
print 变量
6.显示寄存器:
info reg(register)可以显示寄存器。通过与p $eax可以查看寄存器里面的值。
显示寄存器可以使用的格式
x 显示为十六进制
d 显示为十进制数
u 显示为无符号十进制数
o 显示为八进制数
t(two) 显示为二进制数
a 地址
c 显示为字符(ASCII)
f 浮点小数
s 显示为字符串
i 显示为机器语言
例子:
p/c $eax 将eax寄存器中的内容以字符方式显示
通过x命令可以显示内存的内容,x/格式 地址
x $eip
x/i $eip显示eip对应地址的汇编指令 。
x/10i $eip 显示eip所指地址开始的10条指令。
7.单步执行
执行源代码中一行的命令为n(next),执行时如果遇到函数,可能会希望执行到函数内部,此时可以使用s(step)。
8.继续运行
c(continue),程序在遇到断点后再次停止运行。如果没有断点,就会一直运行到结束。
9.监视点
在大型软件或大量使用指针的程序中,很难弄清变量在什么地方被改变。要想找到变量在何处被改变,可以使用watch命令。
watch <表达式> 表达式发生变化是暂停运行。
10.删除断点和监视点
d(delete) <编号>此处的编号我们可以通过使用info b来查看断点的编号
获取core dump(内核转储)文件,保存了问题发生时的状态。
大多数Linux发行版默认情况下关闭了内核转储的功能。通过使用ulimit命令可以查看当前的内核转储功能是否有效。
ulimit -c
0
-c表示内核转储文件的大小限制,为0表示内核转储无效。可以使用ulimit -c ulimited,设为无限制之后,发生问题时进程的内存就可以全部转储到内核转储文件中。
通过file core*文件我们可以查看core文件的相关信息。
例如:
core.7561: ELF 64-bit LSB core file x86-64,version 1(SYSV),SVR4-style,from './a.out'
通过使用gdb ./a.out core.7561启动core文件的调试。
##在专用目录中生成内核储存
在生成core文件时,我们希望指定core文件的所在目录,以及相关的core文件格式,我们可通过sysctl变量kernel.core_pattern设置。假设在/etc/sysctl.conf中这样设置。
cat /etc/sysctl.conf
kernel.core_pattern = /var/core/%t-%e-%p-%c.core
kernel.core_uses_pid = 0
sysctl -p
在这种情况下,就会在/var/core/下生成内核转储文件。
格式说明
|-----%% ----|--------------字符本身----------|
|-----%p ----|--------被转储的进程ID----------|
|-----%u ----|----被转储进程的真实用户ID-------|
|-----%g ----|----被转储进程的真实组ID---------|
|-----%s ----|----引发转储的信号编号-----------|
|-----%t ----|----------转储时刻--------------|
|-----%h ----|-------------主机名-------------|
|-----%e ----|-------------可执行文件名--------|
|-----%c ----|------转储文件的大小上限----------|
##GDB的基本使用方法
1.准备
通过gcc的-g选项生成调试信息。如果使用makefile构建,一般要在CFLAGS中指定-g选项。
2.启动
gdb
3.设置断点
b,断点可以通过函数名,当前文件内的行号来设置,也可以先指定文件名在指定行号,还可以指定与暂停位置的偏移量,或者用地址来设置。
格式:
break 函数名
break 行号
break 文件名:行号
break 文件名:函数名
break +偏移量
break -偏移量
break *地址
例子:
break main
break main.c:10
break +3
break *0x12345678
如果不指定断点位置,默认会在下一行代码上设置断点。通过info break命令可以查看设置好的断点。
4.运行:
run 参数
5.显示栈帧:
bt(backtrace)显示所有的栈帧
bt -N只显示开头N个栈帧
bt full -N只显示最后的N个栈帧
5.显示变量:
print 变量
6.显示寄存器:
info reg(register)可以显示寄存器。通过与p $eax可以查看寄存器里面的值。
显示寄存器可以使用的格式
x 显示为十六进制
d 显示为十进制数
u 显示为无符号十进制数
o 显示为八进制数
t(two) 显示为二进制数
a 地址
c 显示为字符(ASCII)
f 浮点小数
s 显示为字符串
i 显示为机器语言
例子:
p/c $eax 将eax寄存器中的内容以字符方式显示
通过x命令可以显示内存的内容,x/格式 地址
x $eip
x/i $eip显示eip对应地址的汇编指令 。
x/10i $eip 显示eip所指地址开始的10条指令。
7.单步执行
执行源代码中一行的命令为n(next),执行时如果遇到函数,可能会希望执行到函数内部,此时可以使用s(step)。
8.继续运行
c(continue),程序在遇到断点后再次停止运行。如果没有断点,就会一直运行到结束。
9.监视点
在大型软件或大量使用指针的程序中,很难弄清变量在什么地方被改变。要想找到变量在何处被改变,可以使用watch命令。
watch <表达式> 表达式发生变化是暂停运行。
10.删除断点和监视点
d(delete) <编号>此处的编号我们可以通过使用info b来查看断点的编号