嵌入式软件调试技术--1--概览

参考文献:《嵌入式软件调试技术》罗克露主编

0.基础技能掌握

  • 1.嵌入式操作系统内核由五大子系统组成:进程调度(管理),进程间通信,内存管理,虚拟文件系统,网络接口

1.基础调试技术

1.1 控制程序的执行过程和查看程序执行状态这两者是密不可分的。
  • 软件调试是为了发现排除软件程序中的错误,而通过某种方法控制被调试程序的执行过程,以便随时查看和修改被调试程序执行状态的方法。
  • 控制程序的执行过程查看程序执行状态,是任何调试工具调试手段都必须提供的两个功能。
  • 控制程序执行状态的方法:有单步执行设置断点从指定的地址开始执行运行到函数(过程)返回等。所有这些方法中,最重要的手段是设置断点。
  • 查看被调试程序的执行状态:实际上就是针对数据所提供的调试手段。针对数据的调试手段有设置观察点(watchpoint)追踪点(tracepoint)查看堆栈查看CPU寄存器值查看内存空间等。
  • 直接在嵌入式系统上运行调试器的做法非常罕见,通常的做法是采用宿主机(host)加目标机(target)的方式。在目标机上运行被调程序,宿主机则运行调试器。目标机和宿主机之间通过某种媒介通信,典型的媒介有串口、并口、以太网或JTAG。
  • 宿主机上还要配备一套相应的开发工具,如交叉编译器、交叉调试器、性能分析器和映像下载程序等。这一整套工具被称为工具链(Toolchain)。
  • 调试代理:是在目标程序的可执行映像中加入的一个用于调试用途的特殊软件成分,它可以和运行在宿主机端的调试器通信,并根据调试器发出的指令控制目标程序的运行,同时将目标程序的执行状态反馈给调试器。
    在这里插入图片描述

1.2 软件调试分类

1.2.1 以调试所处的阶段来分,可以分为静态调试和动态调试两类;

  • 静态调试技术:对源码进行语法及安全性方面的分析,防止程序语句非法跳转或引用未初始化的变量等。提高并管控代码质量,但是无法保证程序逻辑正确。
  • 动态调试技术:目的是解决程序逻辑问题,“断点”调试器都采用在被调程序中插入断点的方式实现对被调程序的控制。

当被调程序运行到断点位置时,会触发一个中断或异常,在中断处理或异常处理程序中用户就可以检测被调程序的各种状态,如变量值、寄存器值、函数堆栈和函数调用层次等。

动态调试器最常见的用途是用于循环调试(cyclical debugging)。所谓循环调试,是指在程序发生错误之后,在可疑的地方设置断点,反复运行被调程序,检查程序运行过程中的状态,逐步缩小可疑范围,直到找出错误的根源

Linux下的GDB调试器则既有命令行接口,也有图形用户接口(ddd就是常用的GDB图形前端)。

gdb是gnu的调试工具。
在gnu软件列表中能找到gdb的链接:
http://directory.fsf.org/wiki/GNU
https://www.gnu.org/software/gdb/
gdb的文档:
https://www.gnu.org/software/gdb/documentation/
DDD是图形化的gdb。
在gnu软件列表中也能找到ddd的链接:
https://www.gnu.org/software/ddd/
原文链接:https://blog.csdn.net/power1952/article/details/49823487
————————————————

1.2.2 以调试器所处理的指令粒度来分,可以分为机器级调试和源码级调试;

  • 机器级调试器:处理的是最底层的机器指令。通过它可以观察到计算机最基本的工作情况,可以观察到每一条指令执行后对寄存器、存储器产生的影响。

如果要调试的是嵌入式系统的板级支持包(Board-level Support Package,BSP)或操作系统引导程序的话,可能就会面对机器级调试

  • 源码级调试器:面向高级程序设计语言,屏蔽了大量机器底层细节。把精力集中到高级程序设计语言的框架里对程序的执行路径进行追踪。

为了实现源码级调试,调试器必须知道高级语言中的每一条语句与汇编代码的对应关系。多数现代编译器都提供了一个编译选项,用以在编译时生成调试信息。这些调试信息包含了源代码行和编译生成的汇编指令之间的对应关系。当在源代码的某一行上设置断点的时候,实际上是在对应的汇编指令上设置了一条断点指令或非法指令,同时把原来位于该位置处的指令保存到了某个地方。在触发断点之后,调试器把控制权交给用户,此时用户可以查看机器的各种状态。在用户把控制权还给调试器之后,调试器将此前保存的指令恢复,继续往下执行。

1.2.3 以被调程序是运行在用户空间还是内核空间来分,可以分为任务级调试和系统级调试;

  • 任务级调试:运行在操作系统的支持下。任务级调试的范围仅限于任务(某些情况下等价于进程),不包括操作系统内核。
  • 系统级调试:调试对象通常运行在内核空间,如驱动程序或中断处理程序(Interrupt Service Routine,ISR)。

内核通常直接和底层硬件打交道,同时内核关注的重点往往和同步、互斥、共享之类精细的操作有关,一旦内核出现错误,那么整个系统就都无法继续运行了,因为内核被带到了一个不确定的状态。更糟的是,内核错误可能非常难以重现。比如,如果内核中存在一个竞争条件,那么很可能这个错误出现的概率只有万分之一,而在其余的情况下都是正确的。系统级调试往往比任务级调试要困难得多。

1.2.4 以被调程序是否与调试器位于同一运行环境来分,可以分为本地调试和远程(交叉)调试等。

  • 本地调试:调试器和被调程序运行在同一平台下的调试方法称为;
  • 远程(交叉)调试:调试器和被调程序运行于不同平台下的调试方法。

本地调试通常采用进程间通信(Inter-Process Communication,IPC)对被调程序进行控制[3];而远程(交叉)调试则往往是通过某种物理通信媒介控制被调程序。无论本地调试还是远程(交叉)调试,最核心的功能无非两个:通信和控制。在通信功能上,远程(交叉)调试要稍微复杂一些,因为它涉及远程调试协议[6]等


1.3 调试器应当遵守的原则

  1. 调试器必须要客观公正地看待被调程序,既不能受被调程序影响,也不能反过来影响被调程序的执行。
  2. 调试器必须反映真实信息,必须真实可靠。
  3. 提供尽可能多的程序上下文信息。
  4. 尽可能减少对被测系统的影响。

调试器除了要能给出程序中全局变量、局部变量、堆、栈和断点的状态等信息之外,还要能够提供CPU寄存器和存储器的内容。
如果是提供了多进程或多线程支持的调试器,还应该能够给出各个进程或线程的状态;
如果是系统级调试器,还应该能够处理内核符号表等。

1.4 嵌入式调试技术

现在应用广泛的调试技术有:在线仿真(In-Circuit Emulation,ICE)方式、片上调试(On-Chip Debug,OCD)方式,以及软件仿真调试。片上调试属于较新的调试技术,主要包含了BDM(Background Debug Mode)和JTAG(Joint Test Action Group,边界扫描测试)两种。

1.4.1 软件仿真

软件仿真平台所模拟的是一个和目标平台差别甚微的虚拟运行环境。在开发过程中可以使用ARM的模拟器Armulator,并在模拟器上运行编译生成的程序。整个调试过程和在真实的目标平台上进行调试是完全一样的。

软件仿真通常能够做到反映处理器真实的体系结构,但却无法处理系统层次上的细节问题。

1.4.2 JTAG调试

JTAG把芯片的每一个引脚都和一个一位的移位寄存器相连,每一个这样的移位寄存器称做边界扫描单元(Boundary-Scan Cell),并且将所有这些一位的移位寄存器都以顺序的方式连接起来,就像一条链一样,因此把这样的移位寄存器链称为扫描链。

可以控制CPU的整个运行过程。因为无论CPU是取指令还是取数据,都必须进行相应的内存访问操作。而此时通过JTAG扫描链已经完全掌握了CPU的地址总线、数据总线和控制总线,此时既可以提供一个伪造的指令来使CPU断点,也能发出伪造的指令来查看CPU寄存器或存储器的状态。

1.4.3 调试代理

通常情况下的嵌入式调试仍然以采用调试代理的方式居多,尤其是在开发应用程序而非操作系统内核的时候。因此,就目前而言,调试代理仍然是嵌入式调试的基石。


  • 27
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@晓乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值