Debug Monitor中断详细解析

文章目录

  • 0 基本术语
  • 1 相关寄存器和指令
    • 1.1 Debug Halting Control and Status Register (DHCSR), 0xE000EDF0
    • 1.2 Debug Exception and Monitor Control Register (DEMCR), 0xE000EDFC
    • 1.3 Debug Fault Status Register, DFSR, 0xE000ED30
    • 1.4 BKPT指令
  • 2 Debug Monitor中断示例
    • 2.1 Enabling the DebugMonitor Exception
      • 2.1.1 Debug Monitor中断使能的完整C代码
    • 2.2 中断处理函数
      • 2.2.1 A minimal DebugMonitor Handler
      • 2.2.2 在中断处理函数中打印interested寄存器的值
      • 2.2.4 不同中断源的handler处理方式
    • 2.3 触发中断
      • 2.3.1 BKPT指令
      • 2.3.2 通过FPB编程的方式下断点
  • 参考资料

0 基本术语

ARM Cortex-M支持几种“level”的debug功能:

Halting Debug——在使用像GDB这样的debugger的时候的典型的配置。此种模式下,在调试的时候核心会处于halted(停止)状态。这种模式需要通过JTAG或者SWD来访问Debug Port。
通过ITM,DWT和ETM实现的Trace功能——这些外设可以让你在系统运行的过程中流式指令运行和数据访问。是一种非侵入式的debug方式。 像Lauterbach TRACE32这样的工具可以decode指令流,并将结果显示在GUI上面。
Debug Monitor mode——可以通过实现DebugMonitor exception handler的方式来调试全速运行的系统。这在停止核心将导致时序敏感子系统失败或连接调试器不可行的用例中非常有用。

值得注意的是,调试监视器支持不适用于 ARMv6-M 架构 (Cortex-M0)。 但是,它适用于所有其他 Cortex-M 架构。

1 相关寄存器和指令

1.1 Debug Halting Control and Status Register (DHCSR), 0xE000EDF0

在这里插入图片描述

仅当禁用停止调试(halting debug)时,监视模式调试才有效。 值得注意的是,上面的 C_DEBUGEN 设置必须被清除。 该位只能通过 JTAG/SWD 连接进行设置,并且只有在发生完全上电复位 (POR) 或调试器在退出时清除该位时才会复位。

1.2 Debug Exception and Monitor Control Register (DEMCR), 0xE000EDFC

DebugMonitor异常的核心(Core)配置由DEMCR寄存器的高16位控制:
在这里插入图片描述
where:

  • MON_EN - Controls whether the DebugMonitor exception is enabled or not. When enabled, debug “events” will cause the exception to fire.
  • MON_PEND - 可用于触发 DebugMonitor 异常,无论 MON_EN 是否设置为 1。
  • MON_REQ - 不被 MCU 使用。 软件可以使用该位来传达有关监视模式的状态。
  • MON_STEP - 可以从 DebugMonitor 异常切换以启用硬件单步执行。 设置后,从异常处理程序返回后,内核将执行一条指令,然后返回到 DebugMonitor 异常。

**注意:低位(VC_HARDERR 等)控制当发生各种类型的异常时是否自动发生调试陷阱。 这些仅在使用停止调试模式时生效。 它们允许您保证系统在遇到异常路径时停止,这在尝试调试时非常有用!
**

1.3 Debug Fault Status Register, DFSR, 0xE000ED30

通过DFSR可以查看发生了哪一种Debug Event。

当 DebugMonitor 异常触发时,可以检查 DFSR 以获取有关发生的调试事件的信息:
在这里插入图片描述
Some of the events are only possible when using a halting debug. For the DebugMonitor the states of interest are:

  • DWTTRAP Indicates the a debug event was generated due to a configuration in the DWT.
  • BKPT Indicates one or more breakpoint event took place (either via the FPB or a BKPT instruction).
  • HALTED Indicates the core was halted due to a MON_STEP request.

NOTE: DFSR bits are sticky and you have to write 1 to the value to clear them

1.4 BKPT指令

在这里插入图片描述

2 Debug Monitor中断示例

2.1 Enabling the DebugMonitor Exception

基于调试监视器(Debug Monitor)模式的调试通过在发生调试事件(Debug Event)时触发称为“DebugMonitor Exception”的异常来进行。

(1)确保DHCSR.C_DEBUGEN == 0

如果您尝试使用监视模式调试,我建议为此添加启动检查。 否则,当您尝试测试该功能并通过 JTAG/SWD 连接调试器时,您一定会感到困惑:

bool debug_monitor_enable(void) {volatile uint32_t *dhcsr = (uint32_t*)0xE000EDF0;if ((*dhcsr & 0x1) != 0) {EXAMPLE_LOG("Halting Debug Enabled - ""Can't Enable Monitor Mode Debug!");return;}// code to set up debug monitor mode
}

TIP: Disabling Halting Debug from GDB
如果您使用 GDB,可以通过清除 C_DEBUGEN 并为 DBGKEY (0xA05F) 设置适当的值来手动禁用停止模式调试:

(gdb) set *(uint32_t*)0xE000EDF0=(0xA05F<<16)

这也是保持活动 GDB 会话打开并在系统运行时探测其状态的有用方法!
(2)DEMCR.MON_EN = 1
(3)开中断

NVIC_EnableIRQ(DebugMonitor_IRQn);

(4)优先级的设置
DebugMonitor Exception Configuration Nuances
仅当异常的组优先级大于当前执行优先级时,调试事件才会触发 DebugMonitor 异常。

这是一个有用的功能,可以保证在您单步执行系统其他部分的代码时某些高优先级操作(即蓝牙无线电调度)继续运行。

Configuring the DebugMonitor exception priority will require updating SHPR3. More details can be found in our post about ARM Cortex-M exception handling(https://interrupt.memfault.com/blog/arm-cortex-m-exceptions-and-nvic#system-handler-priority-register-shpr1-shpr3—0xe000ed18—0xe000ed20).

2.1.1 Debug Monitor中断使能的完整C代码

为了简单起见,在我们的示例应用程序中,我们将 DebugMonitor 异常设置为最低的可配置中断优先级。 这意味着所有其他中断将能够在调试未从中断运行的代码时运行。

bool debug_monitor_enable(void) {volatile uint32_t *dhcsr = (uint32_t*)0xE000EDF0;if ((*dhcsr & 0x1) != 0) {EXAMPLE_LOG("Halting Debug Enabled - ""Can't Enable Monitor Mode Debug!");return false;}volatile uint32_t *demcr = (uint32_t*)0xE000EDFC;const uint32_t mon_en_bit = 16;*demcr |= 1 << mon_en_bit;// Priority for DebugMonitor Exception is bits[7:0].// We will use the lowest priority so other ISRs can// fire while in the DebugMonitor Interruptvolatile uint32_t *shpr3 = (uint32_t *)0xE000ED20;*shpr3 = 0xff;EXAMPLE_LOG("Monitor Mode Debug Enabled!");return true;
}

2.2 中断处理函数

2.2.1 A minimal DebugMonitor Handler

这个是一个套路。

我们可以使用我们在有关故障处理(our post about fault handling, https://interrupt.memfault.com/blog/cortex-m-hardfault-debug#halting–determining-core-register-state)的文章中组合的相同处理程序来转储有关导致调用 DebugMonitor 异常的代码的寄存器状态:

typedef struct __attribute__((packed)) ContextStateFrame {uint32_t r0;uint32_t r1;uint32_t r2;uint32_t r3;uint32_t r12;uint32_t lr;uint32_t return_address;uint32_t xpsr;
} sContextStateFrame;void debug_monitor_handler_c(sContextStateFrame *frame) {// DebugMonitor Exception Logic// ...
}__attribute__((naked))
void DebugMon_Handler(void) {__asm volatile("tst lr, #4 \n""ite eq \n""mrseq r0, msp \n""mrsne r0, psp \n""b debug_monitor_handler_c \n");
}

2.2.2 在中断处理函数中打印interested寄存器的值

void debug_monitor_handler_c(sContextStateFrame *frame) {volatile uint32_t *demcr = (uint32_t *)0xE000EDFC;volatile uint32_t *dfsr = (uint32_t *)0xE000ED30;const uint32_t dfsr_dwt_evt_bitmask = (1 << 2);const uint32_t dfsr_bkpt_evt_bitmask = (1 << 1);const uint32_t dfsr_halt_evt_bitmask = (1 << 0);const bool is_dwt_dbg_evt = (*dfsr & dfsr_dwt_evt_bitmask);const bool is_bkpt_dbg_evt = (*dfsr & dfsr_bkpt_evt_bitmask);const bool is_halt_dbg_evt = (*dfsr & dfsr_halt_evt_bitmask);EXAMPLE_LOG("DebugMonitor Exception");EXAMPLE_LOG("DEMCR: 0x%08x", *demcr);EXAMPLE_LOG("DFSR:  0x%08x (bkpt=%d, halt=%d, dwt=%d)", *dfsr,(int)is_bkpt_dbg_evt, (int)is_halt_dbg_evt,(int)is_dwt_dbg_evt);EXAMPLE_LOG("Register Dump");EXAMPLE_LOG(" r0  =0x%08x", frame->r0);EXAMPLE_LOG(" r1  =0x%08x", frame->r1);EXAMPLE_LOG(" r2  =0x%08x", frame->r2);EXAMPLE_LOG(" r3  =0x%08x", frame->r3);EXAMPLE_LOG(" r12 =0x%08x", frame->r12);EXAMPLE_LOG(" lr  =0x%08x", frame->lr);EXAMPLE_LOG(" pc  =0x%08x", frame->return_address);EXAMPLE_LOG(" xpsr=0x%08x", frame->xpsr);// ...
}

2.2.3 在中断处理函数中认为决定后续行为
要添加用于 DebugMonitor 处理的 CLI,我们需要的是一种通过 UART 从 ISR 读取字节的方法。 这可以通过轮询外设或使用配置为以比 DebugMonitor 异常更高的优先级运行的中断来完成读取。

In our example app, we will add two commands:

  • c - To continue after the DebugMonitor exception fires
  • s - To step one instruction and then return to the DebugMonitor Exception
typedef enum {kDebugState_None,kDebugState_SingleStep,
} eDebugState;static eDebugState s_user_requested_debug_state = kDebugState_None;void debug_monitor_handler_c(sContextStateFrame *frame) {// ... logic to dump info ...if (is_dwt_dbg_evt || is_bkpt_dbg_evt ||(s_user_requested_debug_state == kDebugState_SingleStep))  {EXAMPLE_LOG("Debug Event Detected, Awaiting 'c' or 's'");while (1) {char c;if (!shell_port_getchar(&c)) {continue;}EXAMPLE_LOG("Got char '%c'!\n", c);if (c == 'c') {s_user_requested_debug_state = kDebugState_None;break;} else if (c == 's') {s_user_requested_debug_state = kDebugState_SingleStep;break;}}} else {EXAMPLE_LOG("Resuming ...");}// ... other logic ...
}

2.2.4 不同中断源的handler处理方式

Debug Monitor Continue and Step Support

Stepping over a breakpoint is a several step process:

  1. If it’s a bkpt instruction, we need to advance the program counter by the size of the instruction (2 bytes).
  2. If a bkpt event was generated from a breakpoint configured in the FPB, we need to:
  • Disable the FPB. Otherwise, any attempt to continue will just hit the breakpoint again.
  • Single-Step one instruction.
  • Re-enable the FPB and disable single-stepping in order to resume program execution.
    In our DebugMon_Handler, we can:
  • inspect the pc from the frame parameter passed to debug_monitor_handler_c to figure out whether or not the debug event was caused by executing a breakpoint instruction.
  • Disable/Enable the FPB by clearing & setting the ENABLE bit in the FPB FP_CTRL register.
  • Enable/Disable single-step functionality by setting and clearing the MON_STEP bit in the DEMCR.
const uint32_t demcr_single_step_mask = (1 << 18);if (is_bkpt_dbg_evt) {const uint16_t instruction = *(uint16_t*)frame->return_address;if ((instruction & 0xff00) == 0xbe00) {// advance past breakpoint instructionframe->return_address += sizeof(instruction);} else {// It's a FPB generated breakpoint// We need to disable the FPB and single-stepfpb_disable();EXAMPLE_LOG("Single-Stepping over FPB at 0x%x", frame->return_address);}// single-step to the next instruction// This will cause a DebugMonitor interrupt to fire// once we return from the exception and a single// instruction has been executed. The HALTED bit// will be set in the DFSR when this happens.*demcr |= (demcr_single_step_mask);// We have serviced the breakpoint event so clear mask*dfsr = dfsr_bkpt_evt_bitmask;
} else if (is_halt_dbg_evt) {// re-enable FPB in case we got here via single-step// for a BKPT debug eventfpb_enable();if (s_debug_state != kDebugState_SingleStep) {*demcr &= ~(demcr_single_step_mask);}// We have serviced the single step event so clear mask*dfsr = dfsr_halt_evt_bitmask;
}

2.3 触发中断

2.3.1 BKPT指令

static int prv_issue_breakpoint(int argc, char *argv[]) {__asm("bkpt 1");return 0;
}

2.3.2 通过FPB编程的方式下断点

在 FPB 中,我们可以对 FP_COMP 寄存器之一进行编程来保存我们想要中断的地址。(这个就是硬件断点的实质。 就是比较器比较pc的值和comp寄存器中的地址是否匹配。)

FP_COMP 寄存器的布局有点奇怪,但基本上对于给定的 instr_addr,FP_COMP[31:30] 映射 instr_addr[1:0],FP_COMP[28:2] 映射到 instr_addr[28:2],最低位 FP_COMP[0]控制断点是否启用。

bool fpb_set_breakpoint(size_t comp_id, uint32_t instr_addr) {if (instr_addr >= 0x20000000) {// for revision 1 only breakpoints in code can be installed :/return false;}// make sure the FPB is enabledFPB->FP_CTRL |= 0x3;const uint32_t replace = (instr_addr & 0x2) == 0 ? 1 : 2;const uint32_t fp_comp = (instr_addr & ~0x3) | 0x1 | (replace << 30);FPB->FP_COMP[comp_id] = fp_comp;return true;
}

For more details on how to configure the Flash Patch And Breakpoint (FPB) unit, check out our “How do breakpoints even work?” post!(https://interrupt.memfault.com/blog/cortex-m-breakpoints#flash-patch–breakpoint-unit)

参考资料

[1] https://interrupt.memfault.com/blog/cortex-m-debug-monitor 【非常好的解释blog】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/687675.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解读OpenAI视频生成模型Sora背后的原理:Diffusion Transformer

Diffusion Models视频生成-博客汇总 前言&#xff1a;OpenAI最近推出的视频生成模型Sora在效果上实现了真正的遥遥领先&#xff0c;很多博主都介绍过Sora&#xff0c;但是深入解读背后原理的博客却非常少。Sora的原理最主要的是核心模型主干《Scalable Diffusion Models with T…

Code Composer Studio (CCS) - Breakpoint (断点)

Code Composer Studio [CCS] - Breakpoint [断点] 1. BreakpointReferences 1. Breakpoint 选中断点右键 -> Breakpoint Properties… Skip Count&#xff1a;跳过断点总数&#xff0c;在断点执行之前设置总数 Current Count&#xff1a;当前跳过断电累计值 References […

CCF编程能力等级认证GESP—C++7级—20231209

CCF编程能力等级认证GESP—C7级—20231209 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)商品交易纸牌游戏 答案及解析单选题判断题编程题1编程题2 单选题…

Vue实现多个input输入,光标自动聚焦到下一个input

遇到一个需求&#xff0c;需要实现和移动端短信输入一样&#xff0c;输入内容后&#xff0c;光标会进入下一个输入框 需要用到2个事件 keydown事件发生在键盘的键被按下的时候 keyup 事件在按键被释放的时候触发 <template><div class"box"><el-fo…

OpenAI重磅发布Sora——首个视频生成模型:利用文本-视频人工智能将想象变为现实

想象一下&#xff0c;现在你有一段文本话描述的故事&#xff0c;通过输入这段文本&#xff0c;就可以立刻展开一个生动详细的视频。这就是 OpenAI 神奇的 Sora&#xff0c;一个革命性的文本到视频的 AI 模型。Sora于2024年2月推出&#xff0c;凭借其仅凭文字提示就能生成现实和…

CSS 不同颜色的小圆角方块组成的旋转加载动画

<template><!-- 创建一个装载自定义旋转加载动画的容器 --><view class="spinner"><!-- 定义外部包裹容器,用于实现整体旋转动画 --><view class="outer"><!-- 定义四个内部小方块以形成十字形结构 --><view clas…

攻防演练后的一点随记

攻防演练 攻防演练算是告一段落了&#xff0c;各位红队和蓝队的兄弟们都辛苦了&#xff0c;写一点随记&#xff0c;供大家参考。 记得第一次参加攻防演练是在2018年&#xff0c;当时被派到北京&#xff0c;在某个政企单位做攻防演练支撑工作&#xff0c;然后2020年又被紧急派到…

Vue首屏优化,12个提速建议

文章目录 代码拆分和懒加载&#xff1a;代码拆分懒加载 图片优化&#xff1a;组件懒渲染&#xff1a;数据预获取和缓存&#xff1a;服务器端渲染&#xff08;SSR&#xff09;&#xff1a;代码压缩和合并&#xff1a;使用 CDN 加速&#xff1a;监控和性能分析&#xff1a;代码优…

AIGC实战——能量模型(Energy-Based Model)

AIGC实战——能量模型 0. 前言1. 能量模型1.1 模型原理1.2 MNIST 数据集1.3 能量函数 2. 使用 Langevin 动力学进行采样2.1 随机梯度 Langevin 动力学2.2 实现 Langevin 采样函数 3. 利用对比散度训练小结系列链接 0. 前言 能量模型 (Energy-based Model, EBM) 是一类常见的生…

c++开发基础之保障多线程编程中的原子操作InterlockedIncrement和InterlockedDecrement用法详解

一、介绍 在多线程编程中&#xff0c;确保对共享变量进行原子操作是至关重要的。当多个线程同时访问和修改同一共享资源时&#xff0c;如果没有合适的同步机制&#xff0c;可能会导致数据竞争、内存一致性问题&#xff0c;甚至造成程序崩溃。为了解决这个问题&#xff0c;C提供…

公众号,h5 链接直接在浏览器打开 拒绝下载视频解决方案

公众号&#xff0c;h5 链接直接在浏览器打开 拒绝下载视频 1.微信打开公众号 2.在微信上打开浏览器 3.F12打开页面 4.播放视频 5.找到video标签代码 6.去掉video标签的属性controlslist“nodownload” 7.全屏播放 8.下载

【个人博客搭建】butterfly主题配置

目录 一、基础配置 (一) 模板配置 1. 文章模板 2. 页面模板 (二) 创建页面和文章 1. 标签页【可选】 2. 分类页【可选】 3. 友链页【可选】 4. 404页面【可选】 5. 文章 (三) 导航栏设置 1. 基础项 2. 菜单项 (四) 页面设置 1. 代码框设置 2. 社交图标设置 3.…

win10下wsl2使用记录(系统迁移到D盘、配置国内源、安装conda环境、配置pip源、安装pytorch-gpu环境、安装paddle-gpu环境)

wsl2 安装好后环境测试效果如下&#xff0c;支持命令nvidia-smi&#xff0c;不支持命令nvcc&#xff0c;usr/local目录下没有cuda文件夹。 系统迁移到非C盘 wsl安装的系统默认在c盘&#xff0c;为节省c盘空间进行迁移。 1、输出wsl -l 查看要迁移的系统名称 2、执行导出命…

JDK8 升级至JDK19

优质博文IT-BLOG-CN 目前部分项目使用JDK8&#xff0c;部分项目使用JDK19因此&#xff0c;环境变量中还是保持JDK8&#xff0c;只需要下载JDK19免安装版本&#xff0c;通过配置IDEA就可以完成本地开发。 一、IDEA 环境设置 【1】通过快捷键CTRL SHIFT ALT S或者File->P…

如何免费访问和使用Gemini API?

Gemini是谷歌开发的一个新模型。有了Gemini可以为查询提供图像、音频和文本&#xff0c;获得几乎完美的答案。 我们在本教程中将学习Gemini API以及如何在机器上设置它。我们还将探究各种Python API函数&#xff0c;包括文本生成和图像理解。 Gemini AI模型介绍 Gemini是谷歌…

两种方法判断Python的位数是32位还是64位

Python从1991年发布以来&#xff0c;凭借其简洁、清晰、易读的语法、丰富的标准库和第三方工具&#xff0c;在Web开发、自动化测试、人工智能、图形识别、机器学习等领域发展迅猛。     Python是一种胶水语言&#xff0c;通过Cython库与C/C语言进行链接&#xff0c;通过Jytho…

[Java][算法 滑动窗口]Day 03---LeetCode 热题 100---08~09

第一题 无重复字符串的最长子串 思路 其实就是在字符串S中 找到没有重复的最长子串的长度 这道题的难点就是在于如何判断最长并且无重复 首先 最长长度 可以使用变量max记录保存 再者 判断有无重复 最简单的方法就是 暴力遍历法 即对于每次找的子串都再次寻找遍历…

《辽宁春晚》开场动画惊艳亮相,蓝海创意云渲染服务再显神通

随着2024年甲辰龙年的脚步日益临近&#xff0c;备受瞩目的《辽宁春晚》于除夕夜为全国观众带来了一场精彩绝伦的视听盛宴。作为整场晚会的亮点之一&#xff0c;开场动画以其独特的创意和精美的画面效果&#xff0c;为观众带来了一个难忘的视觉体验。而这一精彩的呈现&#xff0…

测试物理网络的ping命令

通过发送Internet控制消息协议&#xff08;ICMP&#xff09;并接收其应答&#xff0c;测试验证与另一台TCP/IP计算机的IP级联通性、可达到性和名称解析的疑难问题主要TCP/IP命令。如果不带参数&#xff0c;ping将显示帮助。通过在命令提示符下输入“ping /&#xff1f;”命令&a…

R语言课程论文-飞机失事数据可视化分析

数据来源&#xff1a;Airplane Crashes Since 1908 (kaggle.com) 代码参考&#xff1a;Exploring historic Air Plane crash data | Kaggle 数据指标及其含义 指标名 含义 Date 事故发生日期(年-月-日) Time 当地时间&#xff0c;24小时制&#xff0c;格式为hh:mm Locat…