GDB调试应用

GDB概述

 

GDBGNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VCBCBIDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VCBCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。

 

一般来说,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 2002Free Software Foundation, Inc.

GDB is freesoftware, covered by the GNU General Public License, and you are

welcome tochange it and/or distribute copies of it under certain conditions.

Type"show copying" to see the conditions.

There isabsolutely no warranty for GDB.  Type"show warranty" for details.

This GDB wasconfigured 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) break16    <-------------------- 设置断点,在源程序第16行处。

Breakpoint 1at 0x8048496: file tst.c, line 16.

(gdb) breakfunc  <-------------------- 设置断点,在函数func()入口处。

Breakpoint 2at 0x8048456: file tst.c, line 5.

(gdb) infobreak  <-------------------- 查看断点信息。

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命令简写

Startingprogram: /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 exitfrom #0  func (n=250) at tst.c:5

0x080484e4 inmain () at tst.c:24

24              printf("result[1-250] = %d/n", func(250) );

Value returnedis $6 = 31375

(gdb) c     <--------------------- 继续运行。

Continuing.

result[1-250]= 31375    <----------程序输出。

 

Program exitedwith 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的方法有以下几种:

 

    1gdb <program>

       program也就是你的执行文件,一般在当然目录下。

 

    2gdb <program> core

       gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。

 

    3gdb <program> <PID>

       如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程IDgdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。

 

 

 

GDB启动时,可以加上一些GDB的启动开关,详细的开关可以用gdb-help查看。我在下面只例举一些比较常用的参数:

 

    -symbols <file>

    -s <file>

    从指定文件中读取符号表。

 

    -se file

    从指定文件中读取符号表信息,并把他用在可执行文件中。

 

    -core <file>

    -c <file>

    调试时core dumpcore文件。

 

    -directory <directory>

    -d <directory>

    加入一个源文件的搜索路径。默认搜索路径是环境变量中PATH所定义的路径。

 

 

启动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 GNUGeneral Public License, and you are

    welcome to change it and/or distributecopies of it under certain conditions.

    Type "show copying" to see theconditions.

    There is absolutely no warranty forGDB.  Type "show warranty" fordetails.

    This GDB was configured as"i386-suse-linux".

    (gdb) help

    List of classes of commands:

 

    aliases -- Aliases of other commands

    breakpoints -- Making program stop atcertain 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 executionwithout 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 commandname for full documentation.

    Command name abbreviations are allowed ifunambiguous.

    (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中运行UNIXshell程序

————————————

 

gdb环境中,你可以执行UNIXshell的命令,使用gdbshell命令来完成:

 

    shell <command string>

    调用UNIXshell来执行<command string>,环境变量SHELL中定义的UNIXshell将会被用来执行<command string>,如果SHELL没有定义,那就使用UNIX的标准shell/bin/sh。(在Windows中使用Command.comcmd.exe

 

还有一个gdb命令是make

    make <make-args>

    可以在gdb中执行make命令来重新build自己的程序。这个命令等价于“shell make <make-args>”。

 

 

 

 

GDB中运行程序

————————

 

当以gdb <program>方式启动gdb后,gdb会在PATH路径和当前目录中搜索<program>的源文件。如要确认gdb是否读到源文件,可使用llist命令,看看gdb是否能列出源代码。

 

gdb中,运行程序使用r或是run命令。程序的运行,你有可能需要设置下面四方面的事。

 

1、程序运行参数。

    set args 可指定运行时参数。(如:setargs 10 20 30 40 50

    show args 命令可以查看设置好的运行参数。

 

2、运行环境。

    path <dir> 可设定程序的运行路径。

    show paths 查看程序的运行路径。

    set environment varname [=value] 设置环境变量。如:set envUSER=hchen

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

 

3、工作目录。

    cd <dir> 相当于shellcd命令。

    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::functionfunction(type,type)格式来指定函数名。

 

    break <linenum>

        在指定行号停住。

 

    break +offset

    break -offset

        在当前行号的前面或后面的offset行停住。offiset为自然数。

 

    break filename:linenum

        在源文件filenamelinenum行处停住。

 

    break filename:function

        在源文件filenamefunction函数的入口处停住。

 

    break *address

        在程序运行的内存地址处停住。

 

    break

        break命令没有参数时,表示在下一条指令处停住。

 

    break ... if <condition>

        ...可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环境体中,可以设置break if i=100,表示当i100时停住程序。

 

    查看断点时,可使用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可以是下面的内容:

        1throw 一个C++抛出的异常。(throw为关键字)

        2catch 一个C++捕捉到的异常。(catch为关键字)

        3exec 调用系统调用exec时。(exec为关键字,目前此功能只在HP-UX下有用)

        4fork 调用系统调用fork时。(fork为关键字,目前此功能只在HP-UX下有用)

        5vfork 调用系统调用vfork时。(vfork为关键字,目前此功能只在HP-UX下有用)

        6load load <libname> 载入共享库(动态链接库)时。(load为关键字,目前此功能只在HP-UX下有用)

        7unload unload <libname> 卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在HP-UX下有用)

 

    tcatch <event>

        只设置一次捕捉点,当程序停住以后,应点被自动删除。

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

以上来源于网络。

 

TA中的应用: 

1.修改makefile文件,增加参数-g

CFLAGS=-c -g

2. 建立一个目录gdb

  make gdb

3. 创建gdb.txt

echo "

# #是注释符

set printelement 0

set printpretty on

#breakfare.pc:CltFare

#breakfare.pc:100

"  >> gdb.txt

4. 创建脚本

建立一个gdb.sh的文件

输入以下内容:

 

#!/bin/bash
source ~/.bash_profile
USENAME=m_ta
COMM=batchsv
HOME=/home/${USENAME}/script/gdb
#可以带参数r 表示先重启
while getopts "r" optname
do
case "$optname" in
"r")
#tmshutdown -y
yes|tmipcrm
tmboot -y
;;
esac
done

PID=`ps -ef|grep ${COMM}|grep -v grep|grep  -w  ${USENAME} |awk '{print $2}'`
cd ${HOME}; gdb --tui --pid=${PID} -x ${HOME}/gdb.txt

 

功能: 主要是取到batchsv的进程号,对于多个进程要修改ubb把进程限定在一个进程号上。

5.  chmod +x gdb.sh

 6.  TA调试步骤

 1) 修改gdb.txt文件

把要设的断点位置写好

例如:

breakcheckrequest.pc:100

2) 启动gdb命令

./gdb.sh

3) 可以在TA前台启动要处理的界面

如果执行到断点的位置,此时处理会一直等待

4)回到调试界面,按回车

直到断点出现。

如果断点的条件不满足,则程序会直接执行下去

 

注意:

如果要设置条件断点,我们可以先在程序中写好,然后断点打在该处。

例如:

要调用申请单号为"21000005678"的申请记录。

100 if(strcmp(r.requestno[k],"21000005678")==0)

101 {

102   z=0;

103 }

 

则可以把gdb.txt改成:

breakcheckrequest.pc:102 当程序执行到这条记录时,会停下来。

GDB调试应用_第1张图片

上图是启动gdb后的画面,断点已经正确设置在 checkrequest.pc



TA进行预处理,此时如果断点有作用,则时间会一直走下去,像是“卡”死了。


GDB调试应用_第2张图片

回到gdb界面,N键,多按几次,直到上方出现源代码。


 

GDB调试应用_第3张图片

p命令可以查看数组及变量的值



q 可以退出调试,如果选y, TA程序会接着处理以下的程序


GDB调试应用_第4张图片

s 命令,单步调试,可以跟进函数体内,如图,可以看到进入函数GetFundDay的入口值


GDB调试应用_第5张图片

可以用finish 结束函数体内的调试。



你可能感兴趣的:(GDB调试应用)