ARM各种断点到底有什么区别?

3.2 Flash断点:

Flash断点也就是本次问题的罪魁祸首了,也是从原理上来讲最最容易出现问题的断点。其实现原理是在设置Flash断点时,IDE和仿真器会配合修改控制器Flash上的内容,进一步说就是将断点处的指令修改为断点指令0xBE00,相应地就会牵涉到对Flash的擦除和编程操作。由于Flash内容是非易失的,所以有可能在调试器意外断开后对Flash断点处插入的断点指令还保留着,在用户复位直接运行程序可能就会导致程序无法正常运行。

目前市场上各种宣称支持Unlimited Breakpoint无限断点的仿真器采用的就是这个原理,如下截图的JLINK工具。需要提出的是Flash断点不是任意仿真器+IDE的组合都支持的,需要IDE和仿真器配合起来,譬如Ozone/Embeded Studio配合JLINK,IAR需要配合I-JET才能在断点设置时指定使用Flash断点,如果IAR配合JLINK只能选择软件断点(实际使用的其实也是Flash断点,只是标注上不带F标记)。I-JET和JLINK在支持Flash断点的差别主要是对Flash执行修改的策略,譬如一个Sector地址区域的多个Flash断点是执行一次还是多次的Flash操作,以及Flash插入的断点恢复策略等,需要使用时自行体会。

3.3 软件断点:

软件断点最开始主要用于RAM中设置断点,它的实现机制是将RAM中原有的指令替换为一个断点指令,当CPU执行到该指令之后就会自动暂停,这个时候调试器便会将原有的指令放回原来位置。这个过程都是调试器自动实现的,对RAM的更新速度很快,所以用户一般觉察不到。但实际情况是现在很多MCU受限于RAM大小,程序都是存放在Flash区域的,所以当断点大于硬件断点数量后,即便新的断点选成软件断点,很多时候也会被设置为Flash断点,意味着Flash断点有的问题在使用软件断点时也需要注意,这也是为何将软件断点的讲解放在Flash断点之后。


(资料图)

3.4 数据断点:

数据断点又称为条件断点,在ARM内核手册上称为watchpoint断点,是在CPU对特定地址访问时会触发的一种断点,在芯片内部实现上需要DWT和FPB共同配合完成,在设置断点的时候可以设置触发的条件,比如对特定地址的读访问还是写访问。这种断点对于追踪堆栈溢出相关的问题有奇效。数据断点同样需要硬件支持,数量一般也是有限的,如对应KW38、KW45、S32K1以及S32K3数据断点支持个数统计如下表所示。

4. 断点实验证明:

为了证明以上观点,笔者在KW38板子上做了一系列的测试如下:

4.1 IAR+I-JET 强制使用2个Flash断点,无硬件断点:

如下截图可以看到,在汇编和memory窗口中的数据都是原始的binary文件,但是通过额外的JLINK同时去Attach上去读取可以看到对应0x16996地址和0x169A0物理地址的数据已经被修改为了0xBE00;此处要特别鸣谢下IAR的Wen hao兄给的启发,确实没想到IARMemory窗口读取的数据和汇编窗口的指令居然都是假数据。

Note: IAR需要配合IAR公司自己的I-JET才能选择Flash断点,如果选择JLINK等其他工具只能设置软件断点;

4.2 IAR+JLINK 使用2个硬件断点+1个Flash断点:

如下图1 可以看到,两个硬件断点地址0x1FA2以及0x1FA6都被注册到了FPB寄存器的0xE0002000地址了。要指出的是,此处提到的Flash断点在IAR中显示为软件断点,因为IAR中默认仅支持使用I-JET的工具去打Flash断点,其标志就是会在红点里面显示一个F图标。所以这也就是前文说到的,对于Flash运行的代码软件断点在实现上本质也还是Flash断点。

下图2 可以看到,强制设置为line 38和line40处为硬件断点之后,因为KW38只支持2个硬件断点,main处这个断点就被强制设定为了Flash断点,分别去读取0x1F98, 0x1FA2以及0x1FA6地址的值,可以看到main处断点所在的地址内容被修改为了0xBE00,0x1FA2以及0x1FA6地址是正常的原始数据,存储在硬件断点地址,完全符合预期。

4.3 IAR+JLINK使用2个硬件断点+2个软件断点:

可以看到,line36,line40被强行设置为硬件断点,line38被设置为软件断点,main断点也自动被分配为了软件断点,对比0x1F98, 0x1F9A, 0x1FA2, 0x1FA6地址的内容,只有0x1F98,0x1FA2两个软件断点地址处的内容被修改为了0xBE00,即插入BKPT指令。0x1F9A和0x1FA6两个硬件地址的内容没有被修改,再次证明软件断点对于在Flash调试的控制器,本质上就是Flash断点。

4.4 IAR+JLINK 使用6个软件断点+1个硬件断点:

因为IAR中默认优先使用硬件断点,而当前debug中设置了6个软件断点,所以main出的断点被自动分配为硬件断点。可以看到,全部6个软件断点对应地址区域的值都被修改为了0xBE00,也就是前文提到的软件断点其实也变成了Flash断点,main地址处内容没有发生变化,符合预期。

5. 如何预防Flash断点带来的潜在风险

对于硬件断点和数据断点来说,他们是基于寄存器的实现,脱离Debug状态无法继续生效,不会影响用户代码的脱机运行。但是Flash断点因为牵涉到修改非易失的Flash数据,就有风险导致程序意外被修改无法运行,譬如说突然断电,不合理退出debug状态等。

而且对于该类问题,如果断点断在main函数的主任务上还容易观察到,因为代码很直观的无法运行,而如果断在了某个不常调用的但又会用到的子任务的某个switch case中,就容易埋下隐蔽的bug(本案例遇到的就是这个状况)。还一种情况是实车现场分析过程中,常用的一种方式就是Attach观察分析问题,如果使用到Flash断点(尤其是Flash运行的软件断点),且退出时没注意清除该类型断点,可能会带来新的潜在问题。

设置完Flash断点,对于突然断电这种方式,自然是无解的,只能重新下载代码。而在debug状态时如何退出才是最优雅的方式(还原原本Flash内容)呢?笔者使用IAR+JLINK在KW38 demo板上上做了一系列测试,结论如下;

总的来说,为了避免Flash断点带来的Flash修改后没有恢复的问题,需要在退出Debug模式时,先delete掉所有断点,再去stop debug,或者先在在breakpoint窗口中Disable 所有Flash断点后,再debug状态下执行一次SW reset,让Flash恢复回来,前者的缺点是下次debug时原来的断点都丢失了,需要重新设置,优点是更彻底。

6. 结论:

基于以上分析可以得出几个结论:

7. 免责声明

本公众号所有原创文章中所有的观点和结论均为个人理解,难免有纰漏之处,不代表任何公司官方观点意见;所有demo代码/程序,仅作学习参考,不保证质量,若用于商业用途,责任自负。

关注公众号:

扫码加入嵌入式交流群: