gdb调试
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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