GDB调试概要说明

gdb调试的基本步骤------->


1. 进入gdb环境:
    在命令行输入gdb或者gdb32
2. 从要调试的文件读入调试信息:
    file prj3.exe
3. 设置可执行文件和obj文件的路径,也就是搜索prj3.exe对应的源文件的路径
   path  "yourpath"       最好使用"/"代替"\" 
   show paths             显示当前的path
   可以在gdb中使用cd和pwd查看和改变工作目录
   (不起作用)
4. 设置GDB指令的输出到一个文件gdb_log.txt,并启动日志功能
    set logging file gdb_log.txt       //  设定日志文件名称
set logging on/off                 // 打开/关闭日志
set logging overwrite on/off       // 是否覆盖日志文件
5. 设置断点
6. 使用run/r指令启动调试,如果没有设置断点,则程序一下就运行完了。可以使用run >outfile 来对输出重定向。
7. 单步执行 next/n,也可以使用next num执行后面num行,如果碰到循环,则是把循环展开后的行数。断点有效。
8. until/u location,从当前位置一直运行到指定位置(除非遇到断点),此时循环不展开。常用的location参见下面第7小节
                     需要注意的是,当程序试图离开当前堆栈时,会停下。
9. 进入函数 step/s也会单行执行,但遇到函数会进入函数再继续执行。 
10. 从当前位置继续执行到结束或者下一个断点 continue/c
11. 运行到当前函数结束或者碰到下一个断点为止 finish/fin,对最外层函数无效。该函数内部的断点和该函数调用
   的其它函数的断点仍然有效。
12. 不执行一个函数而直接跳出执行其它的指令或函数 return,该函数内部的断点和该函数调用的其它函数的断点失效。
    格式:
      return [expression]   : 可以通过expression指定函数的返回值。
13. 显示变量的值:print/p var
14. 列出源代码:
             list                      列出从当前行附近的10行源代码;
list m                    列出当前文件第m行附近的10行;
list m,+n                 列出从第m到第(m+n)的行;
list m,-n                 列出从第(m-n)到第(m)的行;
list m,                   列出第[m,m+1,...,m+9]行;
list ,n                   列出第[n-9,n-8,...,n]行;
list filename:function    列出那个文件的那个函数附近的10行;
list filename:linenum     列出那个文件的那一行的10行;
list m,n                  列出从第m行到第n行的源代码;
list -                    列出上次开始行上面的10行;
list +                    列出上次结束行下面的10行;
list *addr                列出程序内存地址addr对应的源代码行附近的10行;
list *addr,              列出程序内存地址addr对应的源代码行开始向下的10行;
list ,*addr               列出程序内存地址addr对应的源代码行开始向上的10行;
list *addr2,*addr2        列出程序内存地址addr1和addr2对应的源代码行之间的行;
list main                 列出函数main开始处对应行号附近的10行;        
15. 结束当前进程的调试: kill。此时仅仅是结束了run的运行,此时使用info b查看断点信息,会显示每个断点已经hit
    的次数,可以根据这些次数设置每个断点的ignore值。再次run时,程序会直接跳到上次kill的位置。
16. 退出gdb:quit/q。


Note1:上面的步骤1和2可以合并为 gdb prj3.exe;
---------------------------------------------------------------------------------------------------------------------------------------
gdb的断点调试("<*>"表示*是一个地址,[*]代表*是可选的)
---------------------------
1. 内存地址和栈帧中相关信息的显示
info program  :显示你的当前程序的状态,包括是否正在运行、其进程号是什么、停止时的原因等。
info locals   :显示当前程序栈帧(所调用函数所占用的栈部分)中的局部变量。
info args     :显示当前程序栈帧的参数。 
info frame    :显示当前程序栈帧的相关信息,包括栈的层级、栈所在的地址、下条指令的地址、ebp等。
info registers:显示当前CPU寄存器的值(不包括浮点数寄存器),如需要包含浮点数寄存器,则使用all-registers
info inferiors:显示GDB程序中调试的exe文件及其对应的进程号。显示的格式如下
                  Num  Description       Executable
                  * 1    process 5044      E:\AGM\winIDE_gcc_gdb\PrjEx_Console\Prj01.exe
info threads [num] :显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。 前面有*的是当前调试的线程。
                暂停程序运行时发送的DebugBreakProcess指令,在本质上就是开启了一个远程线程来触发软件断点异常(int 3)。
                    Id   Target Id         Frame
* 5    Thread 7472.0xb4c 0x77b9000d in ntdll!DbgBreakPoint () from C:\Windows\SysWOW64\ntdll.dll
 1    Thread 7472.0x28fc 0x773b12ea in WriteFile () from C:\Windows\syswow64\kernel32.dll
thread ID     :切换当前调试的线程为指定ID的线程。  
             
x[/[nfu] <addr>]:检查内存(10.6 Examining Memory)
                  从地址 addr(可以是该地址对应的系统变量,比如$sp) 开始,以f选项所定义的格式来显示n个单位的数据,每个单位的数据占用的
                  字节数由u选项定义。如果不给定nfu时,则默认为n=1,f和u跟上一次使用x指令时相同。addr可以显式给出,若不给出,则:
 addr = $_ + 上一次x指令u选项的字节数。
 如果不给出addr,则x指令的addr会受到info breakpoints指令,info line指令和prinf *anotheraddr指令的影响,可参见第9小节的Note3。
 这里的addr,可以使GDB中预定义的register,比如$pc,$sp等。
 另外还有一个专用的不含有u格式的使用方式,如下:
 x/ni  [addr] :这里的也是一个f选项,其表示机器指令,其含义就是从addr处显示n条机器指令,因为机器指令占用的字节数不确定,所
                以这里的u参数自然就失效了。与display/ni $pc等价
                  f选项:可以为第8小节中的输出格式(‘x’, ‘d’, ‘u’, ‘o’, ‘t’,‘a’, ‘c’, ‘f’, ‘s’),默认为x
 u选项:默认每个单位占用4Byte,(b:1 byte  h:2 bytes  w:4 bytes  g:8 bytes)。对于f=s,u默认为b,可以省略掉u选项。
        f选项为s暂时没看懂干什么用,看说明s对应UTF-16编码,ws对应UTF-32格式。
 当不指定n选项时,则只输出1个单位的数据。f和u选项设置后,会一直起作用到下次设置,如果省略的话起作用的就是上次设置的值。
frame n       :切换栈帧(当前函数所在栈帧的层级为0,调用该函数的函数所在栈帧层级为1,以此类推)。切换后可以显示该函数中的局部变量,比
                如切换后直接调用 info locals 来查看栈帧n中的局部变量。  
bt/where/info stack   :都是同一个功能,列出各个栈帧基本信息,堆栈的详细操作参见第19小节
     Note1:检查内存中/远端设备上运行的程序是否与PC上的映像文件相符,可以使用下面的指令,
                  compare-sections [section-name|-r]:  其中,section-name表示要比较的段/节(section),r表示all loadable read-only sections。
                                        如果两个参数都不给出,则表示比较所有的段/节。
 
(gdb) compare-sections -r
Section .text, range 0x401000 -- 0x402224: matched.
Section .rdata, range 0x404000 -- 0x4041ec: matched.
Section .eh_frame, range 0x405000 -- 0x4053a0: matched  
---------------------------
2. 断点操作(Breakpoint, Watchpoint和Catchpoint)
   
   1)断点设置:
     首先是Breakpoint类型的断点,它是指在指定的位置或者函数入口点处设置断点。使用指令break或者b,下面都是用break。
       break  [file_name:]loc_num    :表示在当前源文件或名为file_name文件的第loc_num行设置断点。
  break  [file_name:]func_name  :表示在func_name函数入口处设置断点,不管file_name是否指定,gdb总会找到函数的定义处。
  break  +/-offset              :表示在程序当前停止的行加或者减offset行处设置断点。
  break  *address               :表示在内存地址 address 处设置断点。
  break                         :会在当前stack frame(一个{}内)中的下一条执行的指令处停下
  break  ... if cond            :条件断点,“...” 表示上面的任何一种可能的情况,具体参见条件断点。
  tbreak args                   :只执行一次的断点,args与上面的 “...” 一样,为上面的任何一种可能的情况。
  rbreak regex                  :在所有符合正则表达式regex的函数处设置断点。
  rbreak file_name:regex        :在文件file_name内所有符合正则表达式regex的函数处设置断点。
  rbreak .                      :在所有文件中的所有函数入口设置断点,包括系统的。
  rbreak file_name:.            :在文件file_name中的所有函数入口设置断点。
Note1:
    
其次是Watchpoint类型的断点(也成为数据断点),它是指当一个变量或者内存地址中的值发生改变时,停止执行。这种断点可能是硬件产生,
也可能是软件产生,这依赖于操作系统。在我的win7 64位下,显示是硬件断点。thread threadnum表示只有threadnum线程产生的修改才会起
作用,省略时指当前线程。
  watch expr  [thread threadnum]:设置写watchpoint,当应用程序写expr, 修改了其值时,程序停止运行。watch *(int *)0x400000==20                               
       rwatch expr [thread threadnum]:设置读watchpoint,当应用程序读表达式expr时,程序停止运行。
       awatch expr [thread threadnum]:设置读写watchpoint, 当应用程序读或者写表达式expr时,程序都会停止运行。
  上面的"expr"可以为下面几种情况:a)变量名;
                                  b)某个地址开始的某种类型的数据,例如 ‘*(int *)0x12345678’将会将地址0x12345678开始的4个字节;
  c)任何源程序使用的语言支持的复杂的表达式(变量+操作符)。
  
     再次是Catchpoints类型的断点,用于在某些事件下使程序停止运行,比如C++异常和动态库的加载。
      catch event                    :当事件event发生时,停止程序的运行。windows下常用的event包括,
                                  load [regexp],当不给定regexp时,则一加载动态库就会触发程序停止运行;当给定regexp时,则只有
                 加载满足regexp的动态库时才会起作用。
  unload [regexp],当不给定regexp时,则一卸载动态库就会触发程序停止运行。当给定regexp时,则只
                 有卸载满足regexp的动态库时才会起作用。
     
最后,说一下breakpoint类型断点中的条件断点  break  ... if cond,...处为上面的"[file_name:]loc_num","*address"等,下面看cond是
什么。下面为几个例子
                   break main if argc>1;       break 180 if (string==null && i<0)
                        break myfun if (x&y)==1     break test.c:80 if strlen(mystring)==0  
     上面为定义新的条件断点,还有一种是在已存在的断点上添加附加条件的,主要包含一下两种操作
                   condition bnum expression   :给断点号为bnum的断点添加条件expression
condition bnum              :清除给断点号为bnum的断点添加的条件         
 
 
  Note1:Watchpoint类型的断点类型的断点可以添加到任意内存地址处,但Breakpoint类型的断点往没使用的内存处添加断点可能添加不上。
  Note2:如果给内联函数或者C++中的重载函数添加了断点,gdb会给每一个实例处添加子断点,效果如下,
           Num       Type        Disp        Enb       Address          What
                1          breakpoint keep         y        <MULTIPLE>
               stop only if i==1
               breakpoint already hit 1 time
               1.1                                 y        0x080486a2   in void foo<int>() at t.cc:8
               1.2                                 y        0x080486ca   in void foo<double>() at t.cc:8
 每一个子断点既可以独立控制也可以整体控制。
  Note3:关于动态库的调试,一般会在读入调试符号表之后,调试开始之前(最晚也是在加载dll之前)设置dll的断点,每次载入dll后,gdb会
         重新定位短点的位置。
  Note4:可以为所有类型的断点添加指令(程序遇到该断点时执行的指令),其格式至少包含3行,
                     commands [range...]            为那个断点设置指令
                     ... command-list ...           从该行起为指令,一行一条
                     end                        指令结束
 如果在断点定义时指定执行的指令,则其格式如下:
        break 断点定义
commands
... command-list ...
end
 一个实例:当断点到达时,自动执行command中的三个指令,把func的三个参数值打出来。
        (gdb) break func
                          Breakpoint 1 at 0x3475678: file test.c, line 12.
                     (gdb) command 1
                          Type commands for when breakpoint 1 is hit, one per line.
                          End with a line saying just "end".
                     >print arg1
                     >print arg2
                     >print arg3
                     >end
                     (gdb)
  Note5:在gdb中一次只能输入一条指令,但可以通过def fun....end定义多个指令,通过fun运行,也可以将常用指令放入~/.gdbinit     
   2)断点查看
       info breakpoints/break/b [n]  :查看第n号断点的相关信息,如果不给出n,则会列出所有断点的信息。包括断点号、类型(Breakpoint、
                                  Watchpoint和Catchpoint)、是否为一次断点、是否使能、内存地址、源代码位置。 
       info watchpoints [n]          :查看当前调试的程序中设置的watchpoints相关信息。
  ignore n num                  :对于第n号断点,忽略其后面连续num次的hit,直到第num+1次才会再停在该断点处。
       Note1:在调试的过程中,使用上述指令,会显示从程序执行开始到现在,各断点起作用(hit)的次数。
       Note2:利用上述指令可以实现快速的调试,比如可以实现一边修改一边调试的在线调试功能。   
   3)断点的清除、禁用和使能
       clear                         :删除当前行的断点;
       clear [filename:]func_name    :清除函数func_name入口处的断点;
  clear [filename:]loc_num      :清除当前文件或者filename文件中的第loc_num行处的断点;
             
  delete [breakpoints] [range…] :删除由range指定的范围内的Breakpoint,range范围是指breakpoint的序列号的范围。
                                       如果只有一个delete(简写为d),则删除所有的断点。   
  disable [breakpoints] [range…]:禁用由range指定的范围内的breakpoints;不给出range参数时,为禁用所有断点;
       enable [breakpoints] [range…] :启用由range指定的范围内的breakpoints;不给出range参数时,为使能所有断点;
       enable [breakpoints] once [range…]: 只启用一次由range指定的范围内的breakpoints,等程序停下来后,自动设为禁用;
       enable [breakpoints] delete [range…]: 启用range指定的范围内的breakpoints,等程序停下来后,这些breakpoints自动被删除。
  enable [breakpoints] count num [range]:启用range指定的范围内的breakpoints,num次hit之后,自动设置为禁用,num=1就等价于once。
  
  Note:以上指令中的[breakpoints]可选,完全可以不加。
  Note:clear只用于清除某个位置的breakpoints类型的断点。而delete可用于删除任意类型的断点。
  Note:delete删除多个断点时[range…],delete 16-26,指删除第16号到第26号内存在的所有断点,如果某些编号的断点不存在,则出现提示
        消息”No breakpoint number 20.“。对于disable和enable中的[range…]同样。
   4)断点存到文件和从文件读取
       save breakpoints filename    :将所有类型的断点信息存储到filename文件,注意,包含表达式的watchpoints类型断点可能有点问题。
  source [-s] [-v] filename    :filename为保存断点信息的文件(断点指令+断点的条件+ignore次数)。
                                 -s选项,当前路径下没有,会到path路径搜索。
 -v选项,显示每条指令和它们的执行情况。
   5)dprintf是7.5版本之后加入的一个动态显示类型的断点,它在功能上类似于一个带printf指令的断点+continue。
      其格式为:dprintf location,template,expression[,expression...]
      其中,location参见第7小节说明;
            template,expr[,expr...]就是C语言中的printf(template,expr[,expr...]),应该是讲这一块作为打印函数的参数传递给打印函数 。  
      比如,指令
          dprintf Stdlist.h:__list_add,"here is function--->stdlist.h:__list_add %d\n",$pc
 的作用是,每当程序进入到文件stdlist.h中的__list_add函数时,就会自动打印出相应的信息。
 还有相关的设置指令,
   a)set dprintf-style gdb/call/agent:设置dprintf使用的哪一个printf,gdb表示使用gdb的printf打印;call表示使用你的程序中的函数
                                    打印;agent表示由gdbserver负责打印。
b)set dprintf-function fun_name   :设置dprintf-style为call时调用的打印函数,一般会使用C语言中的printf、fprintf、sprintf等。
c)set dprintf-channel channel     :主要用于指定fprintf、sprintf之类的函数在template前面的参数(打印到的输出),但没看出怎
  么使用来。
   6)停止调试
       kill 
---------------------------
3. 程序的运行、步进和跳转(5.2 Continuing and Stepping | 17章),下面的”/“后为简写   
   1)continue/c [ignore-count]   :继续程序的执行,直到遇到下一个断点为止。如果附加了ignore-count参数,并且当前点为断点,则后面
                                     碰到该断点ignore-count次都不停,直到第ignore-count+1次才停。
   2)step/s [count]               :不带count参数时表示运行到下一个不同的代码行(能进入函数),带count参数表示单步执行count次,直
                                     到遇到断点。until reaches a diff erent source line,只要是不同一行就可以。暗含的意思是,如果一行中
有多条语句,则只停在第一条语句处,再用step时,会到下一个新行。
   3)next/n [count]               :与2)类似,但这里的的下一行只能是同一个stack frame里面的行,所以不进入函数,相当于一般IDE中的step over。                                  
   4)finish/fin                   :函数正常运行完成并返回,相当于一般IDE中的step out。
   5)return [expression]          :销毁当前函数的堆栈,并将返回值设为expression,也就是直接返回到caller处。
   6)until/u [location]           :不带location选项的until主要用于跳到for循环的最后一层;带location的until主要用于运行到光标处。(无论那一种,遇到
                                     断点都会停下)。带location的另一个应用是跳到递归调用的最后一层。
   7)stepi/si [count]             :单步汇编
   8)nexti/ni [count]             :单步汇编
   9)advance location             :与until类似,区别在于不会跳过函数递归。
   10)jump/j location             :相当于set $pc=location, continue两条指令的结合。且jump指令不会改变栈的结构,常先用一个tbreak设定一次断点再跳,防止
                                     立刻运行


         Note1:step指令进入一个函数时,是否可以停在没有调试行信息的地方,是由set step-mode on/off指定的。
Note2:next、nexti指令都是针对current stack frame而言的;step、stepi是相对于整个程序而言的。
---------------------------
4. 跳过函数和文件(Skipping Over Functions and Files)
   假如存在以下代码,且当前运行到103行处,调试时你希望step指令只进入foo函数,而不进入boring函数,则可使用skip boring指令
   101 int func()
   102 {
   103 foo(boring());
   104 bar(boring());
   105 }
   同样,也可以调试时不进入指定的文件,skip file filename
   
   skip也会生成一个类似
   skip function            :step指令不进入指定函数;
   skip file [filename]     :step指令不进入指定文件filename或者当前文件;
   info skip                :显示已经定义的skip信息;
   skip delete [range]      :包括本条在内的下面三条指令跟断点操作中的类似。
   skip enable [range] 
   skip disable [range]  
---------------------------
5. 变量的自动显示 display,只要程序暂停运行(断点或者单步),则使用display指定的变量就会改变,可用于实现添加查看的功能,简写为disp
   display expr            :添加 expr 到自动显示,可以为变量或者表达式;
   display/f expr          :f表示显示的格式,x(十六进制),d(十进制),u(无符号十进制),o(八进制),t(二进制),c(字符),a(十六进制地址+符号)
   display/fmt addr        :类似于2中的x/[nfu] <addr> 指令
   info display            :显示已经定义的自动显示变量
   delete display [range]  :包括本条在内的下面三条指令跟断点操作中的类似。
   disable display [range] :range可以为m-n,表示m号到n号
   enable display [range]  :
----------------------------------------------------------------------------------------------------------------------------------
6. 调试时代码的显示,主要包含三种:带行号的源代码,单独汇编显示,汇编与源代码(带行号)混合显示。
   1)带行号的源代码的显示,使用list 1,n指令(n>=当前文件的源码行数),具体参见上面。
   2)汇编的单独显示,使用disassemble指令
      disassemble  [loc]   :只显示汇编代码,下面为无[loc]时的输出
                               Dump of assembler code for function main:  
                             0x000000a4 <+0>:     push    {r4, r5, r7, lr}
                             0x000000a6 <+2>:     sub     sp, #152        ; 0x98
 0x000000a8 <+4>:     add     r7, sp, #0
                               => 0x000000aa <+6>:     mov.w   r3, #0                                
                                  0x000000ae <+10>:    str.w   r3, [r7, #148]  ; 0x94                                  
                             …………………………………………………………………………………………………………………………………………                                   
 disassemble /r [loc] :汇编代码前附加对应的hex代码,下面为无[loc]时的输出 
                              Dump of assembler code for function main:
                             0x000000a4 <+0>:     b0 b5   push    {r4, r5, r7, lr}
                                  0x000000a6 <+2>:     a6 b0   sub     sp, #152        ; 0x98
                                  0x000000a8 <+4>:     00 af   add     r7, sp, #0
                               => 0x000000aa <+6>:     4f f0 00 03     mov.w   r3, #0
                                  0x000000ae <+10>:    c7 f8 94 30     str.w   r3, [r7, #148]  ; 0x94
 …………………………………………………………………………………………………………………………………………
 可以看到,在汇编代码显示时,会有一个“=>”指明且当前程序停止的位置。
   3)汇编与源代码的混合显示,仍然使用disassemble指令
      disassemble /m [loc] :汇编与源代码混合显示,下面为无[loc]时的输出
                          Dump of assembler code for function main:
                               23      {
 0x000000a4 <+0>:     push    {r4, r5, r7, lr}
 0x000000a6 <+2>:     sub     sp, #152        ; 0x98
 0x000000a8 <+4>:     add     r7, sp, #0


  24        /******************************************************************
  25         *
  26         *  Place your code here.
  27         ******************************************************************/
  28        int cnt;
  29        cnt = 0;
  => 0x000000aa <+6>:     mov.w   r3, #0
 0x000000ae <+10>:    str.w   r3, [r7, #148]  ; 0x94  
 可以看到,混合显示时也会指明当前程序的停止位置。  
   注:上面的格式中,loc为可选项。当不给出时,是指对PC当前所在的函数进行汇编的代码。如果给出loc,则仅仅对loc指定区域的汇编进行显示。
        这里的loc可以为(start和end可以为0x32c4, &main+10’ ,$pc - 8等形式):
                start,end             :对内存地址start到end做汇编;
start,+length         :对内存地址start到(start+length)做汇编;
func_name             :对函数func_name做汇编;
’filename’::func_name :对源文件filename内中func_name函数进行汇编。
   4)info line的使用。用于打印出源文件中给定行在内存中对应的代码包含哪些,或者指定内存地址属于源代码中哪一行,然后再打印出该行在
      内存中对应的代码包含哪些。
                   info line [file:]srclinenum   :其中, srclinenum为源文件中的行号,可用file指定是哪一个文件的行号。
info line memaddr             :其中,memaddr是指内存地址,gdb会首先在原文件中找出该内存地址对应的
                               源文件行号,然后再执行info line [file:]srclinenum。
   5)汇编格式的设定,有两种汇编语言格式,att(默认)和intel
                        show disassembly-flavor,显示当前汇编语言格式
                        set disassembly-flavor intel/att,设置汇编语言格式
----------------------------------------------------------------------------------------------------------------------------------  
7. 对于指定位置loc的说明。在GDB中,很多指令都会用到loc这种用于指定位置的参数,这里做一下统一说明。GDB作为一个源码级别的调试工具,位置
   通常是指源代码的行号或者汇编代码的地址。下面就是对所有可能的情况做一下汇总。
         -offset                      :从当前行向前数offset行(不含当前行);
+offset                      :从当前行向后数offset行;
         linenum              :当前源文件中的行号;
filename:linenum          :源文件filename中的行号;
function                     :当前源文件中的函数function开始的行(指的是“{”)
filename:function            :源文件filename中的函数function开始的行;
label                        :当前原文件中的标号label所在的行;
function:label              :函数function中的标号label所在的行;
*address                     :这里的*address可以是一个数给定的地址,也可以是一个函数名。
   具体的使用实例,可以参见list指令。
----------------------------------------------------------------------------------------------------------------------------------
8. 对于GDB中输出格式的说明。默认情况下,GDB会根据一个值的数据类型来显示其值,但有时我们需要另一个显示方式。例如,你或许想将一个数显示为
   16进制或者十进制形式的指针;又或者你希望内存中的数据以字符串或者指令的形式显示。要实现上述功能,就需要指定显示格式。
   输出格式最简单的用途就是用在指令中显示一个计算好的值,其格式为:print/format expr
   其中,format 就是输出格式选项。其值可以为
         x : 16进制,0x40162b
d : 有符号10进制,4199979
u : 无符号10进制,4199979
o : 8进制,020013053
t : 2进制
a : 地址,0x40162b <main+195>,为16进制+离最近符号的偏移量,使用info symbol expr指令也可以得到类似的信息
c :十进制数+字符,仅仅显示一个字符的信息,43 '+'
f :浮点格式显示,5.88542412e-039
s :字符串显示,不适用于print,因为有些字符打印不出来
r :以上一次的格式显示
----------------------------------------------------------------------------------------------------------------------------------  
9. GDB中的表达式expr。GDB中许多的指令(例如:print,display等)都会将表达式(expr)作为参数并计算该expr的值,任何类型的常量、变量、你所使用
   的编程语言支持的运算符都可以作为expr中的元素,这包含:条件表达式、四则运算、函数调用、数据类型强制转换、字符串常量、甚至预处理器宏。
   并且,在GDB中允许将同种类型的变量作为一个array一次输入,格式为{elem1,elem2,elem3,...},这可以用在disp/print中时将多个变量打包显示。
   下面是GDB支持的C语言之外的运算符(10.1 Expressions),
         @              :是一个二元运算符,它将部分内存看做一个数组,多用于构建人工数组(artificial array)。格式为ST@LEN,其中ST表示数
                 组的起端,LEN表示长度。根据ST的类型不同,情况如下:
 1)ST为一个地址/指针时,则可以使用 *ST@len 显示从地址ST开始的len个元素,比如arr为一个数组名,则*arr@3就是显示数组
    的前3个元素,而arr@3则是将数组看做一个元素,连续显示三个数组的值。
                          2)ST为一个基本数据类型的变量名,ST@len 等价于*(&ST)@len
                          3)ST是一个结构体名时,则可用于显示结构体数组。ST@len表示{ST[0],ST[1],...,ST[len-1]}
::             :变量的引用,主要形式为  file::variable
                                         function::variable
{type} addr    :类型强制转换
  
  Note1:关于人工数组(artificial array)。调试的过程中,连续打印输出内存中的某种数据类型的对象(变量、数组、结构体等)是非常有用的,
        比如,数组的一部分和仅有指针的动态数组的显示,都需要将一块连续内存的数据输出,此时就可以在GDB中使用人工数组。人工数组的构建
有两种方式,一种就是上面的 ST@LEN。另一种方法是使用类型强制转换(cast),这种方式常用于将一个位数多的基本类型数据转换为几个
位数少的基本类型的数据,比如(GDB指令):(10.4 Artifi cial Arrays)
            p/x (short[])0x12345678   ---->  {0x5678, 0x1234}
p/x (char[])0x12345678    ---->  {0x78, 0x56, 0x34, 0x12}
可以看到,它实际上是将一个位数多的基本类型看做一个位数少的基本类型的数组。
可以将多个同类型的变量构成一个人工数组{var1,var2,......}
       Note2:人工数组只能用于处理内存中连续的数据,而对非连续数据(比如结构体数组中每个元素的某个成员)无能为力,此时可以使用在GDB中使用
        set定义自由变量(convenience variable)实现。(10.11 Convenience Variables)
struct my_struct
        {
int id;
char name[20];
int age;
score my_score;
} st_arr[]={...};
比如上面的结构体数组,如果想要输出这20个数组元素(结构体)的name,则可以如下操作(GDB指令,RET表示键盘的回车键),
set $i = 0
print/u  st_arr[i++].id
RET
RET
.....
RET
  Note3:关于自由变量的详细说明。自由变量以"$"开头,以set进行赋值,例如:set $foo = *object_ptr 就是将指针object_ptr指向的值保存到
         GDB中的自由变量$foo中。自由变量是泛型变量,可以随时改变其类型。
 两个指令:
     show convenience/conv                     :列出到目前为止所有已经定义的自由变量及其当前值;
 init-if-undefined $variable = expr        :类似于makedile中的variable ?= expr,或者C语言中带初始化的局部变量。常用于用
                                             户自定义指令时设定初始状态。
 自由变量最常见的用途已在Note2中给出。GDB启动时预定义了一些自由变量如下,
         $_              :保存着内存检测(10.6 Examining data)指令x最后检测的内存地址,其它为x指令提供初始/默认地址的指令
                   (比如info line linenum 和 info breakpoint)都会改变$_的值。info line linenum会将$_设定为源文件中
第linenum行对应的第一条汇编指令的地址;info breakpoint会将$_设定为最后一个breakpoints类型断点的地
址。在不做显式复制的情况下,$_的类型默认为 void *,可以使用 whatis $_指令查看。
     $__             :保存着x指令访问内存的最后一个单元的值,其类型由x/nfu中的u决定。下面为一个$_和$__的例子,
                    break main       # 在main函数入口处设断点,假设其为第一个断点(即断点号为1),断点地址为 0x401568
info break 1     # 会显示1号断点的信息,并且GDB暗中会执行:set $_ = 0x00401568,set $__ = *0x401568
print/x $_     --->  0x401568
x/1xh  0x401568  # 将$__输出格式改为int16
Print/x $__    --->  0x8b10
whatis $_      --->  type = void *
whtais $__     --->  type = int16_t  
     $_exitcode      :保存着程序结束调试时的 exit code 
     $_sdata         :contains extra collected static tracepoint data
     $_siginfo       :contains extra signal information
     $_tlb           :保存着线程信息块的地址,下面例子中可以看到线程号保存在[0x7efdd020,...0x7efdd028]中。
                   x/10xg $_tlb
0x7efdd000:     0x002900000028ffc4      0x000000000028e000
0x7efdd010:     0x0000000000001e00      0x000000007efdd000
0x7efdd020:     0x0000ec340000ec3c      0x00827ed000000000
0x7efdd030:     0x000000007efde000      0x0000000000000000
0x7efdd040:     0x0000000000000000      0x0000000000000000
       info program
Using the running image of child Thread 60476.0xec34.
Program stopped at 0x401664.
It stopped at breakpoint 5.
Type "info stack" or "info registers" for more information.  
----------------------------------------------------------------------------------------------------------------------------------  
10. 当前文件内的搜索。
         search/forward-search regexp :从上次list的最后一行向后搜索到第一个满足正则表达式regexp的行,并显示;
reverse-search regexp        :从上次list的最后一行向前搜索到第一个满足正则表达式regexp的行,并显示;      
----------------------------------------------------------------------------------------------------------------------------------
11. 程序当前执行位置的获取和修改,包括PC值、当前在源程序中的位置(文件名+行号)
         1)获取当前PC值的方式:>print $pc
                       <$8 = (void (*)()) 0x40162b <main+195>
2)获取当前PC值的修改:>print $pc=0x40162F
                       <$9 = (void (*)()) 0x40162f <main+199>
3)只显示pc值:print/x $pc 
4)pc处的汇编指令和内存地址同时给出:x/i $pc, 或者disp/i $pc,两者等价
5)当前pc在源程序中对应的行号,bt指令、f指令,或者先获取$pc的地址值,然后使用info line *addr($pc的值)
----------------------------------------------------------------------------------------------------------------------------------  
12. 检查数据(10 Examining Data)
     1)最常用的检查你的程序中数据的方式是使用print/p指令或者inspect指令,两者是完全等价的。
         print [expr]       :如果不给出expr,则会重复上一条print指令。
print /f [expr]    :f为第8小节中给出的格式,关于expr参见第9小节。如果不给出f,则会以expr本身的类型决定显示格式。
2)修改变量的值。print或者set指令,两者的区别在于print会回显并将,而set不回显。如果该变量与gdb中的指令相混,则使用set variable/var指令设置变量的值。
       比如,gdb有专用的set width指令,而如果你的原程序中有个变量为width,则设置其值时使用set variable/var width=111。所以一般使用set var。
     3)修改内存的值,set {int}0x83040 = 4为将内存地址0x83040处的一块int类型的区域设置为4。
4)使用一小节的x指令显示内存的值
----------------------------------------------------------------------------------------------------------------------------------
13. 检查符号表常用指令(16 Examining the Symbol Table)    
     1)whatis [var]指令和ptype expr指令用于显示一个变量的类型,前者仅给出类型名,后者会给出结构体的具体结构。对于多层的typedef,
  两者只显示当前层的类型名。(16 Examining the Symbol Table)
        (gdb) whatis st1       -----> type = struct my_struct [4]
(gdb) ptype st_arr     ----->
type = struct my_struct {
int id;
char name[20];
int age;
score my_score;
} [4]
2)info scope location,这里的location可以参见上面第7小节。
3)info source:显示当前pc值所在源文件的信息,
   (gdb) info source           ----->
Current source file is main.c                                 # 文件名
Compilation directory is E:\AGM\winIDE_gcc_gdb\PrjEx_Console  # 路径
Located in E:\AGM\winIDE_gcc_gdb\PrjEx_Console\main.c         # 当前pc值所在的源文件名,绝对路径
Contains 101 lines.                                           # 该源文件的行数,(如果包含多个空行,则为总行数-1)
Source language is c.                                         # 源文件的类型
Compiled with DWARF 2 debugging format.                       # 调试信息的模式
Does not include preprocessor macro info.                     # 是否包含预处理宏
4)info sources:列出你的程序中所有涉及到的有调试信息的源文件名,分成两部分:符号表已经被读入的部分和将要读入的部分。
5)info types [regexp]:列出你的程序中涉及到的所有类型(不提供 regexp 选项时)或者满足正则表达式 regexp 的类型。
6)info functions [regexp]:列出你的程序中涉及到的所有函数(不提供 regexp 选项时)或满足正则表达式 regexp 的函数。对于有调试信息的
                            函数会给出其声明原型,没有调试信息的只给出函数名。
7)info variables [regexp]:列出你的程序中所有在函数外部定义的变量(不提供 regexp 选项时)或满足正则表达式 regexp 的所有函数外部定义
                            的变量。通过分析汇编代码可知,链接脚本文件中定义的变量也被包含在内。
     8)info symbol addr:查询地址内存 addr 处的符号名,如果此地址处没有符号则打印出距离最近的符号及偏移量。例如,info symbol 00401010。
     9)info address symbol:查询符号 symbol 的数据所存放的内存地址,例如,info address main。
----------------------------------------------------------------------------------------------------------------------------------
14. 输出格式的控制(10.8 Print Settings)
     1)输出符号地址(print/display 的expr为地址)时是否给出在那个文件的哪一行。
      show print symbol-filename          # 显示是否开启了
           set print symbol-filename on/off    # 开启或者关闭,默认是关闭的
        下面是一个打印输出当前$pc值的例子,即print  $pc
        关闭时:(void (*)()) 0x401664 <main+252>
  开启时:(void (*)()) 0x401664 <main+252 at main.c:42>
但是,当附加/nfu参数之后,就不起作用了。
2)数组显示格式的调整
    set print repeats num  :表示连续有超过num个数组元素相同时,使用"<repeats n times>"表示,当num=0或者unlimited时,会显示所有元素。
show print repeats     :当前的num是多少。
set print array on/off :是否列显示数组,on为列显示,off为行显示(默认)。
show print array       :当前是行还是列显示。
set print array-indexes on/off:是否显示数组的下标(默认off不显示)。
show print array-indexes      :当前的数组下标设置是什么。
set print elements number-of-elements :设置GDB中一次能够显示的数组的元素数,0/unlimited时无限制。
show print elements    :当前GDB一次能显示多少个元素。
set print null-stop on/off    :设置字符串数组显示时是否碰只输出到null(默认全输出)。
show print null-stop          :当前的null-stop设置
3)结构体显示格式都得调整
    set print pretty on/off       :on为以结构树方式显示,off为行显示(默认为off)
show print pretty             :当前的结构体显示方式
4)联合体的显示 
    set print union on/off        :on显示出联合体,off以{...}表示联合体防的值
show print union              :当前设置
----------------------------------------------------------------------------------------------------------------------------------
15. 自由函数(10.12 Convenience Functions)
     1) $_isvoid(expr)        :如果expr为void则返回1,否则返回0。可以用于检测一个自由变量是否已经定义并赋值。也可以用于检测一个函数的返回值类型。
     2) $_memeq(buf1, buf2, length):比较地址buf1和buf2处的长度为length的内存值是否相等,相等为1。
3) $_regex(str, regex)   :如果字符串str符合正则表达式regex,则返回1。
4) $_streq(str1, str2)   :字符串str1与str2比较,相等返回1。
5) $_strlen(str)         :字符串str的长度。
 
可以使用指令help function列出所有自由函数
----------------------------------------------------------------------------------------------------------------------------------  
16. 寄存器(10.13 Registers)
不同的构架的处理器,其内部的寄存器数量和名称各不相同,GDB中给出了4个通用的寄存器:$pc,$sp,$fp,$ps。要查看当前处理器上的寄存器,可使用一下指令
info registers             :查看基本寄存器的值(除了浮点寄存器和向量寄存器之外的寄存器)
info all-registers         :所有寄存器
info registers regname...  :指定寄存器的名字,查看其当前信息,这里的名字前面可以没有$
info float                 :查看浮点数硬件的信息(x86下为16个寄存器),只适用于有FPU的处理器。
info vector                :查看vector寄存器(mm0 ~ mm7,xmm0 ~ xmm7)的信息,也就是与MMX指令和SSE指令相关的寄存器
----------------------------------------------------------------------------------------------------------------------------------
17. 内存和文件之间的复制(10.17 Copy Between Memory and a File)
    dump [format] memory filename start_addr end_addr   :将内存[start_addr,end_addr]中的值输出到文件filename。
dump [format] value filename expr                   :将表达式expr的值输出到文件filename,格式可以是binary,ihex,srec,tekhex。
    append [binary] memory filename start_addr end_addr
    append [binary] value filename expr                 :将相应的内存或表达式的值追加到指定的指定的问价(只能是binary类型)
restore filename [binary] bias start end            :将filename的内容加载到内存。对于binary的文件,必须指明binary选项,其他类型的不需要指明类型。
                                                     如果bias非0,则将bias加到filename中的内容地址中(比如hex文件)。这里的意思是,假设一个hex
 文件内部的地址是[A,B](其中,A<=start, B>=end),则需要将该hex文件[start,end]地址之间的内容
 加载到内存的[start+bias,end+bias]处。
----------------------------------------------------------------------------------------------------------------------------------
18. GDB的帮助系统
    1) help,列出所有指令的分类,包括别名(aliases)、断点(breakpoints)、数据(data)、文件(files)、内部(internals)、隐含(obscure)、运行(running)、栈(stack)、
        状态(status)、支持(support)、跟踪点(tracepoints)和用户自定义(user-defined)这几类。
2) help all,会详细列出所有分类的详细指令。
3) help class,会详细列出class类别指令中的所有指令。
4) help cmd,列出指令cmd的说明,如果cmd后面还有子指令,则会全部列出,并简要说明其使用。例如,help info和help info frame。
5) apropos args,会在GDB的所有指令中搜寻args的匹配项,并全部列出。其中,args可以是正则表达式。
6) complete args,GDB会列出所有以args开始的指令,一般只会列到第一层指令,也就是说如果使用complete info,则只会列出info,而不会列出info的子指令。
7) info,获取正在调试的程序的相关信息,通过输入info或者help info可以查看到所有的info子指令,利用这些子指令就能查看当前程序的各种信息。
8) show,用于获取当前GDB程序本身的各种设置,使用help show可以显示show的各种子指令,如果单独使用show指令,则等于一次运行了所有的show子指令,会把GDB
        的所有设置一次全列出来。
    9) set,可用于设置环境变量、自由变量、show里面的设置。
    
Note:要产生带预编译宏信息,并能将其展开的可GDB调式的程序,在编译时需要使用-g3或者-ggdb3等级的debugging选项。
     也就是说,如果是将宏添加到查看,则需要编译时使用-g3或者-ggdb3等级的debugging选项。
----------------------------------------------------------------------------------------------------------------------------------
19. 检查堆栈(8 Examining the Stack)
    1) bt [n],显示堆栈的回溯结构,主要就是说各个堆栈中最后执行的一条语句对应源文件中的行号。比如,
              #0  list_add (new=0x6c1878, head=0x28fee4) at StdList.h:61
  #1  0x00401801 in main () at main.c:82
  pc指针当前所在的堆栈为#0号堆栈,以此类推,main/winmain函数所在的堆栈为最外层堆栈。
  如果加n参数,则只显示n个堆栈,n>0时,会显示最内层的n个堆栈的回溯结构,n<0时,显示最外层的n个堆栈的回溯结构。
    2) bt full [n],在1)的基础上,还会显示各层堆栈的局部变量。可以调用它来实时显示整个系统的所有局部变量。n的含义如上。
3) 几个设置堆栈回溯结构显示时的指令如下(C语言),
        a) set backtrace past-main on/off,是否到了main层后还继续回溯,默认为off,即到main结束。
   show backtrace past-main, 显示当前的 past-main设置。
b) set backtrace past-entry on/off,是否到了程序的入口函数(linker设置的入口函数)之后还进一步回溯。默认off。
   show backtrace past-entry, 显示past-entry的当前设置。
c) set backtrace limit n/0,设置堆栈回溯的最大层数为n,0表示无限层(默认)。
   show backtrace limit, 当前的层数设置
d) set filename-display relative/basename/absolute,堆栈回溯结构中文件名是否带绝对路径
   show filename-display,当前的文件名路径设置
4) frame/f [n],选择n号堆栈,当前层位0号,不给出n等价于f 0。并显示当前选择的堆栈的基本信息,包含跳转/pc处对应的源文件信息。
  up [n]            ,选择从当前堆栈向上n层的堆栈,如果没有n参数,则等价于up 1。并显示当前选择的堆栈的基本信息,。。。
  down [n]          ,选择从当前堆栈向下n层的堆栈,如果没有n参数,则等价于down 1。并显示当前选择的堆栈的基本信息,。。。
  up-silently [n]   ,与up功能相同,但不会显示任何信息。
       down-silently [n] ,与down功能相同,但不会显示任何信息。
5) info f,显示当前选择的堆栈的详细信息,包括:堆栈号、堆栈地址、上一层的堆栈地址、传递的参数地址、局部变量的地址、上一层的sp,
         保存的ebp和eip等
    6) info args 上一层传递过来的函数参数的信息
7) info locals,本层的局部变量

Note1:bt指令还有两个别名指令,where和info stack。
Note2:可以有两种方法查看各层堆栈的局部变量,
       m1) 直接使用bt full,则依次把各层的局部变量都显示出来
m2) 配合使用 f n和info locals两条指令,用f n跳转到某层堆栈,再用info locals查看哪一层的局部变量,不要忘记查看完了之后,
   使用 f 0跳转回当前层。
----------------------------------------------------------------------------------------------------------------------------------
20. gdb的主要启动选项(2 Getting In and Out of gdb)
    这里的选项是指启动gdb时,在gdb.exe/gdb32.exe后面加的选项(选项为全拼时前面为"-"和"--"一样,但简写时必须为"-",这里只在silent处
说明,后面相同)。
调用gdb的格式为,gdb32.exe [options] [file.exe],如果不给出file.exe,则可以在进入gdb之后使用file file.exe导入。
--silent或-silent:进入GDB时不打印版权信息。
-command或者-x file:执行file文件中的gdb指令,可以通过在这个文件使用source cmdfile指令再导入其它一些指令文件,而每一个cmdfile文件
                         都做一些不同的设置,从而达到对GDB环境的不同配置。然后再通过file file.exe载入要调试的程序,并导入断点信息,
这是一种实现方案。
-init-command或者-ix file:执行file中的gdb指令,与-x指令不同的是,这种指令引入的文件只能在载入符号表之前起作用,所以其中不能存在
                          file file.exe这种指令。也就是说,gdb启动时会先执行-ix后面的文件,然后再执行-x后面的文件。
-nx或者-n:不自动执行所有的三个目录下的.gdbinit文件,实际上从GDB 7.5版本之后,默认已经不执行这些文件了,所以该选项没什么用,但是
          不给出该选项的话,启动的时候会给出提示一堆提示消息说路径下有.gdbinit,但为了安全期间,没有给你导入。
-annotate level:level为0-3的整数,默认为0,dev-cpp使用的level=3,C-free使用的0,Emacs使用的1。区别在于提示符机制不同。
-interpreter或者-i interp:选择GDB使用的解释器系统,interp的值可以为:
                       1) console,传统的命令行(默认)
2) mi,gdb/mi接口,等价于mi2。推荐用于将GDB作为调试后台的GUI或者IDE。
3) mi2,最新的mi
                       4) mi1,GDB 5版本中的mi
-write:打开可执行文件的可写特性,相当于set write on
-statistics:
Note1:GDB中调用shell指令的方式,
                       1) shell cmd-string
2) ! cmd-string
Note2:启动GDB最好使用-nx --silent选项
----------------------------------------------------------------------------------------------------------------------------------
21. 程序的反向执行(6 Running programs backward),暂时不支持windows平台。
    在目标环境支持的情况下,GDB允许你反向执行程序,回到前一个状态。支持反向执行的目标环境应当能够撤销返回点与当前点之间在机器状态上做出
的改变(例如,变量、寄存器等能返回到之前的状态)。所以并不是所有目标环境都能支持该功能。GDB支持的下面的反向执行指令,
reverse-continue/rc [ignore-count] :反向继续执行直到遇到断点,ignore-count如前面continue指令一样。
reverse-step [count]               :反向的step指令,count为行数。
reverse-stepi [count]              :反向执行1/count条汇编指令。这里要注意的是,反向执行的汇编指令是pc上面的那条指令,而不是pc指向的
                                    指令。
reverse-next [count]               :反向的next指令,count为行数。
reverse-nexti [count]              :反向执行的nexti。
reverse-finish                     :回到当前函数的入口处。
set exec-direction reverse         :设置所有的指令都反向执行,影响到的指令包括step, stepi, next, nexti, continue和finish。
set exec-direction forward         :设置所有的指令都正向执行,这是GDB的默认设置。
show exec-direction                :显示当前GDB的指令执行方向。

    Note:GDB反向调试的方法有两个,一个是直接调用相应的reverse-*指令,另一个是设置exec-direction。
----------------------------------------------------------------------------------------------------------------------------------
22. C语言的预编译宏(12 C Preprocessor Macros)的主要指令
    macro expand expression:将宏表达式macro_expr展开,macro_expr必须是完整的表达式
info macro  macro_expr :显示宏macro_expr的信息,对于函数宏只需要给出名字即可
info macro  linespec   :显示在linespec行起作用的所有宏
Note:这里编译时需要使用-ggdb3或者-gdwarf-2 -g3选项
----------------------------------------------------------------------------------------------------------------------------------
23. 调试时修改原程序(17.6 Patching Programs)
    set write on/off 开启或者关闭原程序修改功能,默认关闭
show write       当前是否开启
----------------------------------------------------------------------------------------------------------------------------------
24. 对于GDB的扩展,主要探讨指令序列的打包方式(Canned Sequences of Commands)、使用Python扩展GDB的方式、如何利用alias简化指令。
    GDB提供了一些扩展机制。调试时,GDB能够读取一个脚本文件并根据其后缀启用不同的扩展语言对其进行解释执行,对于不能识别后缀的脚本文件,
统一作为GDB指令文件处理。
set script-extension off/soft/strict:对于脚本文件的处理方式设定,off表示所有脚本文件都作为GDB指令处理;soft表示根据后缀名决定处
                                     理方式,不能识别的作为GDB指令文件处理(默认);strict也是按够追名处理,但不能识别的会报错。
show script-extension               :当前的脚本文件处理方式。
1)除了可以在断点处定义指令序列外,GDB还提供了两种方式来将指令序列作为一个单元执行:用户自定义指令、指令文件,下面分别介绍。
   a)用户自定义指令,是指将一个指令序列起一个名字作为一个指令对待,该自定义指令可以接受10个输入变量:$arg0...$arg9(类似于批处
  理和shell脚本中的参数),具体的输入变量个数可以通过变量$argc获得。例如,
define adder
if $argc == 2
    print $arg0 + $arg1
end
if $argc == 3
    print $arg0 + $arg1 + $arg2
end
end
  则执行,adder 1 2 3就会输出6。
  define   cmd_name  :定义一个名为cmd_name的自定义指令,格式如上面例子。重定义时gdb会询问是否更改->->query。
  document cmd_name  :将已定义的指令cmd_name加入到帮助中,使得使用help能查询到。格式跟define一样,也是以end结束。重定义不询问。
  dont-repeat        :用在自定义指令中,告诉gdb当RET时不重复执行该自定义指令,最好作为第一条指令。
  help user-defined  :会列出所有用户自定义指令和所有COMAND_USER类中定义的python指令。
  show user [cmd_name] :显示所有自定义指令或仅仅cmd_name指令使用到的gdb指令,也就是列出包含的指令序列。
  
  Note1:这里的输入变量编号与shell或者批处理有区别,批处理或shell中,文件名本身是$0或%0,而这里自定义指令名本身不占用变量。
  Note2:这里的参数是文本替换(类似宏替换),所以参数可以是变量、表达式、甚至是函数调用。
   b)指令文件,是由GDB指令序列构成的文件,#开始的行为注释,空行不起作用(跟terminal时交互不同)。指令文件是通过source指令导入执行的,
  跟第2小节“4)断点存到文件和从文件读取”格式相同,本质上都是执行一个文件中的指令。指令文件中可以包含a)中的用户自定义指令,而且最
  好能将自定义指令单独写到一个指令文件,在启动gdb的时候导入。再将source的格式说明如下,
  source [-s] [-v] filename    :filename为指令文件
                                     -s选项,当前路径下没有,会到path路径搜索。作用不大,完全可以不用。
     -v选项,显示每条指令和它们的执行情况。在指令完全正确的情况下,建议不使用该选项。
  当执行source指令时,会先在当前目录下搜索filename,如果找不到则到directory指令指定的目录下寻找。不指定-v选项时,则个指令执行时,
  不会再terminal下面显示该指令,若给出-v选项,则会显示每条指令和它们的执行情况。
c)无论是用户自定义指令还是指令文件,都可以使用流程控制指令(flow-control commands)处理一些复杂情况。
   _______________________________________________
|   if <expression>  |   while <expression>   |
|  cmd_1          |         cmd_1          |        
|  cmd_2          |         cmd_2          |
|  ......         |         ......  |
|  cmd_n          |         [loop_break]   |
|  [else             |         [loop_continue]|
|  cmd_11         |         ......         |
|  cmd_12         |         cmd_n          |
|  ......         |   end                  |
|  cmd_1n]        |                        |
|   end         |                        |
            -----------------------------------------------
    2)用户自定义指令和指令文件中,GDB的输出被禁用了,唯一的输出是print、x类型的指令定义的输出。这里有几个用于输出信息的其它指令。
        a)echo text       :text为要打印的内容,支持转义字符("\n"表示换行,"\ "表示空格,行尾的"\"表示续行)
        b)output[/fmt] expr     :跟print类似,当不会出现print时的"$n = "部分。expr的说明参见第9小节,fmt参见第1和第8小节。
        c)printf template, expressions...  :等同于C语言中的"printf (template, expressions...);"。
        d)eval template, expressions...    :暂时没看懂怎么用
----------------------------------------------------------------------------------------------------------------------------------
25. gdb中的文件(18 gdb Files)
    指定文件操作指令
  1)file  [filename]  :从 filename 中读取符号表和可执行文件,当不指定 filename 时则指舍弃之前的符号表和可执行文件。
  2)exec-file [ filename ] :从 filename 读取可执行文件。
  3)symbol-file [ filename ]:从 filename 读取符号表。
  4)info target/files :打印出当前调试对象的进程+线程号、入口点、可执行程序的完整内存分配情况(包括各个dll文件的段的地址分配)。
run之前不包含dll信息,run之后才会包含相应的dll信息。
  5)maint info sections:打印出目标映像文件的内存映像及属性。 
       6)info sharedlibrary/share/dll [regex]:打印出所调试程序所加载的所有dll或者与正则表达式regex匹配的dll的内存分配情况,逆向工具
                                                中大多会给出这些信息。   
----------------------------------------------------------------------------------------------------------------------------------
26. GDB/MI接口(27 The gdb/mi Interface) 


     所有的GDB/MI输入指令前面都可以加一个区分其输出的token,token是一个纯数字组成的序列。
 
    1)GDB/MI是一种基于命令行与GDB进行文本交互的解释器,可又通过两种方式实现GDB/MI形式的GDB:
    a)启动GDB时添加选项,  --interpreter | -i mi
b)在GDB/console模式下,执行interpreter-exec mi "cmd"
C)在GDB/MI模式下,如果要执行GDB/console指令,也有两种方式:直接输入GDB/console指令,
   或者-interpreter-exec console "GDB/console指令",推荐采用后者。
2)对使用到的符号和术语做以下设定:
      a) |               用于分隔可选项
  b) [ something ]   表示something是可选的,指令中可以/能有也可以/能没有
  c) ( group )*      表示至少有0个group,group可以是选项(对于输入),也可以是各种类型的输出(对于输出)
  d) ( group )+      表示至少有1个group,group含义如上
  e) "string"        表示字符串字面量
    3)前端程序与GDB的交互包含3个要素:前端发给GDB的指令、GDB对这些指令的响应(response)、GDB给前端的一些通知/提示(notification)。
  一条指令会产生一个响应(标识指令是否执行成功):对于查询,响应包含要查询的信息,对于执行或设置类指令,响应会返回是否成功的信息。
   Notification是一种将GDB状态或/和目标设备状态的变化进行汇总并汇报给前端程序的机制(是一种异步输出信息)。4种主要的Notification如下:
a)Exec notifications:反映目标设备状态的改变(开始、停止、继续等),这种信息一般以"*"作为前缀;
b)Status notifications:反映长时间运行的操作的过程,一般以"+"作为前缀(测试中没发现这种信息,故仍不知其具体含义);
c)General notifications:反映GDB的指令可能对GDB或者目标设备的状态产生的一些未知改变(比如resume程序之后会改变堆栈状态、断点表发生
  改变等),一般以"="作为前缀;
d)Console output notifications:命令行指令的文本响应,通常以"~"作为前缀。
4)运行环境管理,
   a)线程和堆栈管理,某些GDB/MI指令需要显式指定它所操作的线程和堆栈(比如-stack-list-variables --thread 1 --frame 0);
b)GDB/consle下有set language lan指令指定当前可执行文件对应的源文件的格式(默认auto),GDB/MI对应--language lan选项,但该选项没有auto
  ,故而在调用GDB/MI下调用C函数时,需要在其前面添加--language c选项。
    5)GDB/MI的输入语法格式,在MI模式下支持console下面的大部分指令,所以可以直接输入console模式下的指令;另外它有一套自己的指令集合。下面说明
  其合适,每一行的";"后面为该行的注释,nl表示回车键。
   command →   ; 下面一行表示可能的command指令集合类型
            cli-command | mi-command     ; cli-command表示GDB的console指令集中的指令,mi-command表示GDB的mi指令集中的指令
cli-command →   ; console指令集的构成
            [ token ] cli-command nl     ; token是一个用于标识一条指令的数字序列,在对应的"Output Records"中会有对应该token的输出。
mi-command →
            [ token ] "-" operation ( " " option )* [ " --" ] ( " " parameter )* nl    ; 其中的" "表示空格
option →
            "-" parameter [ " " parameter ]
parameter →
            non-blank-sequence | c-string
operation →
            any of the operations described in this chapter
non-blank-sequence →
            anything, provided it doesn’t contain special characters such as "-", nl, """ and

Note1:所有的GBD/MI系统的指令都是以"-"开始的,指令的选项以"--"或者"-"为前缀,但是第一个选项必须以"--"为前缀。
Note2:GBD/MI系统可以处理几乎所有的GDB/console指令,但其输出跟console下会有所不同。不支持的指令主要包括"if","when","define"等涉及到多行
      的指令,这些指令的共同点是会在一行的开始出现">"提示。但是可以通过将这些指令放到指令文件中,然后通过source指令导入实现。

6)GDB/MI的输出语法格式,输出由至少0个“out-of-band-record”和1个“result-record”构成。
        output →
       ( out-of-band-record )* [ result-record ] "(gdb)" nl
result-record →
            [ token ] "^" result-class ( "," result )* nl
out-of-band-record →
            async-record | stream-record
async-record →
            exec-async-output | status-async-output | notify-async-output
exec-async-output →
            [ token ] "*" async-output nl
status-async-output →
            [ token ] "+" async-output nl
notify-async-output →
            [ token ] "=" async-output nl
async-output →
            async-class ( "," result )*
result-class →
            "done" | "running" | "connected" | "error" | "exit"
async-class →
            "stopped" | others (where others will be added depending on the needs—this is still in development).
result →
            variable "=" value
variable →
            string
value → const | tuple | list
const → c-string
tuple → "{}" | "{" result ( "," result )* "}"   ; 仅当为variable object时会出现tuple
list → "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
stream-record →
            console-stream-output | target-stream-output | log-stream-output
console-stream-output →
            "~" c-string nl
target-stream-output →
            "@" c-string nl
log-stream-output →
            "&" c-string nl
nl → CR | CR-LF
   
Note1:关于result-record,其基本格式如上所示。具体展开来如下所示,
      a)"^done" [ "," results ],前面的指令操作成功,result是返回值;
  b)"^running",与^done等价,主要用于"继续运行"程序时,一般下一行会是一个"Exec notifications"行---->*running,thread-id="all";
  c)"^connected",调试远程设备时出现;
  d)"^error" "," "msg=" c-string [ "," "code=" c-string ],前面的指令操作失败,msg=c-string中为相应的错误信息,code=c-string
                  中保存错误代码,当前只定义了一个错误代码"undefined-command";
  e)"^exit",GDB退出。
        Note2:log-stream-output是以"&"作为前缀的,它表示输出到日志文件的内容。
        Note3:这里的console-stream-output就是3).d)的Console output notifications。
        Note4:target-stream-output时目标程序产生的输出,它以"@"作为前缀。
    7)GDB/MI中的流记录(stream records)。6)中的GDB的各种输出record可以看作是不同的输出流,GDB/MI通过流记录(stream records)来区分过滤
       这些不同的输出。每一种流记录都有一个独特的前缀来标识该输出属于哪一个流。在前缀的后面是输出字符串(string-output),总结如下,
         "~" string-output,表示console output stream
"@" string-output,表示target output stream
"&" string-output,表示log output stream
"*" string-output,表示exec-async-output stream
"=" string-output,表示notify-async-output stream
"+" string-output,表示status-async-output stream
"^" string-output,表示result output stream 
    ------------------------>
         ------------------------>
         a)可能的exec-async-output stream
            *running,thread-id="thread",一般跟在^running后面表示程序正在运行,"thread"指明正在运行的线程,若"thread"为"all"表示所有线程都在运行;
*stopped,reason="reason",thread-id="id",stopped-threads="stopped",core="core",程序/远程目标已经停止运行, 并给出相应的信息。
    "reason"为停止的原因,其可能的取值为:breakpoint-hit,watchpoint-trigger,read-watchpoint-trigger,access-watchpoint-trigger,function-finished,
    location-reached,watchpoint-scope,end-stepping-range,exited-signalled,exited,exited-normally,solib-syscall-entry,signal-received,
    solib-event,fork,vfork,syscall-return,exec。其具体含义参看P488(27.7.3 gdb/mi Async Records)。
b)可能的notify-async-output stream
    =thread-group-added,id="id"
             =thread-group-removed,id="id"
=thread-group-started,id="id",pid="pid"
=thread-group-exited,id="id"[,exit-code="code"]
=thread-created,id="id",group-id="gid"
=thread-exited,id="id",group-id="gid"
=thread-selected,id="id"
=library-loaded,...
=library-unloaded,...
=traceframe-changed,num=tfnum,tracepoint=tpnum
=traceframe-changed,end
=tsv-created,name=name,initial=initial
=tsv-deleted,name=name
             =tsv-deleted
=tsv-modified,name=name,initial=initial[,current=current]
             =breakpoint-created,bkpt={...}
=breakpoint-modified,bkpt={...}
=breakpoint-deleted,id=number
=record-started,thread-group="id"
=record-stopped,thread-group="id"   
=cmd-param-changed,param=param,value=value
=memory-changed,thread-group=id,addr=addr,len=len[,type="code"]
其中,最常见的就是=breakpoint-开头的哪3个。
c)关于status-async-output stream,出现的很少
d)result output stream参见6)的Note1
e)console output stream应该是等效GDB/console下的输出
         f)log output stream就是日志
         g)target output stream也没见到过,应该是针对远程目标调试的
8)GDB/MI输出中的断点信息、堆栈结构和线程信息参见 和27.7.4  ~  27.7.6(P490左右)
9)GDB/MI 的断点指令列表
| GDB/MI断点指令                        | 对应console指令         |
|---------------------------------------|---------------------------|                                               
|   -break-after n num          | ignore n num   |
| -break-commands n ["cmd1"..."cmdN"] | commands n         |不同之处在于,GDB/MI在一行中给出所有指令,以空格分隔
| -break-condition n expr   | condition n exp     |
| -break-delete [range]               | delete [range]     |
| -break-disable [range]   | disable [range]     |
| -break-enable [range]   | enable [range]   |
| -break-info [range]   |    info b [range]     |
| -break-insert...[一堆选项]   |    break和tbreak         |
| -dprintf-insert...[一堆选项]   |    dprintf...           |
| -break-list   |    info b               |
| -break-watch [ -a | -r ]   |    watch,rwatch,awatch  
| -catch-load [ -t ] [ -d ] regexp   | catch load     |
| -catch-load [ -t ] [ -d ] regexp   | catch unload     |
---------------------------------------------------------------------
10)程序的运行控制指令、查询类指令和堆栈操作指令
| GDB/MI指令                            | 对应的console指令       |
|---------------------------------------|---------------------------|
|   -thread-info [thread-id ]    | info thread [thread-id] |
|   -thread-list-ids    | info thread的一部分 |
| -thread-select ID | thread ID   |
|   -exec-continue | continue |
| -exec-finish       | finish |
| -exec-jump | jump |
|   -exec-next           | next |
| -exec-next-instruction | nexti        |
| -exec-return             | return |
| -exec-run   | run |
| -exec-step                   | step |
| -exec-step-instruction | stepi |
| -exec-until | until     |
| -stack-info-frame | info frame或frame |
| -stack-info-depth [ max-depth ]     | 显示有多少层堆栈 |
| -stack-list-arguments 0|1|2 [lf hf] | 显示堆栈lf到hf的函数参数  |
| -stack-list-frames [lf hf]         | bt |
| -stack-list-locals 0|1|2          | info locals |
| -stack-list-variables 0|1|2 | 在上面的基础上加上函数参数|
            ---------------------------------------------------------------------
11)GDB/MI中的变量对象(Variable Objects)
         变量对象是用于查询和改变表达式的值的面向对象的MI接口,它是专门设计来用于给前端程序使用的。变量对象是一种复杂的数据类型(类似于C中的
struct类型或者matlab中的cell类型),它具有分层树形结构。如果前端程序要获取一个节点对象的子节点的值,则需要显式指定其名字。
默认情况下,一条指令只显示当前层的信息。如果子对象是一个指针,则其value为地址,若子对象为结构体,则value为{...}。
(下文中,将内置基本类型的变量对象称为叶变量对象--->leaf Variable Objects, LVO)
可以获取LVO的值,也可以给LVO赋值;但是非LVO节点,只能获取到表示其类型的字符串,而不能对其赋值。前端程序并不需要每次stop时都读取变量对象的
所有值,GDB/MI提供了一个update指令来列出两次update指令之间所有发生改变的变量对象。
 
                    R1
R11          R12            R13
       R121 R122 R123         R131
                       R1311     R1312
 
变量对象的结构成为tuple,由一组属性名和属性值构成,常见的属性如下,
    name,变量对象/变量对象的某个子对象的名字;
numchild,变量对象的子对象个数,或者变量对象的某个子对象的子对象的个数
value,变量对象/变量对象的某个子对象的标量值(只有简单的基本类型的值才有意义),对于结构体等复合类型没有意义;
type,变量对象/变量对象的某个子对象的类型;
has_more,有两个含义:创建变量对象时,对于非动态对象总为0;查询变量对象或其子对象时表示当前层后面还有没有其它变量对象。比如,
          使用-var-list-children  my_test  3 9,由于my_test由test定义而来,它有9个成员,所以后面没有别的了,故has_more=0;
  使用-var-list-children  my_test  3 8,由于最后还有一个联合体成员没有显示,故has_more=1;
dynamic,只出现dynamic类型的变量对象的属性中,不会出现在一般变量对象的属性中;
thread-id,如果一个变量对象绑定到一个具体的线程(执行指令时--thread  id作为参数出现),则会出现在变量对象的属性中,否则不出现。
exp,变量对象/变量对象的某个子对象的表达式;
frozen,如果使用了-var-set-frozen指令冻结了一个对象,则为1,否则为0;
 
常用指令如下,{...}表示多选1,[...]表示可选项,...表示必选项
a)-var-create   {name | "-"}   {frame-addr | "*" | "@"}  expression
       S1             S2                     S3               S4
    创建变量对象,S2为给变量对象起的名字,如果为"-",则GDB给自动起名;
             S3为指定计算expression时使用的变量所在的堆栈,*表示当前堆栈,@表示创建的是一个floating对象(进入的堆栈不同其值会变化);
 S4为任意C语言表达式,或*addr(地址addr处的值),*addr1-addr2(地址addr1到addr2之间的所有内存值),$regname’(寄存器)。
b)-var-delete [ -c ] name
        S1        S2   S3
删除变量对象,有S2时表示只删除变量对象name的子变量对象节点,否则全删除。
c)-var-set-format name  {binary | decimal | hexadecimal | octal | natural}
        S1          S2                      S3
    设置变量对象的输出格式,仅影响当层。
-var-show-format  name
获取变量对象name显示格式。
d)-var-info-num-children  name
    获取变量对象name的子节点个数。
e)-var-list-children [print-values]  name   [from   to]
S1 S2          S3        S4
    列出变量对象name的子对象,只列出name的子对象,而对name的子对象的子对象并不给出。例如,若name为R1,则只会列出R11,R12和R13。
             S2为显示格式,0 或 --no-values      表示只打印变量的名字,而不显示值,也就是没有value成员。默认;
               1 或 --all-values     表示打印变量的值,指针变量的value会是地址,结构体等复合对象会是{...},数组为[num];
2 或 --simple-values  表示打印基本类型变量的值,符合类型变量和数组没有value成员。
 S4表示从第from个子对象(zero-based)开始打印,一共打印to-from个子对象。比如,若{name,from,to}={R1,2,3},则只会打印R12。
f)-var-info-type   name
    返回变量对象name的类型,这里name或者是一个定义的变量对象,或者是一个已定义的变量对象的子对象。
g)-var-info-expression name
    用于显示变量对象name的表达式,其值跟-var-list-children指令中显示的exp成员的值相同。
h)-var-info-path-expression name
   跟g)作用相同,其区别在于显示表达式时会将前缀属于哪个类给上。比如(test为main.c中的结构体),
定义了 -var-create my_test * test,则
-var-info-expression msgs        ---->   ^done,lang="C",exp="msgT"
-var-info-path-expression msgs   ---->   ^done,path_expr="(test).msgs"
i)-var-show-attributes name
   显示name的属性为 {{editable | noneditable} | TBD },两层,两个二选一,
    基本数据类型为editable,复合数据类型为noneditable,内存地址区域为TBD。
j)-var-evaluate-expression [-f format-spec] name
    显示变量对象的 value属性值,format-spec为输出格式,可以为{binary | decimal | hexadecimal | octal | natural}
k)-var-assign name expression 
    将变量对象name的值改为expression,其中,变量对象name的属性必须是editable,也就是说必须是基本类型。
这里,一般情况下只能对使用-var-create定义的变量对象的子对象中的基本数据类型赋值,而不能对子对象的子对象赋值;如果要对子对象的子对象赋值,
则需要先调用一次-var-list-children child1,然后就可以对child1的子对象中的基本数据类型赋值了,以此类推。
l)-var-update [print-values] {name | "*"}
       S1            S2            S3
该指令执行后会做两件事:首先会更新 name变量对象 或 全部变量对象 中未frozen的对象及其子孙对象的值,然后跟更新前值不同,将变化了的通过
changelist列表返回给前端程序。手册上说name必须是一个根变量对象(root variable object),但通过测试发现,不是根对象也是完全可以的。
    S2部分的含义参见e)。
S3中*表示所有的变量对象及其子孙变量对象。
m)-var-set-update-range name  from  to
    设定变量对象name的更新范围,from to的含义与e)中相同。
这里的设定等效于:首先 -var-set-frozen name 1,然后再对name的子对象child_m(m属于from --- to-1)执行-var-set-frozen child_m 0。
这里针对的是其所有的子孙对象。
n)-var-set-frozen  name  {1|0}
    设定值不被更新的变量对象,1表示frozen,0表示unfrozen,都是通过这一个指令实现。
这里的frozen是指不更新name的子孙对象的值,但比较仍然是做的。unfrozen并不做更新,直到后面碰到update才做更新。
o)-var-set-visualizer name visualizer
    这个是python相关的指令,咱不说明。
12)GDB/MI中的数据操作(27.18 gdb/mi Data Manipulation)
a)-data-disassemble   {[-s start-addr     -e end-addr] | [ -f filename -l linenum [ -n lines ] ]}   [--] mode
          S1                           S2                                   S3                           S4
该指令等效于GDB/console中的 disassemble指令。
这里,S2和S3部分必须二选一
     S2中表示指定起始汇编地址start-addr和结束汇编地址end-addr。这两个地址都可以是包含$pc的表达式,比如"$pc+20"。
 S3表示将filename中linenum行附近的lines行源代码进行汇编
     S4为汇编模式选项,可以为0-3,0表示只汇编显示,1表示混合代码显示,2表示汇编代码 + raw opcode,3表示在1的基础上 + raw opcode。
   mode前面的--可以省略,不省略时,--与mode之间必须有空格。
    比如,-data-disassemble -f main.c -l 20 3
通过输出发现,这种方式不适合人读,它是将每条汇编都作为一个tuple进行处理的,这种方式可以用于实现鼠标放在*.c的源码上显示其汇编,实现方式为:
-data-disassemble -f main.c -l 20 -n 1 3,显示main.c的第20行对应的汇编tuple。
b)-data-evaluate-expression expr
该指令等效于GDB/console中的 print或者output或者call指令。
表示计算表达式expr的值。
c)-data-list-register-names  [ ( regno )+ ]
    若不指定[ ( regno )+ ],列出当前处理器中所有的寄存器名以一个字符串数组的形势列出;
若指定[ ( regno )+ ],则只列出对应编号的寄存器名(zero-based),[ ( regno )+ ]为自然数,多个时以空格分隔。
例如, -data-list-register-names 0 2 3 表示显示第{0,2,3}个寄存器的名字。
d)-data-list-changed-registers
    列出内容发生改变的寄存器编号。
e)-data-list-register-values    [ --skip-unavailable ]   fmt    [ ( regno )*]
    列出对应编号的寄存器的值,fmt表示格式,x Hexadecimal,o Octal,t Binary,d Decimal,r Raw,N Natural。
如果不给定[ ( regno )*],则列出所有寄存器的值。
f)-data-read-memory-bytes   [ -o offset ]   address    count
         S1                     S2          S3        S4
             该指令等效于GDB/console中的 x 指令。
从内存地址address偏移offset处读取count个byte。对于不可读的区域则跳过。
S3处必须是一个地址,对于变量需要使用取地址运算符。
例如,
-data-read-memory-bytes &test 10
^done,memory=[{begin="0x00406440",offset="0x00000000",end="0x0040644a",contents="6440400084fe28000000"}]
         g)-data-write-memory-bytes address contents [count]
该指令可以使用GDB/console中的多个set {int}addr=num实现,或者使用第17小节中的restore实现。
表示将 contents 加载到address开始的内存中。count为可选项,如果不指定,则加载完contents就可以了;如果指定,则分两种情况,
若contents的长度大于count,则截断,若小于count,则重复加载contents。
13)GDB/MI中符号查询指令(27.20 gdb/mi Symbol Query Commands)  
   -symbol-list-lines filename
没看出什么意思来。
    14)其它指令  
GDB/MI指令                GDB/console指令              示例或解释
-file-exec-and-symbols         file                    -file-exec-and-symbols main.exe
-file-exec-file                exec-file               只加载可执行文件
-file-symbol-file              symbol-file   只加载符号表
-target-download               load       主要用于调试远程目标
 
-gdb-exit                      quit                   
-gdb-set                       set                     -gdb-set $foo=3 
-gdb-show   show               -gdb-show annotate
-gdb-version                   show version
-list-thread-groups            info thread
-add-inferior                  add-inferior            添加进程
                               clone-inferior
----------------------------------------------------------------------------------------------------------------------------------
27. x86的寄存器(IA-32架构)
    1)8个通用寄存器(32位): EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP。一般情况下,ESP只用于表示堆栈指针。EBP和ESP之间为一个栈帧。
2)6个段寄存器(16位):CS, DS, ES, FS, GS, SS。CS为代码段寄存器;(DS, ES, FS, GS)为数据段寄存器,且DS为默认的数据段寄存器,
                    字符处理指令总是使用ES段寄存器作为目标操作数的段寄存器;SS为堆栈段寄存器。在IA-32架构下,段寄存器的值意义不大。
3)1个指令指针寄存器(32位):EIP。也就是PC。
4)1个标志寄存器(32位):EFLAGS,格式如下,
              |------------- X -------------|S  C  X  X |--------- S --------|             
|0000000000|ID|VIP|VIF|AC|VM|RF|0|NT|IOPL|OF|DF|IF|TF|SF|ZF|0|AF|0|PF|1|CF|
           21                       13 12                               0
其中,
    a)IOPL标志占用2位,其它的标志都占用1位。0和1的位置表示保留值,不可修改。
b)32位的EFLAGS寄存器包含3种标志:状态标志(S)、系统标志(X)和一个控制标志(C)。
c)6个状态标志用于指示算术指令的结果:CF,进位标志(Carry Flag);PF,奇偶标志(Parity Flag);AF,辅助进位标志
   (Auxiliary Carry Flag);ZF,零标志(Zero Flag);SF,有符号数标志(Sign Flag);OF,溢出标志(Overflow Flag)。
d)系统标志各位的含义:TF,陷阱标记(Trap Flag);IF中断使能标志(Interrupt enable Flag);IOPL,IO特权等级标志
   (I/O Privilege Level Flag);NT,嵌套任务/中断标志(Nested Task Flag);RF,(Resume Flag)用于控制处理器对调试
异常的处理;VM,虚拟8086模式标志(Virtual-8086 Mode Flag);AC,内存对齐检测标志(Alignment Check Flag);VIF,
IF标志的虚拟映像(irtual interrupt flag);VIP,(Virtual Interrupt Pending Flag)该位置1以指示一个中断正在被
挂起,当没有中断挂起时该位清零。ID,(Identification flag)表示对CPUID指令的支持情况。
e)控制标志DF(Direction Flag),这个方向标志控制串指令(MOVS, CMPS, SCAS, LODS以及STOS)。设置DF标志使得串指令
   自动递减(从高地址向低地址方向处理字符串),清除该标志则使得串指令自动递增。
f)一般情况下,程序执行过程中变化最多的是6个状态标志和1个系统标志IF。
5)FPU单元相关的寄存器,8个80位的ST0~ST7,控制寄存器fctrl,状态寄存器fstat,标志寄存器ftag,fiseg,foseg,fioff,fooff,操作码寄存器fop。
6)SSE指令集相关的向量寄存器:mm0~mm7,xmm0~xmm7。
----------------------------------------------------------------------------------------------------------------------------------
28. gdb交互方式的控制(22 Controlling gdb)  
1)提示符(Prompt)
set prompt newprompt:更改console模式下的提示符为newprompt,默认为"(gdb) "
show prompt         :显示当前console模式下的gdb提示符。
2)命令行历史记录(Command History)
set history filename fname               :GDB的指令在退出时保存到的文件为fname。
set history save on                      :启用退出时的指令保存功能,默认为off。
set history size <size|unlimited>        :GDB在历史列表中可以保存的指令条数。
#set history remove-duplicates <count|unlimited> :GDB是否移除重复的指令,unlimited表示会看整个历史,0表示不删除(默认),
其它表示回看的条数,7.10版本刚加入的指令。
set history expansion <on|off>           :是否启用历史扩展功能,默认不启用。
show history                     :显示已经做的设置。
3)GDB打印窗口的大小(Screen Size)
set height <lpp|unlimited> :lpp行
show height
set width <cpl|unlimited>  :每行cpl个字符
show width
set pagination <on|off>    :等价于是否执行set height unlimited
show pagination
    4)GDB中的数字基数设置(number's radix)
set input-radix base   :设置输入数字的基数为base(012, 0x0a, 10等)
set output-radix base  :设置输出数字的基数为base
show input-radix
show output-radix
show radix
5)其它
set confirm <on|off>   :是否使能确认询问。
show confirm
set trace-commands <on|off> :对于用户自定义指令,是否在执行时显示其内容(默认不显示)。

show trace-commands




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值