当前位置:首页 > 嵌入式 > 嵌入式教程
[导读]调试是所有程序员都会面临的问题。如何提高程序员的调试效率,更好、更快地定位程序中的问题从而加快程序开发的进度,是大家都很关注的问题。就如读者熟知的Windows下的一些调试工具,如Visual Studio自带的设置断点、单步跟踪等,都受到了广大用户的赞赏。

3.4gdb调试器

调试是所有程序员都会面临的问题。如何提高程序员的调试效率,更好、更快地定位程序中的问题从而加快程序开发的进度,是大家都很关注的问题。就如读者熟知的Windows下的一些调试工具,如VisualStudio自带的设置断点、单步跟踪等,都受到了广大用户的赞赏。那么,在Linux下有什么很好的调试工具呢?

gdb调试器是一款GNU开发组织并发布的UNIX/Linux下的程序调试工具。虽然,它没有图形化的友好界面,但是它强大的功能也足以与微软的VisualStudio等工具媲美。下面就请跟随笔者一步步学习gdb调试器。

3.4.1gdb使用流程

这里给出了一个短小的程序,由此带领读者熟悉gdb的使用流程。建议读者能够动手实际操作一下。

首先,打开Linux下的编辑器vi或者emacs,编辑如下代码(由于为了更好地熟悉gdb的操作,笔者在此使用vi编辑,希望读者能够参见3.3节中对vi的介绍,并熟练使用vi)。

/*test.c*/

#include<stdio.h>

intsum(intm);

intmain()

{

inti,n=0;

sum(50);

for(i=1;i<=50;i++)

{

n+=i;

}

printf("Thesumof1-50is%d\n",n);

}

intsum(intm)

{

inti,n=0;

for(i=1;i<=m;i++)

{

n+=i;

printf("Thesumof1-mis%d\n",n);

}

}

在保存退出后首先使用gcc对test.c进行编译,注意一定要加上选项“-g”,这样编译出的可执行代码中才包含调试信息,否则之后gdb无法载入该可执行文件。

[root@localhostgdb]#gcc-gtest.c-otest

虽然这段程序没有错误,但调试完全正确的程序可以更加了解gdb的使用流程。接下来就启动gdb进行调试。注意,gdb进行调试的是可执行文件,而不是如“.c”的源代码,因此,需要先通过gcc编译生成可执行文件才能用gdb进行调试。

[root@localhostgdb]#gdbtest

GNUgdbRedHatLinux(6.3.0.0-1.21rh)

Copyright2004FreeSoftwareFoundation,Inc.

GDBisfreesoftware,coveredbytheGNUGeneralPublicLicense,andyouare

welcometochangeitand/ordistributecopiesofitundercertainconditions.

Type"showcopying"toseetheconditions.

ThereisabsolutelynowarrantyforGDB.Type"showwarranty"fordetails.

ThisGDBwasconfiguredas"i386-redhat-linux-gnu"...Usinghostlibthread_dblibrary"/lib/libthread_db.so.1".

(gdb)

可以看出,在gdb的启动画面中指出了gdb的版本号、使用的库文件等信息,接下来就进入了由“(gdb)”开头的命令行界面了。

(1)查看文件。

在gdb中键入“l”(list)就可以查看所载入的文件,如下所示。

注意

在gdb的命令中都可使用缩略形式的命令,如“l”代表“list”,“b”代表“breakpoint”,“p”代表“print”等,读者也可使用“help”命令查看帮助信息。

(gdb)l

1#include<stdio.h>

2intsum(intm);

3intmain()

4{

5inti,n=0;

6sum(50);

7for(i=1;i<=50;i++)

8{

9 n+=i;

10}

(gdb)l

11printf("Thesumof1~50is%d\n",n);

12

13}

14intsum(intm)

15{

16inti,n=0;

17for(i=1;i<=m;i++)

18{

19n+=i;

20}

21printf("Thesumof1~mis=%d\n",n);

20}

可以看出,gdb列出的源代码中明确地给出了对应的行号,这样就可以大大地方便代码的定位。

(2)设置断点。

设置断点是调试程序中一个非常重要的手段,它可以使程序运行到一定位置时暂停。因此,程序员在该位置处可以方便地查看变量的值、堆栈情况等,从而找出代码的症结所在。

在gdb中设置断点非常简单,只需在“b”后加入对应的行号即可(这是最常用的方式,另外还有其他方式设置断点),如下所示:

(gdb)b6

Breakpoint1at0x804846d:filetest.c,line6.

要注意的是,在gdb中利用行号设置断点是指代码运行到对应行之前将其停止,如上例中,代码运行到第6行之前暂停(并没有运行第6行)。

(3)查看断点情况。

在设置完断点之后,用户可以键入“infob”来查看设置断点情况,在gdb中可以设置多个断点。

(gdb)infob

NumTypeDispEnbAddressWhat

1breakpointkeepy0x0804846dinmainattest.c:6

用户在断点键入“backrace”(只输入“bt”即可)可以查到调用函数(堆栈)的情况,这个功能在程序调试之中使用非常广泛,经常用于排除错误或者监视调用堆栈的情况。

(gdb)b19

(gdb)c

Breakpoin2,sum(m=50)attest.c:19

19printf(“Thesumof1-mis%d\n”,n);

(gdb)bt

#0sum(m=50)attest.c:19 /*停在test.c的sum()函数,第19行*/

#10x080483e8inmain()attest.c:6/*test.c的第6行调用sum函数*/

(4)运行代码。

接下来就可运行代码了,gdb默认从首行开始运行代码,键入“r”(run)即可(若想从程序中指定行开始运行,可在r后面加上行号)。

(gdb)r

Startingprogram:/root/workplace/gdb/test

Readingsymbolsfromsharedobjectreadfromtargetmemory...done.

LoadedsystemsuppliedDSOat0x5fb000

Breakpoint1,main()attest.c:6

6sum(50);

可以看到,程序运行到断点处就停止了。

(5)查看变量值。

在程序停止运行之后,程序员所要做的工作是查看断点处的相关变量值。在gdb中键入“p”+变量值即可,如下所示:

(gdb)pn

$1=0

(gdb)pi

$2=134518440

在此处,为什么变量“i”的值为如此奇怪的一个数字呢?原因就在于程序是在断点设置的对应行之前停止的,那么在此时,并没有把“i”的数值赋为零,而只是一个随机的数字。但变量“n”是在第4行赋值的,故在此时已经为零。

小技巧

gdb在显示变量值时都会在对应值之前加上“$N”标记,它是当前变量值的引用标记,所以以后若想再次引用此变量就可以直接写作“$N”,而无需写冗长的变量名。

(6)单步运行。

单步运行可以使用命令“n”(next)或“s”(step),它们之间的区别在于:若有函数调用的时候,“s”会进入该函数而“n”不会进入该函数。因此,“s”就类似于Uisual等工具中的“stepin”,“n”类似与Uisual等工具中的“stepover”。它们的使用如下所示:

(gdb)n

Thesumof1-mis1275

7for(i=1;i<=50;i++)

(gdb)s

sum(m=50)attest.c:16

16inti,n=0;

可见,使用“n”后,程序显示函数sum()的运行结果并向下执行,而使用“s”后则进入sum()函数之中单步运行。

(7)恢复程序运行

在查看完所需变量及堆栈情况后,就可以使用命令“c”(continue)恢复程序的正常运行了。这时,它会把剩余还未执行的程序执行完,并显示剩余程序中的执行结果。以下是之前使用“n”命令恢复后的执行结果:

(gdb)c

Continuing.

Thesumof1-50is:1275

Programexitedwithcode031.

可以看出,程序在运行完后退出,之后程序处于“停止状态”。

小知识

在gdb中,程序的运行状态有“运行”、“暂停”和“停止”3种,其中“暂停”状态为程序遇到了断点或观察点之类的,程序暂时停止运行,而此时函数的地址、函数参数、函数内的局部变量都会被压入“栈”(Stack)中。故在这种状态下可以查看函数的变量值等各种属性。但在函数处于“停止”状态之后,“栈”就会自动撤消,它也就无法查看各种信息了。

3.4.2gdb基本命令

gdb的命令可以通过查看help进行查找,由于gdb的命令很多,因此gdb的help将其分成了很多种类(class),用户可以通过进一步查看相关class找到相应命令,如下所示:

(gdb)help

Listofclassesofcommands:

aliases--Aliasesofothercommands

breakpoints--Makingprogramstopatcertainpoints

data--Examiningdata

files--Specifyingandexaminingfiles

internals--Maintenancecommands

Type"help"followedbyaclassnameforalistofcommandsinthatclass.

Type"help"followedbycommandnameforfulldocumentation.

Commandnameabbreviationsareallowedifunambiguous.

上述列出了gdb各个分类的命令,注意底部的加粗部分说明其为分类命令。接下来可以具体查找各分类的命令,如下所示:

(gdb)helpdata

Examiningdata.

Listofcommands:

call--Callafunctionintheprogram

deletedisplay--Cancelsomeexpressionstobedisplayedwhenprogramstops

deletemem--Deletememoryregion

disabledisplay--Disablesomeexpressionstobedisplayedwhenprogramstops

Type"help"followedbycommandnameforfulldocumentation.

Commandnameabbreviationsareallowedifunambiguous.

若用户想要查找call命令,就可键入“helpcall”。

(gdb)helpcall

Callafunctionintheprogram.

Theargumentisthefunctionnameandarguments,inthenotationofthe

currentworkinglanguage.Theresultisprintedandsavedinthevalue

history,ifitisnotvoid.

当然,若用户已知命令名,直接键入“help[command]”也是可以的。

gdb中的命令主要分为以下几类:工作环境相关命令、设置断点与恢复命令、源代码查看命令、查看运行数据相关命令及修改运行参数命令。以下就分别对这几类命令进行讲解。

1.工作环境相关命令

gdb中不仅可以调试所运行的程序,而且还可以对程序相关的工作环境进行相应的设定,甚至还可以使用shell中的命令进行相关的操作,其功能极其强大。gdb常见工作环境相关命令如表3.11所示。

表3.11 gdb工作环境相关命令

命令格式

含义

setargs运行时的参数

指定运行时参数,如setargs2

showargs

查看设置好的运行参数

Pathdir

设定程序的运行路径

showpaths

查看程序的运行路径

setenvironmentvar[=value]

设置环境变量

showenvironment[var]

查看环境变量

cddir

进入dir目录,相当于shell中的cd命令

Pwd

显示当前工作目录

shellcommand

运行shell的command命令

2.设置断点与恢复命令

gdb中设置断点与恢复的常见命令如表3.12所示。

表3.12 gdb设置断点与恢复相关命令

命令格式

含义

Infob

查看所设断点

break[文件名:]行号或函数名<条件表达式>

设置断点

tbreak[文件名:]行号或函数名<条件表达式>

设置临时断点,到达后被自动删除

delete[断点号]

删除指定断点,其断点号为“infob”中的第一栏。若缺省断点号则删除所有断点

disable[断点号]

停止指定断点,使用“infob”仍能查看此断点。同delete一样,若缺省断点号则停止所有断点

enable[断点号]

激活指定断点,即激活被disable停止的断点

condition[断点号]<条件表达式>

修改对应断点的条件

ignore[断点号]<num>

在程序执行中,忽略对应断点num次

Step

单步恢复程序运行,且进入函数调用

Next

单步恢复程序运行,但不进入函数调用

Finish

运行程序,直到当前函数完成返回

C

继续执行函数,直到函数结束或遇到新的断点

设置断点在gdb的调试中非常重要,下面着重讲解gdb中设置断点的方法。

gdb中设置断点有多种方式:其一是按行设置断点;另外还可以设置函数断点和条件断点。下面具体介绍后两种设置断点的方法。

①函数断点。

gdb中按函数设置断点只需把函数名列在命令“b”之后,如下所示:

(gdb)btest.c:sum(可以简化为bsum)

Breakpoint1at0x80484ba:filetest.c,line16.

(gdb)infob

NumTypeDispEnbAddressWhat

1breakpointkeepy0x080484bainsumattest.c:16

要注意的是,此时的断点实际是在函数的定义处,也就是在16行处(注意第16行还未执行)。

②条件断点。

gdb中设置条件断点的格式为:b行数或函数名if表达式。具体实例如下所示:

(gdb)b8ifi==10

Breakpoint1at0x804848c:filetest.c,line8.

(gdb)infob

NumTypeDispEnbAddressWhat

1breakpointkeepy0x0804848cinmainattest.c:8

stoponlyifi==10

(gdb)r

Startingprogram:/home/yul/test

Thesumof1-mis1275

Breakpoint1,main()attest.c:9

9n+=i;

(gdb)pi

$1=10

可以看到,该例中在第8行(也就是运行完第7行的for循环)设置了一个“i==0”的条件断点,在程序运行之后可以看出,程序确实在i为10时暂停运行。

3.gdb中源码查看相关命令

在gdb中可以查看源码以方便其他操作,它的常见相关命令如表3.13所示。

表3.13 gdb源码查看相关相关命令

命令格式

含义

list<行号>|<函数名>

查看指定位置代码

file[文件名]

加载指定文件

forward-search正则表达式

源代码的前向搜索

reverse-search正则表达式

源代码的后向搜索

dirDIR

将路径DIR添加到源文件搜索的路径的开头

showdirectories

显示源文件的当前搜索路径

infoline

显示加载到gdb内存中的代码

4.gdb中查看运行数据相关命令

gdb中查看运行数据是指当程序处于“运行”或“暂停”状态时,可以查看的变量及表达式的信息,其常见命令如表3.14所示。

表3.14 gdb查看运行数据相关命令

命令格式

含义

print表达式|变量

查看程序运行时对应表达式和变量的值

x<n/f/u>

查看内存变量内容。其中n为整数表示显示内存的长度,f表示显示的格式,u表示从当前地址往后请求显示的字节数

display表达式

设定在单步运行或其他情况中,自动显示的对应表达式的内容

backtrace

查看当前栈的情况,即可以查到哪些被调用的函数尚未返回

5.gdb中修改运行参数相关命令

gdb还可以修改运行时的参数,并使该变量按照用户当前输入的值继续运行。它的设置方法为:在单步执行的过程中,键入命令“set变量=设定值”。这样,在此之后,程序就会按照该设定的值运行了。下面,笔者结合上一节的代码将n的初始值设为4,其代码如下所示:

(gdb)b7

Breakpoint5at0x804847a:filetest.c,line7.

(gdb)r

Startingprogram:/home/yul/test

Thesumof1-mis1275

Breakpoint5,main()attest.c:7

7for(i=1;i<=50;i++)

(gdb)setn=4

(gdb)c

Continuing.

Thesumof1-50is1279

Programexitedwithcode031.

可以看到,最后的运行结果确实比之前的值大了4。

注意

gdb使用时的注意点:

·在gcc编译选项中一定要加入“-g”。

·只有在代码处于“运行”或“暂停”状态时才能查看变量值。

·设置断点后程序在指定行之前停止。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

为了满足日益增长的数据处理需求,铁威马NAS推出了全新的性能巅峰2024年旗舰之作F4-424 Pro,并搭载了最新的操作系统--TOS 6。这款高效办公神器的问世,无疑将为企业和专业人士带来前所未有的便捷与效率。

关键字: 存储 Linux 服务器

Windows Embedded Compact 7(简称WinCE)是一种专为嵌入式系统设计的操作系统,具有体积小、效率高、可定制性强的特点。在WinCE中设置自动运行软件,通常是为了满足设备在启动后自动执行特定任务的...

关键字: 嵌入式系统 软件 操作系统

双系统将是下述内容的主要介绍对象,通过这篇文章,小编希望大家可以对双系统的相关情况以及信息有所认识和了解,详细内容如下。

关键字: 双系统 Windows Linux

今天,小编将在这篇文章中为大家带来Windows 11系统的有关报道,通过阅读这篇文章,大家可以对Windows 11系统具备清晰的认识,主要内容如下。

关键字: Windows 操作系统

全新随插即用方案简化虚拟化实时IIoT平台的设置

关键字: 计算机模块 IIoT 操作系统

目前,HarmonyOS NEXT星河预览版已经正式面向开发者开放申请,面向鸿蒙原生应用及元服务开发者提供的集成开发环境——DevEco Studio也迎来功能更细化的4.1版本。

关键字: HarmonyOS 操作系统

华为P40是一款备受关注的高端智能手机,搭载了华为自研的鸿蒙操作系统。鸿蒙系统作为华为自主研发的操作系统,具有高度的可定制性和扩展性,能够为用户带来全新的使用体验。本文将详细介绍华为P40鸿蒙系统的升级方法,帮助用户更好...

关键字: 华为P40 智能手机 操作系统

安装Linux操作系统并不复杂,下面是一个大致的步骤指南,以帮助您完成安装。1. 下载Linux发行版:首先,您需要从Linux发行版官方网站下载最新的ISO镜像文件。

关键字: Linux 操作系统 ISO镜像

计算机是由一堆硬件组成的,为了有限的控制这些硬件资源,于是就有了操作系统的产生,操作系统是软件子系统的一部分,是硬件基础上的第一层软件。

关键字: Linux 操作系统 计算机

Linux操作系统是一套免费使用和自由传播的类Unix操作系统,通常被称为GNU/Linux。它是由林纳斯·托瓦兹在1991年首次发布的,并基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。Lin...

关键字: Linux 操作系统
关闭
关闭