1.4 log
如果你想把GDB
命令输出到一个文件有,有几种方法控制
set logging on
set logging off
set logging file <filename>
set logging overwrite [on|off] #默认会追加到logfile里
set logging redirect [on|off] #默认GDB输出会在terminal和logfile里显示,用redirect让它只在logfile里显示
show logging
可以用下面命令得到相应行的地址:
(gdb) i line gdbprog.cc:14
Line 14 of "gdbprog.cc" starts at address 0x4007d9 <InitArrays(int*)+17> and ends at 0x4007f7 <InitArrays(int*)+47>.
或者
(gdb) disas /m InitArrays
Dump of assembler code for function InitArrays(int*):
8 void InitArrays(int* array)
0x00000000004007c8 <+0>: push %rbp
0x00000000004007c9 <+1>: mov %rsp,%rbp
0x00000000004007cc <+4>: mov %rdi,-0x18(%rbp)
9 {
10
11
12 for(int i = 0;i < 10;i++)
0x00000000004007d0 <+8>: movl $0x0,-0x4(%rbp)
0x00000000004007d7 <+15>: jmp 0x40080a <InitArrays(int*)+66>
0x0000000000400807 <+63>: incl -0x4(%rbp)
0x000000000040080a <+66>: cmpl $0x9,-0x4(%rbp)
0x000000000040080e <+70>: jle 0x4007d9 <InitArrays(int*)+17>
13 {
14 ptrArray[i] = array + i;
0x00000000004007d9 <+17>: mov -0x4(%rbp),%ecx
0x00000000004007dc <+20>: mov -0x4(%rbp),%eax
0x00000000004007df <+23>: cltq
0x00000000004007e1 <+25>: shl $0x2,%rax
0x00000000004007e5 <+29>: mov %rax,%rdx
0x00000000004007e8 <+32>: add -0x18(%rbp),%rdx
0x00000000004007ec <+36>: movslq %ecx,%rax
0x00000000004007ef <+39>: mov %rdx,0x6013e0(,%rax,8)
15 iArray[i] = i;
0x00000000004007f7 <+47>: mov -0x4(%rbp),%eax
0x00000000004007fa <+50>: movslq %eax,%rdx
0x00000000004007fd <+53>: mov -0x4(%rbp),%eax
0x0000000000400800 <+56>: mov %eax,0x6013a0(,%rdx,4)
16 }
17 }
0x0000000000400810 <+72>: leaveq
0x0000000000400811 <+73>: retq
End of assembler dump.
4.2.Pending breakpoints
如果试图将断点设在位于还未加载的shared library
代码内,那么就会显示类似下面warning
Make breakpoint pending on future shared library load? (y or [n])
但它可能永远不会工作,如果是下列情况:
shared library
不包含任何debugging symbols
(被用‘strip
’命令移除掉)GDB
无法检测到library
被加载 (比如,在android
上使用GDB 6.x
)- 你输入的是一个错误文件名或函数名
所以可以用下面几个命令来做调试
info sharedlibrary
: 目前加载的shared library
info sources
: 被GDB
识别的源文件info breakpoints
: 创建的断点和它们的状态
4.3. 条件断点
大约有以下几种形式
break main if argc > 1
break 180 if (string == NULL && i < 0)
break test.c:34 if (x & y) == 1
break myfunc if i % (j+3) != 0
break 44 if strlen(mystring) == 0
b 10 if ((int)$gdb_strcmp(a,"chinaunix") == 0)
b 10 if ((int)aa.find("dd",0) == 0)
经常犯的一个错误就是 在if
和后面的(
之间没放空格
另外注意条件表达式的返回值类型是int
当设置了断点后, 后面可以使用condition
和ignore
来修改这个断点条件
4.4.condition
condition <break_list> (condition)
比如
cond 3 (i==4)
上面命令把breakpoint 3
的条件修改成(i==4)
4.5. ignore
ignore <break_list> count
上面命令表示break_list
指定的断点将被忽略count
次
比如现在i=0
, 设置i>
4为条件,那么忽略3
次后,它停在i=8
, 忽略了i=5, 6, 7
4.6. commands
commands <break_list>
当断点被触发时,运行相应的命令
可以用info breakpoints
来查看相应断点上附着的命令
(gdb) i b
Num Type Disp Enb Address What
3 breakpoint keep y 0x00000000004007d9 in InitArrays(int*) at gdbprog.cc:14
stop only if (i>4)
breakpoint already hit 5 times
silent
printf "hz: i=%d\n",i
c
7 breakpoint keep y 0x0000000000400962 in main() at gdbprog.cc:51
breakpoint already hit 1 time
一个断点上只允许附着一条命令,再次调用commands 3
后会覆盖掉前面的命令
因此如果要删除相应的命令,只需用空的commands 3
就行了
4.7. define
用define
可以录制宏,这些宏就像shell
脚本一样,可以传入参数,依次是arg1, ...
可以把这些宏放在.gdbinit
文件中
录制好宏后就可以在commands
中使用
宏并不支持所有GDB
命令,比如silent
就不能用于宏中, 它会在运行时报错: Undefined commands: "silent"
(gdb) define printAndGo
Type commands for definition of "printAndGo".
End with a line saying just "end".
>printf "i=%d\n",$arg0
>cont
>end
(gdb) commands 3
Type commands for breakpoint(s) 3, one per line.
End with a line saying just "end".
>silent
>printAndGo
>end
(gdb) i b
Num Type Disp Enb Address What
3 breakpoint keep y 0x00000000004007d9 in InitArrays(int*) at gdbprog.cc:14
stop only if (i>4)
silent
printAndGo i
7 breakpoint keep y 0x0000000000400962 in main() at gdbprog.cc:51
如果要查看这些宏的定义,可以用show user
来查看
(gdb) show user
User command "pbuf":
set $i=0
while ($i<strlen(netiring.supply))
print netiring.supply[$i]
set $i=$i+1
end
User command "pobuf":
set $i=0
while ($i<strlen(netoring.consume))
print netoring.consume[$i]
set $i=$i+1
end
4.8 tbreak
只生效一次临时断点
4.9 rbreak
在所有匹配regexp
的函数名处都设置断点。它的regexp
和grep
相同
4.10 管理
clear localtion
location
可以是function, file:func, linenum, file:linenum
delete [breakpoints] [range...]
[breakpoints]
是可选项
disable|enable [breakpoints] [range...]
禁用|启用断点
enable [breakpoints] once range...
启用断点一次
enable [breakpoints] once range...
雇用断点cnt次
enable [breakpoints] delete range...
临时启用断点,一旦被激活就会把删除,和tbreak
相似
五. 检查数据
pirnt
x
display
set
watch
catch
tracepoint
5.1 print
print
接受表达式和计算它的值。任何该语言支持常值,变量和操作符都可以使用,像条件表达式,函数调用,类型转换,字符常量。GDB
还支持数组常量,语法是{element, element...}
, 比如print {1,2,3}
.GDB
支持还支持下面操作符
- @
二进制操作符, 可以把momery
当成数组。
int *array = (int*) malloc( len * sizeof(int));
可以使用下面命令来打印它的值:
(gdb) p *array@len
(gdb) p/x (short[2])0x12345678
$1 = {0x1234, 0x5678}
另外还可以自定义变量
set $i = 0
p dtab[$i++]->fv
RET
RET
上面的RET
表示重复上面的表达式
- ::
定义属于某个文件或函数的变量
{type} addr
把addr
的变量按{type}
类型解释
5.2 x
x/nfu addr
x addr
x
n, the repeat count
f, the display format (x, d, u, o, t, a, c, f, s, i)
u, the unit size (b: bytes, h: halfwords, w: words, g: giant words)
(gdb) x/5i $pc-6
0x804837f <main+11>: mov %esp,%ebp
0x8048381 <main+13>: push %ecx
0x8048382 <main+14>: sub $0x4,%esp
=> 0x8048385 <main+17>: movl $0x8048460,(%esp)
0x804838c <main+24>: call 0x80482d4 <puts@plt>
5.3display
如果你发现你经常要打印某个表达式,你可以把它加入到"automatic display list
"
display expr
display/fmt expr
display/fmt addr
undisplay <dnums>
delete display dnums
disable display dnums
enable display dnums
5.4 set
可以使用set <var>=<expr>
来修改程序中变量的值
5.5 数值历史(value Hisitory
)
通过使用print
命令显示的值会被自动保存在GDB
的数值历史当中,该值会一直被保留直到符号表被重新读取或者放弃的时候(比如使用file
或symbol-file
),此时所有的值历史将会被丢弃。
在使用print
打印值的时候,会将值编以整形的历史编号,然后可以使用$num
的方式方便的引用,单个的&dollar
;表示最近的数值历史,而$$
表示第二新的数值历史,$$n
表示倒数第n
新的数值历史(所以可以推断$$0==$; $$1==$$;
)。
比如刚刚打印了一个指向结构体的指针,那么print $
就可以显示结构体的信息,而命令print $.nex
甚至可以显示结构体中的某些字段。