因为执行脚本的时候会自动新启用一个子 bash因此在脚本中设置的ulimit -c unlimited
并不能产生核心转存储文件,需要执行可执行文件之前手动设置一下
ulimit -c unlimited
DEBUG 是在linux下使用dbg的记录,一下的文件是在UBUNTU 16.04上验证通过的
1.通过gcc 的 -g 选项生成调试信息。
gcc -Wall -O2 -g 源文件
2.如果使用Makefile构建,一般要给CFLAGS中指定 -g 选项
CFLAGS = -Wall -O2 -g
CFLAGS = -Wall -Werror -O2 -g
加上 -Werror会在警告发生时,将其当成错误处理
3.如果使用configure脚本生成Makefile文件,可以这样使用。
./configure CFLAGS = "-Wall -O2 -g"
启动
gdb 可执行文件名
可以在函数名和行号等上设置断点,程序运行后,达到断点就会自动暂停运行。此时可以查看时刻的变量值、显示栈帧、重新设置断点或重新运行等。断点命令(break),可以简写为b.
##格式:
break 断点
(gdb) b main
断点可以通过函数名、当前文件内的行号来设置,也可以先指定文件名在指定行号,还可以指定与暂停位置的偏移量,或者地址来设置。
#格式说明:
break 函数名
break 行号
break 文件名:行号
break 文件名:函数名
break +偏移量
break -偏移量
break *地址
例:
在函数处加断点
(gdb)b iseq_compile
在文件名和行号处加断点
(gdb)b compile.c:516
设置偏移量
(gdb)b +3
在某地址处加断点
(gdb)b *0x88116fd6
如果不指定位置,就是在下一行代码上设置断点
(gdb)b
设置好的断点可以通过 info break 查看
andrew@andrew-Thurley:/work/linux-sys/DEBUG/segmentation$ gdb segment
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from segment...done.
(gdb) b main
Breakpoint 1 at 0x4004e1: file segment.c, line 12.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004004e1 in main at segment.c:12
(gdb) b +2
Note: breakpoint 1 also set at pc 0x4004e1.
Breakpoint 2 at 0x4004e1: file segment.c, line 5.
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004004e1 in main at segment.c:12
2 breakpoint keep y 0x00000000004004e1 in main at segment.c:5
(gdb)
##运行
使用run命令开始运行,不加参数直接执行run 就会执行到设置断点的位置后暂停运行。可以简写为 r
##格式
run 参数
run 后面跟的参数,也就是你执行可执行文件后面需要跟的参数
(gdb)run -a
start命令会达到同样的效果。
格式:
start
##显示栈帧
backtrace 命令可以在遇到断点而停止执行时显示栈帧。该命令简写为 bt 。此外,backtrace的别名还有
where 和 info stack(info s)
##格式:
显示所有栈帧
backtrace
bt
只显示开头N个栈帧
backtrace N
bt N
只显示最后N个栈帧
backtrace -N
bt -N
不仅显示backtrace,还要显示局部变量。N与前述的意思相同,表示N个(或者最后N个)栈帧
backtrace full
bt full
backtrace full N
bt full N
backtrace full -N
bt full -N
例:
显示所有栈帧
(gdb)bt
只显示前三个栈帧
(gdb)bt 3
从外向内显示3个栈帧,及局部变量
(gdb)bt full -3
#显示变量
print命令可以显示变量。print可以简写为p
##格式;
print 变量
(gdb)p argv
info registers 可以显示寄存器,简写info reg
(gdb) info reg
rax 0x0 0
rbx 0x0 0
rcx 0x0 0
rdx 0x7ffcab228958 140723179653464
rsi 0x7ffcab228948 140723179653448
rdi 0x1 1
rbp 0x7ffcab228860 0x7ffcab228860
rsp 0x7ffcab228860 0x7ffcab228860
r8 0x400570 4195696
r9 0x7f2203168ab0 139784057424560
r10 0x846 2118
r11 0x7f2202dae740 139784053516096
r12 0x4003e0 4195296
r13 0x7ffcab228940 140723179653440
r14 0x0 0
r15 0x0 0
rip 0x4004ed 0x4004ed <main+23>
eflags 0x10246 [ PF ZF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
---------------------
在寄存器之前添加 $,即可以显示各个寄存器的内容
(gdb)p $eax
(gdb) p $rip
$1 = (void (*)()) 0x4004ed <main+23>
(gdb) p $eflags
$2 = [ PF ZF IF RF ]
(gdb) p $eax
$3 = 0
(gdb) p $r8
$4 = 4195696
(gdb) p $rax
$5 = 0
(gdb) p $rdx
$6 = 140723179653464
显示时可以使用一下格式:
p/格式 变量
显示寄存器可以使用的格式:
格式 说明
x 显示为十六进制数
d 显示为十进制数
u 显示为无符号十进制数
o 显示为八进制数
t 显示为二进制数,t的由来是two
a 地址
c 显示为字符(ASCII)
f 浮点小数
s 显示为字符串
i 显示为机器语言(仅在显示内存的X命令中可以使用)
------------------------------------------------------
使用x命令可以显示内存的内容,x这个名字的由来是eXamining。
格式:
x/格式 地址
(gdb) x $pc
0x4004ed <main+23>: 0x000100c7
(gdb) x /x 0x4004ed
0x4004ed <main+23>: 0x000100c7
(gdb) x/i $pc
=> 0x4004ed <main+23>: movl $0x1,(%rax)
##x/i 的意思是显示汇编指令
一般使用 x 命令时,格式为 x/NFU ADDR。此处ADDR为希望显示的地址,N为重复的次数,F为前面讲过的格式(x,d,u,,o,t,a,c,f,s,i),U为表示2-4中所示的单位。
----------------------------------------------
U代表的单位
单位 说明
b 字节
h 半字(2字节)
w 字(4字节)(默认值)
g 双字(8字节)
----------------------------------------------
#--> 从pc处显示十条指令
(gdb) x/10i
0x4004f3 <main+29>: mov $0x0,%eax
0x4004f8 <main+34>: pop %rbp
0x4004f9 <main+35>: retq
0x4004fa: nopw 0x0(%rax,%rax,1)
0x400500 <__libc_csu_init>: push %r15
0x400502 <__libc_csu_init+2>: push %r14
0x400504 <__libc_csu_init+4>: mov %edi,%r15d
0x400507 <__libc_csu_init+7>: push %r13
0x400509 <__libc_csu_init+9>: push %r12
0x40050b <__libc_csu_init+11>:
lea 0x2008fe(%rip),%r12 # 0x600e10
--------------------------------------------------------
1.disassemble.
2.disassemble 程序计数器
3.disassemble 开始地址 结束地址
1 --> 反汇编当前整个函数
2 --> 反汇编程序计数器所在函数的整个函数
3 --> 反汇编从开始地址到结束地址之间的部分
(gdb) disassemble $pc $pc+50
单步执行的意思是根据源代码一行一行执行。
执行源代码中的一行的命令为next(简写为 n)。执行时如果遇到函数调用,可能想执行到函数内部,此时可以使用step(简写为p) 命令。
也就是说当有子函数调用的时候,使用n命令直接执行子函数获得返回值,但是 step命令会进入子函数中执行;
next命令和step命令都是执行源代码中的一行,若果要逐条执行汇编指令,可以分别使用nexti命令和stepi命令
调试时,可以使用continue(简写为c)命令继续运行程序,程序会在遇到断点后再次暂停运行,
如果 没有遇到断点就会一直运行到结束。
格式:
continue
continue 次数
指定次数可以忽略断点,例如,continue 5则5次遇断点不停止,第六次遇到断点才停止执行
大型软件或大量使用指针的程序中,很难男女感情变量在什么地方被改变。想要找到变量在何处被改变,可以使用watch命令(监视点,watchpoint)。
格式:
watch <表达式>
<表达式>发生变化时暂停运行。
此处表达式的意识是常量或变量等。
格式:
awatch <表达式>
<表达式>被访问,改变时暂停运行。
格式:
rwatch <表达式>
<表达式>被访问时暂停运行。
用delete(简写为 d)命令删除断点和监视点。
格式:
delete <编号>
删除编号指示的断点或监视点
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000400450 in main at watch.c:10
breakpoint already hit 1 time
4 breakpoint keep y 0x0000000000400450 in main at watch.c:10
breakpoint already hit 1 time
-->删除1号断点
(gdb) d 1
(gdb) info b
Num Type Disp Enb Address What
4 breakpoint keep y 0x0000000000400450 in main at watch.c:10
breakpoint already hit 1 time
```bash
------------------------------------------------------------------
## 其他断点
硬件断点(hbreak),适用于ROM空间等无法修改的内存区域中的程序。在有些框架中无法使
用,临时断点(tbreak)和临时硬件断点(thbreak),与断点(硬件断点)相同,都会运行到该
处时暂停,不同之处就是临时断点(临时硬件断点)会在此时被删除,所以在只需要停止一次
时使用起来很方便。
------------------------------------------------------------------
## 改变变量的值
该功能可以在运行时,随意修改变量的值,因此无须修改源代码就能确认各种值的情况
格式:
```bash
set variable <变量> = <表达式>
例:
(gdb)p options
$7 =1
(gdb)set varaable options = 0
(gdb)p options
$8 = 0
使用generate-core-file可将调试中的进程生成核心转存储文件
功能,将正在调试的文件生成核心转存储文件
有了内核转存储文件和调试对象,以后就能查看生成转存储文件时的运行历史(寄存器值,内存值等)。
例:
(gdb) generate-core-file
Saved corefile core.16579
此外,gcore命令可以从命令行直接生成内核转存储文件。
gcore 'pidof emacs'
该命令无须停止正在运行的程序以获得内核转存储文件,当需要在其他机器上单独分析问题原因,或者是分心客户现场发生的问题时,十分有用。
确认行为之后,需要在gdb和进程分离时使用detach命令,这样调试中的进程就被从gdb的控制下释放出来,进程被detach后会继续运行
进程信息可以使用info proc命令显示
(gdb) info proc
process 22440
cmdline = '/work/linux-sys/DEBUG/watch/watch'
cwd = '/work/linux-sys/DEBUG/watch'
exe = '/work/linux-sys/DEBUG/watch/watch'
要调试守护进程(daemon process)等已经启动的进程,或者调试陷入死循环而无法返回的控制台进程时,可以使用attach命令
格式:
attach pid
执行这一命令就可以attach到进程ID为pid的进程上。
下面使用sleep命令进行GDB调试
andrew@andrew-Thurley:/work/linux-sys/DEBUG/segmentation$ sudo gdb
[sudo] andrew 的密码:
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) attach 21414
Attaching to process 21414
Reading symbols from /bin/sleep...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so...done.
done.
0x00007ff7d77732f0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: 没有那个文件或目录.
(gdb) frame
#0 0x00007ff7d77732f0 in __nanosleep_nocancel ()
at ../sysdeps/unix/syscall-template.S:84
84 in ../sysdeps/unix/syscall-template.S
(gdb) list
79 in ../sysdeps/unix/syscall-template.S
(gdb) generate-core-file
warning: target file /proc/21414/cmdline contained unexpected null characters
Saved corefile core.21414
---------------------------------------------------------------------
andrew@andrew-Thurley:/work/linux-sys/DEBUG/watch$ sudo gdb
[sudo] andrew 的密码:
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) attach 21531
Attaching to process 21531
Reading symbols from /bin/sleep...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so...done.
done.
0x00007f5e7b00e2f0 in __nanosleep_nocancel ()
at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: 没有那个文件或目录.
(gdb) bt
#0 0x00007f5e7b00e2f0 in __nanosleep_nocancel ()
at ../sysdeps/unix/syscall-template.S:84
#1 0x00000000004040bf in ?? ()
#2 0x0000000000403f18 in ?? ()
#3 0x000000000040169a in ?? ()
#4 0x00007f5e7af62830 in __libc_start_main (main=0x4014e0, argc=2,
argv=0x7ffe79e6e518, init=<optimized out>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7ffe79e6e508)
at ../csu/libc-start.c:291
#5 0x0000000000401789 in ?? ()
在特定条件下执行中断
格式:
break 断点 if 条件
这条命令将测试给定的条件,如果条件为真暂停运行。
例:
(gdb) b iseq_compile if node == 0
格式:
删除指定断点的出发条件
condition 断点编号
添加指定断点的出发条件
condition 断点编号 条件
ignore 断点编号 次数
在指定的断点、监视点(watchpoint)或捕获点(catchpoint)忽略指定的次数。
continue命令与ignore命令一样,可以指定次数,达到指定次数前执行到断点时不暂停,
二者意义相同。
格式;
continue 次数
step 次数
stepi 次数
next 次数
nexti 次数
这些命分别执行指定次数的相应命令。
格式:
finish
until
until 地址
finish 命令执行完当前函数后暂停,until命令执行完当前函数等代码块后暂停,
若果是循环,则执行完循环后暂停,常用于跳出循环。
用clear 命令删除已定义的断点,如果要保留定义,只想临时禁用断点的话,可以使用disable命令;
将禁用的断点重新启用,可以使用enable命令;
格式:
clear
clear 函数名
clear 行号
clear 文件名:行号
clear 文件名:函数名
delete [breakpoints] 断点编号
格式:
disable [breakpoints]
disable [breakpoints] 断点编号
disable display 显示编号
disable mem 内存区域
如果不指定断点编号,则禁用多有的断点,否则禁用指定断点
第3种命令禁用display命令定义的自动显示
第4中格式禁用mem命令定义的内存区域
可以省略breakpoints关键字
格式:
enable [breakpoints]
enable [breakpoints] 断点编号
enable [breakpoints] once 断点编号
enable [breakpoints] delete 断点编号
enable display 显示编号
enable mem 内存区域
这些格式用于显示断点,once指定的断点只启用一次,也就是说,程序运行到该断点并暂停后,该断点即被禁用。
这与delete命令助攻的once不同,后者在运行暂停后删除断点
断点命令(commands)可以定义在断点中断后执行的命令
格式:
commands 断点编号
命令
...
end
程序在执行到断点处暂停后,就会自动执行命令
(gdb)b main
(gdb)command 2
>p *b
>end
(gdb)c
与前面的条件断点组合使用,就可以在断点暂停时,执行复杂的显示动作等
break foo if x>0
commands
silent
printf "x is %d\n", x
cont
end
命令 简写形式 说明
backtrace bt、where 显示backtrace
break b 设置断点
continue c、cont 继续执行
delete d 删除断点
finish 运行到函数结束
info breakpoints 显示断点信息
next n 执行下一行
print p 显示表达式
run r 运行程序
step s 一次执行一行,包括函数内部
x 显示内存内容
until u 执行到指定行
其他命令
directory dir 插入目录
disable dis 禁用断点
down do 在当前调用的栈帧中选择要显示的栈帧
edit e 编辑文件或者函数
frame f 选择要显示的栈帧
forward-search fo 向前搜索
generate-core-file gcore 生成内核转存储
help h 显示帮助一览
info i 显示信息
list l 显示函数或行
nexti ni 执行下一行(以汇编代码为单位)
print-object po 显示目标信息
sharelibrary share 加载共享的符号
stepi si 执行下一行
info命令能够显示调试对象的各种各样的信息,另外show命令能够显示GDB内部的功能、变量和选项等。
通过print 命令显示过的值会记录在内部的值历史中,这些值可以在其他表达式中使用
(gdb)p argc
(gdb)p *argc
最后的值可以通过 p $ 访问
也就说在这种情况下, p $ == > p *argc
用 show value 命令可以显示历史中的最后 10 个值
(gdb)show value
$1
$2
$3
$4
.
.
.
值历史的访问说明
变量 说明
$ 值历史的最后一个值
$n 值历史的第n个值
$$ 值历史的倒数第2个值
$$n 值历史倒数第n个值
$_ x命令显示过的最后的地址
$__ x命令显示过的最后的地址的值
$_exitcode 调试中的程序的返回码
$bpnum 最后设置的断点编号
可以随意的定义变量,变量以$ 开头,由英文字母和数字组成
(gdb)set $i = 0
(gdb)p $i
$1 = 0
可以将命令历史保存在文件中,保存命令历史后,就能在其它调试会话中重复利用这些命令(通过箭头键以查找以前的命令)、
十分方便,默认的历史文件位于 ./.gdb_history
显示历史命令
show history
格式:
set hitory expansion
show history expansion
可以使用csh风格的!字符
格式:
set hitory filename 文件名
show history filename
可将命令历史保存到文件中,可以通过环境变量GDBHISTFILE改变默认文件名
格式:
set history save
show history save
启用命令历史保存到文件和恢复的功能
格式:
set history size 数字
show history size
设置保存到命令历史中的命令数量,默认值是256
星期六, 23. 二月 2019 12:20下午
linux环境下初始化文件为 .gdbinit。如果存在.gdbinit 文件,GDB就会在启动之前将其作为命令文件运行,初始化文件和命令文件的运行顺序如下:
1、$HOME/.gdbinit
2、运行命令选项
3、./.gdbinit
4、通过 -x 选项给出的命令文件
初始化文件的语法和命令文件的语法相同,都由gdb命令组成
利用define命令可以定义命令,还可以使用document命令给自定义的命令添加说明,用help命令名,可以查看定义的命令名
格式:
define 命令名
命令
..
end
格式:
document 命令名
说明
end
格式:
help 命令名
例:
定义了一个 名为 li的命令,它能显示当前 $pc 所指的位置开始的10条指令。另外,用document命令给li命令定义了说明,使用help li可以查看说明;
define li
x/10i $pc
end
document
list machine instruction
end
除了使用初始化文件,还可以将各种设置文件写在文件中,,在运行调试器时读取这些文件
格式;
source 文件名
栈是程序存放数据的内存区域之一,其特征是LIFO(last in first out,后进先出)式数据结构,即后放进的数据先被取出,向栈中存储数据的操作称为PUSH(压入),从栈中取出数据称为POP(弹出),保存动态分配的自动变量时要使用栈,此外在函数调用时,栈还用于传递函数参数,以及用于保存返回地址和返回值。
-mno-red-zone
Do not use a so-called "red zone" for x86-64 code. The red zone is
mandated by the x86-64 ABI; it is a 128-byte area beyond the
location of the stack pointer that is not modified by signal or
interrupt handlers and therefore can be used for temporary data
without adjusting the stack pointer. The flag -mno-red-zone
disables this red zone.
调试选择栈帧,除了使用frame n 指定,还可以使用up down up是选择上一层栈帧,dowm是选择下一层栈帧
使用 info 命令的 frame 选项可以查看到更详细的栈帧信息,可以用帧编号作为该命令的选项
(gdb) info frame 0
Stack frame at 0x7fffffffdd50:
rip = 0x40060e in main (sum.c:34); saved rip = 0x7ffff7a2d830
source language c.
Arglist at 0x7fffffffdd28, args: argc=<optimized out>, argv=0x7fffffffde28
Locals at 0x7fffffffdd28, Previous frame's sp is 0x7fffffffdd50
Saved registers:
rip at 0x7fffffffdd48
x/i $pc --> 以汇编的形式查看当前栈帧处的代码
(gdb) x/i $pc
=> 0x400590 <main>: sub $0x18,%rsp
(gdb) info proc mapping --> 查看该进程内存映射的命令
process 13193
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /work/linux-sys/DEBUG/sum/sum
0x600000 0x601000 0x1000 0x0 /work/linux-sys/DEBUG/sum/sum
0x601000 0x602000 0x1000 0x1000 /work/linux-sys/DEBUG/sum/sum
0x7ffff7a0d000 0x7ffff7bcd000 0x1c0000 0x0 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7bcd000 0x7ffff7dcd000 0x200000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7dcd000 0x7ffff7dd1000 0x4000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7dd1000 0x7ffff7dd3000 0x2000 0x1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7dd3000 0x7ffff7dd7000 0x4000 0x0
0x7ffff7dd7000 0x7ffff7dfd000 0x26000 0x0 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7fd0000 0x7ffff7fd3000 0x3000 0x0
0x7ffff7ff7000 0x7ffff7ffa000 0x3000 0x0 [vvar]
0x7ffff7ffa000 0x7ffff7ffc000 0x2000 0x0 [vdso]
0x7ffff7ffc000 0x7ffff7ffd000 0x1000 0x25000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x26000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack] -->表示栈空间 , 0x21000也就是栈空间的顶端
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
(gdb) p $pc
$1 = (void (*)()) 0x400590 <main> pc的值为 0x400590 > 0x21000 说明还在栈内,没有栈溢出要是PC的值小于栈空间顶端的值,就是出现了栈溢出
(gdb) x/i $pc
=> 0x400590 <main>: sub $0x18,%rsp
说明:
可以使用info proc mapping 查看进程的内存映射,要保证占空间的栈顶端的值小于 p c 的 , 否 则 就 是 出 现 了 栈 溢 出 进 程 的 内 存 映 射 也 就 是 / p r o c / < P I D > / m a p s 信 息 注 意 后 面 显 示 的 [ s t a c k ] 。 它 表 示 栈 空 间 , 占 空 间 的 顶 端 的 值 要 小 于 pc的,否则就是出现了栈溢出 进程的内存映射也就是 /proc/<PID>/maps信息 注意后面显示的[stack] 。它表示栈空间,占空间的顶端的值要小于 pc的,否则就是出现了栈溢出进程的内存映射也就是/proc/<PID>/maps信息注意后面显示的[stack]。它表示栈空间,占空间的顶端的值要小于pc的值,程序才能正常运行,说明栈没有溢出
但是使用该命令时,GDB文件会打开/proc//maps,因此在分析coredump文件的时候无法使用,分析coredump文件的时候
可以使用下面的命令得到相同的信息。
(gdb)info files
或者
(gdb)info target
星期六, 23. 二月 2019 12:20下午
GDB等调试器的backtrace功能是通过搜索栈中的保存信息来实现的。
栈信息对于调试器来说非常重要,关于栈破坏可以看HACK#27 backtrace无法正确显示和 HACK#28 数组非法访问导致内存破坏
编译时使用GCC指定 -formit-frame-pointer选项,即可生成不使用栈指针的二进制文件即使这样使用GDB依然能够正确理解帧,
因为GDB是根据记录在调试信息中的栈使用量来计算帧的位置的
使用bt命令可以查栈的状态
使用frame可以查看现在选择的帧
(gdb) frame
#0 main (argc=1, argv=0x7fffffffde08) at segment.c:12
12 int *a = NULL;
(gdb) bt
#0 main (argc=1, argv=0x7fffffffde08) at segment.c:12
(gdb) frame 1
查看上一层栈帧
同样使用
(gdb) up 意识查看上一层栈帧
(gdb) down是查看下一层栈帧
使用 i 命令的frame选项可以查看更加详细的栈信息,可以使用栈编号作为该命令的选项
(gdb) i frame 0====
Stack frame at 0x7fffffffdd30:
rip = 0x4004e1 in main (segment.c:12); saved rip = 0x7ffff7a2d830
source language c.
Arglist at 0x7fffffffdd20, args: argc=1, argv=0x7fffffffde08
Locals at 0x7fffffffdd20, Previous frame's sp is 0x7fffffffdd30
Saved registers:
rbp at 0x7fffffffdd20, rip at 0x7fffffffdd28
调试没有调试信息的程序,使用 b *func 即函数前面加上 * 因为不使用 断点就不会设置到汇编语言层次的函数开头,
而是设置到地址偏后一点的源代码级别的开头,如果在break命令中不加 直接使用函数名,就无法用于参数确认。
Oops信息的解读方法Oops信息是内核发生致命错误时输出的内核信息
说明栈被破坏的就不嗯给你信任调试器生成的backtrace信息,极端一点说,新来backtrace只有在栈没有被破坏的前提下才成立
认为调试器的信息绝对正确是十分危险的
利用GDB进行调试,寄存器信息是绝对不能忽视的
调查栈破坏的方法有很多种,但是最显示的方法就是根据被破坏的数据内容,判断执行写入的位置,看看又没哟对栈空间(也就是自动变量空间)的引用、指针传递处理。
数组的错误操作
错误的操作数组导致典型的bug之一就是缓存区溢出,也就是说向已分配的内存空间写入数据,特别是如果这类bug发生在栈上的缓存区中,就可能引发安全漏洞
当使用-g编译选项之后利用GDB读入core并显示backtrace之后栈中的还是没有显示符号名,可以怀疑是缓冲区溢出的情况
这时使用 x/i +地址显示查看栈中地址的汇编语言,再根据程序在该架构中常放置的地址和共享内存常放置的地址判断是否是数组越界
(gdb) x/30c $esp-15
p (char *) $esp-20
魔法键 = CTRL+PgUp键 之后按键 h p打印寄存器信息