GDB单步调试程序

正文同时发表在
https://github.com/zhangyachen/zhangyachen.github.io/issues/134

linux下gdb单步调试

之所以 GDB 调试程序

GDB 概述 ————**

GDB 是 GNU开源集团公布的一个无敌的 UNIX下之程序调试工具。或许,各位比较欣赏那种图形界面方式的,像 VC、 BCB等 IDE的调试,但只要你是在 UNIX平台下举行软件,你晤面发现 GDB这个调试工具来较 VC、 BCB的图形化调试器更强的机能。所谓 “寸有所长,尺有短 ”就是其一道理。

一般的话, GDB主要帮忙而完了下面四单方面的职能:

    1 、启动你的顺序,可以随卿的自定义的求自由的运转程序。
   
2 、可被被调剂之次第于你所指定的调置的断点处停住。(断点可以是法表达式)
    3 、当次为终止住时,可以检查此时您的主次中所来的行。
    4 、动态的更动而程序的实行环境。

从者看来, GDB和一般的调节工具没有啊两类,基本上也是得这些职能,不过在细节及,你晤面发现 GDB这个调试工具的有力,大家莫不比较习惯了图形化的调节工具,但奇迹,命令行的调节工具也有着图形化工具所未能够完成的法力。让咱一一看来。

一个调试示例 ——————**

源程序: tst.c

     1 #include <stdio.h>
     2
     3 int func(int n)
     4 {
     5         int sum=0,i;
     6         for(i=0; i<n; i++)
     7         {
     8                 sum+=i;
     9         }
    10         return sum;
    11 }
    12
    13
    14 main()
    15 {
    16         int i;
    17         long result = 0;
    18         for(i=1; i<=100; i++)
    19         {
    20                 result += i;
    21         }
    22
    23        printf(“result[1-100] = %d \n”, result );
    24        printf(“result[1-250] = %d \n”, func(250) );
    25 }

编译生成执行文书:( Linux下)
    hchen/test> cc -g tst.c -o tst

使用 GDB调试:

hchen/test> gdb tst  <———- 启动 GDB
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB.  Type “show warranty” for
details.
This GDB was configured as “i386-suse-linux”…
(gdb) l     <——————–
l 命令相当给 list,从第一尽开始例出原码。
1        #include <stdio.h>
2
3        int func(int n)
4        {
5                int sum=0,i;
6                for(i=0; i<n; i++)
7                {
8                        sum+=i;
9                }
10               return sum;
(gdb)       <——————– 直接回车表示,重复上一致糟命令
11       }
12
13
14       main()
15       {
16               int i;
17               long result = 0;
18               for(i=1; i<=100; i++)
19               {
20                       result += i;   
(gdb) break 16   
<——————– 设置断点,在源程序第 16行处。
Breakpoint 1 at 0x8048496: file tst.c, line 16.
(gdb) break func 
<——————– 设置断点,在函数 func()入口处。
Breakpoint 2 at 0x8048456: file tst.c, line 5.
(gdb) info break  <——————– 查看断点信息。
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x08048496 in main at tst.c:16
2   breakpoint     keep y   0x08048456 in func at tst.c:5
(gdb) r           <——————— 运行程序, run命令简写
Starting program: /home/hchen/test/tst

Breakpoint 1, main () at tst.c:17    <———- 在断点处停住。
17               long result = 0;
(gdb) n         
<——————— 单漫漫告句子执行, next命令简写。
18               for(i=1; i<=100; i++)
(gdb) n
20                       result += i;
(gdb) n
18               for(i=1; i<=100; i++)
(gdb) n
20                       result += i;
(gdb) c         
<——————— 继续运行程序, continue命令简写。
Continuing.
result[1-100] = 5050       <———- 程序输出。

Breakpoint 2, func (n=250) at tst.c:5
5                int sum=0,i;
(gdb) n
6                for(i=1; i<=n; i++)
(gdb) p i       
<——————— 打印变量 i的价值, print命令简写。
$1 = 134513808
(gdb) n
8                        sum+=i;
(gdb) n
6                for(i=1; i<=n; i++)
(gdb) p sum
$2 = 1
(gdb) n
8                        sum+=i;
(gdb) p i
$3 = 2
(gdb) n
6                for(i=1; i<=n; i++)
(gdb) p sum
$4 = 3
(gdb) bt        <——————— 查看函数堆栈。
#0  func (n=250) at tst.c:5
#1  0x080484e4 in main () at tst.c:24
#2  0x400409ed in __libc_start_main () from /lib/libc.so.6
(gdb) finish    <——————— 退出函数。
Run till exit from #0  func (n=250) at tst.c:5
0x080484e4 in main () at tst.c:24
24              printf(“result[1-250] = %d \n”, func(250) );
Value returned is $6 = 31375
(gdb) c     <——————— 继续运行。
Continuing.
result[1-250] = 31375    <———- 程序输出。

Program exited with code 027. <——– 程序退出,调试了。
(gdb) q     <——————— 退出 gdb。
hchen/test>

哼了,有了上述之神志认识,还是叫咱们来系统地认识一下 gdb吧。

 

使用 GDB ————**

貌似的话 GDB主要调试之凡 C/C++的次第。要调节 C/C++的程序,首先以编译时,我们要要把调试信息加到可执行文件中。使用编译器( cc/gcc/g++)的 -g参数可以形成即一点。如:

    > cc -g hello.c -o hello
    > g++ -g hello.cpp -o hello

万一没有 -g,你用关押不显现程序的函数叫作、变量名,所取代的全都是运行时的内存地址。当您用 -g把调试信息加入后,并成编译目标代码以后,让咱来看望哪用 gdb来调节他。

启航 GDB的道发生以下几种:

    1 、 gdb <program>
       program 也即是你的履行文书,一般以自然目录下。

    2 、 gdb <program> core
       用 gdb同时调试一个周转程序和 core文件, core是次非法执行后 core
dump后发的文书。

    3 、 gdb <program> <PID>
       如果你的主次是一个服务程序,那么您可以指定这个服务程序运行时的经过 ID。 gdb会自动 attach上去,并调试他。 program应该以 PATH环境变量中寻找得到。

 

GDB 启动时,可以加上有的 GDB的启航开关,详细的开关可以用 gdb
-help查看。我于脚仅例举一些比较常用的参数:

    -symbols <file>
    -s <file>
    从指定文件中读取符号表。

    -se file
    从指定文件中读取符号表信息,并将他就此在可执行文件中。

    -core <file>
    -c <file>
    调试时 core dump的 core文件。

    -directory <directory>
    -d <directory>
    加入一个自文件之找路径。默认搜索路径是环境变量中 PATH所定义的门道。

GDB 的通令概貌 ———————**

起步 gdb后,就你给带走 gdb的调剂环境受到,就好用 gdb的下令开始调试程序了,gdb的下令可以使 help命令来查阅,如下所示:

    /home/hchen> gdb
    GNU gdb 5.1.1
    Copyright 2002 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and
you are
    welcome to change it and/or distribute copies of it under certain
conditions.
    Type “show copying” to see the conditions.
    There is absolutely no warranty for GDB.  Type “show warranty” for
details.
    This GDB was configured as “i386-suse-linux”.
    (gdb) help
    List of classes of commands:

    aliases — Aliases of other commands
    breakpoints — Making program stop at certain points
    data — Examining data
    files — Specifying and examining files
    internals — Maintenance commands
    obscure — Obscure features
    running — Running the program
    stack — Examining the stack
    status — Status inquiries
    support — Support facilities
    tracepoints — Tracing of program execution without stopping the
program
    user-defined — User-defined commands

    Type “help” followed by a class name for a list of commands in that
class.
    Type “help” followed by command name for full documentation.
    Command name abbreviations are allowed if unambiguous.
    (gdb)

gdb 的授命很多, gdb把的分成很多只品种。 help命令只是例出 gdb的吩咐种类,如果要看项目中的下令,可以运用 help
<class>命令,如: help
breakpoints,查看设置断点的装有命令。也可以一直 help
<command>来查看命令的救助。

gdb 中,输入指令时,可以不用从都命令,只所以自命令的眼前几独字符就得了,当然,命令的前几个字符应该要表明在一个唯一的命,在 Linux下,你可以打击两次等 TAB键来填补一起命令的全,如果发双重的,那么 gdb会把那例出来。
   
    示例一:在进入函数 func时,设置一个断点。可以敲入 break
func,或是直接就是 b func
    (gdb) b func
    Breakpoint 1 at 0x8048458: file hello.c, line 10.
 
    示例二:敲入 b按两糟 TAB键,你见面看出所有 b打头的下令:
    (gdb) b
    backtrace  break      bt
    (gdb)

    示例三:只记得函数的前缀,可以这么:
    (gdb) b make_ < 按 TAB键 >
    (再依下一致不行 TAB键,你见面见到 :)
    make_a_section_from_file     make_environ
    make_abs_section             make_function_type
    make_blockvector             make_pointer_type
    make_cleanup                 make_reference_type
    make_command                 make_symbol_completion_list
    (gdb) b make_
    GDB 把装有 make开头的函数全部规章出来给你查看。

    示例四:调试 C++的程序时,有得函数号称相同。如:
    (gdb) b ‘bubble( M-?
    bubble(double,double)    bubble(int,int)
    (gdb) b ‘bubble(
    你可查看到 C++中的富有的重载函数和参数。(注: M-?和 “按两浅 TAB键 ”是一个意)

假若退出 gdb时,只用发 quit或指令简称 q就行了。

 

GDB 中运行 UNIX 的 shell 程序 ————————————**

于 gdb环境受到,你得推行 UNIX的 shell的吩咐,使用 gdb的 shell命令来形成:

    shell <command string>
    调用 UNIX的 shell来执行 <command
string>,环境变量 SHELL中定义之 UNIX的 shell将会晤为用来实施 <command
string>,如果 SHELL没有概念,那即便动 UNIX的正统shell: /bin/sh。(在 Windows中动用 Command.com或 cmd.exe)

再有一个 gdb命令是 make:
    make <make-args>
    可以于 gdb中实施 make命令来更 build自己之主次。这个令等于 “
shell make <make-args> ”。

以 GDB 中运作程序 ————————**

当以 gdb
<program>方式启动 gdb后, gdb会在 PATH路径和当前目录中查找 <program>的源文件。如要肯定 gdb是否读到来自文件,可运 l或 list命令,看看 gdb是否能排出源代码。

当 gdb中,运行程序采取 r或是 run命令。程序的运转,你发出或要装下面四上面的从事。

1 、程序运行参数。
    set args 可指定运行时参数。(如: set args 10 20 30 40 50)
    show args 命令可以查设置好之周转参数。

2 、运行环境。
    path <dir> 可设定程序的运作路线。
    show paths 查看程序的周转路线。
    set environment varname [=value] 设置环境变量。如: set env
USER=hchen
    show environment [varname] 查看环境变量。

3 、工作目录。
    cd <dir> 相当于 shell的 cd命令。
    pwd 显示当前之四处目录。

4 、程序的输入输出。
    info terminal 显示你程序用到之极端的模式。
    使用重定向决定次输出。如: run > outfile
    tty 命令可以指写输入输出的极设备。如: tty /dev/ttyb

调剂已运转的程序 ————————**

鲜栽办法:
1 、在 UNIX下用 ps查看着运转的先后的 PID(进程 ID),然后据此 gdb
<program> PID格式挂接正在运作的次序。
2 、先用 gdb
<program>关联上源代码,并开展 gdb,在 gdb中之所以 attach命令来吊通进程的 PID。并就此 detach来取消挂接的过程。

 

停顿 / 恢复程序运行 —————————**

调试程序中,暂停程序运行是必的, GDB可以方便地暂停程序的运行。你得设置程序的当哪行停住,在啊条件下停住,在收到什么信号时停往等等。以便为您查运行时之变量,以及运行时的流水线。

当进程被 gdb停住时,你可行使 info
program来查阅程序的是不是在运行,进程号,被暂停的因由。

以 gdb中,我们可发以下几栽暂停方式:断点( BreakPoint)、观察点(WatchPoint)、捕捉点( CatchPoint)、信号( Signals)、线程停止( Thread
Stops)。如果如恢复程序运行,可以利用 c或是 continue命令。

相同、设置断点( BreakPoint )
   
    我们用 break命令来安断点。正面有几乎沾装断点的方:
   
    break <function>
        在入指定函数时已住。 C++中可以采取 class::function或 function(type,type)格式来指定函数称呼。

    break <linenum>
        在指定行号停住。

    break +offset
    break -offset
        在时下行号的面前或后的 offset行停止住。 offiset也自然数。

    break filename:linenum
        在自文件 filename的 linenum行处停住。

    break filename:function
        在起源文件 filename的 function函数的入口处已住。

    break *address
        在程序运行的内存地址处已住。

    break
        break 命令没有参数时,表示于产一致漫漫指令处已住。

    break … if <condition>
       
… 可以是上述的参数, condition表示法,在条件建立时停下住。比如当循环境体中,可以装 break
if i=100,表示当 i为 100时常停住程序。

    查看断点时,可采用 info命令,如下所示:(注: n表示断点号)
    info breakpoints [n]
    info break [n]
   

次、设置观察点( WatchPoint )
   
    观察点一般来观察某个表达式(变量也是千篇一律栽表达式)的值是否发转移了,如果生转移,马上停住程序。我们出下面的几乎栽方法来安装观察点:
   
    watch <expr>
        为表达式(变量) expr设置一个观察点。一量表述式值有浮动时,马上停住程序。
       
    rwatch <expr>
        当表达式(变量) expr被读常,停住程序。
       
    awatch <expr>
        当表达式(变量)的值为读或于形容时,停住程序。
   
    info watchpoints
        列出当前所装了底装有观察点。

老三、设置捕捉点( CatchPoint )

    你只是装捕捉点来补捉程序运行时的片段事件。如:载入共享库(动态链接库)或是C++的百般。设置捕捉点的格式为:
   
    catch <event>
        当 event发生时,停住程序。 event可以是下的情:
        1 、 throw一个 C++抛来底可怜。( throw为要字)
        2 、 catch一个 C++捕捉到之挺。( catch也重中之重字)
       
3 、 exec调用系统调用 exec时。( exec为首要字,目前是意义就以 HP-UX下有因此)
       
4 、 fork调用系统调用 fork时。( fork也要字,目前以此作用只在 HP-UX下发出因此)
       
5 、 vfork调用系统调用 vfork时。( vfork为重要字,目前之作用就于 HP-UX下产生因此)
        6 、 load或 load
<libname>载入共享库(动态链接库)时。( load为重大字,目前这功能只当 HP-UX下发生因此)
        7 、 unload或 unload
<libname>卸载共享库(动态链接库)时。( unload为关键字,目前夫功效就以 HP-UX下出因此)

    tcatch <event>
        只设置同一次于捕捉点,当次停住后,应点吃活动删除。

季、维护停止点

方说了什么设置程序的告一段落点, GDB中的告一段落点啊就是上述的三类。在 GDB中,如果你看就定义好之平息点并未因此了,你可以使用 delete、 clear、 disable、 enable这几只令来进行维护。

    clear
        清除所有的既定义的停下点。

    clear <function>
    clear <filename:function>
        清除所有安装在函数上之终止点。

    clear <linenum>
    clear <filename:linenum>
        清除所有安装以指定行及之停点。

    delete [breakpoints] [range…]
        删除指定的断点, breakpoints为断点号。如果非指定断点号,则象征去所有的断点。 range代表断点号的限定(如: 3-7)。其简写命令为 d。

比较去更好之均等种方式是 disable停止点, disable了底住点, GDB不会见删除,当你还欲时, enable即可,就象是回收站一样。

    disable [breakpoints] [range…]
       
disable 所指定的终止点, breakpoints为已点号。如果什么都未指定,表示disable所有的息点。简写命令是 dis.

    enable [breakpoints] [range…]
        enable 所指定的已点, breakpoints为平息点号。

    enable [breakpoints] once range…
       
enable 所指定的告一段落点同样破,当次停止后,该打住点即吃 GDB自动 disable。

    enable [breakpoints] delete range…
       
enable 所指定的息点同样不好,当次停止后,该停点即为 GDB自动删除。

 

五、停止条件保障

眼前在游说及安装断点时,我们干了好装一个尺码,当极建立时,程序自动终止,这是一个不行强劲的效果,这里,我眷恋特别说说之规则的连锁保障命令。一般的话,为断点设置一个准绳,我们采用 if关键词,后面和那个断点条件。并且,条件设置好后,我们可用 condition命令来修改断点的基准。(只有 break和 watch命令支持 if, catch目前暂勿支持 if)

    condition <bnum> <expression>
        修改断点号为 bnum的终止条件也 expression。

    condition <bnum>
        清除断点号为 bnum的停条件。

再有一个比较特殊之护命令 ignore,你可以指定程序运行时,忽略停止条件几乎差。

    ignore <bnum> <count>
        表示忽略断点号为 bnum的停止条件 count次。

 

六、为已点设定运行命令

咱们得采用 GDB提供的 command命令来装已点的运转命令。也就是说,当运行的次第于叫停止住时,我们得以为该活动运行有别的命令,这万分有利行自动化调试。对依据 GDB的自动化调试是一个劲的支撑。

    commands [bnum]
    … command-list …
    end

    为断点号 bnum指写一个指令列表。当次于拖欠断点停住时, gdb会依次运行命令列表中之通令。

    例如:

        break foo if x>0
        commands
        printf “x is %d\n”,x
        continue
        end
        断点设置在函数 foo中,断点条件是 x>0,如果程序于断住后,也不怕是,一旦 x的价值在 foo函数中超越 0, GDB会自动打印出 x的值,并持续运行程序。

假定您一旦排断点上的吩咐序列,那么要简单的履一下 commands命令,并一直当打独 end就行了。

七、断点菜单

每当 C++中,可能会见重新出现同一个名字的函数若干破(函数重载),在这种状况下,break
<function>不能够告 GDB要停下于哪个函数的进口。当然,你得行使 break
<function(type)>也尽管是管函数的参数类型告诉 GDB,以指定一个函数。否则的话, GDB会被您列有一个断点菜单供您选择你所待的断点。你如输入而菜单列表中的数码就好了。如:

    (gdb) b String::after
    [0] cancel
    [1] all
    [2] file:String.cc; line number:867
    [3] file:String.cc; line number:860
    [4] file:String.cc; line number:875
    [5] file:String.cc; line number:853
    [6] file:String.cc; line number:846
    [7] file:String.cc; line number:735
    > 2 4 6
    Breakpoint 1 at 0xb26c: file String.cc, line 867.
    Breakpoint 2 at 0xb344: file String.cc, line 875.
    Breakpoint 3 at 0xafcc: file String.cc, line 846.
    Multiple breakpoints were set.
    Use the “delete” command to delete unwanted
     breakpoints.
    (gdb)

足见, GDB列有了拥有 after的重载函数,你得选一下列表编号就行了。 0表示放弃设置断点, 1代表拥有函数都安装断点。

八、恢复程序运行和单步调试

当次于停住了,你可以用 continue命令恢复程序的运行直到程序结束,或下一个断点到来。也得采用 step或 next命令单步跟踪程序。

    continue [ignore-count]
    c [ignore-count]
    fg [ignore-count]
        恢复程序运行,直到程序结束,或是下一个断点到来。 ignore-count表示忽略其后的断点次数。 continue, c, fg三独命还是一模一样的意。

    step <count>
        单步跟踪,如果出函数调用,他会晤进该函数。进入函数的前提是,此函数被编译有debug信息。很像 VC等工具被的 step
in。后面可以加 count也得以无加以,不加以表示一条条地实践,加表示执行后的 count条指令,然后再次住住。

    next <count>
        同样单步跟踪,如果生函数调用,他无会见进来该函数。很像 VC等工具中之 step
over。后面可以加 count也可以不加以,不加以表示一条条地尽,加表示执行后的 count久指令,然后还住住。

    set step-mode
    set step-mode on
        打开 step-mode模式,于是,在进行单步跟踪时,程序不见面因无 debug信息要无歇住。这个参数有格外方便查看机器码。

    set step-mod off
        关闭 step-mode模式。

    finish
        运行程序,直到当前函数完成回。并打印函数返回时之堆栈地址与返回值及参数值等消息。

    until 或 u
        当你厌倦了当一个循环体内单步跟踪时,这个令可以运行程序直到退出循环体。

    stepi 或 si
    nexti 或 ni
        单步跟踪一长长的机器指令!一长长的程序代码有或出于数长条机器指令完成, stepi和 nexti可以单步执行机器指令。与之同发生雷同功能的下令是 “
display/i $pc
”,当运行了这个命令后,单步跟踪会以打出程序代码的还要于来机器指令(也即是集编代码)

九、信号( Signals )

信号是平栽软中断,是一模一样种植处理异步事件之方。一般的话,操作系统还支持多信号。尤其是 UNIX,比较关键应用程序一般都见面处理信号。 UNIX定义了众信号,比如SIGINT表示暂停字符信号,也就是是 Ctrl+C的信号, SIGBUS表示硬件故障的信号;SIGCHLD表示子进程状态改变信号; SIGKILL表示已程序运行的信号,等等。信号量编程是 UNIX下很关键的一致种技术。

GDB 有力量在公调试程序的时候处理任何一样种植信号,你可以告诉 GDB需要处理啊一样种信号。你可要求 GDB收到你所指定的信号时,马上停住正在运行的次第,以供应而进行调试。你可就此 GDB的 handle命令来就这无异作用。

    handle <signal> <keywords…>
        在 GDB中定义一个信号处理。信号 <signal>可以坐 SIG开头或未盖 SIG开头,可以用定义一个只要处理信号的界定(如: SIGIO-SIGKILL,表示处理由 SIGIO信号到 SIGKILL的信号,其中包括 SIGIO, SIGIOT, SIGKILL三单信号),也堪运用要字 all来表明要处理所有的信号。一旦为调剂之先后接收至信号,运行程序及时会被 GDB停住,以供应调试。其 <keywords>可以是以下几种主要字的一个还是多个。

        nostop
            当给调剂的先后收到信号时, GDB不会见停住程序的周转,但会起有消息告诉你接到这种信号。
        stop
            当给调剂之顺序收到信号时, GDB会停住你的次。
        print
            当于调剂的主次收到信号时, GDB会显示出一致漫漫信息。
        noprint
            当让调剂之顺序收到信号时, GDB不会见报您接信号的信息。
        pass
        noignore
            当让调剂的次序收到信号时, GDB不处理信号。这象征, GDB会把此信号交给被调试程序会处理。
        nopass
        ignore
            当让调剂之先后收到信号时, GDB不见面吃让调试程序来处理是信号。

    info signals
    info handle
        查看有怎么样信号于让 GDB检测中。

十、线程( Thread Stops )

一经您程序是多线程的话,你可以定义你的断点是否当具备的线程上,或是在某个特定的线程。 GDB很易帮您就就无异行事。

    break <linespec> thread <threadno>
    break <linespec> thread <threadno> if …
       
linespec 指定了断点设置以的源程序的行号。 threadno指定了线程的 ID,注意,这个 ID是 GDB分配的,你可由此 “
info threads ”命令来查阅在运作程序中的线程信息。如果您无指定 thread
<threadno>则象征若的断点设于装有线程上面。你还可为某某线程指定断点条件。如:
   
        (gdb) break frik.c:13 thread 28 if bartab > lim

    当你的次于 GDB停住时,所有的周转线程都见面被终止住。这有利于而而翻运行程序的完整情况。而当您恢复程序运行时,所有的线程也会见吃恢复运转。那恐惧是主进程在吃单步调试时。

翻开栈信息 —————**

当次于停住了,你要举行的首先宗事即是查程序是于哪停住的。当你的主次调用了一个函数,函数的地址,函数参数,函数内的组成部分变量都见面叫压制入 “栈 ”( Stack)中。你得为此 GDB命令来查看时底栈中的音。

下是局部查看函数调用栈信息之 GDB命令:

    backtrace
    bt
        打印当前底函数调用栈的拥有信息。如:
       
        (gdb) bt
        #0  func (n=250) at tst.c:6
        #1  0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30
        #2  0x400409ed in __libc_start_main () from
/lib/libc.so.6
       
        从达到可以看出函数的调用栈信息: __libc_start_main –>
main() –> func()
       
   
    backtrace <n>
    bt <n>
        n 是一个正整数,表示无非打印栈顶上 n层的库信息。

    backtrace <-n>
    bt <-n>
        -n 表一个负整数,表示只是打印栈底下 n层的堆栈信息。
       
假若你若查有平重叠的信息,你要在切换时之库,一般的话,程序停止时,最顶层的库房就是现阶段栈,如果您只要查看栈下面层的详细信息,首先要举行的是切换时栈。

    frame <n>
    f <n>
        n 是一个于 0开始的整数,是栈中的层编号。比如: frame
0,表示栈顶, frame 1,表示栈的亚叠。
   
    up <n>
        表示为栈的点移动 n层,可以免起 n,表示发展走一重叠。
       
    down <n>
        表示为栈的下边移动 n层,可以免由 n,表示向下移动一交汇。
       

    上面的下令,都见面打印出活动至之栈层的消息。如果你切莫思为该于起消息。你得运用就三只令:
   
            select-frame <n> 对应于 frame命令。
            up-silently <n> 对应于 up命令。
            down-silently <n> 对应于 down命令。

   
查阅时栈层的音信,你得用来下 GDB命令:

    frame 或 f
        会打印出这些消息:栈的层编号,当前之函数号称,函数参数值,函数所当文书以及行号,函数执行到的讲话。
   
    info frame
    info f
        这个命令会打印出更详细的此时此刻栈层的音,只不过,大多数且是运行时的内内地址。比如:函数地址,调用函数的地方,被调用函数的地方,目前的函数是由于哪的程序语言写成的、函数参数地址与价值、局部变量的地方等等。如:
            (gdb) info f
            Stack level 0, frame at 0xbffff5d4:
             eip = 0x804845d in func (tst.c:6); saved eip 0x8048524
             called by frame at 0xbffff60c
             source language c.
             Arglist at 0xbffff5d4, args: n=250
             Locals at 0xbffff5d4, Previous frame’s sp is 0x0
             Saved registers:
              ebp at 0xbffff5d4, eip at 0xbffff5d8
             
     info args
        打印出当下函数的参数名及其值。
    
     info locals
        打印出时函数中具有片变量和其值。
       
     info catch
        打印出脚下的函数中的慌处理信息。

查看源程序 —————**

一样、显示源代码

   
GDB 可以打印出所调试程序的源代码,当然,在次编译时一定要是长 -g的参数,把源程序信息编译到执行文书中。不然就是看不到源程序了。当次停下来后, GDB会报告先后停在了异常文件的第几行及。你得就此 list命令来打印程序的源代码。还是来拘禁同样看查看源代码的 GDB命令吧。
   
    list <linenum>
        显示程序第 linenum行的周围的源程序。
   
    list <function>
        显示函数名为也 function的函数的源程序。
       
    list
        显示当前推行后的源程序。
   
    list –
        显示当前实施前面的源程序。

相似是打印当前推行之上 5行和下 5履行,如果显示函数是凡上 2行下 8执行,默认是 10实施,当然,你啊得定制显示的界定,使用下发号施令可以装同一不行显示源程序的行数。

    set listsize <count>
        设置同一糟糕展示源代码的行数。
       
    show listsize
        查看时 listsize的设置。
       

list 命令还有下面的用法:

    list <first>, <last>
        显示从 first行到 last行之间的源代码。
   
    list , <last>
        显示从脚下履行至 last行之间的源代码。
       
    list +
        往后显示源代码。
       

貌似的话在 list后面可以与以下就等的参数:

    <linenum>   行号。
    <+offset>   当前行号的正偏移量。
    <-offset>   当前行号的负偏移量。
    <filename:linenum>  哪个文件的呀一行。
    <function>  函数名。
    <filename:function> 哪个文件被的哪个函数。
    <*address>  程序运行时的言辞在内存中的地点。
   

亚、搜索源代码

不仅如此, GDB还提供了来代码搜索的吩咐:

    forward-search <regexp>
    search <regexp>
        向前方搜索。

    reverse-search <regexp>
        全部招来。
       
其间, <regexp>就是正则表达式,也预示一个字符串的匹配模式,关于正则表达式,我不怕无在此地说了,还伸手各位查看相关资料。

老三、指定源文件之门道

一点时段,用 -g编译过后的执行顺序中唯有是包了自文件之讳,没有路径名。 GDB提供了足以被您指定源文件之门路的指令,以便 GDB进行检索。

    directory <dirname … >
    dir <dirname … >
        加一个起源文件路径到眼前路线的前。如果你如果指定多只路子, UNIX下您得下“
: ”, Windows下而可使用 “ ; ”。
    directory
        清除所有的自定义的源文件搜索路径信息。
   
    show directories
        显示定义了之源文件搜索路径。
       

季、源代码的内存

乃可以 info line命令来查看源代码在内存中的地址。 info
line后面可以跟 “行号 ”,“函数名 ”, “文件名 :行号 ”, “文件名 :函数名 ”,这个命令会打印出所指定的源码在运转时之内存地址,如:

        (gdb) info line tst.c:func
        Line 5 of “tst.c” starts at address 0x8048456 <func+6> and
ends at 0x804845d <func+13>.

还有一个指令( disassemble)你得查看源程序的手上实行时的机器码,这个令会将目前内存中的指令 dump出来。如下面的演示表示查看函数 func的汇编代码。

        (gdb) disassemble func
        Dump of assembler code for function func:
        0x8048450 <func>:       push   %ebp
        0x8048451 <func+1>:     mov    %esp,%ebp
        0x8048453 <func+3>:     sub    $0x18,%esp
        0x8048456 <func+6>:     movl   $0x0,0xfffffffc(%ebp)
        0x804845d <func+13>:    movl   $0x1,0xfffffff8(%ebp)
        0x8048464 <func+20>:    mov    0xfffffff8(%ebp),%eax
        0x8048467 <func+23>:    cmp    0x8(%ebp),%eax
        0x804846a <func+26>:    jle    0x8048470 <func+32>
        0x804846c <func+28>:    jmp    0x8048480 <func+48>
        0x804846e <func+30>:    mov    %esi,%esi
        0x8048470 <func+32>:    mov    0xfffffff8(%ebp),%eax
        0x8048473 <func+35>:    add    %eax,0xfffffffc(%ebp)
        0x8048476 <func+38>:    incl   0xfffffff8(%ebp)
        0x8048479 <func+41>:    jmp    0x8048464 <func+20>
        0x804847b <func+43>:    nop
        0x804847c <func+44>:    lea    0x0(%esi,1),%esi
        0x8048480 <func+48>:    mov    0xfffffffc(%ebp),%edx
        0x8048483 <func+51>:    mov    %edx,%eax
        0x8048485 <func+53>:    jmp    0x8048487 <func+55>
        0x8048487 <func+55>:    mov    %ebp,%esp
        0x8048489 <func+57>:    pop    %ebp
        0x804848a <func+58>:    ret
        End of assembler dump.

 

查看运行时数 ———————**
   
    在公调试程序时,当次让停止住时,你得用 print命令(简写命令为 p),或是同义命令 inspect来查阅时程序的运作数据。 print命令的格式是:
   
    print <expr>
    print /<f> <expr>
       
<expr> 是表达式,是公所调试之顺序的语言的表达式( GDB可以调节多种编程语言), <f>是出口的格式,比如,如果要是拿表达式按 16进制的格式输出,那么就是是 /x。
       
   
一、表达式**

   
print 和许多 GDB的指令一样,可以领一个表达式, GDB会根据目前之程序运行的多寡来测算这表达式,既然是表达式,那么就算足以是眼下程序运行中的 const常量、变量、函数等内容。可惜的凡 GDB不可知下你当次中所定义的极大。
   
    表达式的语法应该是眼下所调试的语言的语法,由于 C/C++是千篇一律栽大众型的语言,所以,本文中的例证都是有关 C/C++的。(而至于用 GDB调试其它语言的章,我以在后头介绍)
   
    在表达式中,有几乎栽 GDB所支撑之操作符,它们得以据此当其余一样种植语言中。
   
    @
        是一个和数组有关的操作符,在后面会有双重详实的证明。
       
    ::
        指定一个当文书或者一个函数中的变量。
       
    {<type>} <addr>
        表示一个针对性内存地址 <addr>的项目为 type的一个对象。
       
       
次、程序变量

    在 GDB中,你得随时查阅以下三种植变量的价值:
        1 、全局变量(所有文件可见的)
        2 、静态全局变量(当前文件可见的)
        3 、局部变量(当前 Scope可见的)
       
    如果你的有些变量和全局变量发生冲突(也即是重名),一般景象下是有些变量会暗藏全局变量,也就是说,如果一个全局变量和一个函数中之片段变量同名时,如果手上止点当函数中,用 print显示出的变量的值会是函数中之有些变量的价值。如果此时若想查全局变量的价时,你可使用 “
:: ”操作符:
   
        file::variable
    function::variable
    可以透过这种形式指定你所想查看的变量,是孰文件中的或者哪个函数中之。例如,查看文件 f2.c挨的全局变量 x的值:
   
    gdb) p ‘f2.c’::x
   
    当然, “ :: ”操作符会和 C++中之发生冲突, GDB能自动识别 “ ::
”是否 C++的操作符,所以若不要顾虑在调试 C++程序时见面出现异常。
   
    另外,需要留意的是,如果您的次第编译时打开了优化增选,那么以用 GDB调试被优化了之次时,可能会见产生一些变量不可知访问,或是取值错误码的场面。这个是格外正规的,因为优化程序会删改你的顺序,整理而程序的语顺序,剔除一些虚无的变量等,所以于 GDB调试这种程序时,运行时的授命和您所编写指令就发出无平等,也不怕见面油然而生而所想像不顶的结果。对付这种情形经常,需要以编译程序时关闭编译优化。一般的话,几乎拥有的编译器都支持编译优化的开关,例如, GNU的 C/C++编译器 GCC,你得使用 “
-gstabs
”选项来缓解这个题材。关于编译器的参数,还恳请查看编译器的用验证文档。
   

三、数组

    有时候,你待查阅一截连接的内存空间的值。比如数组的同段落,或是动态分配的数目的轻重。你可采取 GDB的 “
@ ”操作符, “ @ ”的左边是率先只内存的地方的值, “ @
”的右手则你你想翻内存的长。例如,你的顺序中生这么的说话:
    
        int *array = (int *) malloc (len * sizeof (int));
       
    于是,在 GDB调试过程中,你得坐如下命令显示有这动态数组的取值:

        p *array@len

   
@ 的左是一再组的首地址的值,也就是是变量 array所指向的始末,右边则是数码的长度,其保存于变量 len中,其出口结果,大约是下面这法的:
   
        (gdb) p *array@len
        $1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40}

    如果是静态数组的话,可以一直用 print数组名,就足以展示数组中负有数据的内容了。

   
季、输出格式

    一般的话, GDB会根据变量的种输出变量的价。但若也可于定义 GDB的输出的格式。例如,你想出口一个整数的十六进制,或是二进制来查阅此整型变量的饱受的各项之情况。要水到渠成这样,你可以动用 GDB的数据展示格式:
   
    x  按十六上前制格式显示变量。
    d  按十进制格式显示变量。
    u  按十六向前制格式显示无符号整型。
    o  按八迈入制格式显示变量。
    t  按次上前制格式显示变量。
    a  随十六进制格式显示变量。
    c  按照字符格式显示变量。
    f  按浮点数格式显示变量。

        (gdb) p i
        $21 = 101   
       
        (gdb) p/a i
        $22 = 0x65
       
        (gdb) p/c i
        $23 = 101 ‘e’
       
        (gdb) p/f i
        $24 = 1.41531145e-43
       
        (gdb) p/x i
        $25 = 0x65
       
        (gdb) p/t i
        $26 = 1100101

五、查看内存

    你可采取 examine命令(简写是 x)来查阅内存地址中的价值。 x命令的语法如下所示:
   
    x/<n/f/u> <addr>
   
    n 、 f、 u是可选的参数。
   
   
n 是一个正要整数,表示显示内存的尺寸,也就是说从眼前地方为后出示几乎单地点之情节。
   
f 表示显示的格式,参见上面。如果地方所负的是字符串,那么格式可以是 s,如果地十是令地址,那么格式可以是 i。
   
u 表示从今目前地点为后呼吁的字节数,如果非点名的话, GDB默认是 4个 bytes。 u参数可以用底的字符来代表, b代表单字节, h表示双字节, w表示四字节, g代表八字节。当我们指定了字节长度后, GDB会从指内存定的内存地址开始,读写指定字节,并把其看作一个值取出来。
   
    <addr> 表示一个内存地址。

    n/f/u 三独参数可以同步以。例如:
   
    命令: x/3uh
0x54320表示,从内存地址 0x54320念博内容, h代表以对字节为一个单位, 3表示三只单位, u代表遵照十六进制显示。
   
   
六、自动显示

    你可以安装有机关显示的变量,当次停住时,或是在你单步跟踪时,这些变量会自行显示。相关的 GDB命令是 display。
   
    display <expr>
    display/<fmt> <expr>
    display/<fmt> <addr>
   
   
expr 是一个表达式, fmt代表显示的格式, addr表示内存地址,当您用 display设定好了一个还是多个表达式后,只要你的先后让终止下来, GDB会自动显示你所设置的这些表达式的价值。
   
    格式 i和 s同样让 display支持,一个特别实用的指令是:
   
        display/i $pc
   
   
$pc 是 GDB的环境变量,表示正命令的地址, /i则意味着输出格式为机器指令码,也不怕是汇编。于是当次停下后,就会冒出源代码和机器指令码相对应之状态,这是一个不行风趣的成效。
   
    下面是一对与 display相关的 GDB命令:
   
    undisplay <dnums…>
    delete display <dnums…>
    删除自动显示, dnums意为所设置好了底机关显式的号。如果假定而删除几只,编号可以为此空格分隔,如果如抹一个限量外之号子,可以用减号表示(如: 2-5)
   
    disable display <dnums…>
    enable display <dnums…>
    disable 和 enalbe不去自动显示的安装,而就是于那个失效和还原。
   
    info display
    查看 display设置的自动显示的音信。 GDB会打有同样摆设表,向而告诉当调试中安了有些只自动显示设置,其中包,设置的号码,表达式,是否 enable。

七、设置显示选项

    GDB 中有关显示的抉择项于多,这里我特例举大多数常用的取舍项。

    set print address
    set print address on
        打开地址输出,当次显示函数信息经常, GDB会显出函数的参数地址。系统默认为打开的,如:
       
        (gdb) f
        #0  set_quotes (lq=0x34c78 “<<“, rq=0x34c88
“>>”)
            at input.c:530
        530         if (lquote != def_lquote)

    set print address off
        关闭函数的参数地址显示,如:
       
        (gdb) set print addr off
        (gdb) f
        #0  set_quotes (lq=”<<“, rq=”>>”) at input.c:530
        530         if (lquote != def_lquote)

    show print address
        查看时地点显示选项是否打开。
       
    set print array
    set print array on
        打开数组显示,打开后当数组显示时,每个元素占一尽,如果非打开的话,每个元素虽然因为逗号分隔。这个选项默认是关的。与的休戚相关的个别只命如下,我虽不再多说了。
       
    set print array off
    show print array

    set print elements <number-of-elements>
        这个选项主要是安装数组的,如果您的数组太特别了,那么即使得指定一个 <number-of-elements>来指定数量显示的无限充分尺寸,当到这个长度时, GDB就不再为生显得了。如果安也 0,则意味着未限定。
       
    show print elements
        查看 print elements的挑选项信息。
       
    set print null-stop <on/off>
        如果打开了之选项,那么当显示字符串时,遇到了符则停止显示。这个选项默认为 off。
       
    set print pretty on
        如果打开 printf
pretty这个选项,那么当 GDB显示结构体时会较优良。如:

            $1 = {
              next = 0x0,
              flags = {
                sweet = 1,
                sour = 1
              },
              meat = 0x54 “Pork”
            }

    set print pretty off
        关闭 printf pretty这个选项, GDB显示结构体时会如下显示:
       
            $1 = {next = 0x0, flags = {sweet = 1, sour = 1}, meat = 0x54
“Pork”}
           
    show print pretty
        查看 GDB是什么展示结构体的。
       
   
    set print sevenbit-strings <on/off>
        设置字符显示,是否按 “ \nnn
”的格式显示,如果打开,则字符串或字符数据按 \nnn显示,如 “ \065 ”。
   
    show print sevenbit-strings
        查看字符显示开关是否打开。
       
    set print union <on/off>
        设置显示结构体时,是否显式其内的联合体数据。例如有以下数据结构:
       
        typedef enum {Tree, Bug} Species;
        typedef enum {Big_tree, Acorn, Seedling} Tree_forms;
        typedef enum {Caterpillar, Cocoon, Butterfly}
                      Bug_forms;
       
        struct thing {
          Species it;
          union {
            Tree_forms tree;
            Bug_forms bug;
          } form;
        };
       
        struct thing foo = {Tree, {Acorn}};

        当打开这开关时,执行 p foo命令后,会如下显示:
            $1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
       
        当关闭是开关时,执行 p foo命令后,会如下显示:
            $1 = {it = Tree, form = {…}}

    show print union
        查看联合体数据的显示方式
       
    set print object <on/off>
        在 C++中,如果一个对象指针指为其派生类,如果打开这选项, GDB会自动按虚方法调用的规则显示输出,如果关闭这个选项的话, GDB就不管虚函数表了。这个选项默认是 off。
   
    show print object
        查看对象选择的安。
       
    set print static-members <on/off>
        这个选项表示,当显一个 C++对象中的情是,是否出示中间的静态数据成员。默认是 on。
   
    show print static-members
        查看静态数据成员选项设置。
       
    set print vtbl <on/off>
        当以此选项打开时, GDB将用比规整的格式来展示虚函数表时。其默认是倒闭的。
       
    show print vtbl
        查看虚函数显示格式的选项项。
       
       
八、历史记录

    当你用 GDB的 print查看程序运行时之数常常,你各个一个 print都见面为 GDB记录下来。GDB会以 $1,
$2, $3
…..这么的主意也公各个一个 print命令编上号。于是,你可以动用是编号访问以前的表达式,如 $1。这个作用所带动的裨益是,如果你以前输入了一个于长之表达式,如果你还惦记查看这表达式的价,你得利用历史记录来拜会,省去了重新输入。
   
   
九、 GDB 环境变量

    你得以 GDB的调节环境被定义自己的变量,用来保存有调试程序中的运作数据。要定义一个 GDB的变量很粗略就需要。使用 GDB的 set命令。 GDB的环境变量和 UNIX一样,也是为 $起头。如:
   
    set $foo = *object_ptr
   
    使用环境变量时, GDB会在你首先破采用时创造是变量,而在后的施用受到,则直接针对那賦值。环境变量没有种,你得给环境变量定义任一的花色。包括结构体和数组。
   
    show convenience
        该令查看时所设置的有着的环境变量。
       
    这是一个较强硬的效能,环境变量和次变量的相互使用,将让程序调试更为灵活方便。例如:
   
        set $i = 0
        print bar[$i++]->contents
   
    于是,当你就不用, print bar[0]->contents, print
bar[1]->contents地输入指令了。输入这样的指令后,只所以敲掉车,重复执行上一致漫漫语句,环境变量会自行抬高,从而做到逐个出口的功用。
   
   
十、查看寄存器

    要翻寄存器的价值,很简短,可以下如下命令:
   
    info registers
        查看寄存器的事态。(除了浮点寄存器)
   
    info all-registers
        查看所有寄存器的状态。(包括浮点寄存器)
   
    info registers <regname …>
        查看所指定的寄存器的场面。
       
    寄存器中放置了程序运行时的数据,比如程序当前运行的下令地址( ip),程序的脚下堆栈地址( sp)等等。你平可以采用 print命令来访问寄存器的情,只需要在寄存器名字前加一个 $符号就好了。如: p
$eip。

改变程序的实行 ———————**

    一旦采用 GDB挂上于调试程序,当程序运行起来后,你可以依据自己的调节思路来动态地于 GDB中改变当前为调试程序的运作线路或其变量的值,这个强大的效能会吃您还好的调节你的次,比如,你可以于次的均等涂鸦运行面临走遍程序的拥有支行。
   
   
一致、修改变量值

    修改为调试程序运行时的变量值,在 GDB中杀轻实现,使用 GDB的 print命令即可成功。如:
   
        (gdb) print x=4
   
   
x=4 这个表达式是 C/C++的语法,意为将变量 x的价修改为 4,如果你眼前调试之言语是 Pascal,那么你得运用 Pascal的语法: x:=4。
   
    在某些时刻,很有或而的变量和 GDB中之参数冲突,如:
   
        (gdb) whatis width
        type = double
        (gdb) p width
        $4 = 13
        (gdb) set width=47
        Invalid syntax in expression.

    因为, set width是 GDB的命令,所以,出现了 “ Invalid syntax in
expression ”的安错误,此时,你可以运用 set
var命令来告诉 GDB, width不是你 GDB的参数,而是程序的变量名,如:
   
        (gdb) set var width=47
       
    另外,还可能小情况, GDB并无晓这种不当,所以管起见,在公改变程序变量取值时,最好还使用 set
var格式的 GDB命令。
   

仲、跳反执行

    一般的话,被调试程序会以程序代码的运作顺序依次执行。 GDB提供了乱序执行的效用,也就是说, GDB可以修改程序的推行各个,可以叫程序执行随意跳跃。这个效应可以由 GDB的 jump命令来了:
   
    jump <linespec>
    指定下一致久告句之运行点。 <linespce>可以是文件的行号,可以是 file:line格式,可以是 +num这种偏移量格式。表式着下一样漫长运行语句从哪里开始。
   
    jump <address>
    这里的 <address>是代码行的内存地址。
   
    注意, jump命令不会见转目前的先后栈中的内容,所以,当您自一个函数跳到另外一个函数时,当函数运行了回到时展开弹栈操作时肯定会生出误,可能结果要么特别奇怪的,甚至于产生程序 Core
Dump。所以最是跟一个函数中开展跳转。
   
    熟悉汇编的丁都懂得,程序运行时,有一个寄存器用于保存时代码所在的内存地址。所以, jump命令也就是是改了此寄存器中之价值。于是,你得使用 “
set $pc ”来转跳反执行的地点。如:
   
    set $pc = 0x485

其三、产生信号量

    使用 singal命令,可以产生一个信号量给被调剂之次。如:中断信号 Ctrl+C。这万分方便于程序的调节,可以在程序运行的自由位置设置断点,并于该断点用 GDB产生一个信号量,这种准地以某处产生信号好有利于程序的调剂。
   
    语法是: signal
<singal>, UNIX的网信号量通常由 1到 15。所以 <singal>取值也在此界定。
   
   
single 命令和 shell的 kill命令不同,系统的 kill命令发信号给吃调试程序时,是由于 GDB截获的,而 single命令所生一信号则是直发给被调试程序的。
   

季、强制函数返回

    如果您的调剂断点在某个函数中,并还有语句没有尽了。你可以动用 return命令强制函数忽略还没有履行的讲话并回。
   
    return
    return <expression>
    使用 return命令撤销时函数的实践,并立刻回去,如果指定了 <expression>,那么该表达式的值会被认作函数的回值。
   
   
五、强制调用函数

    call <expr>
    表达式中唯独坐同凡函数,以此达到强制调用函数的目的。并显示函数的回值,如果函数返回值是 void,那么就未亮。
   
    另一个形似之一声令下也堪成功就无异成效 ——
print, print后面可以同表达式,所以呢可以为此他来调用函数, print和 call的差是,如果函数返回 void, call则无出示, print则显得函数返回值,并拿该值存入历史数据遭到。

 

在不同语言中应用 GDB ——————————**

GDB 支持下列语言: C, C++, Fortran, PASCAL, Java, Chill,
assembly,和 Modula-2。一般说来, GDB会根据你所调试的次来确定当然的调节语言,比如:发现文件名后缀为 “
.c ”的, GDB会认为是 C程序。文件名后缀为 “ .C, .cc, .cp, .cpp, .cxx,
.c++ ”的, GDB会认为是 C++程序。而后缀是 “ .f, .F
”的, GDB会认为是 Fortran程序,还有,后缀为使是 “ .s, .S
”的会面看是汇编语言。

也就是说, GDB会根据你所调试之次的语言,来安装好的言语环境,并叫 GDB的指令就语言环境之改而改。比如有 GDB命令需要动用表达式或变量时,这些表达式或变量的语法,完全是依据当前之言语环境一旦改的。例如 C/C++中对指针的语法是*p,而于 Modula-2中则是 p^。并且,如果您眼前的主次是由几栽不同语言一同编译成的,那顶当调试过程中, GDB也能够因不同的语言自动地切换语言环境。这种跟着语言环境而变更之效应,真是体贴开发人员的同等种植设计。

下面是几独相关于 GDB语言环境的通令:

    show language
        查看时底言语环境。如果 GDB不能够认识为您所调试之编程语言,那么, C语言让当是默认的条件。
       
    info frame
        查看时函数的程序语言。
       
    info source
        查看时文件之程序语言。
   
若 GDB没有检测出时的程序语言,那么你为堪手动设置当前底程序语言。使用 set
language命令即可成功。

    当 set
language命令后什么呢未与的话,你可查阅 GDB所支撑之言语类:
   
        (gdb) set language
        The currently understood settings are:
       
        local or auto    Automatic setting based on source file
        c                Use the C language
        c++              Use the C++ language
        asm              Use the Asm language
        chill            Use the Chill language
        fortran          Use the Fortran language
        java             Use the Java language
        modula-2         Use the Modula-2 language
        pascal           Use the Pascal language
        scheme           Use the Scheme language
       
    于是你可以 set
language后与达到被排下的程序语言名,来安当前底语言环境。
   
相关图片解释

 

符号表

 

l         
符号即变量或函数。符号表负责变量或函数曰到那个内存地址的关系。没有标记表,GDB无法理解变量或函数号称,如无法透过变量名查看变量。

l         
如果要是呢可执行文件产生符号表,需要在编译时以gcc的-g-ggdb选项。

l         
可以为-g-ggdb慎选指定出的音级别(1到3级),如-g3。级别越强,信息量越来越怪。默认级别为2。


过程地址空间

 

高地址

命令行参数和环境变量

 

 

向下增长;

 

未使用空间

 

 

向上增长;

 

未初始化数据段(BSS)

未初始化全局变量,程序执行前初始化为0或NULL;

 

已初始化数据段

由exec从程序文件读取;

低地址

文本段

由exec从程序文件读取;

l         
栈中保存了函数调用关系。每调用一个函数,分配一个栈帧,记录函数返回地址、传递的参数和部分变量。

l         
可以运用GDB的backtrace(缩写为bt)命令查看栈信息。最前边的数字代表帧号。

(gdb) bt

#0  func2 () at gdb_test.c:35

#1  0x080484a9 in func1 (iptr=0xbf98a2f0) at gdb_test.c:28

#2  0x08048453 in main (argc=Cannot access memory at address 0xc) at gdb_test.c:14

l         
可以以frame(缩写为f)命令查看时栈帧,即眼前所于的函数。

l         
GDB只能查看时函数内的变量。如果如查其他函数内之变量,需要切换栈帧,方法是为frame令传递帧号。

(gdb) p i

No symbol "i" in current context.

(gdb) frame 2

#2  0x08048453 in main (argc=Cannot access memory at address 0xc) at gdb_test.c:14

(gdb) p i

$1 = 3


运转程序

 

l          要以GDB中运行程序,可以在shell中输入gdb ./filename

l          或者当运行GDB后,通过file一声令下打开程序。

l         
调用run(缩写为r)命令开始施行。可以呢run命传递命令执行参数。set
args
令撤销之前传递的参数。

(gdb) run 1 2 3

Starting program: /home/pydeng/gdb_test/gdb_test 1 2 3

There are 4 args.

l         
调用kill(缩写为k)命令已程序的实施,然后使run再度运行。

l         
或者以程序运行的下还调用run命令,GDB将了解是否再运行程序。


查阅代码

 

l         
可以应用list(缩写为l)命令显示当前职务后的十行代码。加上负号则显得前面十行,如list

l          可以以多道指定显示的职位,如:

从第5行开始

(gdb) list 5, 

到28行结束

(gdb) list ,28 

显示21到25行之间的代码

(gdb) list 21,25 

显示func1函数

(gdb) list func1 

显示其它文件的12行

(gdb) list otherfile.c:12 

显示其它文件的函数

(gdb) list otherfile.c:func

l          可以经过set命改变显示的代码行数,如set listsize 5


装断点

 

l          使用break命令设置断点,断点的位置好经过四种植方式指定。

通过函数名指定

(gdb) break func1 

通过行号指定

(gdb) break 9 

通过文件名和行号指定

(gdb) break main.c:10 

通过内存地址指定

(gdb) break *0x80483f4

l          也可于抵达断点的时候,根据目前的职位设置断点。如break
+2
当当前职后第2执行之职务设置断点,break
-3
在时下职务的先头第3履的位置设置断点。

l          可以透过where一声令下查看时所于的职位。

l          可以吧断点添加条件,只有当规则满足时才见面在断点处暂停程序。

(gdb) b 17 if i==1

Breakpoint 8 at 0x8048455: file gdb_test.c, line 17.

l          程序到达断点暂停后,可以使用continue令恢复执行。

l         
或者采取stepnext指令单步执行。两者的分在于,step命将跻身被调用的函数,而next命令将函数调用看作一久语句。

l          info breakpoints(缩写为i
b
)命令能查阅设置的装有端点。Num为断点号,Enb标识端点是否启用。

(gdb) i b

Num     Type           Disp Enb Address    What

6       breakpoint     keep n   0x08048436 in main at gdb_test.c:12

8       breakpoint     keep y   0x08048455 in main at gdb_test.c:17

     stop only if i==1

l         
可以应用cleardelete命去断点,前者以上述四种植指定断点位置的主意标识断点,后者以断点号标识断点。

l         
通过传递断点号,disableenable命能少停用或另行启用断点。


翻变量

 

l         
使用ptype(缩写为pt)命令查看变量的路。要牢记,只能查看时栈帧内之变量。

l         
使用print(缩写为p)命令加变量名,可以翻变量的价,也可行使取地址符查看变量的地点,并且能指导显示的格式。

 

o octal   x hex   d decimal  u unsigned decimal

t binary  f float  a address  c char 

 

(gdb) p /x i

$3 = 0x1

 

 

 

l         
查看数组时,可以指定显示的素起始位置和因素个数,但是非会见检查是否越界。

(gdb) p array[2]@5

$4 = {3, 4, 5, 6, 134514064}

l          也得翻结构体。使用set print pretty令优化显示格式。

(gdb) p p

$6 = {age = 25, name = 0x80485a7 "cying"}

(gdb) set print pretty

(gdb) p p

$7 = {

  age = 25,

  name = 0x80485a7 "cying"

}

l         
可以动用setprint指令,在程序执行过程遭到,改变变量的价值,如set
i = 5
print i = 5。两者分别在,后者打印改变后的价值。

(gdb) set array[0]=11

(gdb) p array[1]=22

$8 = 22

(gdb) p array

$9 = {11, 22, 3, 4, 5, 6}

 

后记 ——**

   
GDB 是一个强硬的命令行调试工具。大家领略命令行的精锐就在于,其可形成执行序列,形成脚本。 UNIX下的软件都是命令行的,这吃程序支付提代供了特大的好,命令执行软件的优势在,它们可非常容易的合并以联合,使用几个简易的曾发生工具的命令,就好做出一个好强的效益。  

事先在看汇编的时段一直是眼看GCC
-S的结果,缺点是甚无直观,无法实时的见到寄存器的价值,所以研究了生怎么用GDB调试汇编。当然,写这篇文章又要的一个目的是半年莫写博客了,博客要长草了。^_^

自家调试汇编的需有几沾:

  • 会单步进行汇编调试。
  • 克实时看到寄存器值的变通。
  • 能够看出源代码和相应汇编的涉嫌。

下分享下用GDB实现者的3触及要求:

单步进行汇编调试

下si和ni。与s与n的别在:s与n是C语言级别之单步调试,si与ni是汇编级别之单步调试。

能实时看到寄存器值的变动。

使用gdb时增加-tui选项,打开gdb后运行layout regs令。注意最好长-tui,否则很挺或会见面世花屏现象。

图片 1

能看出源代码和对应汇编的关系

在gdb中运行set disassemble-next-line on,表示自动反汇编后面要执行之代码。

图片 2

得清晰的看到int c=sum(x,y);和下红框内之汇编指令成对诺涉及。

如果大家不思量就此这么原始之方式,可以给GDB安装插件或者使emacs达到地方的目的,推荐两篇稿子:

  • GDB 从裸奔到穿戴整齐
  • GDB实用插件(peda, gef,
    gdbinit)全解

最后以一个聊例子结束:

int sum(int x,int y){
        return x+y;
}

int main(){
        int x=10;
        int y=20;
        int c=sum(x,y);

        return 0;
}

gcc版本4.4.7,默认的优化增选项。

我们单步调试下就段代码对应的汇编:

安装断点

留意要想使拿断点设置以汇编指令层次函数的初步,应该使b *fun而不是b func,这里我们管断点设置在b *main

分配栈帧

0x0000000000400489 <main+0>:     55 push   %rbp
0x000000000040048a <main+1>:     48 89 e5   mov    %rsp,%rbp
0x000000000040048d <main+4>:     48 83 ec 10    sub    $0x10,%rsp

%rbp和%rsp表示的是当前栈帧的栈底和栈顶。其中%rbp是叫调用者需要保留的寄存器。sub $0x10,%rsp意味着为main函数分配栈帧空间。
留神这里分配了16字节底栈空间,会生4许节用不上,我个人猜与gcc汇编产生的cfi_def_cfa_offset 16关于,这个没探究。

int x=10

0x0000000000400491 <main+8>:     c7 45 f4 0a 00 00 00   movl   $0xa,-0xc(%rbp)

将x的值放到栈中

int y=20

0x0000000000400498 <main+15>:         c7 45 f8 14 00    00 00   movl   $0x14,-0x8(%rbp)

用y的值放到栈中

sum函数调用

 0x000000000040049f <main+22>:         8b 55 f8 mov    -0x8(%rbp),%edx
 0x00000000004004a2 <main+25>:         8b 45 f4 mov    -0xc(%rbp),%eax
 0x00000000004004a5 <main+28>:         89 d6    mov    %edx,%esi
 0x00000000004004a7 <main+30>:         89 c7    mov    %eax,%edi
 0x00000000004004a9 <main+32>:         e8 c6 ff ff ff   callq  0x400474 <sum>

将x与y分别赋值到%esi和%edi中,其中%edi和%esi被确定用来传递函数的第一个跟第二单参数。(一个问号是怎非克直接mov -0x8(%rbp),%esi呢?)
callq会将生同样修指令的地址压入栈中,并跳到sum函数的首先长达指令。

进入sum函数

0x0000000000400474 <sum+0>:  55 push   %rbp
0x0000000000400475 <sum+1>:  48 89 e5   mov    %rsp,%rbp
0x0000000000400478 <sum+4>:  89 7d fc   mov    %edi,-0x4(%rbp)
0x000000000040047b <sum+7>:  89 75 f8   mov    %esi,-0x8(%rbp)

及main函数一样,首先将%rbp保存,然后起%edi和%esi中取出函数参数。

求和

0x000000000040047e <sum+10>:     8b 45 f8   mov    -0x8(%rbp),%eax
0x0000000000400481 <sum+13>:     8b 55 fc   mov    -0x4(%rbp),%edx
0x0000000000400484 <sum+16>:     8d 04 02   lea    (%rdx,%rax,1),%eax

将x和y相加,这里以的凡lea指令,关于lea指令介绍参考LEA
instruction?,这里不赘述了。
以返回值放到%eax中,%rax寄存器规定存放函数的归来值。像GO语言如果函数可以产生多只返回值的言语,返回值是放开至栈中。

sum函数收尾

0x0000000000400487 <sum+19>:     c9 leaveq
0x0000000000400488 <sum+20>:     c3 retq

俺们先看下现在之库:

图片 3
(这里不晓干什么从来不sub
xx,$rsp,我猜是gcc发现此最终一坏函数调用,之后休见面起栈的提高仅会来栈的回退,所以用%rsp和%rbp的结果是如出一辙的。简单说明了生,应该是这么)。
以函数结束时首先得回收时函数的栈帧、恢复保存了的寄存器、恢复%rip的价,即返地址。

leaveq指令相当给:

mov  %rbp,%rsp     
pop %rbp

意是假释(deallocate)当前函数的栈帧并还原为封存之寄存器的值。由此我们也得看出%rbp的作用:记住%rsp应该回退的位置,否则函数结束时%rsp不懂得该回退到啊。

req指令相当给:

pop %rip

用上面保存了之callq的生一样条指令地址恢复至%rip中。

接收函数返回值

0x00000000004004ae <main+37>:         89 45 fc  mov    %eax,-0x4(%rbp)

用%eax的价放入到main函数的栈帧中。

return 0

0x00000000004004b1 <main+40>:         b8 00 00 00 00    mov    $0x0,%eax

暨地方sum函数一样。

main函数收尾

0x00000000004004b6 <main+45>:         c9    leaveq
0x00000000004004b7 <main+46>:         c3    retq

倘若上面%rsp和%rbp指向同一内存区域看起不顶直观的话,看下现在main函数即将终结时的栈空间:

图片 4

及地方sum函数的诠释一样,不再赘言。

程序运行成功脱。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图