首页 > 代码库 > gdb调试汇总

gdb调试汇总

 

1. 启动GDB开始调试:

(1)gdb program ///最常用的用gdb启动程序,开始调试的方式
(2)gdb program core ///用gdb查看core dump文件,跟踪程序core的原因
(3)gdb program pid ///用gdb调试已经开始运行的程序,指定pid即可

2. 应用程序带命令行参数的情况,可以通过下面两种方法启动:

(1)启动GDB的时候,加上–args选项,然后把应用程序和其命令行参数带在后面,具体格式为:gdb –args program args
(2)先按1中讲的方法启动GDB, 然后再执行run命令的时候,后面加上参数

3. 退出GDB:

(1)End-of-File(Ctrl+d)
(2)quit或者q

4. 在GDB调试程序的时候执行shell命令:

(1)shell command args(也可以先执行shell命令,GDB会退出到当前shell, 执行完command后,然后在shell中执行exit命令,便可回到GDB)
(2)make make-args(等同于shell make make-args

5. 在GDB中获取帮助:

(1)在GDB中执行help命令,可以得到如图1所示的帮助信息:

图1 GDB帮助菜单
由图1可以看出,GDB中的命令可以分为八类:别名(aliases)、断点(breakpoints)、数据(data)、文件(files)、内部(internals)、隐含(obscure)、运行(running)、栈(stack)、状态(status)、支持(support)、跟踪点(tracepoints)和用户自定义(user-defined)。
(2)help class-name:查看该类型的命令的详细帮助说明
(3)help all:列出所有命令的详细说明
(4)help command:列出命令command的详细说明
(5)apropos word:列出与word这个词相关的命令的详细说明
(6)complete args:列出所有以args为前辍的命令

6. info和show:

(1)info:用来获取和被调试的应用程序相关的信息
(2)show:用来获取GDB本身设置相关的一些信息

 

 

1. Breakpoint: 作用是让程序执行到某个特定的地方停止运行

  • (1)设置breakpoint:

a. break function: 在函数funtion入口处设置breakpoint
b. break +offset: 在程序当前停止的行向前offset行处设置breakpoint
c. break offset: 在程序当前停止的行向衙offset行处设置breakpoint
d. break linenum: 在当前源文件的第linenum行处设置breakpoint
e. break filename:linenum: 在名为filename的源文件的第linenum行处设置breakpoint
f. break filename:function: 在名为filename的源文件中的function函数入口处设置breakpoint
g. break *address: 在程序的地址address处设置breakpoint
h. break … if cond: …代表上面讲到的任意一个可能的参数,在某处设置一个breakpoint, 但且仅但cond为true时,程序停下来
i. tbreak args: 设置一个只停止一次的breakpoints, args与break命令的一样。这样的breakpoint当第一次停下来后,就会被自己删除
k. rbreak regex: 在所有符合正则表达式regex的函数处设置breakpoint

  • (2)info breakpoints [n]:

查看第n个breakpoints的相关信息,如果省略了n,则显示所有breakpoints的相关信息

  • (3)pending breakpoints:

是指设置在程序开始调试后加载的动态库中的位置处的breakpoints
a. set breakpoint pending auto: GDB缺省设置,询问用户是否要设置pending breakpoint
b. set breakpoint pending on: GDB当前不能识别的breakpoint自动成为pending breakpoint
c. set breakpoint pending off: GDB当前不能识别某个breakpoint时,直接报错
d. show breakpoint pending: 查看GDB关于pending breakpoint的设置的行为(auto, on, off)

  • (4)breakpoints的删除:

a. clear: 清除当前stack frame中下一条指令之后的所有breakpoints
b. clear function clear filename:function: 清除函数function入口处的breakpoints
c. clear linenum clear filename:linenum: 清除第linenum行处的breakpoints
d. delete [breakpoints] [range…]: 删除由range指定的范围内的breakpoints,range范围是指breakpoint的序列号的范围

  • (5)breakpoints的禁用、启用:

a. disable [breakpoints] [range…]: 禁用由range指定的范围内的breakpoints
b. enable [breakpoints] [range…]: 启用由range指定的范围内的breakpoints
c. enable [breakpointsonce [range…]: 只启用一次由range指定的范围内的breakpoints,等程序停下来后,自动设为禁用
d. enable [breakpointsdelete [range…]: 启用range指定的范围内的breakpoints,等程序停下来后,这些breakpoints自动被删除

  • (6)条件breakpoints相关命令:

a. 设置条件breakpoints可以通过break … if cond来设置,也可以通过condition bnum expression来设置,在这里首先要通过(1)中介绍的命令设置好breakpoints,然后用condition命令来指定某breakpoint的条件,该breakpoint由bnum指定,条件由expression指定
b. condition bnum: 取消第bnum个breakpoint的条件
c. ignore bnum count: 第bnum个breakpoint跳过count次后开始生效

  • (7)指定程序在某个breakpoint处停下来后执行一串命令:

a. 格式:commands [bnum]
… command-list …
end
b. 用途:指定程序在第bnum个breakpoint处停下来后,执行由command-list指定的命令串,如果没有指定bnum,则对最后一个breakpoint生效
c. 取消命令列表: commands [bnum]
end
d. 例子:
break foo if x>0
commands
silent
printf “x is %d\n”,x
continue
end
上面的例子含义:当x>0时,在foo函数处停下来,然后打印出x的值,然后继续运行程序

2. Watchpoint: 它的作用是让程序在某个表达式的值发生变化的时候停止运行,达到‘监视’该表达式的目的

  • (1)设置watchpoints:

a. watch expr: 设置写watchpoint,当应用程序写expr, 修改其值时,程序停止运行
b. rwatch expr: 设置读watchpoint,当应用程序读表达式expr时,程序停止运行
c. awatch expr: 设置读写watchpoint, 当应用程序读或者写表达式expr时,程序都会停止运行

  • (2)info watchpoints:

查看当前调试的程序中设置的watchpoints相关信息

  • (3)watchpoints和breakpoints很相像,都有enable/disabe/delete等操作,使用方法也与breakpoints的类似

3. Catchpoint: 的作用是让程序在发生某种事件的时候停止运行,比如C++中发生异常事件,加载动态库事件

  • (1)设置catchpoints:

a. catch event: 当事件event发生的时候,程序停止运行,这里event的取值有:

      1)throw: C++抛出异常

 

      2)catch: C++捕捉到异常

 

      3)exec: exec被调用

 

      4)fork: fork被调用

 

      5)vfork: vfork被调用

 

      6)load: 加载动态库

 

      7)load libname: 加载名为libname的动态库

 

      8)unload: 卸载动态库

 

      9)unload libname: 卸载名为libname的动态库

 

    10)syscall [args]: 调用系统调用,args可以指定系统调用号,或者系统名称

b. tcatch event: 设置只停一次的catchpoint,第一次生效后,该catchpoint被自动删除

    • (2)catchpoints和breakpoints很相像,都有enable/disabe/delete等操作,使用方法也与breakpoints的类似

 

本文是手把手教你玩转GDB的第三篇,主要内容是介绍一些在程序调试过程中最常用的GDB命令,废话不多话,开始今天的正题。
1.attach process-id/detach

  • (1)attach process-id: 在GDB状态下,开始调试一个正在运行的进程,其进程ID为process-id
  • (2)detach: 停止调试当前正在调试有进程,与attach配对试用

2.kill

  • (1)基本功能:杀掉当前GDB正在调试的应用程序所对应的子进程
  • (2)如果想不退出GDB而对当前正在调试的应用程序重新编译、链接,可以在GDB中执行kill杀掉子进程,等编译、链接完后,再重新执行run,GDB便可加载新的可执行程序启动调试

3.多线程程序调试相关:

  • (1)thread threadno:切换当前线程到由threadno指定的线程
  • (2)info threads:查看GDB当前调试的程序的各个线程的相关信息
  • (3)thread apply [threadno] [allargs:对指定(或所有)的线程执行由args指定的命令

4.多进程程序调试相关(fork/vfork):

  • (1)缺省方式:fork/vfork之后,GDB仍然调试父进程,与子进程不相关
  • (2)set follow-fork-mode mode:设置GDB行为,modeparent时,与缺省情况一样;modechild时,fork/vfork之后,GDB进入子进程调试,与父进程不再相关
  • (3)show follow-fork-mode:查看当前GDB多进程跟踪模式的设置

5.step & stepi

  • (1)step [count]: 如果没有指定count, 则继续执行程序,直到到达与当前源文件不同的源文件中时停止;如果指定了count, 则重复行上面的过程count
  • (2)stepi [count]: 如果没有指定count, 继续执行下一条机器指令,然后停止;如果指定了count,则重复上面的过程count
  • (3)step比较常见的应用场景:在函数func被调用的某行代码处设置断点,等程序在断点处停下来后,可以用step命令进入该函数的实现中,但前提是该函数编译的时候把调试信息也编译进去了,负责step会跳过该函数。

6.next & nexti

  • (1)next [count]: 如果没有指定count, 单步执行下一行程序;如果指定了count,单步执行接下来的count行程序
  • (2)nexti [count]: 如果没有指定count, 单步执行下一条指令;如果指定了count, 音频执行接下来的count条执行
  • (3)stepinexti的区别:nexti在执行某机器指令时,如果该指令是函数调用,那么程序执行直到该函数调用结束时才停止。

7.continue [ignore-count] 唤醒程序,继续运行,至到遇到下一个断点,或者程序结束。如果指定ignore-count,那么程序在接下来的运行中,忽略ignore-count次断点。
8. finish & return

  • (1)finish: 继续执行程序,直到当前被调用的函数结束,如果该函数有返回值,把返回值也打印到控制台
  • (2)return [expression]: 中止当前函数的调用,如果指定了expression,把expresson值当做当前函数的返回值;如果没有,直接结束当前函数调用

9.信号的处理

  • (1)info signals info handle:打印所有的信号相关的信息,以及GDB缺省的处理方式:

  • (2)handle signal action: 设置GDB对具体某个信号的处理方式。signal可以为信号整数值,也可以为SIGSEGV这样的符号。action的取值有:

a. stopnostopnostop表示当GDB收到指定的信号,不会应用停止程序的执行,只会打印出一条收到信号的消息,因此,nostop也暗含了下面的print; 而stop则表示,当GDB收到指定的信号,停止应用程序的执行。
b. printnoprintprint表示如果收到指定的信号,打印出一条信息; noprintprint表示相反的意思
c. passnopasspass表示如果收到指定的信号,把该信号通知给应用程序; nopass表示与pass相反的意思
d. ignorenoignoreignorenopass同义,同理,noignorepass同义

 

 

 

 

 

 

 

==================================================================

转自:Linux gdb调试器用法全面解析

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,GDB主要可帮助工程师完成下面4个方面的功能:

  • 启动程序,可以按照工程师自定义的要求随心所欲的运行程序。
  • 让被调试的程序在工程师指定的断点处停住,断点可以是条件表达式。
  • 当程序被停住时,可以检查此时程序中所发生的事,并追索上文。
  • 动态地改变程序的执行环境。

不管是调试Linux内核空间的驱动还是调试用户空间的应用程序,掌握gdb的用法都是必须。而且,调试内核和调试应用程序时使用的gdb命令是完全相同的,下面以代码清单22.2的应用程序为例演示gdb调试器的用法。

[cpp] view plaincopy
 
  1. 1  int add(int a, int b)  
  2. 2  {  
  3. 3    return a + b;  
  4. 4  }  
  5. 5    
  6. 6  main()  
  7. 7  {  
  8. 8    int sum[10] =   
  9. 9    {  
  10. 10     0, 0, 0, 0, 0, 0, 0, 0, 0, 0       
  11. 11   }  ;  
  12. 12   int i;  
  13. 13     
  14. 14   int array1[10] =  
  15. 15   {  
  16. 16     48, 56, 77, 33, 33, 11, 226, 544, 78, 90  
  17. 17   };  
  18. 18   int array2[10] =  
  19. 19   {  
  20. 20     85, 99, 66, 0x199, 393, 11, 1, 2, 3, 4  
  21. 21   };  
  22. 22   
  23. 23   for (i = 0; i < 10; i++)  
  24. 24   {  
  25. 25     sum[i] = add(array1[i], array2[i]);  
  26. 26   }  
  27. 27 }  

使用命令gcc –g gdb_example.c –o gdb_example编译上述程序,得到包含调试信息的二进制文件example,执行gdb gdb_example命令进入调试状态:

 

[cpp] view plaincopy
 
  1. [root@localhost driver_study]# gdb gdb_example  
  2. GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)  
  3. Copyright 2003 Free Software Foundation, Inc.  
  4. GDB is free software, covered by the GNU General Public License, and you are  
  5. welcome to change it and/or distribute copies of it under certain conditions.  
  6. Type "show copying" to see the conditions.  
  7. There is absolutely no warranty for GDB.  Type "show warranty" for details.  
  8. This GDB was configured as "i386-redhat-linux-gnu"...  
  9. (gdb)  

 

1、list命令

在gdb中运行list命令(缩写l)可以列出代码,list的具体形式包括:

  • list <linenum> ,显示程序第linenum行周围的源程序,如:
[cpp] view plaincopy
 
  1. (gdb) list 15  
  2. 10          
  3. 11        int array1[10] =  
  4. 12        {  
  5. 13          48, 56, 77, 33, 33, 11, 226, 544, 78, 90  
  6. 14        };  
  7. 15        int array2[10] =  
  8. 16        {  
  9. 17          85, 99, 66, 0x199, 393, 11, 1, 2, 3, 4  
  10. 18        };  
  11. 19  
  • list <function> ,显示函数名为function的函数的源程序,如:
[cpp] view plaincopy
 
  1. (gdb) list main  
  2. 2       {  
  3. 3         return a + b;  
  4. 4       }  
  5. 5  
  6. 6       main()  
  7. 7       {  
  8. 8         int sum[10];  
  9. 9         int i;  
  10. 10          
  11. 11        int array1[10] =  
  • list,显示当前行后面的源程序。
  • list - ,显示当前行前面的源程序。

下面演示了使用gdb中的run(缩写r)、break(缩写b)、next(缩写n)命令控制程序的运行,并使用print(缩写p)命令打印程序中的变量sum的过程:

(gdb)break add
Breakpoint1 at 0x80482f7: file gdb_example.c, line 3.(gdb) run  
Starting program:/driver_study/gdb_example 

Breakpoint1, add (a=48, b=85) at gdb_example.c:3
warning:Source file is more recent than executable.3         return a + b;(gdb)next4       }(gdb)next
main () at gdb_example.c:2323        for(i =0; i <10; i++)(gdb)next25          sum[i]= add(array1[i], array2[i]);(gdb)print sum
$1 ={133,0,0,0,0,0,0,0,0,0}

2、run命令

在gdb中,运行程序使用run命令。在程序运行前,我们可以设置如下4方面的工作环境:

  • 程序运行参数

set args 可指定运行时参数,如:set args 10 20 30 40 50;show args 命令可以查看设置好的运行参数。

  • 运行环境

path <dir> 可设定程序的运行路径;how paths可查看程序的运行路径;set environment varname [=value]用于设置环境变量,如set env USER=baohua;

show environment [varname]则用于查看环境变量。

  • 工作目录

cd <dir> 相当于shell的cd命令;pwd 显示当前所在的目录。

  • 程序的输入输出

info terminal 用于显示程序用到的终端的模式;gdb中也可以使用重定向控制程序输出,如run > outfile

tty命令可以指定输入输出的终端设备,如:tty /dev/ttyS1

3、break命令

在gdb中用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>

“...”可以是上述的break <linenum>break +offset / break –offset中的参数,condition表示条件,在条件成立时停住。比如在循环体中,可以设置break if i=100,表示当i为100时停住程序。

查看断点时,可使用info命令,如info breakpoints [n]info break [n](n表示断点号)。

4、单步命令

在调试过程中,next命令用于单步执行,类似VC++中的step over。next的单步不会进入函数的内部,与next对应的step(缩写s)命令则在单步执行一个函数时,会进入其内部,类似VC++中的step into。下面演示了step命令的执行情况,在23行的add()函数调用处执行step会进入其内部的“return a+b;”语句:

 

[cpp] view plaincopy
 
  1. (gdb) break 25  
  2. Breakpoint 1 at 0x8048362: file gdb_example.c, line 25.  
  3. (gdb) run  
  4. Starting program: /driver_study/gdb_example   
  5.   
  6. Breakpoint 1, main () at gdb_example.c:25  
  7. 25          sum[i] = add(array1[i], array2[i]);  
  8. (gdb) step  
  9. add (a=48, b=85) at gdb_example.c:3  
  10. 3         return a + b;  

单步执行的更复杂用法包括:

 

  • step <count>

单步跟踪,如果有函数调用,则进入该函数(进入函数的前提是,此函数被编译有debug信息)。step后面不加count表示一条条地执行,加表示执行后面的count条指令,然后再停住。

  • next <count>

单步跟踪,如果有函数调用,它不会进入该函数。同样地,next后面不加count表示一条条地执行,加表示执行后面的count条指令,然后再停住。

  • set step-mode

set step-mode on用于打开step-mode模式,这样,在进行单步跟踪时,程序不会因为没有debug信息而不停住,这个参数的设置可便于查看机器码。set step-mod off用于关闭step-mode模式。

  • finish

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

  • until (缩写u)

一直在循环体内执行单步,退不出来是一件令人烦恼的事情,until命令可以运行程序直到退出循环体。

  • stepi(缩写si)和nexti(缩写ni)

stepi和nexti用于单步跟踪一条机器指令,一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令。 另外,运行“display/i $pc”命令后,单步跟踪会在打出程序代码的同时打出机器指令,即汇编代码。

5、continue命令

当程序被停住后,可以使用continue命令(缩写c,fg命令同continue命令)恢复程序的运行直到程序结束,或到达下一个断点,命令格式为: 

 

[cpp] view plaincopy
 
  1. continue [ignore-count]  
  2. c [ignore-count]  
  3. fg [ignore-count]  

ignore-count表示忽略其后多少次断点。 假设我们设置了函数断点add(),并watch i,则在continue过程中,每次遇到add()函数或i发生变化,程序就会停住,如:

 

 

[cpp] view plaincopy
 
  1. (gdb) continue  
  2. Continuing.  
  3. Hardware watchpoint 3: i  
  4.   
  5. Old value = 2  
  6. New value = 3  
  7. 0x0804838d in main () at gdb_example.c:23  
  8. 23        for (i = 0; i < 10; i++)  
  9. (gdb) continue  
  10. Continuing.  
  11.   
  12. Breakpoint 1, main () at gdb_example.c:25  
  13. 25          sum[i] = add(array1[i], array2[i]);  
  14. (gdb) continue  
  15. Continuing.  
  16. Hardware watchpoint 3: i  
  17.   
  18. Old value = 3  
  19. New value = 4  
  20. 0x0804838d in main () at gdb_example.c:23  
  21. 23        for (i = 0; i < 10; i++)  

 

6、print命令

在调试程序时,当程序被停住时,可以使用print命令(缩写为p),或是同义命令inspect来查看当前程序的运行数据。print命令的格式是: 

 

[cpp] view plaincopy
 
  1. print <expr>  
  2. print /<f> <expr>  


<expr>是表达式,是被调试的程序中的表达式,<f>是输出的格式,比如,如果要把表达式按16进制的格式输出,那么就是/x。在表达式中,有几种GDB所支持的操作符,它们可以用在任何一种语言中,“@”是一个和数组有关的操作符,“::”指定一个在文件或是函数中的变量,“{<type>} <addr>”表示一个指向内存地址<addr>的类型为type的一个对象。

下面演示了查看sum[]数组的值的过程: 

 

[cpp] view plaincopy
 
  1. (gdb) print sum  
  2. $2 = {133, 155, 0, 0, 0, 0, 0, 0, 0, 0}  
  3. (gdb) next  
  4.   
  5. Breakpoint 1, main () at gdb_example.c:25  
  6. 25          sum[i] = add(array1[i], array2[i]);  
  7. (gdb) next  
  8. 23        for (i = 0; i < 10; i++)  
  9. (gdb) print sum  
  10. $3 = {133, 155, 143, 0, 0, 0, 0, 0, 0, 0}  

当需要查看一段连续内存空间的值的时间,可以使用GDB的“@”操作符,“@”的左边是第一个内存地址,“@”的右边则是想查看内存的长度。例如如下动态申请的内存:

 

int*array =(int*) malloc (len *sizeof(int));

在GDB调试过程中这样显示出这个动态数组的值:

p *array@len

print的输出格式包括:

  • x 按十六进制格式显示变量。
  • d 按十进制格式显示变量。
  • u 按十六进制格式显示无符号整型。
  • o 按八进制格式显示变量。
  • t 按二进制格式显示变量。
  • a 按十六进制格式显示变量。
  • c 按字符格式显示变量。
  • f 按浮点数格式显示变量。

我们可用display命令设置一些自动显示的变量,当程序停住时,或是单步跟踪时,这些变量会自动显示。 如果要修改变量,如x的值,可使用如下命令:

print x=4

当用GDB的print查看程序运行时的数据时,每一个print都会被GDB记录下来。GDB会以$1,$2,$3 …这样的方式为每一个print命令编号。我们可以使用这个编号访问以前的表达式,如$1

7、watch命令

watch一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。我们有下面的几种方法来设置观察点: watch <expr>:为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。rwatch <expr>:当表达式(变量)expr被读时,停住程序。awatch <expr>:当表达式(变量)的值被读或被写时,停住程序。info watchpoints:列出当前所设置了的所有观察点。 下面演示了观察i并在连续运行next时一旦发现i变化,i值就会显示出来的过程:

 

[cpp] view plaincopy
 
  1. (gdb) watch i  
  2. Hardware watchpoint 3: i  
  3. (gdb) next  
  4. 23        for (i = 0; i < 10; i++)  
  5. (gdb) next  
  6. Hardware watchpoint 3: i  
  7.   
  8. Old value = 0  
  9. New value = 1  
  10. 0x0804838d in main () at gdb_example.c:23  
  11. 23        for (i = 0; i < 10; i++)  
  12. (gdb) next  
  13.   
  14. Breakpoint 1, main () at gdb_example.c:25  
  15. 25          sum[i] = add(array1[i], array2[i]);  
  16. (gdb) next  
  17. 23        for (i = 0; i < 10; i++)  
  18. (gdb) next  
  19. Hardware watchpoint 3: i  
  20.   
  21. Old value = 1  
  22. New value = 2  
  23. 0x0804838d in main () at gdb_example.c:23  
  24. 23        for (i = 0; i < 10; i++)  

 

8、examine命令

我们可以使用examine命令(缩写为x)来查看内存地址中的值。examine命令的语法如下所示:

x/<n/f/u><addr>

<addr>表示一个内存地址。“x/”后的n、f、u都是可选的参数,n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容;f 表示显示的格式,如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是i;u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4字节。u参数可以被一些字符代替:b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指定的内存地址开始,读写指定字节,并把其当作一个值取出来。n、f、u这3个参数可以一起使用,例如命令“x/3uh 0x54320”表示从内存地址0x54320开始以双字节为1个单位(h)、16进制方式(u)显示3个单位(3)的内存。 == 

 

譬如下面的例子:

[cpp] view plaincopy
 
  1. main()  
  2. {  
  3.         char *c = "hello world";  
  4.         printf("%s\n", c);  
  5. }  


我们在

[cpp] view plaincopy
 
  1. char *c = "hello world";  

下一行设置断点后:

[cpp] view plaincopy
 
  1. (gdb) l  
  2. 1    main()  
  3. 2    {  
  4. 3        char *c = "hello world";  
  5. 4        printf("%s\n", c);  
  6. 5    }  
  7. (gdb) b 4  
  8. Breakpoint 1 at 0x100000f17: file main.c, line 4.  
  9. (gdb) r  
  10. Starting program: /Users/songbarry/main  
  11. Reading symbols for shared libraries +. done  
  12.   
  13. Breakpoint 1, main () at main.c:4  
  14. 4        printf("%s\n", c);  

可以通过多种方式看C指向的字符串:

方法1:

[cpp] view plaincopy
 
  1. (gdb) p c  
  2. $1 = 0x100000f2e "hello world"  

方法2:

[cpp] view plaincopy
 
  1. (gdb) x/s 0x100000f2e  
  2. 0x100000f2e:     "hello world"  

方法3:

[cpp] view plaincopy
 
  1. (gdb) p (char *)0x100000f2e  
  2. $3 = 0x100000f2e "hello world"  

将第一个字符改为大写:

[cpp] view plaincopy
 
  1. (gdb) p *(char *)0x100000f2e=‘H‘  
  2. $4 = 72 ‘H‘  

再看看C:

[cpp] view plaincopy
 
  1. (gdb) p c  
  2. $5 = 0x100000f2e "Hello world"  

 

9、set命令

 

修改寄存器:

[cpp] view plaincopy
 
  1. (gdb) set $v0 = 0x004000000  
  2. (gdb) set $epc = 0xbfc00000   

修改内存:

 

[cpp] view plaincopy
 
  1. (gdb) set {unsigned int}0x8048a51=0x0  

譬如对于第8节的例子:

 

 

[cpp] view plaincopy
 
  1. (gdb) set {unsigned int}0x100000f2e=0x0         
  2. (gdb) x/10cb 0x100000f2e  
  3. 0x100000f2e:    0 ‘\0‘  0 ‘\0‘  0 ‘\0‘  0 ‘\0‘  111 ‘o‘ 32 ‘ ‘  119 ‘w‘ 111 ‘o‘  
  4. 0x100000f36:    114 ‘r‘ 108 ‘l‘  
  5. (gdb) p c  
  6. $10 = 0x100000f2e ""  

 

 

10、jump命令

一般来说,被调试程序会按照程序代码的运行顺序依次执行,但是GDB也提供了乱序执行的功能,也就是说,GDB可以修改程序的执行顺序,从而让程序随意跳跃。这个功能可以由GDB的jump命令:jump <linespec> 来指定下一条语句的运行点。<linespec>可以是文件的行号,可以是file:line格式,也可以是+num这种偏移量格式,表示下一条运行语句从哪里开始。jump <address> 这里的<address>是代码行的内存地址。 注意,jump命令不会改变当前的程序栈中的内容,所以,如果使用jump从一个函数跳转到另一个函数,当跳转到的函数运行完返回,进行出栈操作时必然会发生错误,这可能导致意想不到的结果,所以最好只用jump在同一个函数中进行跳转。

11、signal命令

使用singal命令,可以产生一个信号量给被调试的程序,如中断信号“Ctrl+C”。这非常方便于程序的调试,可以在程序运行的任意位置设置断点,并在该断点用GDB产生一个信号量,这种精确地在某处产生信号的方法非常有利于程序的调试。 signal命令的语法是:signal <signal>,UNIX的系统信号量通常从1到15,所以<signal>取值也在这个范围。

12、return命令

如果在函数中设置了调试断点,在断点后还有语句没有执行完,这时候我们可以使用return命令强制函数忽略还没有执行的语句并返回。 

 

[cpp] view plaincopy
 
  1. return  
  2. return <expression>  

上述return命令用于取消当前函数的执行,并立即返回,如果指定了<expression>,那么该表达式的值会被作为函数的返回值。

 

13、call命令

call命令用于强制调用某函数: call <expr> 表达式中可以一是函数,以此达到强制调用函数的目的,它会显示函数的返回值(如果函数返回值不是void)。 其实,前面介绍的print命令也可以完成强制调用函数的功能。

14、info命令

info命令可以在调试时用来查看寄存器、断点、观察点和信号等信息。要查看寄存器的值,可以使用如下命令: info registers (查看除了浮点寄存器以外的寄存器)info all-registers (查看所有寄存器,包括浮点寄存器)info registers <regname ...> (查看所指定的寄存器) 要查看断点信息,可以使用如下命令:info break 列出当前所设置的所有观察点,使用如下命令:info watchpoints 查看有哪些信号正在被GDB检测,使用如下命令:info signals info handle 也可以使用info line命令来查看源代码在内存中的地址。info threads可以看多线程。info line后面可以跟行号、函数名、文件名:行号、文件名:函数名等多种形式,例如下面的命令会打印出所指定的源码在运行时的内存地址:

 

[cpp] view plaincopy
 
  1. info line tst.c:func  

 

15、set scheduler-locking off|on|step

 

off 不锁定任何线程,也就是所有线程都执行,这是默认值。 
on 只有当前被调试程序会执行。 
step 在单步的时候,除了next过一个函数的情况以外,只有当前线程会执行。

与多线程调试相关的命令还包括:

thread ID 
切换当前调试的线程为指定ID的线程。 
 
break thread_test.c:123 thread all
在所有线程中相应的行上设置断点
 
thread apply ID1 ID2 command 
让一个或者多个线程执行GDB命令command。 
 
thread apply all command 
让所有被调试线程执行GDB命令command。

16、disassemble

disassemble命令用于反汇编,它可被用来查看当前执行时的源代码的机器码,其实际上只是把目前内存中的指令dump出来。下面的示例用于查看函数func的汇编代码:

[cpp] view plaincopy
 
    1. (gdb) disassemble func  
    2. Dump of assembler code for function func:  
    3. 0x8048450 <func>:       push   %ebp  
    4. 0x8048451 <func+1>:     mov    %esp,%ebp  
    5. 0x8048453 <func+3>:     sub    $0x18,%esp  
    6. 0x8048456 <func+6>:     movl   $0x0,0xfffffffc(%ebp)  
    7. ...  
    8. End of assembler dump.