gdb调试
1.概论
我们将学习使用gdb来调试通过一个通过串行线同PC相连的嵌入式系统.
Gdb可以调试各种程序,包括C、C++、JA V A、PASCAL、FORAN和一些其它的语言。包括GNU所支持的所有微处理器的汇编语言。
在gdb的所有可圈可点的特性中,有一点值得注意,就是当运行gdb的平台(宿主机)通过串行端口(或网络连接,或是其他别的方式)连接到目标板时(应用程序在板上运行),gdb 可以调试对应用程序进行调试。这个特性不光在将GNU工具移植到一个新的操作系统或微处理器时侯很有用,对于那些使用GNU已经支持的芯片的嵌入式系统进行开发的设计人员来讲,也是非常有用的。
当gdb被适当的集成到某个嵌入式系统中的时候,它的远程调试功能允许设计人员一步一步的调试程序代码、设置断点、检验内存,并且同目标交换信息。Gdb同目标板交换信息的能力相当强,胜过绝大多数的商业调试内核,甚至功能相当于某些低端仿真器。
2.Gdb在嵌入式领域的功能实现
当调试一个远端目标设备时,gdb依靠了一个调试stub来完成其功能。调试stub 即是嵌入式系统中一小段代码,它提供了运行gdb的宿主机和所调试的应用程序间的一个媒介。
Gdb和调试stub通过GDB串行协议进行通信。GDB串行协议是一种基于消息的ASCII码协议,包含了诸如读写内存、查询寄存器、运行程序等命令。由于绝大多数嵌入式系统设计人员为了最好的利用他们手中特定的硬件的特征,总是自己编写自己的stub。所以我们有必要清楚的了解一下gdb的串行通信协议。在后面我们会详细介绍。
为了设置断点,gdb使用内存读写命令,来无损害地将原指令用一个TRAP命令或其它类似的操作码(在此假定,被调试的应用程序是处在RAM中的,当然,如果stub 有足够好的性能,硬件也不错的话,这个条件也不是必须的)代替,使得执行该命令时,可以使得控制权转移到调试stub手中去。在此时,调试stub的任务就是将当前场景传送给gdb (通过远程串行通信协议),然后从gdb处接收命令,该命令告诉了stub下一步该做什么。
为了说明,下面的代码是Hitachi SH-2处理器的一个TRAP异常处理程序:
/*将当前寄存器的值存储到堆栈中*/
/* 然后调用gdb_exception. */
asm("
.global _gdb_exception_32
_gdb_exception_32:
/* 将堆栈指针和r14压入堆栈*/
mov.l r15, @-r15
mov.l r14, @-r15
/*当执行一个陷阱异常时,sh2 自动的将pc 和sr 放入堆栈*/
/*所以我们必须调整我们给gdb的堆栈指针值,以此来说明这个特别的数据*/
/* 换言之,在该陷阱被执行前,gdb想看看堆栈指针的值,*/
/* 而不是陷阱被执行当前时的值。*/
/*所以,从我们刚压入堆栈的sp值中减去8*/
/*(pc和sr都是4个字节的)*/
mov.l @(4,r15), r14
add #8, r14
mov.l r14, @(4,r15)
/*将其它寄存器值压入堆栈*/
mov.l r13, @-r15
mov.l r12, @-r15
mov.l r11, @-r15
mov.l r10, @-r15
mov.l r9, @-r15
mov.l r8, @-r15
mov.l r7, @-r15
mov.l r6, @-r15
mov.l r5, @-r15
mov.l r4, @-r15
mov.l r3, @-r15
mov.l r2, @-r15
mov.l r1, @-r15
mov.l r0, @-r15
sts.l macl, @-r15
sts.l mach, @-r15
stc vbr, r7
stc gbr, r6
sts pr, r5
/* 调用gdb_exception, 令其异常值=32 */
mov.l _gdb_exception_target, r1
jmp @r1
mov #32, r4
.align 2
_gdb_exception_target: .long _gdb_exception
");
/* 下面是一个从调试stub返回对某个应用程序的控制的样例(针对Hitachi SH2)*/ /*如果用C语言写,那么该语句的原型为:*/
/* void gdb_return_from_exception( gdb_sh2_registers_T registers );*/
/* 总而言之,我们可以用同gdb_exception_nn把寄存器压入堆栈同样的方式*/
/* 将其从堆栈中弹出。然而,通常返回指针同我们的返回堆栈指针不一样。*/
/*所以如果我们在拷贝pc和sr到返回指针之前将r15弹出的话,我们就回*/
丢失掉pc和sr。
*/
asm("
.global _gdb_return_from_exception
_gdb_return_from_exception:
/*恢复某些寄存器*/
lds r4, pr
ldc r5, gbr
ldc r6, vbr
lds r7, mach
lds.l @r15+, macl
mov.l @r15+, r0
mov.l @r15+, r1
mov.l @r15+, r2
mov.l @r15+, r3
mov.l @r15+, r4
mov.l @r15+, r5
mov.l @r15+, r6
mov.l @r15+, r7
mov.l @r15+, r8
mov.l @r15+, r9
mov.l @r15+, r10
mov.l @r15+, r11
mov.l @r15+, r12
/* 将pc和sr弹出到应用程序的堆栈*/ mov.l @(8,r15), r14
mov.l @(16,r15), r13
mov.l r13, @-r14
mov.l @(12,r15), r13
mov.l r13, @-r14
/* 完成恢复寄存器的工作*/
mov.l @r15+, r13
mov.l @r15+, r14
mov.l @r15, r15
/*调整应用程序的堆栈,来说明pc, sr */ add #-8, r15
/* ...返回到应用程序*/
rte
nop
");
当处理器遇到了一个TRAP指令(该指令是由gdb 设置的,做断点用)时,该指令使得处理器的当前场景转向一个名为gdb_exception()的函数。最终,目标调用了gdb_return_from_exception()函数,该函数恢复了处理器的场景并将控制权交给应用程序。
远程串行协议的步进命令稍微更有挑战性些,特别当目标处理器不提供一个“跟踪位”或类似的功能时。在这些情况下,唯一的替代办法就是让stub把将要执行的指令反汇编。这样它就会知道程序下一步要执行到何处。
幸运的是,在gdb的源代码中也提供了关于如何一些实现这些步近命令的建议。对于Hitachi SH-2芯片而言,在gdb/sh-stub.c文件中说明了函数doSStep()的使用,对于其它种类的芯片,函数的名字也差不多,请看文件gdb/i386-stub.c和gdb/m68k-stub.c
3.gdb的其它功能
Gdb还可以求解在控制台中输入的任意的C表达式的值,包括包含有对远端目标的函数功能调用的表达式。我们可以输入如下命令:
print foo( sh_sci[current_sci]->smr.brg )
gdb就会将mr.brg的值传送给foo(),并报告其返回值。
当然,gdb也可以反汇编代码。只要可能的话,它还可以很好的为所需的数据提供等价的符号信息。例如,gdb用下列输出:
jmp 0x401010
告诉了我们,所显示的地址与从函数main()的起始地址起偏移80个字节的地址相等。
Gdb 可以显示其自身和所调试的目标间的远程串行调试信息,也可以将该信息记录到日志文件中去。这些特性对于我们调试一个新的stub,了解stub是如何使用远程串行协议来实现用户对数据、程序内存、系统调用等等的需求是十分有用的。
Gdb拥有脚本语言,允许对目标自动的设置和检测。该语言是对目标处理器独立的,所以应用程序从一个目标处理器移植到另外的处理器时,脚本可以重用。
最后,gdb还提供了跟踪点的功能,该功能可以记录某个运行程序的信息,而尽可能的不打断程序收集数据。跟踪点需要特别的调试stub来实现。
4.一个典型的gdb会话过程
现在我们已经探讨了gdb的通用功能,现在我们来看看gdb的执行。下面给出了一个典型的gdb 调试会话过程。在该过程中,gdb初始化了同一个运行调试stub的远端目标间的通信,然后下载程序,设置断点,并运行该程序。当遇到断点时,调试stub通知gdb,gdb然后就将其源代码行显示给用户。接着,用户显示了一个变量,步近执行一个指令,然后推出gdb 。
请注意,下面并未显示用户在使用gdb时所见到的内容。用户所见到的是一个终端,
显示的内容都是用英文写成的源代码、要显示的变量等等。但是,下面显示的脚本说明了当用户键入命令时在幕后发生的内容。
典型的gdb 会话过程的描述
用户键入的内容 串行口发生的内容
gdb 发送 目标响应
host>gdb myprogram
gdb>target remote /dev/ttyS0
gdb> load
gdb> breakpoint main [什么都没有。 Gdb 在随后的命令发送之前物理地设置断点]
gdb> continue
[程序运行直到main()函数]
[目标在main()处停止,地址为0x4015cc]
gdb> display foo +$2f86#06
[foo 的地址为0x4015bc; 其值为0x2f86]
gdb> stepi
+
[PC 的值现在为0x4015ce]
gdb> quit +
上图中,左边一栏显示了gdb 控制台的一部分。在此用户键入命令并监视数据。右边一栏显示了一些使用GDB 远程串行协议在宿主机和嵌入式设备之间的通信消息。在方括号中是一些解释信息。如果想清楚的了解这些信息的含义,请见附录《GDB 远程串行协议》部分。
5.Gdb 调试stub 的源代码
虽然远程软件调试具有依赖于目标的特性,但是还是可以创建一个有高度的可移植性的调试stub ,在不同的嵌入式处理器芯片之间可以被重用,而所需的修改最小。
有人已经尝试了这方面的工作。如果各位感兴趣,可以去上网查阅相关的资料。例如https://www.360docs.net/doc/386682897.html,/projects/gdbstubs 。
处理器特定的代码包含在与处理器相关的文件名中,例如gdb_sh2*.c 。我们可以针对我们特定的处理器下载相关的文件(例如gdb_m68k*.c ),然后在用其替代我们机器上的相关内容。
6.关于改造gdb 来解决特定问题的考虑
gdb 使用了一个模块化的体系结构来实现,那么对它某些不适合我们需要的特性就可以很直接的加以处理。例如,如果我们的产品仅仅有一个通信端口,而它使用的并不是gdb 的通信协议的话,那么,可以修改gdb ,使得调试器的信息同我们产品已经使用的信息包相匹配。
类似地,如果我们的产品没有串行端口,而有些别的通信接口(例如CAN 端口),那么我们可以加强gdb 的远程通信功能,来适应该端口。
我们也可以修改gdb 的工作方式使其同我们嵌入式应用程序更加的相容。例如,
如果我们正在使用TRAPA #32来做些同gdb无关的工作,我们就可以改变gdb为了设置断点而使用的操作码,或者我们可以使用gdb来产生一个新的消息告诉我们的目标板开启指令追踪的功能或使能芯片内的断点产生硬件。
文件gdb/remote.c包含了gdb的远程串行协议的实现过程。对于研究gdb的模块化的实现是如何允许我们快速的将其改造以适应特定的调试目标而言,该文件是个很好的起点。其它的文件,例如gdb/remote-hms.c 和gdb/remote-e7000.c,使用了该模块化的结构来为诸如Hitachi, Motorola等公司的芯片的调试器和仿真器提供支持。
7.总结
gdb对于调试目标(包括对其内存的使用,通信媒介等等方面)的可适应性使得它对于目标板的调试而言,常常是唯一的选择。考虑到单芯片高集成度、基于IP的嵌入式产品的普及,情况更是如此。在今天,嵌入式设备的复杂性与日俱增,在进行新的设计时,其供选择的技术的选择也越来越多,要找到一个商业的开发产品是越来越困难了。
而使用GNU工具将是个很好的选择。GNU工具对各种流行的嵌入式处理器的支持意味着,当我们正在使用的开发工具对我们将要在下一个设计中使用的处理器不支持时,我们可以减少寻找新的开发工具所带来的危险。
利用gdb调试core文件
利用gdb调试core文件 什么是core dump core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump。(linux中如果内存越界会收到SIGSEGV信号,然后就会core dump) 在程序运行的过程中,有的时候我们会遇到Segment fault(段错误)这样的错误。这种看起来比较困难,因为没有任何的栈、trace信息输出。该种类型的错误往往与指针操作相关。往往可以通过这样的方式进行定位。 造成segment fault,产生core dump的可能原因 1、内存访问越界 a) 由于使用错误的下标,导致数组访问越界 b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符 c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。 2、多线程程序使用了线程不安全的函数。 3、多线程读写的数据未加锁保护。 对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成core dump 4、非法指针 a) 使用空指针 b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内
实例—使用gdb调试器
2.4 实例—使用gdb调试器 1.编写实例程序gcctest.c,见2.2小节的开头部分 2.编译 3.启动GDB,执行程序 启动gdb,进入gdb调试环境,可以使用gdb的命令对程序进行调试。 [root@localhost gdbtest txt]# gdb //启动gdb GNU gdb Fedora (6.8-27.el5) Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later
国嵌视频教程下载
嵌入式Linux视频教程 相关搜索:简体中文, 学习方法, 视频教程, 普通话, 嵌入式 中文名: 嵌入式Linux视频教程 资源格式: 光盘镜像 学校: 成都国嵌嵌入式培训中心版本: 成都国嵌嵌入式培训中心的基于广州友善之发行日期: 2010年 地区: 大陆 对白语言: 普通话 文字语言: 简体中文 视频光盘目录结构 国嵌视频1.iso -学习方法与课程体系介绍(学前必看) -学习方法介绍.avi -国嵌嵌入式课程体系.pdf -嵌入式Linux学习方法.pdf -国嵌课程1-嵌入式入门体验班(上) -第1天(嵌入式系统概述) -国嵌体验入门班-1-1(嵌入式系统概述).avi -国嵌体验入门班-1-2(ARM概述).avi -国嵌体验入门班-1-3(嵌入式Linux概述).avi -国嵌体验入门班-1-4(2440开发板介绍).avi -国嵌体验入门班-1-5(软硬件环境搭建).avi -第2天(开发板快乐体验) -国嵌体验入门班-2-1(开发板系统安装).avi -国嵌体验入门班-2-1(开发板系统安装-Jlink方式).avi -国嵌体验入门班-2-1(开发板系统安装-并口方式).avi -国嵌体验入门班-2-2(裸机程序体验).avi -国嵌体验入门班-2-3(QT系统体验).avi -国嵌体验入门班-2-4(Android系统体验).avi 国嵌视频2.iso
-国嵌课程1-嵌入式入门体验班(下) -第3天(Linux系统体验) -国嵌体验入门班-3-1(Linux定制安装).avi -国嵌体验入门班-3-2(Linux命令).avi -国嵌体验入门班-3-3(VI使用).avi -国嵌体验入门班-3-4(Linux系统管理).avi -国嵌体验入门班-3-5(Shell编程).avi -国嵌体验入门班-3-6(Qcd功能演示).avi -国嵌体验入门班-3-7(必修实验).avi -国嵌课程2-嵌入式Linux应用开发班 -第1天(编程基础) -国嵌应用班-1-1(GCC程序编译).avi -国嵌应用班-1-2(GDB程序调试).avi -国嵌应用班-1-3(makefile工程管理).avi -国嵌应用班-1-4(必修实验).avi -第2天(文件时间编程) -国嵌应用班-2-1(系统调用方式访问文件).avi -国嵌应用班-2-2(库函数访问文件).avi -国嵌应用班-2-3(时间编程).avi -国嵌应用班-2-4(必修实验).avi -第3天(多进程程序设计) -国嵌应用班-3-1(进程控制原理).avi -国嵌应用班-3-2(进程控制程序设计).avi -国嵌应用班-3-3(必修实验).avi -第4天(进程间通讯) -国嵌应用班-4-1(进程间通讯概述).avi -国嵌应用班-4-2(管道通讯).avi -国嵌应用班-4-3(信号通讯).avi -国嵌应用班-4-4(共享内存通讯).avi -国嵌应用班-4-5(必修实验).avi -第5天(进程间通讯) -国嵌应用班-5-1(消息队列).avi
gdb单步调试(中)
一、设置断点(BreakPoint ) 我们用break 命令来设置断点。正面有几点设置断点的方法: break
gbd调试
用GDB调试程序 GDB概述 ———— GDB 是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在 UN IX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。 一般来说,GDB主要帮忙你完成下面四个方面的功能: 1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。 2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式) 3、当程序被停住时,可以检查此时你的程序中所发生的事。 4、动态的改变你程序的执行环境。 从上面看来,GDB和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现GDB这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。让我们一一看来。 一个调试示例 —————— 源程序:tst.c
1 #include
GDB调试精粹及使用实例
GDB调试精粹及使用实例 一:列文件清单 1. List (gdb) list line1,line2 二:执行程序 要想运行准备调试的程序,可使用run命令,在它后面可以跟随发给该程序的任何参数,包括标准输入和标准输出说明符(<和>)和外壳通配符(*、?、[、])在内。 如果你使用不带参数的run命令,gdb就再次使用你给予前一条run命令的参数,这是很有用的。 利用set args 命令就可以修改发送给程序的参数,而使用show args 命令就可以查看其缺省参数的列表。 (gdb)set args –b –x (gdb) show args backtrace命令为堆栈提供向后跟踪功能。 Backtrace 命令产生一张列表,包含着从最近的过程开始的所以有效过程和调用这些过程的参数。 三:显示数据 利用print 命令可以检查各个变量的值。 (gdb) print p (p为变量名) whatis 命令可以显示某个变量的类型 (gdb) whatis p type = int * print 是gdb的一个功能很强的命令,利用它可以显示被调试的语言中任何有效的表达式。表达式除了包含你程序中的变量外,还可以包含以下内容: l 对程序中函数的调用 (gdb) print find_entry(1,0) l 数据结构和其他复杂对象 (gdb) print *table_start $8={e=reference=’\000’,location=0x0,next=0x0} l 值的历史成分 (gdb)print $1 ($1为历史记录变量,在以后可以直接引用 $1 的值) l 人为数组 人为数组提供了一种去显示存储器块(数组节或动态分配的存储区)内容的方法。早期的调试程序没有很好的方法将任意的指针换成一个数组。就像对待参数一样,让我们查看内存中在变量h后面的10个整数,一个动态数组的语法如下所示: base@length 因此,要想显示在h后面的10个元素,可以使用h@10: (gdb)print h@10 $13=(-1,345,23,-234,0,0,0,98,345,10)
GDB调试及实例
GDB调试及实例 一:列文件清单 1.List (gdb) list line1,line2 二:执行程序 要想运行准备调试的程序,可使用run命令,在它后面可以跟随发给该程序的任何参数,包括标准输入和标准输出说明符(<和>)和外壳通配符(*、?、[、])在内。 如果你使用不带参数的run命令,gdb就再次使用你给予前一条run命令的参数,这是很有用的。 利用set args 命令就可以修改发送给程序的参数,而使用show args 命令就可以查看其缺省参数的列表。 (gdb)set args –b –x (gdb) show args backtrace命令为堆栈提供向后跟踪功能。 Backtrace 命令产生一张列表,包含着从最近的过程开始的所以有效过程和调用这些过程的参数。 三:显示数据 利用print 命令可以检查各个变量的值。 (gdb) print p (p为变量名) whatis 命令可以显示某个变量的类型 (gdb) whatis p type = int * print 是gdb的一个功能很强的命令,利用它可以显示被调试的语言中任何有效的表达式。表达式除了包含你程序中的变量外,还可以包含以下内容: l 对程序中函数的调用 (gdb) print find_entry(1,0) l 数据结构和其他复杂对象 (gdb) print *table_start $8={e=reference=’\000’,location=0x0,next=0x0} l 值的历史成分 (gdb)print $1 ($1为历史记录变量,在以后可以直接引用$1 的值) l 人为数组 人为数组提供了一种去显示存储器块(数组节或动态分配的存储区)内容的方法。早期的调试程序没有很好的方法将任意的指针换成一个数组。就像对待参数一样,让我们查看内存中在变量h后面的10个整数,一个动态数组的语法如下所示: base@length 因此,要想显示在h后面的10个元素,可以使用h@10: (gdb)print h@10 $13=(-1,345,23,-234,0,0,0,98,345,10)
使用QEMU+GDB调试Linux内核
使用QEMU调试Linux内核 一.使用QEMU安装Ubuntu10.04 1.安装qemu ubuntu下使用sudo apt-get install 安装的qemu版本是0.12.3,该版本中存在bug,使得无法在断点处停下;因此需要在qemu官方网站https://www.360docs.net/doc/386682897.html,/Download上下载最新的版本qemu-0.12.5.tar.gz的源代码包自己进行编译安装: ●Sudo apt-get install zlib1g-dev libsdl-dev ●解压源代码后,进入源代码所在目录执行./confingure ●执行make ●执行sudo make install 2.创建QEMU格式的硬盘 qemu-img create –f qcow2name.img size 例如:qemu-img create –f qcow2 ubuntu10.04.img 4GB 3.在创建的硬盘上安装操作系统 qemu–hdaname.img–cdrom ~/Download/ubuntu10.04.iso –boot d 说明:使用hda指定硬盘镜像,使用CDROM选定光驱。-boot d 指从cdrom启动,-boot a是软盘,-boot c 是硬盘;使用qemu或qemu-system-x86_64(64为机子),有时安装系统会很慢,这是可以考虑使用kvm来代替。 例如:kvm–hda ubuntu10.04.img –cdrom ./ubuntu-10.04.iso -boot
d 4.从已经装好操作系统的硬盘启动 qemu–hda ubuntu10.04.img 5.在64位的主机上要使用qemu-system-x86_64命令来代替qemu 二.自己编译内核 现将Linux的编译调节过程简述为: 1. 下载自己要调试的Linux内核的源代码,这个可以从Linux内 核的官方网站上得到:https://www.360docs.net/doc/386682897.html, 2. 编译内核最主要的便是配置文件.config,为了能够准确的得到 结果(第一次不要求编译时间),将本机的config文件直接拷 贝到解压后的源代码中。 3.然后进行make操作,结束后将产生的bzImage文件拷到boot 目录下,重启,选择自己编译的内核,这样一般不会出问题,但时间较慢,大约编译一次需要40分钟。 3.1以前编译内核是为调试内核服务的,现在做华为的项目, 发现需要在实际的机器上运行自己编译的内核,参考网站: https://www.360docs.net/doc/386682897.html,/tips/compiling-linux-kernel-26.html 4.为了降低编译时间,就需要对配置文件进行裁剪,在配置文件 中有好多是本机不需要的模块,参考: https://www.360docs.net/doc/386682897.html,/Linux/kernel_options.html。另外调试内 核与模块无关,所以辨识为M的直接可以不选。 5.剪裁的时候采用“逐步瘦身”法,先剪裁掉某个或某几个模块, 然后在进行编译,若没错,在进行模块裁剪,这样可以最大程
如何在Linux中使用gdb调试C程序
如何在Linux中使用gdb调试C程序 无论多么有经验的程序员,开发的任何软件都不可能完全没有bug。因此,排查及修复bug 成为软件开发周期中最重要的任务之一。有许多办法可以排查bug(测试、代码自审等等),但是还有一些专用软件(称为调试器)可以帮助准确定位问题的所在,以便进行修复。 如果你是C/C++ 程序员,或者使用Fortran 和Modula-2 编程语言开发软件,那么你将会很乐意知道有这么一款优秀的调试器- GDB - 可以帮你更轻松地调试代码bug 以及其它问题。在这篇文章中,我们将讨论一下GDB 调试器的基础知识,包括它提供的一些有用的功能/选项。 在我们开始之前,值得一提的是,文章中的所有说明和示例都已经在Ubuntu 14.04 LTS 中测试过。教程中的示例代码都是 C 语言写的;使用的shell 为bash(4.3.11);GDB 版本为7.7.1。 GDB 调试器基础 通俗的讲,GDB 可以让你看到程序在执行过程时的内部流程,并帮你明确问题的所在。我们将在下一节通过一个有效的示例来讨论GDB 调试器的用法,但在此之前,我们先来探讨一些之后对你有帮助的基本要点。 首先,为了能够顺利使用类似GDB 这样的调试器,你必须以指定的方式编译程序,让编译器产生调试器所需的调试信息。例如,在使用gcc 编译器(我们将在本教程之后的章节用它来编译C 程序示例)编译代码的时候,你需要使用 -g 命令行选项。 IT网,http://it 想要了解gcc 编译器手册页中关于 -g 命令行选项相关的内容,请看这里。 下一步,确保在你的系统中已经安装GDB 调试器。如果没有安装,而且你使用的是基于Debian 的系统(如Ubuntu),那么你就可以使用以下命令轻松安装该工具: sudo apt-get install gdb 在其他发行版上的安装方法,请看这里。 现在,当你按照上述的方式编译完程序(gcc -g 命令行选项),同时也已经安装好GDB 调
用GDB调试程序--调试器GDB常用功能
一,GDB调试器简介 GDB是Linux下的常用调试器,主要用于调试源代码、调试运行中的进程和查看core dump文件。Linux下的调试器主要有gdb、cgdb、ddd、eclipse。GDB调试器的运行速度快、能够进行源代码同步显示。 使用-tui 选项开启gdb命令输入和源代码的分屏显示,tui即Terminal User Interface。 二,GDB常用调试命令 a)调试可执行文件 以源代码为/home/zebra/目录下的test.c文件产生的可执行文件test为例(可执行文件使用gcc进行编译,并使用-g选项以产生调试信息),进行命令的说明(详细源代码参见第三部分:三,调试实例分析 )。 gdb调试源代码流程: 1,开启gdb程序,即运行如下命令:gdb -q (-q用以使得gdb不输出gdb程序的版本等信息)2,指定调试的二进制文件:file test 3,list查看源代码 4,设定断点breakpoint main breakpoint sub 上述分别在main函数和sub函数处设定了断点。 断点可以设置在任意已知源代码文件的某一行,某一个函数,同时可以指定是设置在哪个/哪些线程上(见下边描述)。 5,运行可执行文件: run 6,这样程序会运行到断点处停止下来,gdb会打印当前断点的信息。 7,使用s 或者n进行单步调试。 s即step,n即next都是执行一条语句,然后停下来。 如果想执行一条汇编语句,则可以使用si ,ni,即step instruction,next instruction。 8,bt命令查看当前的调用栈,bt即backtrace。 9,info frame查看函数帧信息。 10,frame n 进入某个函数帧(编号为n) 11,info 命令可以对当前的函数帧的寄存器、局部变量、函数的参数进行查看。 info register;info local;info args。 12,disassemble对当前函数对应的二进制进行反汇编。 13,x/nfu address 查看内存其中address是内存开始的地址,从该地址向高地址增加, x是examinate的缩写,n表示重复次数,f表示输出格式,u表示内存大小的单位(默认是字,即4个字节)。 一般我都用x/nx address,即打印n个从address开始的内存,每个是4字节,以十六进制打印。14,continue,执行至该函数退出 15,info threads,显示当前可调试的所有线程 16,thread
linux下的静态库与动态库的区别,Gdb调试段错误,自动生成Makefile
linux下的静态库与动态库的区别 1.什么是库 在windows平台和linux平台下都大量存在着库。 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。 由于windows和linux的本质不同,因此二者库的二进制是不兼容的。 2.库的种类 linux下的库有两种:静态库和共享库(动态库)。 二者的不同点在于代码被载入的时刻不同。 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。 共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。 3.库存在的意义 库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。 共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。 4.库文件是如何产生的在linux下 静态库的后缀是.a,它的产生分两步 Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表 Step 2.ar命令将很多.o转换成.a,成文静态库 动态库的后缀是.so,它由gcc加特定参数编译产生。 例如: $ gcc -fPIC -c *.c $ gcc -shared -Wl,-soname, libfoo.so.1 -o libfoo.so.1.0 *. 5.库文件是如何命名的,有没有什么规范 在linux下,库文件一般放在/usr/lib /lib下, 静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称 动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号,minor是副版本号 6.如何知道一个可执行程序依赖哪些库 ldd命令可以查看一个可执行程序依赖的共享库, 例如# ldd /bin/lnlibc.so.6 => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2 => /lib/ld- linux.so.2 (0×40000000) 可以看到ln命令依赖于libc库和ld-linux库 Gdb调试段错误 1.段错误是什么
GDB基本命令
1. 本文介绍使用gdb调试程序的常用命令。 主要内容: [简介] [举例] [其他] [简介] ============= GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。同时GDB也具有例如ddd这样的图形化的调试端。 一般来说,GDB主要完成下面四个方面的功能: (1)启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。 (2)可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式) (3)当程序被停住时,可以检查此时你的程序中所发生的事。 (4)动态的改变你程序的执行环境。 [举例] ============= *启动gdb $gdb 这样可以和gdb进行交互了。 *启动gdb,并且分屏显示源代码: $gdb -tui 这样,使用了'-tui'选项,启动可以直接将屏幕分成两个部分,上面显示源代码,比用list方便多了。这时候使用上下方向键可以查看源代码,想要命令行使用上下键就用[Ctrl]n和[Ctrl]p. *启动gdb调试指定程序app: $gdb app 这样就在启动gdb之后直接载入了app可执行程序,需要注意的是,载入的app程序必须在编译的
时候有gdb调试选项,例如'gcc -g app app.c',注意,如果修改了程序的源代码,但是没有编译,那么在gdb中显示的会是改动后的源代码,但是运行的是改动前的程序,这样会导致跟踪错乱的。 *启动程序之后,再用gdb调试: $gdb
LINUX gdb调试命令手册
常用的gdb命令 backtrace 显示程序中的当前位置和表示如何到达当前位置的栈跟踪(同义词:where)breakpoint 在程序中设置一个断点 cd 改变当前工作目录 clear 删除刚才停止处的断点 commands 命中断点时,列出将要执行的命令 continue 从断点开始继续执行 delete 删除一个断点或监测点;也可与其他命令一起使用 display 程序停止时显示变量和表达时 down 下移栈帧,使得另一个函数成为当前函数 frame 选择下一条continue命令的帧 info 显示与该程序有关的各种信息 jump 在源程序中的另一点开始运行 kill 异常终止在gdb 控制下运行的程序 list 列出相应于正在执行的程序的原文件内容 next 执行下一个源程序行,从而执行其整体中的一个函数 print 显示变量或表达式的值 pwd 显示当前工作目录 pype 显示一个数据结构(如一个结构或C++类)的内容 quit 退出gdb reverse-search 在源文件中反向搜索正规表达式 run 执行该程序 search 在源文件中搜索正规表达式 set variable 给变量赋值 signal 将一个信号发送到正在运行的进程 step 执行下一个源程序行,必要时进入下一个函数 undisplay display命令的反命令,不要显示表达式 until 结束当前循环 up 上移栈帧,使另一函数成为当前函数 watch 在程序中设置一个监测点(即数据断点) whatis 显示变量或函数类型
GDB命令分类详解 一:列文件清单 (2) 二:执行程序 (2) 三:显示数据 (2) 四:断点(breakpoint) (3) 五.断点的管理 (3) 六.变量的检查和赋值 (4) 七.单步执行 (4) 八.函数的调用 (4) 九.机器语言工具 (4) 十.信号 (4) 十一.原文件的搜索 (5) 十二. UNIX接口 (5) 十三. 命令的历史 (5) 十四. GDB帮助 (5) 十五. GDB多线程 (6) 十六. GDB使用范例 (7) 一:列文件清单 1.List (gdb) list line1,line2 二:执行程序 要想运行准备调试的程序,可使用run命令,在它后面可以跟随发给该程序的任何参数,包括标准输入和标准输出说明符(<和>)和外壳通配符(*、?、[、])在内。 如果你使用不带参数的run命令,gdb就再次使用你给予前一条run命令的参数,这是很有用的。 利用set args 命令就可以修改发送给程序的参数,而使用show args 命令就可以查看其缺省参数的列表。 (gdb)set args –b –x (gdb) show args backtrace命令为堆栈提供向后跟踪功能。 Backtrace 命令产生一张列表,包含着从最近的过程开始的所以有效过程和调用这些过程的参数。 三:显示数据 利用print 命令可以检查各个变量的值。 (gdb) print p (p为变量名) whatis命令可以显示某个变量的类型 (gdb) whatis p type = int * print 是gdb的一个功能很强的命令,利用它可以显示被调试的语言中任何有效的表达式。表达式除了包含你程序中的变量外,还可以包含以下内容:
用 GDB 调试程序
用 GDB 调试程序 用 gdb 调试 GCC 程序 Linux 包含了一个叫 gdb 的 GNU 调试程序. gdb 是一个用来调试 C 和 C++ 程序的强力调试器. 它使你能在程序运行时观察程序的内部结构和内存的使用情况. 以下是 gdb 所提供的一些功能: ?它使你能监视你程序中变量的值. ?它使你能设置断点以使程序在指定的代码行上停止执行. ?它使你能一行行的执行你的代码. 在命令行上键入 gdb 并按回车键就可以运行 gdb 了, 如果一切正常的话, gdb 将被启动并且你将在屏幕上看到类似的内容: GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.14 (i486-slakware-linux), Copyright 1995 Free Software Foundation, Inc. (gdb) 当你启动 gdb 后, 你能在命令行上指定很多的选项. 你也可以以下面的方式来运行 gdb : gdb
gdb汇编跟踪调试与objdump查看汇编代码
gdb汇编跟踪调试与objdump查看汇编代码 使用objdump生成可读性好的汇编代码 g++ -g3 secret.cpp -o secret objdump -SIz secret -j .text > secret.s man objdump ================ 常用命令: 如何跳出for 循环 -- until 行号 如何在多重循环中监视某变量变化情况 -- watch + until 打印数组a的前10个元素 -- p o GDB 反汇编命令 set disassembly-flavor 设置ATT或INTEL格式 set disassemble-next-line 设置下一步是否显示汇编码 disas function_name 反汇编函数function_name info line function_name 查看function_name 开始和结束地址 如果调试一个stripped 的程序,就只有依赖地址了: b *0x00401365 设置断点,这个地址与没有stripped的程序相同 watch *(int*)0x00401369 设置硬件断点 ni -- 下一条指令,n 命令是无法使用的。 si -- 单步指令,s 命令也是无法使用的。 disas start_addr,end_addr 反汇编[start_addr,end_addr]之间的指令 x /3i $pc 查看eip 开始的三条指令 o 没有调试符号的实例 假设 gcc t.c (gdb) b *0x401365 Breakpoint 1 at 0x401365 (gdb) r Starting program: F:\work/a.exe [New Thread 1752.0x560] Breakpoint 1, 0x00401365 in ?? () (gdb) disas /r 0x401365,0x401370 Dump of assembler code from 0x401365to 0x401370: => 0x00401365: c7 44 24 1c 44 13 40 00 movl $0x401344,0x1c(%esp) 0x0040136d: 8b 44 241c mov 0x1c(%esp),%eax End of assembler dump. (gdb) p /x *(int*)0x401365 $1 = 0x1c2444c7
使用 GDB 调试多进程程序的子程序
GDB 是 linux 系统上常用的 c/c++ 调试工具,功能十分强大。对于较为复杂的系统,比如多进程系统,如何使用 GDB 调试呢?考虑下面这个三进程系统: 进程 Proc2 是 Proc1 的子进程,Proc3 又是 Proc2 的子进程。如何使用 GDB 调试 proc2 或者 proc3 呢? 实际上,GDB 没有对多进程程序调试提供直接支持。例如,使用GDB调试某个进程,如果该进程fork了子进程,GDB会继续调试该进程,子进程会不受干扰地运行下去。如果你事先在子进程代码里设定了断点,子进程会收到SIGTRAP 信号并终止。那么该如何调试子进程呢?其实我们可以利用GDB的特点或者其他一些辅助手段来达到目的。此外,GDB 也在较新内核上加入一些多进程调试支持。 接下来我们详细介绍几种方法,分别是 follow-fork-mode 方法,attach 子进程方法和 GDB wrapper 方法。 follow-fork-mode 在2.5.60版Linux内核及以后,GDB对使用fork/vfork创建子进程的程序提供了follow-fork-mode选项来支持多进程调试。 follow-fork-mode的用法为: set follow-fork-mode [parent|child] ?parent: fork之后继续调试父进程,子进程不受影响。 ?child: fork之后调试子进程,父进程不受影响。 因此如果需要调试子进程,在启动gdb后: (gdb) set follow-fork-mode child 并在子进程代码设置断点。 此外还有detach-on-fork参数,指示GDB在fork之后是否断开(detach)某个进程的调试,或者都交由GDB控制:
gdb+gdbserver安装及调试(总结)
Ubuntu下gdb+gdbserver安装及调试 1、g db+gdbserver介绍 1.1、说明 远程调试(即gdb+gdbserver)环境由宿主机GDB和目标机调试stub共同构成,两者通过串口或TCP连接。使用 GDB标准程串行协议协同工作,实现对目标机上的系统内核和上层应用的监控和调试功能。调试stub是嵌入式系统中的一段代码,作为宿主机GDB和目标机调试程序间的一个媒介而存在。 就目前而言,嵌入式Linux系统中,主要有三种远程调试方法,分别适用于不同场合的调试工作:用ROM Monitor调试目标机程序、用KGDB调试系统内核和用gdbserver调试用户空间程序。这三种调试方法的区别主要在于,目标机远程调试stub 的存在形式的不同,而其设计思路和实现方法则是大致相同的。而我们最常用的是调试应用程序。就是采用gdb+gdbserver的方式进行调试。 1.2、功能 一般来说,GDB可以帮你办以下几件事: 1、启动程序,可以按照用户自定义的要求随心所欲的运行程序。 2、可让被调试的程序在用户所指定的调置的断点处停住。 3、当程序被停住时,可以检查此时用户的程序中所发生的事。 1.3、优点 在很多情况下,用户需要对一个应用程序进行反复调试,特别是复杂的程序。采用GDB方法调试,由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,所以通常采用gdb+gdbserver的方式进行调试。 2、安装包下载 嵌入式Linux的GDB调试环境由宿主机host和目标机(开发板)target两部分组成,arm-linux-gdb安装运行于宿主机,gdbserver安装运行于目标机,但
GDB调试之跨平台驱动调试
GDB调试之跨平台代码调试 一个问题引发的思考: 问题描述:使用交叉编译工具(mips64-nlm-linux-gcc) 将某一段程序编译为目标开发板上所可以使用的可执行程序后,在目标开发板上报了如下的错误: 乍一看很明显的是oops(kernel panic)了 那么我们应该如何去定位这种问题并解决呢?那就当然要用到我们的GDB了!不过是需要支持mips架构的gdb而已 一、gdb跨平台环境搭建 首先我们可以使用如下命令来查看Debian中对于体系架构的一张描述表 cat /usr/share/dpkg/archtable #
x86_64-kfreebsd-gnu kfreebsd-amd64 对于我们当前来说:我们仅仅需要 x86_64-linux-gnu amd64 mips-linux-gnu mips 明确了我们的需求,就开始生成我们自己的编译器了! 1、创建一个目录并且下载gdb源码到此目录 目录自己选择(此处为opt) //注意需要切换root mkdir /opt/build-gdb apt-get source gdb 2、根据需求配置我们的configure ./configure --enable-targets=x86_64-linux-gnu,mips-linux-gnu 3、编译 make 4、将生成的gdb复制到/usr/sbin下 cp gdb/gdb /usr/sbin/gdb-all 以上操作就可以完成跨平台gdb调试的基本安装! 二、如何使用 我们回到我们的问题的最开始: 如何定位? 1、gdb-all vmlinux (这个为开发板上所使用的vmlinx) 2、设置目标架构 set architecture mips:isa64r2 3、定位错误 info line *0x我们上述oops的epc地址 info line *0xffffffff804c120c 定位结果:第293行 Line 293 of "drivers/tl_modules/xlp_module/command_kernel/command_kernel.c" starts at address 0xffffffff804c1204