工欲善其事,必先利其器。GDB的扩展可以通过command file和python脚本完成,这里针对Command file,一个简单高效的扩展方案。
一.简介
GDB Command File可以简单地理解为一串自定义的GDB指令,GDB同时允许用户使用define将一串GDB操作定义为一个指令。比如在命令行模式下将断点保存起来,下次执行时再加载进来,就可以通过两个自定义命令来完成:
define bsave
shell rm -f brestore.txt
set logging file brestore.txt
set logging on
info break
set logging off
# reformat on-the-fly to a valid gdb command file
shell perl -n -e 'print "break $1\n" if /^\d+.+?(\S+)$/g' brestore.txt >brestore.gdb
end
define brestore
source brestore.gdb
end
在使用时就可以使用initGDB来代替执行其中的一组指令了。bsave可以把现有的断点以设定断点的指令存放到brestore.gdb中,加载时相当于直接执行brestore.gdb中的断点指令完成断点设定。 其中每一行都是有效的GDB指令或者注释。
如果这些指令定义在一个command文件中并由GDB在执行时自动加载,就可以简化操作。
二.GDB Command File的加载与使用
GDB Command File是一个纯文本文件,包含一串GDB指令,也包括define定义的自定义指令。在加载时使用GDB指令:
source [-s] [-v] filename
-s 表示在系统的PATH中搜索指定的文件,找到后加载。
-v 表示打开verbose模式,会显示每条指令的执行。
*-s和-v并不是所有的gdb都能支持。
在使用时,可以在GDB的命令行里手动执行,也可以在gdb的启动文件里(.gdbinit)定义。如果使用Eclipse调试时,还可以在Debugger里的Command File中指定:
2.1 为新指令添加帮助
使用document可以方便地为已通过define定义的指令添加注释,注释的内容也是以end结束。
比如:
document showKURL
显示KRURL的内容,直接传入KRUL变量即可。
*Horky
end
在gdb里分别使用show显示函数说明如下:
(gdb) help user-defined
showkurl -- 显示KRURL的内容
(gdb) help showkurl
显示KRURL的内容,直接传入KRUL变量即可。
*Horky
(gdb)
三.自定义指令的撰写
一个自定义指令可以理解为一个函数,基本结构如下:
define command_name
#GDB指令或注释
end
几个要点:
1. 函数的参数可以使用$arg0,$arg1,..来取得。
2. 变量使用GDB指令set赋值,如set $var=2
3. 返回值 因为各个自定义指令中的变量是共享的,就可以直接前面函数中定义的变量。
4. 注释使用#打头即可。
5. 一个代码块都是以end结束的。
6. 指令间可以相互调用。
3.1 流程控制指令
在自定义指令中可以使用如下的控制语句,做一些比较复杂的操作。
1. 条件判断语句if
if {expression}
else
end
条件判断语句, if 后面所带的表达式为一般的GDB表达式, 可以使用==,&&,||之类的逻辑操作符。如:
if $a==5
#do something
else
#do something else
end
2.循环语句while
while {expression}
end
对应于C++循环中的break和continue, 可以使用loop_break和loop_continue指令。
3.2 补充指令
1. 变量赋值
对于一变量直接赋值即可。字串变量可以使用下面的指令:
set $string="value is %d",5
详见参考1.
2. 输出内容
程序中的输出可以使用以下几个指令:
echo
echo用于输出字串, 不会自换行, 字串的引号会同样输出,适用输出一些提示信息。比如:
echo "ouput is:"
echo output\n
输出的结果会是: "output is:"output
output {expression}
用于输出表达式的结果。与print的区别在于,它的输出结果不会生成新的变量,且不会自动换行。比如:
(gdb) output index
2 (gdb)
而print则会是下面的效果:
(gdb) print index
$1=2
(gdb)
printf
输出格式化字串. 比如printf "Value will be 0x%x",value
最后一个是最常用的print了, 前面已经分析过它与output的区别了,print还有一个好处,可以在后面的语句使用$取出上次print的结果。这是因为GDB定义了一组内部变量:
$ : 取出上次的值
$_ : 取出上次x指令最后输出的位置地址
详见参考2.
3. 内存输出
内存输出操作x, 功能强大。基本格式为
x/FMT address
FMT的详细格式为:nfu
n : 是输出的个数
f : 以什么格式输出, 比如 s:字串,i:机器指令, x:16进制
u : 输出数据的单位长度,比如b:单字节,h:双字节, w: Words,四字节,g: Gian words, 八字节
比如,下面示例中会用的,x/s 是输出ASCII字串,而x/hs则是输出UTF-16字串。
其它不在这里赘述。详见参考6.
四. 应用
4.1. 打印出JSDOMWindowShell关系列表
这个简单,就是基于一个值,打出它的上下依赖关系
#Print Hierarchy of JSDOMWindowShell
define showDOMWindowShell
p $arg0
p $arg0->world()
p $arg0->window()
p $arg0->window()->impl()
p $arg0->window()->shell()
p $arg0->impl()
p $arg0->impl()->frame()
p $arg0->impl()->document()
end
4.2. 打印出WTF::String的内容
在调用WebKit代码时,字串内容没办法直接显示出来。可以使用下面的指令完成:
define showStringVar
showStringContent $arg0
echo String:\n
if $flag&(1<<6)||$flag==0
echo [ASCII]:
x/s *(int *)((char *)($arg0.m_impl.m_ptr)+8)
end
echo [Unicode]:
x/hs *(int *)((char *)($arg0.m_impl.m_ptr)+8)
if $flag&(1<<2)
print "*This is a identifier."
end
if $flag&(1<<1)
print "*Masked Buffer Ownership."
end
end
一开始先调用了一个指令showStringContent,内容如下:
#Paramter: String
define showStringContent
echo Reference Count:
p *(int *)($arg0.m_impl.m_ptr)
echo Length:
p *(int *)((char *)($arg0.m_impl.m_ptr)+4)
echo Flag:
set $flag = *(int *)((char *)($arg0.m_impl.m_ptr)+16)
p/x $flag
end
转载请注明出处:http://blog.csdn.net/horkychen
参考:
2. Expressions
3. Commands for Controlled Output
8. 转换GDB堆栈到流程图