Arm的Debug机制

一、调试类型

Debug按侵入性(invasive)可以分为两大类:

  • 侵入式调试(Invasive Debug :暂停处理器执行,干预程序运行,包括停机调试(Halting Debug)和调试监控异常(DebugMonitor Exception)两种模式。
  • 非侵入式调试(Non-invasive Debug :不中断程序运行,仅采集运行数据,包括指令跟踪、数据跟踪、性能统计三类。

Halting Debug 会使PE进入halt状态,也就是处于Debug state 。当PE没有处于halt状态,它就处于Non-debug state。Halting Debug下,调试器可通过调试接口读写通用寄存器、特殊寄存器、内存与外部资源,支持断点、单步、变量查看等经典在线调试操作,是常规IDE调试的底层基础。当PE处于Debug state时:

  • PE停止从PC指示的位置执行指令,而是由外部调试接口控制;
  • PE不会服务任何中断;

以下几个行为可以使PE退出debug state:

  • 当调试器将0写入DHCSR.C_HALT;
  • 接收到外部restart请求;
  • Warm reset;

DebugMonitor Exception会进入异常,由软件异常处理程序完成调试交互,适合实时性要求高、外设不能暂停的场景,在不冻结系统的前提下完成调试动作。

Embedded Trace Macrocell (ETM)、Instrumentation Trace Macrocell (ITM)、Data Watchpoint and Trace (DWT) Unit、Performance Monitoring Unit (PMU)可用于生成trace数据。

二、调试资源

在System Address Map中,debug资源位于Private Peripheral Bus (PPB)区域。除了SCS中的资源外,每个debug组件占用固定的4KB地址区域。SCS中的debug资源有:

  • Debug Control Block (DCB)
  • 在System Control Block (SCB)中的Debug controls

SCB的debug功能包括:

  • 两个处理程序相关的标志位ICSR.ISRPREEMPT和ICSR.ISRPENDING:
  • DFSR寄存器;

Debug 资源的地址分布如下:

上图中最后一个是ROM table的地址空间,调试器通过读取 ROM 表自动识别芯片内所有调试模块(DWT/ITM/ETM/CTI 等)的基地址与类型,实现通用工具适配。

ROM table是一个表项,它提供了一种机制来标识实现所支持的debug基础结构。ROM table指示实现的调试组件有哪些,以及这些组件在内存映射中的位置。ROM table的格式如下:

三、调试安全认证

Debug authentication interface提供了4个伪函数:

  • ExternalInvasiveDebugEnabled().
  • ExternalSecureInvasiveDebugEnabled().
  • ExternalNoninvasiveDebugEnabled().
  • ExternalSecureNoninvasiveDebugEnabled().

对于使用CoreSight信号DBGEN、NIDEN、SPIDEN和SPNIDEN的实现来说:

  • 如果ExternalInvasiveDebugEnabled()为真,那么DBGEN为1;
  • 如果ExternalSecureInvasiveDebugEnabled()为真,那么DBGEN和SPIDEN都为1;
  • 如果ExternalNoninvasiveDebugEnabled()为真,那么NIDEN或DBGEN为1;
  • 如果ExternalSecureNoninvasiveDebugEnabled()为真,那么以下使用以下两者条件:
    • NIDEN或DBGEN为1;
    • SPNIDEN或SPIDEN为1;

配合 TrustZone 安全扩展,对调试权限做分级管控,防止非授权调试泄露安全域数据:

  • Halting debug认证:控制外部调试器能否让内核进入hating状态;
  • Non-invasive debug认证:控制trace、profiling等non-invasive功能的访问权限;
  • DebugMonitor exception认证:控制DebugMonitor exception的触发权限;
  • DAP access权限:配置调试访问端口(DAP)对安全 / 非安全地址空间的访问边界。当HaltingDebugAllowed()为TRUE时,外部调试器可以通过DAP向整个物理地址空间发出请求。DAUTHCTRL.UIDAPEN指示软件允许外部调试器通过DAP对所选PPB寄存器进行非特权访问。

四、调试事件

由于调试原因而触发的事件称为debug event,它们定义所有可触发debug行为的硬件事件,是断点、单步等功能的底层依据。Debug event会使PE发生以下情况之一:

  • 如果Halting debug实现且启用了,那么会进入Debug state;
  • DebugMonitor exception发生;
  • 产生HardFault exception;
  • Lockup;

上面两种通常是debug event想要触发来进行调试PE的。下面两种是可能debug event无法正常处理而产生的,比如:当PE既不能进入Halting debug也不能产生DebugMonitor exception时,这时候执行BKPT指令就会进入下面两种情况的了。

debug event如下所示:

这些event导致PE halt或产生DebugMonitor exception时,会更新DFSR寄存器中对应的bit,这些bit是通过写1来清理的。下表显示了为每个debug event设置的位。

Debug events可以是synchronous或是asynchronous。Synchronous的debug events有:

  • 由BKPT指令的执行或FPB中的匹配引起的breakpoint debug events。
  • Vector catch debug events,由一个或多个DEMCRVC_*位被设置为1引起的,PE进入相应的异常。
  • Step debug events,由DHCSR.C_STEP或DEMCR.MON_STEP引起。

一条指令可以生成多个synchronous debug events。synchronous debug events与生成它们的指令相关联,并被采用而不是执行该指令。PE不会生成任何其他可能由于执行指令而发生的synchronous exception或debug event。

4.1 Debug stepping

Armv8-M体系结构在halting debug和DebugMonitor exception中都支持debug stepping。

  • Halting debug stepping:调试器可以使用halting debug stepping退出调试状态,执行单个指令,然后重新进入调试状态。
  • debug monitor stepping:调试器可以使用debug monitor stepping从DebugMonitor异常处理程序返回,执行单个指令,然后重新进入DebugMonitor异常处理程序。

Step debug event发生在被stepped的指令之后的指令上。这意味着event的优先级适用于后续指令的任何其他exception或debug events,而不是正在执行的指令。

4.2 Vector catch

Vector catch是生成debug event并在进入特定exception处理程序或复位时进入debug状态的机制。Vector catching只支持halting debug,用于异常入口调试;

4.3 Breakpoint instructions

BKPT指令,软件断点指令,执行 BKPT 时触发调试事件,是软件断点的硬件基础。

4.4 External debug request

当PE处于non-debug state时,外部agent可以发出外部debug请求的信号。外部调试请求可能触发debug event,导致以下两种情况:

  • 进入debug state。
  • 如果Main extension被实现,DebugMonitor异常。

PE处于debug state时,忽略外部调试请求。

五、调试与跟踪功能组件

调试与跟踪功能组件(Debug and Trace Components)是实现breakpoint、watchpoint、trace输出的实体模块,全部为内存映射寄存器,可通过 DAP 或特权软件配置。

5.1 ITM(Instrumentation Trace Macrocell)

定位:软件插入式跟踪,轻量级非侵入调试

核心功能

  • 支持 32 个stimulus端口,软件通过写寄存器输出调试数据,实现类似 printf 的打印调试;如果ITM实现支持超过32个stimulus端口,则使用分页来指示stimulus端口号。
  • 硬件事件跟踪:可上报异常进入 / 退出、PC 采样、数据观察点匹配等硬件事件;
  • 时间戳功能:为跟踪数据包添加时间标记,支持时序分析;
  • 同步包机制:周期性插入同步帧,保证跟踪数据解析的准确性。

特点:软件可控、开销低,适合应用层日志输出与事件打点。

5.2 DWT(Data Watchpoint and Trace)

定位:数据访问监控 + 基础性能统计

核心功能

  • 地址比较器:实现数据观察点,可配置为监控指令取指、内存读、内存写三类访问,地址匹配时触发调试事件或跟踪包;
  • 支持地址范围匹配、数据值匹配(部分实现),满足条件断点、变量监控需求;
  • 性能计数器:内置多个硬件计数器,可统计时钟周期、指令执行数、休眠周期、异常次数等,用于代码性能分析;
  • 可生成跟踪数据包,将观察点命中事件、采样信息输出到跟踪链路。

特点:通用比较器资源,兼顾数据断点和性能统计。

5.3 ETM(Embedded Trace Macrocell)

定位:全量指令流跟踪,non-invasive程序路径trace,它是Armv8-M架构可选的non-invasive调试特性。

核心功能

  • 实时记录内核执行的全部指令流,支持压缩编码输出,调试器可重构完整程序执行路径;
  • 支持触发控制:可配置开始 / 停止跟踪的条件(如地址匹配、外部触发),只捕获关注的代码段;
  • 带时间戳标记,支持指令级时序分析;
  • 完全non-invasive,不影响程序正常运行时序。

特点:适合排查偶发异常、时序相关问题,是高端调试的核心组件。

5.4 FPB(Flash Patch and Breakpoint)

定位:硬件指令断点 + Flash 在线热补丁

核心功能

  • 硬件指令断点:比较取指地址,匹配时触发断点,无需修改指令,适合 Flash 代码调试;
  • Flash 补丁重定向:将指定 Flash 地址的取指 / 读操作,硬件重定向到 RAM 中的替代代码 / 数据,实现不擦写 Flash 的在线补丁;(该功能已废弃)

特点:是 IDE 硬件断点的底层实现,也是 Flash 在线升级 / 修复的硬件基础。

5.5 TPU(Trace Port Interface Unit)

Armv8-M的跟踪端口接口单元(TPIU)支持为来自DWT、ITM和ETM的trace data提供输出路径。TPIU是一个跟踪接收器。TPIU是否支持并行跟踪端口输出是由IMPLEMENTATION定义的。Arm建议TPIU同时提供并行和异步串行端口,以获得与外部捕获设备的最大灵活性。

5.6 PMU(Performance Monitor Unit)

性能监视器扩展描述了一个可选的非侵入性调试组件,它允许识别和计数性能事件。性能监视器扩展的一个实现称为性能监视单元(PMU)。

定位:系统级硬件事件统计,面向性能优化与调优

核心功能

  • 提供多个可编程计数器,可选择统计不同的硬件事件;最多可容纳31个IMPLEMENTATION DEFINED事件计数器(event counter)。每个性能事件计数器是一个16位的通用计数器。通过成对链接计数器,计数器范围可以通过将计数器数量减半来增加。如果实现了PMU,则至少需要2个16位的性能事件计数器和1个32位的cycle计数器。
  • 标准化事件编号:规范定义了必选事件和可选事件,包括:
    • 指令执行类:指令提交数、分支指令数、异常次数;
    • 缓存类:指令缓存命中 / 失效、数据缓存命中 / 失效、缓存写回;
    • 总线类:总线访问周期、内存访问等待周期;
    • 调试类:DWT 比较器匹配事件、跟踪外部事件;
  • 支持计数器溢出中断,可实现事件阈值告警、周期采样。

意义:为代码性能分析、瓶颈定位提供硬件级准确数据,无需软件插桩。

PMU提供广泛准确和统计上有用的计数信息。为了保持较低的实现和验证成本,计数中的合理程度的不准确性是可以接受的。PMU的常见事件列表如下。event类型有两大类:

Arch:

  • Architecture event。这些事件在所有实现中都是相同的。

uArch:

  • Microarchitecture event。这些事件在不同的实现中可能有所不同。