学习GDB(一)

1、停下来环顾程序程序员

一、暂停机制正则表达式

     三种方法能够通知GDB暂停程序的执行:express

     - 断点:通知GDB在特定位置暂停执行。sass

     - 监视点:通知GDB当特定内存(或者涉及一个或多个位置的表达式)的值发生变化时暂停执行。函数

     - 捕获点:通知GDB当特定事件发生时暂停执行。优化

     GDB文档中把这三种机制所有认为是断点,而delete命令也是删除所有这三种类型。ui

二、暂停概述spa

     在程序特定“位置”设置断点,到那一点时,调试器会暂停程序执行。GDB中的“位置”含义很是灵活,它能够是各类源代码行、代码地址、源代码文件中的行号或者函数入口等。线程

     GDB中设置断点的那一行是将要执行的下一行源代码(能够认为GDB在源代码的断点行和前一行之间等待)。调试

     GDB的工做针对的是机器语言指令,而不是源代码行,一行代码可能对应于数行机器语言。GDB之因此能够在源代码行工做,是由于可执行文件中包括了额外的信息。

三、断点跟踪

     程序员建立的每个断点(包括三种类型)都被标识为从1开始的惟一整数标识符。这个标识符用来执行该断点上的各类操做。调试器还有列出全部断点及其属性的方式。

     建立断点:break  行号/函数名  ;

     GDB会告知你分配给该断点的编号。

     查看断点编号:info  breakpionts  ;

     删除断点: delete  编号  ;

四、设置断点

     GDB指定断点的方式:

     -break  function  ;在函数function()的入口(第一行可执行代码)处设置断点。

     -break  line_number  ;在当前活动源代码文件的line_number处设置断点。

     -break  filename:line_number  ;在源代码文件filename的line_number处设置断点,若是filename不在当前工做目录中,则可给出相对路径名或彻底路径名来帮助GDB查找该文件。

     -break  filename:function  ;在文件filename中的函数function()的入口处设置断点。

      在某个函数上设置断点.当使用容许函数重载的语言(如:C++,若是使用static限定符声明带文件做用域,C语言中也能够有重载函数)时,有可能同时在几个重载的函数上设置了断点;

      比 如:CLogManager类有三个重载的成员函数insert(const struct log_mo_simple&)、insert(const struct log_mt_simple&)、 insert(const struct log_st_simple&)

      设置断点: break CLogManager::insert

      执行该命令以后,gdb会找到实现CLogManager类的源文件,而后在这三个重载的成员函数上都设置一个断点;

      要没有歧义,能够经过如在源代码行号设置断点等方法。

     -tbreak  filename:function/line_number  ;临时断点设置,即首次到达后就会被自动删除的断点。

     -break  +offset/-offset  ;在当前选中栈帧中正在执行的源代码行前面或后面设置断点偏移行数。

     -break  *address  ;在虚拟内存地址处设置断点。这对于程序没有调试信息的部分(好比当源代码不可用时,或者对于共享库)是必须的。    

     GDB实际设置断点的位置可能与请求断点的位置不一样,如:

int main(void)
{
  int i;
  i = 3;
  
  return 0;
}

     不加优化的编译这个程序,并尝试在main()的入口处设置断点。觉得会放在第一行,而实际放在第四行。

     一个缘由是这一行是可执行代码。GDB实际使用的是机器语言指令工做,有了加强的符号表后,会产生一种GDB使用源代码行的错觉。实际上,声明i确实会产生机器码,但GDB认为这对于咱们的代码调试没用,因此直接在第四行设置断点。

     其余断点类型

     -hbreak  ;设置硬件辅助断点,能够在内存中设置断点,不须要修改该内存位置的内容。须要硬件支持,主要用于EEPROM/ROM调试。临时断点设置为:-thbreak。

     -rbreak  ;采用grep风格的正则表达式,并在匹配该正则表达式的任何函数入口处设置断点。

     优化编译程序后,断点设置更不明确,GDB扮演了一个更主动的角色,这是在调试完前永远不该当优化代码的缘由之一。

     在同一行设置多个断点,GDB只会中断一次。在具备多个断点的代码行上,触发中断的断点将是编号最小的断点。

     捕获点

     -catch  ;设置捕获点,这相似于断点,但能经过如抛出异常、捕获异常、发信号通知、调用fork()、加载和卸载库以及其余不少事件触发。

五、展开GDB示例

    在任什么时候间点上,GDB都有一个焦点,能够将它看做当前“活动”文件。这意味着除非对命令作了限定,不然都是在GDB的焦点文件上执行命令。下面动做会使焦点会转移到不一样文件上;

     -向不一样的源文件应用list命令。

     -进入位于不一样的源代码文件中的代码。

     -当在不一样源代码文件中执行代码时GDB遇到断点。

    离开GDB的命令是:-quit  ;

六、断点的持久性

     不用在修改和从新编译代码时退出GDB,由于这样作很繁琐,还会从新进入断点。当不退出GDB修改编译时,执行run命令,GDB会感知到代码已修改,并自动从新加载新版本。

     修改代码后,代码会动,而断点自己不会动。便可能会在那一行不包括原来其上设置断点的语句。所以,须要经过删除这个断点并从新设置一个新的来移动断点。

     保存断点的方法是把断点储存在源代码所在目录(或者从中调用GDB的目录)的.gdbinit启动文件中。

七、在GDB中删除断点

     -delete  breakpoint-list  ;删除断点使用数值标识符。能够是个数字,如delete 2;也能够是一个数字列表,如:delete 2 4 6;

     -delete  ;删除全部断点。在.gdbinit启动脚本文件中设置:set confirm off,可关闭GDB要确认删除操做。

     -clear  ;清除GDB将要执行的下一个指令处的断点。适用于要删除GDB已经到达的断点的状况。

     -clear   function 、clear  filename:function、clear line_number和clear filename:line_number  ;根据具体位置清楚断点,与break相似。

八、在GDB中禁用断点

     要保留断点以便之后使用,暂时又不但愿GDB中止执行,就能够禁用它们。

     -disable  breakpoint-list  ;禁用断点。不带参数则禁用全部断点。

     -enable  breakpoint-list  ;启用断点。不带参数则启用全部断点。

     -enable  once  breakpoint-list  ;使断点下次引发GDB暂停执行后被禁用。

九、进一步浏览断点的属性

     每个断点都有各个属性--行号、加在断点上的条件(若是有的话)、当前启用/禁用状态等。

     -info breakpoints  ;得到设置的全部断点的清单,以及它们的属性。详细分析以下:

     (1)标识符(Num):断点的惟一标识符。

     (2)类型(Typ):这个字段指出该断点是断点、监视点仍是捕获点。

     (3)部署(Disp):每一个断点都有一个部署,指示断点下次引发GDB暂停程度的执行后该断点上会发生什么事情,可能的部署有如下3种:

              -保持(keep),下次到达断点后不会改变断点。这是新建断点的默认部署。

              -删除(del),下次到达断点后删除该断点。使用tbreak命令建立的任何断点都使这样的断点。

              -禁用(dis),下次到达断点时会禁用该断点。这是使用enable once命令设置的断点。

     (4)启用状态(Enb):这个字段说明断点当前是启用仍是禁用。

     (5)地址(Address):这是内存中设置断点的位置。这主要用于汇编语言程序员,或者试图调试没有扩充的符号表编译的可执行文件的人。

     (6)位置(What):各个断点位于源代码中的特定行上。What字段显示了断点所在位置的行号和文件名。对于监视点,这个字段点表示正在监视哪一个位置。

十、恢复执行

     -next  ;执行下一行代码,执行函数时不会在其中暂停,而后在调用以后的第一条语句处暂停。把函数调用看作一行代码,并在一个操做中执行整个函数,这称为单步越过(stepping over)函数。后面可加一个可选数值参数:

-next line_number  ;表示next执行的额外行数。

     -step  ;执行下一行代码,执行函数时会进入其中,在其中暂停,而后在函数的第一条语句处暂停。称为单步进入(stepping into)函数。后面可加一个可选数值参数:-step line_number  ;表示step执行的额外行数。

     GDB不会在不具备调试信息的代码(即符号表)内中止,如C库中的printf() 。

     -continue  ;恢复GDB程序执行,直到触发断点或程序结束。后面可加一个可选数值参数:-continue  number  ;这个数字要求GDB忽略下面n个断点。

     -finish  ;简称fin,恢复GDB程序执行,直到刚好在当前栈帧完成以前为止。例如,不在main()函数中,finish命令会致使GDB恢复执行,直到刚好在函数返回以后为止。finish的另外一个常见用途是当不当心单步进入本来但愿单步跨过的函数时,这种状况下,finish能够将你正好返回到使用next会位于的位置。若是在一个递归函数中,finish只会将你带到递归的上一层。

     -until  ;执行程序,直到到达当前循环下一个源代码。until实际上作的是执行程序直到它到达内存地址比当前内存地址更高的机器指令,而不是直到达到源代码中的更大的行号。disassemble p/x $pc来输出当前位置。until命令也能够接受源代码中的位置做为参数:-until  line_number、-until  function、-until  filename:line_number、-until  filename:function。

十一、条件断点

     -break  break-args if (condition)  ;其中break-args是能够传递给break以指定断点位置的任何参数。condition是下面定义的布尔表达式。括着condition的圆括号是可选的。中断条件也极其灵活,包括:

            -相等、逻辑和不相等运算符(<、<=、==、!=、>、>=、&&、||等)。

            -按位和移位运算符(&、|、^、>>、<<等)。

            -算术运算符(+、-、*、/、%)。

            -你本身的函数,只要它们被连接到程序中,如,

break test.c:myfunc if !check_variable_sanity(i)

            -库函数,只要该库被连接到代码中,如,

break 4 if strlen(mystring) == 0

     因为优先级的次序规则在起做用,所以可能须要使用括号将一些结构括起来,如,

(x & y) == 0

     此外,若是在GDB表达式中使用不是用调试符号编译(几乎确定是这种状况)的库函数,那么惟一能在条件中使用的返回值类型为int。换而言之,若是没有调试信息,GDB会假设函数的返回值是int类型。这种假设有时候会致使曲解:

(gdb) print cos(0.0)
$1 = 14368

     然而,强制类型转换也不行:

(gdb) print (double)cos(0.0)
$1 = 14336

     实际上,有一种能够在GDB表达式中使用不返回int的函数,但这种方法至关神秘,技巧在于使用指向函数的恰当数据类型定义GDB方便变量。

(gdb) set $p = (double (*) (double))cos
(gdb) ptype $p
type = double(*)()
(gdb) print cos(3.1415926)
$2 = 14368
(gdb) print $p(3.1415926)
$3 = -1

     能够对正常断点设置条件设置条件将它们变成条件断点。例如,若是设置了断点3做为无条件断点,但如今但愿加入条件i==3,只要键入:

(gdb)cond 3 i==3

     若是之后要删除条件,并保持该断点,只需键入:

(gdb)con 3

十二、断点命令列表

     -commands  ;使用commands命令设置命令列表:

commands breakpoint-number
...
commands
...
end

     其中breakpoint-number是要将命令添到其上的断点的标识符,commands是用新行分隔的任何有效GDB命令列表。逐条键入命令,而后键入end表示输入结束。从那之后,每当GDB在这个断点处中断时,它都会执行你输入的任何命令。例如,

(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent
>printf "mimiasd was passed %d.\n",n
>continue
>end

     可用GDB的define命令建立宏,这样能够在其余程序或者该程序的其余代码行中作这样的事,

(gdb) define mimiasd_print_and_go
Type commands for definition of "mimiasd_print_and_go".
End with a line saying just "end".
>printf $arg0,$arg1
>continue
>end

     要像上述代码那样使用这个宏,应键入:

(gdb) commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent 
>mimiasd_print_and_go "mimiasd was passed %d\n" n
>end

     注意,mimiasd_print_and_go的参数之间没有逗号。能够将宏保存在.gdbinit文件中以便其余程序使用。参数最多能够有10个。-show user能够获得全部宏的列表。

     实际上,任何有效的GDB表达式均可以进入命令列表。可使用库函数,甚至本身的函数,只要它被连接到执行文件便可。可使用它们的返回值,只要它们返回的值是int类型。例如:

(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent
>printf "mimiasd was passed %d.\n",strlen(string)
>continue
>end

1三、监视点

     监视点是一种特殊类型的断点,它相似于正常断点,是要求GDB会暂停程序执行的指令。区别在于监视点没有“住在”某一行源代码中。取而代之的是,监视点是指示GDB每当某个表达式改变原值就暂停执行的指令。一旦变量再也不存在于调用栈的任何帧中(当包含局部变量的函数返回时),GDB会自动删除监视点。监视点只能监视单线程的变量。

     13.1  设置监视点

     -watch  var  ;该命令会致使每当var改变值时GDB都会中断。

     -watch  var expression  ;当变量知足表达式expression,且发生变化时GDB会中断。

相关文章
相关标签/搜索