在进行TRACE32调试的时候,断点并不是随便点一下就可以的,因为断点的位置、符号文件、代码运行的区域,还有优化等级以及变量所在的作用域,这些因素都会对后面的调试结果产生影响;当遇到断点设置和变量查看的问题时,作者建议把这两者放在同一个流程里去排查,也就是去检查断点能不能设置成功、程序能不能停下来、停下来之后具体在哪个地方、当前的栈帧是否正确,以及变量是不是被编译器优化掉了。
一、TRACE32断点怎么设置
在TRACE32里面,大家经常使用的是程序断点,也就是让处理器在执行到某些特定的函数、内存地址或者代码行的时候停下来;在设置断点之前,用户需要先确定符号文件是不是已经加载好了,否则的话,函数名和代码行号可能就没办法被软件识别出来。
1、按函数名设置断点
如果软件里的ELF符号是正常的,那么最普通的办法就是直接在函数的入口地方去设置断点。当然也可以把名字换成自己要看的功能函数。
这种设置方法比较适合用来调试应用层的代码、驱动的初始化地方,或者是任务的入口;设置好了之后,用户可以把【Break.List】这个窗口打开,去看看里面的断点列表,确认断点是不是已经处于开启的状态。
2、按地址设置断点
在有些启动的阶段,系统还没有加载源码符号,或者说程序需要停在异常向量、复位的地方以及汇编的入口处,这时候直接使用地址来下断点会更方便。
这种办法不需要依赖函数的名字,但是要求用户知道准确的地址;比如在调试复位句柄、引导程序跳转的地方,或者硬件错误入口的时候,直接用地址来设置会比较直接。
3、按源码文件和行号设置断点
在源码级别的调试能正常工作时,用户直接在代码窗口里双击行号就能设置断点,或者也可以用命令通过文件和行号来设置。
这种写法的用处是可以放在脚本里面搞自动化调试,比如在.cmm脚本文件里提前把好几个关键的断点都写好;在一些技术问答网站的示例里,也能看到这种用完整路径或者文件名加行号来设断点的写法。
二、TRACE32断点命中后变量值怎么看
当断点停下来之后,处理器就已经停在了某个具体的环境里面,在这个时候去查看变量才是比较准确的;不过对于全局变量、静态变量、局部变量,还有结构体和指针这些不同的数据,查看它们的办法也是不一样的。
1、用Var.View查看变量
最普通的查看办法就是利用Var.View这个命令去直观地看某个变量:
Var.View counter
如果遇到结构体类型的变量,那就可以直接把整个结构体都显示出来:
Var.View g_systemState
要是只关心这里面的某一个成员,把成员的路径写出来也是可以的:
Var.View g_systemState.mode
面对数组的时候,既可以直接去看数组的名字,也可以指定看某一个下标的数据:
Var.View buffer
Var.View buffer[0]
如果看到变量显示的格式不容易看懂,用户可以在变量上点击右键并选择【Format】,从而把显示方式调整为十进制、十六进制或者把类型展开;在整个变量命令的体系里面,其实包含了许多像查看、观察、局部变量显示以及表达式接口等通用的工具。
2、用Var.Watch长期观察变量
在调试那些循环跑的任务、状态机或者通信收发的流程时,用这个观察窗口会比每次都用手动敲命令方便很多;当断点停下后,用户可以观察这些变量有没有变成想看到的值,然后配合单步执行或者运行命令,去进一步确定代码走得对不对。
若是想要看清变量刚刚发生的改变,还可以利用高亮功能来显示;调试软件支持在查看和观察的窗口里,使用特定的高亮标记来把发生变化的变量突显出来。
3、用Frame和Stack确认局部变量上下文
局部变量并不能随时随地都被看到,因为它是跟当前函数的栈帧绑定的,同时也需要编译器把调试信息保留下来。
如果断点此时停在函数的外面,用户去查看函数里面的局部变量时,软件往往会显示不出来,或者显示出来的值根本就不是对应的那一次调用的情况。
三、断点命中后变量值不对怎么办
虽然断点已经停下来了,但是变量却显示成了0、乱码,或者是提示被优化掉了,甚至每次刷新数值都不一样,这种情况在调试时是经常发生的。这倒不一定是调试工具本身有毛病,很多时候是因为符号文件、编译器优化、缓存或者是运行环境没有对齐导致的。
1、检查变量是否被编译优化
要是工程在编译的时候选了比较高的优化等级,局部变量就很可能会被直接塞进寄存器里,或者被优化抹去了,也有可能被编译器进行了合并。这样就会导致用户在源码里能看到这个变量,但在调试器里面却没办法稳定地把它显示出来。
2、检查当前是不是正确的运行上下文
在多核或者多任务的系统环境里,看错运行环境导致变量不对是很常见的;比如断点虽然停下来了,但实际上停在了别的核心上,或者当前的系统任务并不是用户以为的那个,这样的话局部变量自然就对应不上了。
如果是带操作系统的工程,用户还要确保操作系统相关的调试插件已经配置妥当了;否则虽然调试器可以把程序停下来,但是任务、栈帧以及局部变量这些环境信息可能没办法完整地显示出来。
3、检查缓存和运行时访问影响
有些时候变量的值看起来不对,其实并不是变量真的算错了,而是调试器读到的内存数据和处理器实际在用的缓存数据是不一样的;特别是在一些特定的多核芯片、带缓存的系统或者多核共享内存的场景下,这种由于缓存导致的问题会特别明显。
总结
关于TRACE32断点怎么设置以及断点命中后变量值怎么看的问题,核心的解决办法就是先让断点准确地卡在目标代码的位置上,然后在正确的环境里去读取变量。设置函数断点可以用Break.Set加名字,地址断点就用Break.Set加地址,源码行断点则可以用文件名配合行号来完成。在程序停下来之后,大家通常会配合使用变量查看、观察窗口、局部变量窗口以及调用栈窗口来一起看数据。把这些步骤都理顺了之后,用TRACE32看断点和变量才会变得比较顺手。