【MDK应用】Keil高阶调试技术(一)

参考资料:

Keil5软件使用-进阶调试篇_keil调试教程-优快云博客

keil mdk 设置监测断点,高级断点使用_keil调试 变量修改断点-优快云博客

调试笔记--keil 断点调试小技巧_keil5断点调试教程-优快云博客

Keil 手册——DEBUG:

注意事项:

调试笔记--keil 断点调试小技巧_keil5断点调试教程-优快云博客

1.1. 【断点 原理】给变量打断点的前提是,这个是全局变量

打断点其实就是DEBUG模块检测固定RAM地址,当有指令用的预定的RAM地址,将指令进行替换

局部变量存放在栈中,地址不固定因此不能这样操作

全局静态变量的作用域只是当前文件内可访问,因此如果强行使用可能导致结果不确定(有可能按照预期断点停止,也有可能不会)

既然原理是检测固定RAM地址,那么直接从Menory找到对应地址设置断点也是一样可行的

1.2. 断点配置好后不可修改条件

断点设定好后,不能在原来的上面进行修改,需要将改断点删除然后重新设置一个。

如下图,想要修改成只在写入时检测,即去掉Read的勾选,需要将改断点删除然后重新设置一个,不能在原来的上面进行修改。

1.3. 遇到如下错误,一般是当前变量已经设置了断点,有些表达式不能重复设置断点

如下图的==

1.4. 断点数量

断点分为软件断点和硬件断点,硬件断点数量由单片机内部硬件决定,实测M3、M4、M7内核是8个硬件断点,软件断点是调试器根据一定算法,动态的设置硬件断点,或者在调试过程中动态修改FLASH,达到断点数量无限制效果。

  • 手头有个CMSIS-DAP(第一代DAP)实测不支持软件断点,只由硬件按断点,当断点超出后MDK会给出提示

CMSIS-DAP 实在是需要软件断点,可以手动在需要加断点的代码前加上 __asm(“BKPT 0”); 可以无限个,但是在正式代码中一定记得剔除

  • jlinkV9 支持软件断点,但是软件断点可能会动态修改flash内容(本质也是添加 __asm(“BKPT 0”); 语句,只是由jlink自动添加)

MDK5断点调试,有时候断点乱跳,就有可能是用jlink调试 断点设置多了,jlink会修改flash内容,这个时候如果直接拔掉jlink,flash中就会保存断点信息,会影响正常运行而且下次调试时如果没有更新程序,mdk里面不会显示该断点,但是断点信息已经在flash中了,执行到对应语句依然会暂停

1. 高级断点(条件/消息/数据)-Breakpoints:断点管理

1.1. Breakpoints 窗口:(手册

1.2. Breakpoints 菜单作用

    • Expression:表达式,即断点的条件,可以看到,手动设置的断点结尾为\123,表示在 main.c 文件的 123 行。这里支持基本的 >、<、==、!= 等操作符。(变量到达某条件)
    • Count:次数,表示运行多少次中断一次,手动设置的断点Count都是1。
    • Command:当达到断点时要执行的命令。在这个例子中,我们没有设置任何命令,所以默认为空。如果需要,可以在这里添加自定义命令,以便在达到断点时执行特定的操作。

Breakpoints 使用:

非变量的话可以提前打好断点再进断点管理,可以双击直接编写条件

1.3. 当断点的运行次数为某值时触发断点

1.3.1. 案例

以下面程序为例,在循环的第十次将程序停止。首先在循环中手动打一个断点:

点击Debug菜单,选择BreakPoints / 或者直接 Ctrl+B =>> 打开 Breakpoints 菜单

弹出下面菜单:

最上面的断点是手动打的,双击该断点,会看到 Expression 会显示该断点的信息,修改 Count 的值为 10,点击 Define,然后关闭该窗口。

这里说明一下:

  • Expression为表达式,即断点的条件,可以看到,手动设置的断点结尾为\123,表示在 main.c 文件的 123 行。这里支持基本的 >、<、==、!= 等操作符。
  • Count为次数,表示运行多少次中断一次,手动设置的断点Count都是1。
  • Command为命令,表示到达该断点时执行的命令,默认为空。

按照上面的设置,运行程序。可以看到,程序运行到断点时没有马上停下,而是在第10次才停下来:

1.3.2. 实现步骤:

  1. 在想要的地方打断点
  2. 点击Debug菜单,选择BreakPoints / 或者直接 Ctrl+B =>> 打开 Breakpoints 菜单
  • Breakpoints 菜单中存放了所有断点的位置

  • Breakpoints 菜单作用

    • Expression:表达式,即断点的条件,可以看到,手动设置的断点结尾为\123,表示在 main.c 文件的 123 行。这里支持基本的 >、<、==、!= 等操作符。
    • Count:次数,表示运行多少次中断一次,手动设置的断点Count都是1。
    • Command:当达到断点时要执行的命令。在这个例子中,我们没有设置任何命令,所以默认为空。如果需要,可以在这里添加自定义命令,以便在达到断点时执行特定的操作。
  1. 然后点击define,如果出现这个,不用管,选择是就行,然后选择close;

1.4. 当变量的读取或者写入次数为某值/被时触发断点

用Keil仿真调试查看变量内存地址被篡改的方法_keil查看变量地址-优快云博客

当改变量地址的值被篡改,则软件停止运行,便于查看内存溢出的现象

  1. 找个变量,将变量添加到watch窗口

  1. 右击该变量,选择Set Access Breakpoint at

  1. 在 Breakpoints 窗口中
    1. Expression 中是 变量名(如果是结构体要具体到成员)
    2. 在 Acess 中选择 读取 或者 写入
    3. 在 Count 中填写 读入 或者 写入的次数

勾选 Access 方式 Read 或 Write(写入)

设置 Count 值,点击 Define。

这里选择 Write,Count 值为 4,表示该变量第四次被写入时程序会停止

1.5. 当变量>、<、==、!=某值时触发断点

  1. 删除Expression中的内容,写入咱的判断条件,在Acess中选择Read或者Write,点击Define,运行程序

  1. 可以看到,程序将会在i==10的语句停下

1.6. 当 达到断点后/断点达到条件后 执行命令(一般是打印,输出在 Command 中不是串口!)

打印——可以搭配printf使用,只能输出字符串(中文都行),不能搭配变量使用

注意命令行中的cmd命令需要加\n,否则不会输出信息,而\是一个转义字符,需要\\才能输出\

记得要重定义 printf(可能)

printf(\"xxx\n\")

输出效果:

1.6.1. 到达断点后执行命令

  • 设置:其他都默认

  • 执行:

1.6.2. 断点达到条件后执行命令

  1. 设置断点条件

  1. 达成,执行

1.7. 直接从 Menory 中打断点(追踪内存值是否异常 [ 是否被人修改 ])

keil利用Breakpoints追踪内存值异常修改分析说明-电子工程世界

使用中并不能100%命中,不能过分依赖。

可以看是不是有人修改了某个不能修改的地址的值!!!

断点原理是检测固定RAM地址,那么直接从Menory找到对应地址设置断点也是一样可行的

其他案例:

  1. 查看内存地址

  1. 当访问者修改这片内存时,程序会中断,这时断点的位置为访问者(访问程序)

1.8. 当变量被读/写,且变化内存大小超过某值断点(不确定对不对)

2. Command 窗口:可通过命令实现大多数调试功能(有点麻烦)[Keil 的 cmd]

  • 输入的时候最下面会有提示

2.1. Keil 手册——Command Window

2.2. 相关语法

2.2.1. BS 命令:中断命令

BreakSet命令为指定的表达式 ( exp )设置断点。断点是程序地址或表达式,当它们为真时,会停止目标程序的执行或执行指定的命令(“cmd”)

断点的相关参数释义如下:

  • exp

是执行期间的一个地址或者一个表达式。

  • cnt

是一个表达式,用于确定在目标程序停止或执行指定命令之前满足断点条件的次数。默认计数值为 1。第一个断点触发后,计数被忽略。

  • cmd

是在断点触发时执行的 µVision 命令字符串。程序执行不会停止。用户定义函数可用于命令表达式。在函数中,您可以将系统变量 _break_设置为 1 以停止程序执行。未指定命令时,程序执行停止。

  • 表达式(exp)

在表达式中,常用到的就是程序变量(符号),程序变量是程序的变量。它们通常被称为符号或符号名称。表达式只支持简单的操作符,&, &&, <, , >=, ==, and !=。符号名称的一般形式是如下。

[\\ExecName][[\[Path/]Module][\Identifier]]
    • ExecName

表示在Target-Output-Name of Executable字段选项中定义的应用程序名称 ,必须以双反斜杠 (\\) 开头。

    • Path

表示源代码文件的路径。用斜杠 (/) 将文件夹与子文件夹分开。必须以斜杠 (/) 结尾。路径可以有绝对或相对符号。

    • Module

表示源模块的名称(*.c、*.cpp)。可以以Path 开头。必须以反斜杠 (\) 开头。可以使用调试命令从命令行窗口查询模块名称:DIR module。

    • Identifier

表示源代码对象。必须用反斜杠 (\)与Module分隔。当在应用程序中唯一时,可以独立使用并且没有反斜杠。标识符可以是:

代码行号。

变量(char、int、long、float、double)。

复合变量(数组、结构、文件)。

函数。

上述的有意义的组合。

使用案例:

2.3. 命令行使用案例(实现高级断点功能)

2.3.1. 命令窗中设置断点

首先将命令行的窗口打开,在View->Command Windows。

BS就是BreakSet的缩写,设置的时候就和断点的语法一样就行了,使用逗号隔开。因为Identifier这一选项已经说明如果符号唯一则前面的应用程序、路径以及模块都可以省略。命令输入时候会有提示的,会告诉你下一步应该输入的语法。使用命令行设置断点之后按下回车就可以了,在断点观察窗就可以看到详细信息了,如下图:

2.3.2. 变量何时改变的?

BS WRITE TmpData

当变量进行写的时候,程序会暂停。

2.3.3. 变量被改变了多少次才出现的问题?

BS WRITE TmpData,10

当变量进行写10次,程序会暂停

2.3.4. 当这个变量被设置成某个数据后,我想让程序暂停下来继续分析,该怎么办?

BS WRITE TmpData==10,1

当该变量为10时,程序会暂停。

2.3.5. 我不想让程序停下来,又没有串口重定位,又想输出一些额外信息,又该怎么办?

BS WRITE TmpData==10,1,"printf(\"TmpData\\n\")"

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值