libgdb过时了,目前的GDB调试前端都不用libgdb 目前有两种比较流行: - MI接口,现在应该是MI II接口,是Eclipse CDT所采用的方式 - emac输出接口,这个似乎有更多的调试前端所采用,例如DDD,kdbg,codeblocks等等 另外还有一种比较另类的一种方式:insight,直接把gdb给包含进去了 ========================================= GDB MI Interface虽
然使用GDB已经很多年了,但是直到最近因为工作需要才知道GDB除了CLI(Commnad Line
Interface)命令外,还有一个更重要的MI (Machine
Interface)命令。之所以“更重要”,因为MI不但包括了CLI的所有命令,还具备一些CLI所不提供的功能。当然,MI接口的设计初衷是面向将
GDB作为系统组件之一的复杂系统。在类似于DDD,Insight等以GDB为backend的GUI
debugger的实现中,就是充分利用了GDB
MI接口。MI最大的不足在于其输出比较复杂,必须很熟悉其输出格式才能理解,不如CLI输出直观。但这只是习惯问题,多用多读自然就OK啦。
简单地说,GDB MI interpreter
接受字符串形式的命令输入,然后产生一行表示命令执行结果的输出。当然,这里的输入命令和输出记录都有严格的格式和内容定义。而且,根据命令的不同(同步
命令或异步命令),GDB的输出也代表不同的含义。当利用GDB
MI实现一个GUI的debugger时,通常的做法是使用一个进程负责管理GDB,将GDB作为其子进程派生出来后,接管其标准I/O,并通过pipe
向GDB注入MI命令,并接收GDB MI输出。自然,该进程的另一个工作就是与GUI前端交互,完成GUI命令解析以及返回相应record.
Insight使用Tcl/tk实现前端GUI,DDD使用的则是Gtk。前段时间正好学习了Python,是不是可以用Python+GDB MI来作一个GUI Debugger?正好还可以复习一下前一阵子看过的程序link and load 过程。
注:GDB MI的详细介绍参见GDB 手册: Debugging with GDB.其中专门一章讨论MI接口。 ================================== 对于gdb的命令很多人可能都已经很熟悉了,本文介绍的mi层命令可能很少有人用到,它也是gdb的一部分,主要目的是为一些目标系统如IDE等提 供调试功能,如eclipse下c/c++的cdt插件的底层就是调用的mi层命令,cdt的包里面有两个类RxThread,TxThread就是一个 发送mi命令,一个接收返回数据的,大家有兴趣可以研究下。 mi的命令依然是以文本行方式提供的,并兼容我们常用的gdb CLI命令,下面我们看一下它的进入和退出: 进入命令 gdb --interpreter mi ****.exe 退出命令 quit 效果如下: libo@libo-desktop:~$ gdb --interpreter mi~"GNU gdb (GDB) 7.1-ubuntu\n" ~"Copyright (C) 2010 Free Software Foundation, Inc.\n" ~"License GPLv3+: GNU GPL version 3 or later <http:///licenses/gpl.html>\n" ~"This is free software: you are free to change and redistribute it.\n" ~"There is NO WARRANTY, to the extent permitted by law. Type \"show copying\"\n" ~"and \"show warranty\" for details.\n" ~"This GDB was configured as \"i486-linux-gnu\".\n" ~"For bug reporting instructions, please see:\n" ~"<http://www./software/gdb/bugs/>.\n" =thread-group-created,id="42000" =thread-created,id="1",group-id="42000" *stopped,frame={addr="0x00000000",func="??",args=[]},thread-id="1",stopped-threads="all" @"JTAG speed set to 100 kHz\r\n" @"Target endianess set to \"little endian\"\r\n" @"Select flash device: STM32F103RB\r\n" @"Flash download enabled\r\n" @"Flash breakpoints enabled\r\n" @"Resetting target\r\n" @"Sleep 500ms\r\n" @"Writing register (SP = 0x20005000)\r\n" @"Writing register (PC = 0x08001739)\r\n" (gdb) quit &"quit\n" =thread-group-exited,id="42000" libo@libo-desktop:~$ mi的命令总共分为以下几个部分: 1.断点(Breakpoint) 2.程序环境(Program Context) 3.线程(Thread) 4.程序执行(Program Execution) 5.栈(Stack) 6.变量(Variable) 7.数据(Da 8.跟踪点(Tracepoint) 9.符号(Symbol) 10.文件(File) 11.目标数据(Target Manipulation) 12.其它杂项 我们以下面这段代码为例演示各种命令的执行结果: ![]() ![]() ![]() ![]() #include <stdio.h> ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 执行gcc -g demo.c -o demo.exe编译。 具体详细的命令还请大家看gdb手册,下面一一介绍: 1.断点 -break-after 用法:-break-after number count -break-condition 用法:-break-condition number expr -break-delete 用法:-break-delete ( breakpoint number )+ -break-disable 用法:-break-disable ( breakpoint number)+ -break-enable 用法:-break-enable ( breakpoint number)+ -break-info 用法:-break-info breakpoint -break-insert 用法: -break-insert [ -t ] [ -h ] [ -r ] 语义:-t 插入一个临时断点 -h 插于一个硬件端点 -r 插入一个正则断点,当函数名匹配正则表达式时有效 -c 插入一个条件断点 -i 插入一个指定无效次数的断点 如果指定了line选项,可以使用如下格式: 函数 文件名:行号 文件名:函数 地址 -break-list 用法:-break-list -break-watch 用法:-break-watch [ -a | -r ] variable 运行效果: libo@libo-desktop:~/temp$ gdb --interpreter mi demo.exe (gdb) 2.程序环境 -exec-arguments 用法:-exec-arguments args -exec-show-arguments 用法:-exec-show-arguments 语义:显示命令行参数 -environment-cd 用法:-environment-cd pathdir -environment-directory 用法:-environment-directory [ -r ] [ pathdir ]+ -environment-path 用法:-environment-path [ -r ] [ pathdir ]+ -environment-pwd 用法:-environment-pwd 3.线程 -thread-info 尚没实现 -thread-list-all-threads -thread-list-ids 用法:-thread-list-ids -thread-select 用法:-thread-select threadnum 语义:使threadnum成为当前线程 效果如下: (gdb) 4. 程序执行 这些命令都是异步命令 -exec-continue 用法:-exec-continue 语义:继续执行程序,直到有断点或者程序退出 -exec-finish 用法:-exec-finish -exec-interrupt 用法:-exec-interrupt -exec-next 用法:-exec-next -exec-next-instruction 用法:-exec-next-instruction -exec-return 用法:-exec-return -exec-run 语义:开始执行程序,直到遇到断点或退出 -exec-step 用法:-exec-step -exec-step-instruction 用法:-exec-step-instruction 语义:执行一条机器指令 -exec-until 用法:-exec-until [ location ] 效果如下:-break-insert main ^done,bkpt={number="7",type="breakpoint",disp="keep",enabled="y",addr="0x08048498",func="main",file="demo.c",fullname="/home/libo/temp/demo.c",line="23",times="0",original-location="main"} (gdb) -break-insert swap ^done,bkpt={number="8",type="breakpoint",disp="keep",enabled="y",addr="0x0804841b",func="swap",file="demo.c",fullname="/home/libo/temp/demo.c",line="8",times="0",original-location="swap"} (gdb) -exec-run =library-unloaded,id="/lib/ld-linux.so.2",target-name="/lib/ld-linux.so.2",host-name="/lib/ld-linux.so.2" =library-unloaded,id="/lib/tls/i686/cmov/libc.so.6",target-name="/lib/tls/i686/cmov/libc.so.6",host-name="/lib/tls/i686/cmov/libc.so.6" =thread-group-created,id="19708" =thread-created,id="1",group-id="19708" ^running *running,thread-id="all" (gdb) =library-loaded,id="/lib/ld-linux.so.2",target-name="/lib/ld-linux.so.2",host-name="/lib/ld-linux.so.2",symbols-loaded="0" =library-loaded,id="/lib/tls/i686/cmov/libc.so.6",target-name="/lib/tls/i686/cmov/libc.so.6",host-name="/lib/tls/i686/cmov/libc.so.6",symbols-loaded="0" *stopped,reason="breakpoint-hit",disp="keep",bkptno="4",frame={addr="0x08048498",func="main",args=[],file="demo.c",fullname="/home/libo/temp/demo.c",line="23"},thread-id="1",stopped-threads="all",core="0" (gdb) -exec-continue ^running *running,thread-id="1" (gdb) *stopped,reason="breakpoint-hit",disp="keep",bkptno="3",frame={addr="0x080484f6",func="main",args=[],file="demo.c",fullname="/home/libo/temp/demo.c",line="28"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-continue ^running *running,thread-id="1" (gdb) swap before:0 1 2 3 4 5 6 7 8 9 *stopped,reason="breakpoint-hit",disp="keep",bkptno="8",frame={addr="0x0804841b",func="swap",args=[{name="a",value="0xbffff254"},{name="len",value="10"}],file="demo.c",fullname="/home/libo/temp/demo.c",line="8"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-next ^running *running,thread-id="1" (gdb) *stopped,reason="end-stepping-range",frame={addr="0x08048424",func="swap",args=[{name="a",value="0xbffff254"},{name="len",value="10"}],file="demo.c",fullname="/home/libo/temp/demo.c",line="10"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-next ^running *running,thread-id="all" (gdb) *stopped,reason="end-stepping-range",frame={addr="0x08048432",func="swap",args=[{name="a",value="0xbffff254"},{name="len",value="10"}],file="demo.c",fullname="/home/libo/temp/demo.c",line="11"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-next-instruction ^running *running,thread-id="all" (gdb) *stopped,reason="end-stepping-range",frame={addr="0x08048435",func="swap",args=[{name="a",value="0xbffff254"},{name="len",value="10"}],file="demo.c",fullname="/home/libo/temp/demo.c",line="11"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-step ^running *running,thread-id="all" (gdb) *stopped,reason="end-stepping-range",frame={addr="0x08048454",func="swap",args=[{name="a",value="0xbffff254"},{name="len",value="10"}],file="demo.c",fullname="/home/libo/temp/demo.c",line="12"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-step-instruction ^running *running,thread-id="all" (gdb) *stopped,reason="end-stepping-range",frame={addr="0x08048457",func="swap",args=[{name="a",value="0xbffff254"},{name="len",value="10"}],file="demo.c",fullname="/home/libo/temp/demo.c",line="12"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-finish ^running *running,thread-id="all" (gdb) *stopped,reason="function-finished",frame={addr="0x08048516",func="main",args=[],file="demo.c",fullname="/home/libo/temp/demo.c",line="32"},gdb-result-var="$1",return-value="0",thread-id="1",stopped-threads="all",core="1" (gdb) -exec-step ^running *running,thread-id="all" (gdb) *stopped,reason="end-stepping-range",frame={addr="0x08048523",func="main",args=[],file="demo.c",fullname="/home/libo/temp/demo.c",line="33"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-step ^running *running,thread-id="all" (gdb) *stopped,reason="end-stepping-range",frame={addr="0x0804852d",func="main",args=[],file="demo.c",fullname="/home/libo/temp/demo.c",line="34"},thread-id="1",stopped-threads="all",core="1" (gdb) -exec-step ^running *running,thread-id="all" (gdb) *stopped,reason="end-stepping-range",frame={addr="0x08048546",func="main",args=[],file="demo.c",fullname="/home/libo/temp/demo.c",line="33"},thread-id="1",stopped-threads="all",core="0" (gdb) -break-insert 35 ^done,bkpt={number="9",type="breakpoint",disp="keep",enabled="y",addr="0x08048552",func="main",file="demo.c",fullname="/home/libo/temp/demo.c",line="35",times="0",original-location="demo.c:35"} (gdb) -exec-continue ^running *running,thread-id="all" (gdb) *stopped,reason="breakpoint-hit",disp="keep",bkptno="9",frame={addr="0x08048552",func="main",args=[],file="demo.c",fullname="/home/libo/temp/demo.c",line="35"},thread-id="1",stopped-threads="all",core="0" (gdb) -exec-continue ^running *running,thread-id="1" (gdb) swap after:9 8 7 6 5 4 3 2 1 0 =thread-exited,id="1",group-id="19708" =thread-group-exited,id="19708" *stopped,reason="exited-normally" (gdb) 5. 栈 -stack-info-frame 尚没实现 -stack-info-depth 用法:-stack-info-depth [ max-depth ] -stack-list-arguments 用法:-stack-list-arguments show-values 则只显示它们之间的参数 -stack-list-frames 用法:-stack-list-frames [ low-frame high-frame ]语义:列举所有帧,如果指定low-frame和high-frame则只显示它们之间的帧-stack-list-locals用法:-stack-list-locals print-values -da 用法: -da 语义:address指定开始地址,byte-offset指定从开始地址的偏移值, word-format每个字的显示格式,word-size每个字的长度 nr-rows,nr-cols指定输出格式为几行几列 效果如下: (gdb) (gdb) (gdb) (gdb) 以后的8、9等命令GDB大部分尚没实现,或很少使用,不再解释。 不同的GDB版本极少数命令可能稍有差异,可自己查看GDB手册或命令行提示。 |
|