劳特巴赫TRACE32多核调试:SMP/AMP/iAMP建模与Trace对齐 简介《Trace 劳特巴赫 多核系统调试方法详解》是一份聚焦SMP、AMP与iAMP三种多核调试模式的中文技术资料面向嵌入式软件开发、硬件调试工程师及具备一定基础的中级读者用于理解多核处理器在TRACE32环境下的调试配置、核分配管理、同步控制和问题排查。资料共1个PDF文件压缩包约18.97MB内容围绕启动配置、核的分配与管理、常用命令、符号表差异及实际芯片案例展开涉及NXP S32G274A、英飞凌TC275TF、big.LITTLE等典型平台。读者可从中获得SMP、AMP与iAMP的概念对比掌握Core.assign、Core.number等命令的使用要点了解多核显示、核状态查看与切换方法并熟悉不同架构下的调试流程和最佳实践。已有352人学习适合需要在项目中提升多核调试效率、快速建立调试思路并解决实际问题的工程师参考尤其适用于多核启动、核间同步、子系统划分及AMP独立调试等场景。1. 从一颗 SoC 上跑三套软件说起劳特巴赫多核调试到底在解什么问题一块域控板卡上四核 Cortex-A 跑 Linux一颗 Cortex-R 跑安全岛 RTOS还有一颗 Cortex-M 管外设时序。板子上只有一条 JTAG 链路引出来。系统偶发卡死时你既想看 A 核的调度器状态又想知道 R 核的锁步有没有走偏还想抓 M 核那条异常中断的来龙去脉。这不是接个调试器能解决的问题而是一个调试访问端口怎么同时服务三套互不相干的软件栈。劳特巴赫 TRACE32 在这类场景里的角色更像一个多核会话管理器它把每一个可调试实体建模成一个 CORE再按核之间的软件关系和硬件路径关系决定它们是共享一套上下文还是各持一套。SMP、AMP、iAMP 这三组词描述的就是这份建模关系的三种形态选错了症状不是连不上而是断点飘核、符号串台、trace 时间戳对不齐——排查起来比连不上更费时间。这篇内容面向 SoC 底层软件、BSP 驱动、安全核验证这几类工程师。2. SMP、AMP、iAMP 的判定标准与 TRACE32 建模选型2.1 三种模型在运行时的真实差别SMP 的特征是一套软件、多份执行。多个同构核共享同一个 OS 实例、同一份物理内存映射、同一套页表。Linux SMP、Zephyr 的 SMP 配置、FreeRTOS 的多核端口都属于这一类。它对调试提出的核心诉求是我设的断点应该哪里执行到都拦因为我根本不关心某个函数最终跑在哪颗核上。AMP 的特征是多套软件、各管各的。A 核跑 LinuxR 核跑 RTOS两者的链接脚本、向量表、启动入口完全不同甚至指令集都不同。这种情况下调试 A 核时绝不能把 R 核一起停住——R 核可能正在跑安全监控或者电机换相停几毫秒就是事故。iAMP 容易被误解成AMP 的子集其实它描述的是硬件路径而不是软件模型。同一个 SoC 内部的多个核共享同一个调试访问端口典型是共享一个 DAP挂在不同的 AP 上但每一核的软件栈相互独立。它和跨芯片 AMP 的真正区别在于跨芯片时你有两条物理链路可以真正并行操作iAMP 只有一条链路所有核的调试动作都在这一条链路上排队切换核就是切换链路的事务目标。2.2 TRACE32 侧的三个建模对象TRACE32 里最基础的概念叫 CORE。SYStem.CONFIG.CORE n.是一条作用域切换命令它本身不产生动作只是声明接下来的配置语句归属于第 n 个核。这一点决定了 .cmm 脚本的写法多核启动脚本不是一条自上而下的配置流而是一串按核分块的配置段落。很多人第一次写多核脚本踩的坑就是忘了在某一段开头写作用域结果后一段配置全部覆盖到前一个核上。顺着这个作用域还要理解主从关系。SYStem.CONFIG.Slave ON|OFF决定该核是主动去建立调试链路还是被动跟随别的核已经建立的链路。SMP 场景下通常只需要一个 master其余全部 slave否则多个核会争抢同一个访问端口现象是 attach 阶段随机超时重试几次又能连上非常难定位。第三个对象是访问端口本身。AMP 跨器件时每个器件对应独立的调试器物理接口config.t32 里会体现为不同的 PBI 配置iAMP 共享一个 DAP 时靠 AP 编号和核索引加以区分。所以在写脚本之前先确认目标板到底有几条物理链路这个判断错了后面所有命令都是在错误的树上配置。2.3 探测先行配置之前先看调试器认到了什么不要凭数据手册猜核数。连上之后先执行两条探测命令让调试器把它实际看到的东西打印出来; 探路脚本不改变任何目标状态 SYStem.CONFIG ; 不带参数时会列出当前 SYStem 树下的可用配置项 CORE.ASSIGN ; 打印核分配表已连接哪些核、各自归属哪个组SYStem.CONFIG的价值在于版本差异。不同 TRACE32 版本、不同芯片的 SYStem 子树并不完全一致与其照抄别人的脚本报错不如让调试器把可用项列出来按提示补全。CORE.ASSIGN则回答另一个问题板子上明明有四核为什么只认到两个——常见原因是另外两颗核的时钟被门控了或者复位还没释放。2.4 三模型对照与判定流程维度SMPAMPiAMP软件栈一套 OS 实例每核独立每核独立符号表共享一份每核独立加载每核独立加载物理链路同一 DAP各自端口或器件同一 DAP多 AP断点默认作用域组内全拦单核单核注意 AP 切换主从配置一 master 多 slave各自 master一 master 多 slave最典型故障断点飘核、单步被锁拖住复位与时钟耦合切核后地址视图没跟着换落到判定上按顺序问三个问题就够了第一多个核是否运行同一个 OS 映像是则偏向 SMP第二各核能否独立复位、独立停止不能则说明存在耦合必须按 iAMP 的思路分核控制第三调试访问端口是一个还是多个只有一个就要提前规划分时复用的顺序。3. SMP 调试流程一套符号带宽多个核的最小可行配置3.1 把连接配置和会话配置拆开放config.t32 负责调试器怎么接到主机.cmm 脚本负责连上目标以后怎么建立会话。多核项目里把两者混在一起写换一块板子就要改两处是维护成本的主要来源。OS IDSoCDebug SYS2000 PBIUSB USBUSB0 PRINTERWINDOWS SCREEN FONTSMALLPBI指定调试器与 TRACE32 软件之间的物理接口类型USB0是设备实例号接多个调试器时需要区分。SYS2000是本地通信端口同一台主机跑多份 TRACE32 实例时必须错开。这几个参数与目标有几个核完全无关SMP 和 AMP 通用所以它们应该待在 config.t32 里而不是脚本里。3.2 四核同构 SMP 的最小启动脚本; smp_up.cmm —— 四核同构 Cortex-A运行同一个 Linux 映像 SYStem.CPU CortexA53 ; 同构核只声明一次 CPU 类型 SYStem.CONFIG.DEBUGPORTTYPE DAP ; 走 CoreSight DAP SYStem.CONFIG.CORE 0. ; 作用域以下配置只作用于 core0 SYStem.CONFIG.Slave OFF ; core0 作为 master负责建立访问链路 SYStem.CONFIG.CORE 1. ; 切到 core1 SYStem.CONFIG.Slave ON ; 从核跟随主核不自己抢链路 SYStem.CONFIG.CORE 2. SYStem.CONFIG.Slave ON SYStem.CONFIG.CORE 3. SYStem.CONFIG.Slave ON SYStem.Mode Attach ; 不断电挂载保留现场 CORE.ASSIGN ; 确认四核都被识别 Data.LOAD.Elf vmlinux /NoClear ; 四个核共享同一份符号 TASK.ACTIVATE Linux ; 打开 Linux 任务感知这段脚本的逻辑主线是先定作用域再定主从最后一次性挂载。SYStem.CONFIG.CORE n.后面的点号不能省它是作用域的结束标记漏掉会导致后续语句归属错误。Slave ON在 SMP 场景几乎是标配因为四个核跑的是同一套代码让它们各自去竞争同一条调试访问链路没有任何收益只会让 attach 阶段的成功率下降。SYStem.Mode Attach和SYStem.Mode Up的区别值得单独记住Attach 不对目标做复位直接挂到当前运行状态适合调试已经在跑的系统Up 会走一遍复位序列。在 SMP 组里这两条命令都作用于整组不存在只复位 CPU1的用法。符号加载放在 Attach 之后是因为 Linux 的 vmlinux 是位置相关的地址翻译依赖当前 MMU 状态。如果先加载符号再挂载碰上系统正在切换页表的窗口期符号地址会偏移一截后面设断点全部落空。3.3 组断点的行为与单步的锁依赖问题SMP 组里最需要提前建立心理预期的是断点语义。Break.Set addr默认是组断点任意一颗核执行到该地址都会触发并且触发后组内其他核一起停下。这正是 SMP 调试的价值所在——你不需要关心代码最终跑在哪颗核上。但它同时是最大的坑你以为在调 CPU0 的驱动代码实际命中它的可能是 CPU2因为调度器把那个线程迁过去了。判断当前命中的是哪颗核最直接的办法是看状态栏的 active core或者先跑一次CORE.ASSIGN记住核列表。要进一步确认线程位置用TASK.List看该线程当前挂在哪个核上必要时临时把线程的 affinity 钉住让它在调试期间不迁移。单步在 SMP 下还有一个特有现象Step只作用于当前选中的核其他核保持停止。如果目标代码路径上有一把自旋锁单步时你会看到程序卡在 spinlock 里不动因为持锁的那颗核没在跑锁永远不会释放。这不是调试器的问题是单核单步破坏了多核执行语义。碰到这种情况要么改用组单步要么先确认这段临界区不依赖别的核推进。现象根因处置断点命中核与预期不符组断点加线程迁移查TASK.List临时钉 affinity单步卡在自旋锁持锁核被停改用组单步或跳过临界区断点提示无法写入代码区在 cache 中被改写先 flush或改用硬件断点符号地址整体偏移MMU 状态与加载时机不匹配Attach 后再Data.LOADattach 随机超时多个核同时争抢访问链路只留一个 master其余 slave3.4 符号与内存视图的一致性维护SMP 下四个核共享一份页表理论上符号加载一次就够。但实际项目里经常见到有人对每个核都跑一遍Data.LOAD.Elf vmlinux结果是符号表被重复合并查询变慢、同名符号出现多份、断点解析到错误地址。正确做法是只加载一次切核不重载。另一类问题是内核模块。模块的地址是运行时分配的必须等系统起来之后再加载符号而且模块卸载后要记得清理否则符号表里会残留一批指向已释放内存的条目查询时给出误导性的结果。4. AMP 与 iAMP 调试流程多核各自持一套上下文的配置方法4.1 先分清是跨芯片 AMP 还是片内 iAMP判断依据是物理链路数量。板上有两颗独立芯片、各自引出调试口那是 AMP两套配置互不干扰可以同时操作。如果所有核都在一颗 SoC 里共用一组调试引脚那就是 iAMP所有操作串行排队切核等于切换访问目标。这个区分直接影响脚本结构。AMP 场景下你写两份独立的 .cmm各自SYStem.CPU、各自 AttachiAMP 场景下是一份脚本多个作用域分段段与段之间有明确的切换点。把 iAMP 当 AMP 写最常见的报错是第二次SYStem.Mode Attach把已经挂好的核一起带重启了。4.2 同一 DAP 下多核独立上下文的完整脚本; iamp_up.cmm —— A核 Linux R核 RTOS M核 裸机共享一个 DAP ; ---- 第一段A 核作为 master 建立链路 ---- SYStem.CPU CortexA53 SYStem.CONFIG.DEBUGPORTTYPE DAP SYStem.CONFIG.CORE 0. SYStem.CONFIG.Slave OFF SYStem.Mode Attach Data.LOAD.Elf vmlinux TASK.ACTIVATE Linux ; ---- 第二段R 核异构必须重新声明 CPU 类型 ---- SYStem.CONFIG.CORE 1. SYStem.CPU CortexR52 ; 异构核切换时必须重设否则按 A 核解码 SYStem.CONFIG.Slave ON SYStem.Mode Attach ; 从核单独挂载不带复位 Data.LOAD.Elf safety.elf ; ---- 第三段M 核裸机无 OS 感知 ---- SYStem.CONFIG.CORE 2. SYStem.CPU CortexM7 SYStem.CONFIG.Slave ON SYStem.Mode Attach Data.LOAD.Elf m7_fw.elf这段脚本里最关键的一条是第二段的SYStem.CPU CortexR52。很多人以为 CPU 类型在一份脚本里声明一次就够结果 R 核的指令被按 A 核的方式解码反汇编窗口显示出来的全是乱码断点也设不准。只要核的架构不同切换作用域之后必须重新声明。SYStem.Mode Attach在每个从核上单独执行这一点和 SMP 不同。SMP 是一次 Attach 覆盖整组iAMP 是每核一次。如果从核的挂载失败报错只会出现在从核那一段前面的 A 核不受影响这也算是个排查上的便利。4.3 多核同步启停与实时性保护TRACE32 是当前核视角的调试器所有窗口、命令、断点都跟着 active core 走。CORE.SELECT n切换视角之后反汇编窗口、寄存器窗口、内存窗口显示的都会换成那颗核的内容。这一点在 iAMP 下尤其要注意因为切核之后地址视图也变了——A 核看到的是虚拟地址M 核看到的是物理地址同一个数字在两颗核上代表完全不同的东西。启停策略上需要保护实时性的核不要参与全停。做法是先CORE.SELECT到需要停的核再执行Break这样其他核继续运行。反过来如果确实需要多核同时暂停来观察一致性用组操作但要提前确认那些实时核停下来的后果可接受——在安全岛场景里这个确认往往需要和系统负责人过一遍。现象可能原因处置从核 Attach 超时从核时钟被门控或未出复位查时钟控制器与复位寄存器状态符号加载后地址错乱active core 没切换到目标核先CORE.ASSIGN再 load断点只在单核生效断点作用域跟随 active core切到目标核重设设置 A 核断点时 R 核被停跨核复位或时钟存在耦合关闭复位联动分核操作反汇编窗口全是乱码异构核未重设 CPU 类型切核后重新SYStem.CPU4.4 调试动作的作用域检查清单每执行一次可能改变目标状态的命令之前按这个顺序确认当前 active core 是哪一颗、这条命令的作用域是单核还是整组、目标核当前是否在跑、停止它会不会影响别的核的时序。这四条不需要写进脚本但值得在团队里形成固定的作业习惯——尤其是在 iAMP 这种一条链路服务多个核的结构下误停一颗实时核的代价通常比多花十秒确认要大得多。5. 进阶多核 trace 触发与跨核时序对齐跑通 attach 和断点之后真正能定位疑难问题的能力来自 trace。多核 trace 有一个绕不开的物理约束每颗核的 trace 源ETM、PTM 之类最终汇聚到有限的 trace 输出带宽上核越多每颗核分到的带宽越少。抓全四个核的完整指令流和抓一个核的完整指令流能覆盖的代码范围完全不是一个量级。所以多核 trace 的第一原则是用触发缩小窗口而不是全量录下来。典型做法是让一颗核的事件去触发另一颗核的采样。比如 A 核进入某个异常处理入口时把 R 核前后的执行流录下来; 多核 trace 触发配置 SYStem.CONFIG.CORE 0. Trace.METHOD Onchip ; 使用片上 trace buffer不依赖外部探头 Trace.AutoArm ON ; 程序启动即开始采集避免漏掉早期事件 Trace.Trigger 0x80001234 ; A 核异常向量入口作为触发点 SYStem.CONFIG.CORE 1. Trace.METHOD Onchip Trace.AutoArm ON ; 从核同步开抓等待交叉触发条件Trace.AutoArm ON的含义是让采集在程序恢复运行的那一刻自动开始而不是等人手动下命令。多核场景下这条几乎必须打开因为两个核的采集起点差几微秒后面的时间轴对齐就无从谈起。Trace.Trigger指定的是一个地址当任一被使能的核执行到该地址时触发缓冲区冻结。采集完之后Trace.List用来看指令流Trace.STATistic用来看核间的执行占比分布。跨核时序对齐是最容易出问题的一环两颗核的时间戳可能来自不同的时钟域如果只看各自的时间轴会得出两颗核同时执行了同一段代码这种明显不成立的结论。验证对齐是否可信有一个便宜又好用的办法——让两颗核在同一时刻翻转同一个 GPIO然后看两条 trace 里这个 GPIO 写事件的时间差。差值是固定偏移就说明只是时钟域不同补偿掉即可差值是抖动的说明采集本身有丢包得先回去调带宽和触发窗口。带宽不够时的取舍顺序先砍掉不需要的核再砍 data trace 只留指令 trace最后才考虑降低采样密度。反过来做往往是把关键的那笔数据 trace 砍掉了问题反而看不见。本文还有配套的精品资源点击获取