GDB调试工具的实践

GDB是GNU Debuger的简称,是GNU发布的一款unix下应用程序调试工具。它被广泛使用在各个产家各种应用中。GDB和所有常用的调试工具一样,它的主要功能有:监视变量的值、设置断点及单步执行。
注意,在源程序编译时,要使用gcc -g 或 cc -g 或 g++ -g将源程序编译成可执行文件,然后才能使用gdb进行调试。只有这样,生成的可执行文件才包含调试信息。
参考别人的写一个简单的c程序,在linux下使用gcc编译成可执行文件,然后使用gdb进行调试。

程序源代码如下

#include <stdio.h>  
  
int func(int n)  
{  
        int sum=0,i;  
        for(i=0; i<n; i++)  
        {  
                sum+=i;  
        }  
        return sum;  
}  
  
int main()  
{  
        int i;  
        long result = 0;  
        for(i=1; i<=100; i++)  
        {  
                result += i;  
        }  
  
       printf("result[1-100] = %d \n\r", result );  
       printf("result[1-250] = %d \n\r", func(250) );  
}
使用gcc -g变成生成可执行文件miki,方法为 gcc -g miki.c  -o miki
使用gdb开始调试miki应用,如下:

$gdb miki  
GNU gdb (GDB) CentOS (7.0.1-42.el5.centos)  
Copyright (C) 2009 Free Software Foundation, Inc.  
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>  
This is free software: you are free to change and redistribute it.  
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"  
and "show warranty" for details.  
This GDB was configured as "x86_64-redhat-linux-gnu".  
For bug reporting instructions, please see:  
<http://www.gnu.org/software/gdb/bugs/>…  
Reading symbols from /u01/home/oracle/miki…done.  
(gdb) l 1  
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<=10; i++)  
19              {  
20                      result += i;  
(gdb)  
21              }  
22  
23             printf("result[1-10] = %d \n\r", result );  
24             printf("result[1-5] = %d \n\r", func(5) );  
25      }  
(gdb)  
Line number 26 out of range; miki.c has 25 lines.  
(gdb) r  
Starting program: /u01/home/oracle/miki  
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000  
result[1-10] = 55  
result[1-5] = 10  
Program exited with code 023.  

l 1         表示显示源码第一行开始的10行记录,可以写成list 1
l           表示显示源码中间的前后10行记录,可以写成list 
空白回车     表示重复上一次命令操作
r            表示程序开始运行

(gdb) b 23  
Breakpoint 1 at 0x4004f2: file miki.c, line 23.  
(gdb) info b  
Num     Type           Disp Enb Address            What  
1       breakpoint     keep y   0x00000000004004f2 in main at miki.c:23  
(gdb) i b  
Num     Type           Disp Enb Address            What  
1       breakpoint     keep y   0x00000000004004f2 in main at miki.c:23  
(gdb) break func  
Breakpoint 2 at 0x40049f: file miki.c, line 5.  
(gdb) info break  
Num     Type           Disp Enb Address            What  
1       breakpoint     keep y   0x00000000004004f2 in main at miki.c:23  
2       breakpoint     keep y   0x000000000040049f in func at miki.c:5  
  
  
(gdb) i b  
Num     Type           Disp Enb Address            What  
1       breakpoint     keep y   0x00000000004004f2 in main at miki.c:23  
2       breakpoint     keep y   0x000000000040049f in func at miki.c:5  
3       breakpoint     keep y   0x000000000040049f in func at miki.c:2  
(gdb) d 2  
(gdb) i b  
Num     Type           Disp Enb Address            What  
1       breakpoint     keep y   0x00000000004004f2 in main at miki.c:23  
3       breakpoint     keep y   0x000000000040049f in func at miki.c:2  
(gdb) delete 3  
(gdb) i b  
Num     Type           Disp Enb Address            What  
1       breakpoint     keep y   0x00000000004004f2 in main at miki.c:2

break 23 表示设置第23行为断点,可以简写成 b 23
break func 表示设置func函数入口为断点,可以简写成 b func
info break 表示查询设置的断点,可以简写成 i b
delete 2 表示删除第二个断点,可以简写成 d 2

(gdb) r  
Starting program: /u01/home/oracle/miki  
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000  
  
Breakpoint 1, main () at miki.c:23  
23             printf("result[1-10] = %d \n\r", result );  
(gdb) n  
result[1-10] = 55  
24             printf("result[1-5] = %d \n\r", func(5) );  
(gdb)  
  
Breakpoint 2, func (n=5) at miki.c:5  
5               int sum=0,i;  
(gdb) p n  
$1 = 5  
(gdb) p i  
$2 = 10922  
(gdb) p sum  
$3 = -1431642112  
(gdb) n  
6               for(i=0; i<n; i++)  
(gdb) p i  
$4 = 10922  
(gdb) n  
8                       sum+=i;  
(gdb) p i  
$5 = 0  
(gdb) p sum  
$6 = 0  
(gdb) n  
6               for(i=0; i<n; i++)  
(gdb) p i  
$7 = 0  
(gdb) p n  
$8 = 5  
(gdb) p i  
$9 = 0  
(gdb) n  
8                       sum+=i;  
(gdb) p i  
$10 = 1  
(gdb) p sum  
$11 = 0  
(gdb) n  
6               for(i=0; i<n; i++)  
(gdb) p sum  
$12 = 1  
(gdb) n  
8                       sum+=i;  
(gdb) n  
6               for(i=0; i<n; i++)  
(gdb) p sum  
$13 = 3  
(gdb) n  
8                       sum+=i;  
(gdb) n  
6               for(i=0; i<n; i++)  
(gdb) n  
8                       sum+=i;  
(gdb) c  
Continuing.  
result[1-5] = 10  
  
Program exited with code 023.  
(gdb) 

r 表示程序开始运行
n 表示执行下一条语句
c 表示继续执行
p i 表示打印出变量i的值
p sum 表示打印出变量sum的值
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 0×8048458: 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/tty
调试已运行的程序
————————
两种方法:
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>
只设置一次捕捉点,当程序停住以后,应点被自动删除。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在了解GDB可以做什么,怎么做之前,让我们先来看看为什么要用GDB,或者说对调试工具有什么期望。 一般我们使用GDB(或其他调试工具)是为了发现程序bug,更经常地是在已知程序有错的情况下定位bug。既然这样,我们就需要跟踪程序的执行情况,查看程序执行是否正常,当然这就需要有个让我们与执行程序交互的环境,调试工具提供一个能让程序在你的掌控下执行,并让你能够查看一些执行过程中的“内幕信息”的环境。 为了查看程序运行过程中的状态,我们就希望程序能在适当的位置或者在一定的条件下能够暂停运行;为此,调试工具提供了断点、查看变量/表达式、显示程序栈等功能。看了某个点的“内幕”后,我们还期望更多,所以要能控制程序运行才行,这就要求断点、继续运行、单步(多步)运行、进入函数运行等功能,在某些情况下,还需要通过修改当前的执行环境(变量等)来达到期望的执行顺序。也就是说,光看着是不够的,还需要能改才行。 理解了这些问题后,我们就明白GDB的各个功能的用意了,自然也就明白该如何使用调试工具了。当然,要让GDB有效的发挥作用,还是需要一定的经验与技巧,而这主要靠实践,学习资料(包括本文)充其量只能帮你一把(小心别让它帮倒忙)。 总而言之,我们首先要明白使用调试工具的目的和用意,才能理解它的各项功能,才能借助它快速有效的发现问题;否则,即使工具再强大,你也不知道该如何使用才好。 另外要多结合使用代码检视、运行日志、测试工具等方法来发现潜在的问题,提供程序的质量。这些问题将在另文探讨,先做个广告。
因为后台开发所需要的技术广泛而坚深,要成为一名后台开发工程师门槛很高,所以相关人才比较紧缺。作者是在腾讯工作多年的后台开发工程师,不仅技术精湛,而且在处理大量实际业务的过程中积累了丰富的开发经验。在这本书中,她不仅首次为后台开发工程师勾勒出了完整的知识能力体系结构图,而且还对后台开发工程师所需要掌握的大量复杂的技术知识进行了提炼、剥离和整合,专注于成为一名后台开发工程师所需掌握的核心技术、开发工具和实践方法,大幅度降低后台开发工程师的学习曲线。本书的内容获得了来自腾讯、Facebook、微软、阿里、百度的多位资深技术专家的高度认可。 全书一共13章,在逻辑上分为六大部分: 第一部分(第1~3章)介绍了编程语言方面的知识,包括常用语法、类与常用STL的使用。 第二部分(第4~5章)介绍了编译原理和调试方法相关的知识,编译原理包括编译与链接的具体过程、Makefile的编写、目标文件的内容与处理目标文件相关工具的使用,调试方法主要介绍了strace、gdb、top、ps与valgrind工具的使用等。 第三部分(第6~8章)介绍了网络相关的知识,包括TCP协议的关键知识点和TCP server的实现,网络IO模型和select、poll与epoll三个重要函数的使用,还有ping、tcpdump、netstat和lsof这四个网络分析工具的使用。 第四部分(第9~11章)主要是多线程、进程和进程间通信相关的知识,包括多线程的使用、多线程的同步和重入问题,进程方面有父子进程、僵死进程、守护进程和进程间通讯的方式。 第五部分(第12章)主要是HTTP协议的介绍与使用、CGI的设计原理、实现和FASTCGI的简单介绍。 第六部分(第13章)通过常用类库JsonCPP和Protobuf的使用,演示如何使用第三方库。 目录 第1章 C++编程常用技术 1 第2章 面向对象的C++ 26 第3章 常用STL的使用 65 第4章 编译 117 第5章 调试 148 第6章 TCP协议 188 第7章 网络IO模型 248 第8章 网络分析工具 290 第9章 多线程 299 第10章 进程 334 第11章 进程间通信 352 第12章 HTTP协议 375 第13章 常用类库 399
因为后台开发所需要的技术广泛而坚深,要成为一名后台开发工程师门槛很高,所以相关人才比较紧缺。作者是在腾讯工作多年的后台开发工程师,不仅技术精湛,而且在处理大量实际业务的过程中积累了丰富的开发经验。在这本书中,她不仅首次为后台开发工程师勾勒出了完整的知识能力体系结构图,而且还对后台开发工程师所需要掌握的大量复杂的技术知识进行了提炼、剥离和整合,专注于成为一名后台开发工程师所需掌握的核心技术、开发工具和实践方法,大幅度降低后台开发工程师的学习曲线。本书的内容获得了来自腾讯、Facebook、微软、阿里、百度的多位资深技术专家的高度认可。 全书一共13章,在逻辑上分为六大部分: 第一部分(第1~3章)介绍了编程语言方面的知识,包括常用语法、类与常用STL的使用。 第二部分(第4~5章)介绍了编译原理和调试方法相关的知识,编译原理包括编译与链接的具体过程、Makefile的编写、目标文件的内容与处理目标文件相关工具的使用,调试方法主要介绍了strace、gdb、top、ps与valgrind工具的使用等。 第三部分(第6~8章)介绍了网络相关的知识,包括TCP协议的关键知识点和TCP server的实现,网络IO模型和select、poll与epoll三个重要函数的使用,还有ping、tcpdump、netstat和lsof这四个网络分析工具的使用。 第四部分(第9~11章)主要是多线程、进程和进程间通信相关的知识,包括多线程的使用、多线程的同步和重入问题,进程方面有父子进程、僵死进程、守护进程和进程间通讯的方式。 第五部分(第12章)主要是HTTP协议的介绍与使用、CGI的设计原理、实现和FASTCGI的简单介绍。 第六部分(第13章)通过常用类库JsonCPP和Protobuf的使用,演示如何使用第三方库。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值