尧图精选

MDK调试RTX5报osRtxInfo not found?五招破解符号丢失难题

🕒 发布时间:2026/10/1 1:36:26 📁 来源:尧图网络
在MDK里调试RTX5工程很多人都会有这么一段经历程序跑得好好的任务调度也正常但一点开调试模式里的OS窗口或者System Analyzer底部直接甩出来一行红字——os_Info: osRtxInfo not found。我第一次遇到这个提示时第一反应是工程坏了重装了CMSIS Pack、清理了缓存折腾了半天还是一样。后来把RTX5的源码结构、map文件、编译链接选项逐个过了一遍才彻底搞明白这个提示背后的真正逻辑。这篇文章我把能落地的解决方法整理齐全了从最常规的组件重装到链接器强制保留符号再到改源码加属性一共五种思路覆盖了MDK CMSIS RTX5调试的全部常见场景。不管你是刚接触RTX5的新手还是被这个问题卡了两天的老手按着文章里的顺序排查基本都能在十分钟内解决。1. 问题定位先搞清楚这行提示到底在说什么1.1 现场还原RTX5调试窗口到底报了什么先描述一下报错现场。在MDK里进入调试模式后点击菜单栏的View - Watch Windows - OS或者打开System Analyzer这时候在Output窗口或者RTX调试视图里会看到类似这样的信息os_Info: osRtxInfo not found注意一个关键细节这个提示不是编译错误也不是链接错误。工程编译能通过烧录后程序照常运行任务照样切换但就是看不到调试器给我们渲染出来的实时线程状态、运行队列、信号量列表这些信息。这也是最迷惑人的地方——很多人在网上搜“osRtxInfo undefined”出来的全是编译链接报错的处理方法跟这个完全不是一回事。这个提示的完整意义是MDK的调试插件在尝试读取目标程序里的RTX5内核状态结构时在ELF调试信息里找不到对应符号。它试图把一个名为osRtxInfo的全局变量从符号表里解析出来结果扑了个空。调试窗口是个空壳自然什么都显示不出来。1.2 根因拆解osRtxInfo是谁调试插件靠什么工作要明白为什么not found先得知道osRtxInfo是个什么东西。在RTX5源码中osRtxInfo是一个全局结构体变量类型是osRtxInfo_t定义在rt_CMSIS.c或者rt_System.c这类内核源文件里。这个结构体堪称RTX5的“大脑中枢”里面保存着当前正在运行的任务指针、任务就绪链表、等待链表、定时器链表以及内核锁状态和调度器状态等一切运行核心数据。MDK的RTX5调试插件不是靠猜的它启动OS调试视图时做的事情其实就是三步从当前工程的调试符号信息中查找osRtxInfo符号读出该符号对应的内存地址从目标芯片的RAM里读取这个地址上的结构体内容解析成线程列表、状态机等可视化信息。所以问题就很清晰了只要osRtxInfo这个符号在编译链接后没能留在最终ELF文件的符号表里调试插件第一步就挂了。那它为什么会丢最常见的元凶有以下几类。第一类是链接器的“尸体清理”功能。ARM Compiler 6 (ArmClang) 默认会在链接阶段移除未被引用的section像osRtxInfo这种内核内部变量如果用户代码里没有直接引用它而它的section又恰好被标记成可丢弃链接器就会把它整个从镜像里挪走。第二类是库模式导致的符号缺失。如果你在Keil RTE里选的是RTX5的Library模式系统用的是预编译好的库文件库的制作过程如果裁剪了调试符号或者库里对符号做了本地化处理最终也会出现找不到的情况。第三类是编译器优化导致的符号被改写。当用户代码中确实没有引用osRtxInfo但优化选项又开到-O2以上时编译器可能将全局符号转为局部符号甚至在符号表中直接抹掉为的是减少符号表体积。别急下面我们就按一个标准的排查顺序一步一步把这些坑填平。2. 排查三件套源码、map文件、编译选项2.1 先确认RTX5组件是不是真的加全了这不是废话很多RTX5工程是从老项目上改过来的RTE组件配置可能早就乱了。打开Manage Run-Time Environment窗口可以右键目标工程 - Manage Run-Time Environment展开CMSIS - RTOS2看看当前RTX5的显示状态。如果你发现RTX5前面的勾是虚的或者展开后没有出现任何源文件条目说明组件没有正确实例化。更隐蔽的情况是你同时勾了Library和Source两个选项或者工程里既有RTE自动生成的RTX_Config.c又手动拷贝了一份旧版RTX源码导致编译时符号定义混乱。一个健康的RTX5工程应该看到类似下面的文件列表CMSIS RTOS2 Keil RTX5 [Source] RTX_Config.c rt_CMSIS.c rt_Event.c rt_Message.c rt_Memory.c rt_Mutex.c rt_Scheduler.c rt_Semaphore.c rt_System.c rt_Thread.c rt_Time.c ...如果缺少了rt_CMSIS.c或rt_System.c那osRtxInfo十有八九根本没有被编译连接进来。解决办法也简单在RTE窗口先取消RTX5的勾选Apply并保存工程然后再重新勾上建议直接选Source模式点击确定让MDK把完整源文件重新生成到RTE目录。Source模式的好处是源码以你的工程编译选项重新编译符号表信息完整出问题也好排查调试阶段我一直推荐用Source模式而不是Library模式。2.2 翻map文件看osRtxInfo到底有没有进镜像源码组件检查完了下一个动作就是打开工程的map文件搜索osRtxInfo。这个动作能直接定位问题在哪一层。先确保map文件生成了。在Options for Target - Listing标签页勾选“Map File”选项重新编译然后在工程目录下的Listings文件夹找到.map文件用文本编辑器打开搜索osRtxInfo。搜索结果无非三种情况。情况一完全搜不到任何osRtxInfo。这说明该符号根本没有被链接进最终镜像基本可以判定是section被GC垃圾回收掉了或者RTX源文件压根没链接进来。这时候重点看编译和链接选项。情况二搜到了osRtxInfo但前面有标注local、static或者被放在某个弱符号区域。这说明符号存在但在符号表里被本地化了调试插件默认查找的是全局符号找到的局部符号不一定能被识别。情况三搜到了而且是全局符号后面有明确的内存地址和大小。如果map文件里已经有完整信息但调试窗口还是报not found那就要考虑是调试插件版本和RTX版本不兼容或者MDK的调试器配置没有正确识别RTX5。顺便说一句map文件里应该也能搜索到类似.bss.os.rtos.c的section名。如果有这个section但符号名改变了说明定义处被加了别名或修饰如果连section都找不到那基本就是GC错了对象。2.3 对编译器和链接器做一次体检既然定位到是符号“被弄丢了”那就要审查工程里的C/C编译选项和Linker选项。在Options for Target - C/C (AC6)标签里重点看编译器优化等级。调试阶段强烈建议先把Optimization设置为-O0或-O1高优化级别下编译器对全局符号的各种“自作聪明”操作往往是not found的来源之一。其次是Language / Code Generation区域里有一个“One ELF Section per Function”的选项这个选项如果勾上编译器会为每个函数和数据对象单独生成一个ELF section这么做本来是方便链接器做细粒度裁剪但副作用就是如果链接器同时开了“Remove Unused Sections”那些没有用户代码引用的内核数据section比如osRtxInfo所在的section就会被当成垃圾丢进回收站。Linker选项的检查同样关键。不同MDK版本Linker标签下可能直接显示“Remove Unused Sections”的勾选框。如果你的链接器使用了类似--gc-sections的参数建议先取消它重新编译看看问题是否解决。确认是GC问题后最优雅的做法是在Misc controls里加上保留参数--keeposRtxInfo对于ARM Compiler 6 (ArmClang)以上参数写在Linker标签下的Misc controls框里。如果你确认保留精准符号不起作用还可以退而求其次按section名保留--keep*(.bss.os.rtos.c)这个方式是把整个RTX5内核数据段都保下来粗暴但有效。3. 五种有效解法按优先级逐个试3.1 正规姿势用RTE重装组件杜绝手动丢文件先说最应该养成的习惯。我在带团队的时候反复强调凡是使用CMSIS-RTX5的项目一律通过Manage Run-Time Environment来管理组件不要有人手动从安装目录拷贝RTX的源码文件到工程里。手动拷贝的问题在于MDK的软件包版本和工程文件版本一旦不匹配轻则编译选项冲突重则RTE组件状态混乱。尤其是RTX5这种深度依赖CMSIS-Core的组件头文件路径、设备启动文件、链接脚本都需要配合。正确的重建步骤是这样的在RTE窗口里先取消RTOS2 - Keil RTX5的勾选点OK等MDK完成组件移除后再次打开RTE窗口重新勾选Keil RTX5并且选择Source模式点击OKMDK会提示生成/更新RTX_Config.c和RTX_Config.h等文件确认重新编译工程查看编译日志里有没有新增的rt_开头的源文件被编译按第2.2节的方法重新查看map文件搜索osRtxInfo。很多时候“重装一下组件”听起来普通实际上能解决大量隐藏问题。因为MDK在重新生成时会自动修正版本冲突、头文件路径问题和分散加载文件里的RTX段配置。3.2 调整编译优化和链接选项最常用、见效最快如果你不想大动干戈这个方法最多花两分钟。步骤很直接第一把C/C编译器优化级别设置为-O1或-O0。对于调试器变量查看-O0最稳但有些工程依赖高优化才能跑在预算内那就降到-O1大多数情况下-O1对RTX5符号表的影响已经很小。第二打开C/C标签取消勾选“One ELF Section per Function”。这一步能避免每个小对象独立成节被后续GC精准打击。第三在Linker标签的Misc controls里加入保留符号的命令--keeposRtxInfo然后重新编译。编译完成后直接去map文件里搜索osRtxInfo看到类似下面的条目就说明保留成功了osRtxInfo 0x200000b8 Data 4 rt_CMSIS.o(.bss.os.rtos.c)这里是我踩过的坑里的一个重点不同编译器版本的--keep语法不完全一样。ARMCC 5里的写法一般是--keep osRtxInfo而ARM Compiler 6里通常要求等号写法--keeposRtxInfo。如果你折腾了半天发现参数没生效不妨检查一下是不是栽在这里。3.3 源码模式 retain属性强制保住符号如果你用的就是RTX5的Source模式那第三个方案更彻底修改RTX源码中osRtxInfo的定义加上编译器的保留属性。以ARM Compiler 6为例打开rt_CMSIS.c找到osRtxInfo的定义处。原始代码大致是osRtxInfo_t osRtxInfo __attribute__((section(.bss.os.rtos.c)));把它改成osRtxInfo_t osRtxInfo __attribute__((used, retain)) __attribute__((section(.bss.os.rtos.c)));其中used属性告诉编译器即使看起来没被引用也保留这个对象retain属性告诉链接器这个section不可以被垃圾回收。这是ARM Compiler 6下面最直接的对抗GC的手段。修改完成后重新编译链接再查看map文件。正常情况下即使你开启了Remove Unused SectionsosRtxInfo也会被完好保留下来。这个方法也有一个需要小心的地方如果你以后在MDK里更新CMSIS Pack或者重新应用RTE配置MDK可能会用包里的原始文件覆盖你手动改过的文件。所以改完源码后最好做个备份或者在工程文档里留个记录免得下次升级Pack之后又莫名其妙复发。3.4 在代码里制造一次“真实引用”有些场景比较特殊比如你不能改RTX源码源码可能来自第三方封装库又没法随便关GC那么还有一个非常实用的土办法在用户代码里主动引用一次osRtxInfo。原理很简单链接器GC的依据是“是否被引用”。你只要让某个不被GC的代码段引用它它就保住了。写一个简单函数#include cmsis_os2.h extern osRtxInfo_t osRtxInfo; volatile uint32_t rtx_os_info_anchor; void rtx_os_info_keep(void) { rtx_os_info_anchor (uint32_t)(uintptr_t)osRtxInfo; }然后确保这个函数在某个地方被调用或者在main函数里调用一次rtx_os_info_keep();这个方法相当于告诉链接器看你的程序里真的有一行代码在用这个变量别把它删了。它不需要修改任何RTX源码适合代码结构不便改动的情况。不过要注意一个小细节这个函数最好保留在main.c或某个不会被高优化裁剪的文件里而且rtx_os_info_anchor明显要声明成volatile防止编译器认为赋值是死代码直接优化掉。我实际验证过如果是-O2优化普通值的赋值真的会被优化干净用了volatile才稳定。3.5 升级MDK与CMSIS Pack版本如果你试了上面几种方法还是不行或者你用的是很早版本的MDK那就要考虑版本匹配问题。MDK的RTX5调试插件对osRtxInfo的解析是内置在软件里的它不是读取任意结构体就能展示而是按照特定版本的布局来解析。RTX5在演进过程中osRtxInfo结构体内部字段是有过调整的调试插件版本过旧解析不了新布局也会出现类似not found或者即使找到了也不完整的情况。我没有办法追溯从哪个版本开始出现布局变化但这些年用过之后我个人的判断标准是MDK 5.27以下的版本搭配CMSIS Pack 5.8.0以上的RTX5出问题的概率明显更高。解决办法说来简单但也麻烦在Keil官网下载最新版MDK或者至少在Pack Installer里把CMSIS Pack更新到当前项目支持的较新版本更新后重新编译再进调试。如果你所在的项目对编译器版本有强制要求不能升级那么退而求其次保持MDK版本不变单独把CMSIS Pack换成与MDK调试插件兼容的旧版RTX5也值得一试。我曾经在一个老项目上把CMSIS Pack从5.9.0回退到5.6.0问题立竿见影地消失了。4. 实操演示从一个翻车现场到正常OS调试窗口4.1 复现问题默认配置新建RTX5工程为了把整个排查过程讲得更直观我带大家完整走一遍。假设我在STM32F407上新建了一个基础工程使用STM32F4xx_DFP勾选了CMSIS里的RTX5组件默认用的就是Library模式优化等级保持默认的-O0。编译烧录都没问题但进入调试后打开RTX OS视图输出窗口弹出osRtxInfo not found。第一步打开map文件搜索osRtxInfo结果搜索了整个文件只有零散几条rtx相关的函数名完全看不到osRtxInfo变量条目。这基本坐实了符号未进入镜像。第二步回头看RTE组件状态勾选的是“Keil RTX5”但不是Source模式展开后只有RTX_Config.c一个文件。这就合理了Library模式下RTX5内核是一个静态库文件库内部如果对符号做过裁剪用户根本无法干预。4.2 逐步排查按照章节2的流程走一遍这个场景非常适合演示因为问题出在Library模式。我花了大概五分钟把组件切换成Source模式右键工程 - Manage Run-Time Environment - 取消RTX5 - Apply重新打开RTE勾选RTX5并选择Source确认后MDK生成了完整的rt_CMSIS.c、rt_System.c等源码文件。重新编译后我又去map文件里搜osRtxInfo。运气不错这次能搜到了但还是有些奇怪符号出现在了“Local Symbol”区域不是全局符号表区域。这说明即便切换到Source模式由于编译器优化选项里可能有隐藏的符号裁剪还是没能让它以全局身份出现在调试符号表里。紧接着我做了两件事把C/C标签下的Optimization从默认改成-O0然后再改回-O1并且检查“One ELF Section per Function”是未勾选状态在Linker标签的Misc controls里加入了--keeposRtxInfo再次编译map文件里的osRtxInfo条目终于规规矩矩地出现在全局符号区带有明确的RAM地址。4.3 最终修复应用第3章的组合拳进入调试模式打开OS调试窗口这次线程列表、任务状态、运行队列全都出来了。实际在这个项目中我最后的处理是两步组合保留Source模式RTX5内核的源码文件参与编译Linker保留参数--keeposRtxInfo。从工程维护角度看这样既不用改RTX源码也不会在Pack升级时被覆盖算是最好的平衡。如果你遇到的情况非要走源码级修改不可——比如团队其他人总是误关Source模式或者构建脚本会重写链接参数——那就按3.3节的方法直接在rt_CMSIS.c里加上used, retain属性。这属于最后一道保险基本能保证在任何构建环境下符号都不会丢。5. 常见问题速查与最后的避坑技巧5.1 问题排查速查表我把自己和身边同事在实际开发中遇到的同类问题整理成了一张表方便你在不同场景下快速对号入座。症状最常见原因解决动作调试窗口报osRtxInfo not foundmap中无符号Linker GC移除了未引用section加--keeposRtxInfo或取消Remove Unused Sectionsmap中无符号同时编译日志缺少rt_开头的源文件RTX5组件未正确加载或用了Library模式用RTE重新安装选Source模式map中符号存在但提示not found符号是local/static调试插件读不到降低优化等级或用retain属性强制为全局符号存在且是全局仍打不开OS视图MDK调试插件与RTX5版本不匹配升级MDK或回退CMSIS Pack版本程序能跑但调试窗口显示内容全是错误/乱码配置了分散加载但漏了RTX段检查.sct文件确保RTX段被正确放置在RAM区通过源码方式加retain后Pack更新又复发源码被Pack覆盖修改后备份或记录修改位置更新后重新修改5.2 几个别人踩过的坑先说一个最常见的坑在Linker标签里添加--keeposRtxInfo之后如果编译报错提示参数无效千万别急着怀疑参数写错。先确认你的编译器版本ARMCC 5和ARM Compiler 6的armlink参数语法有差异有些版本不认等号。遇到这种问题最简单的验证方式是先在Output窗口看是哪个阶段报错如果是armlink报的就对参数格式做调整。第二个坑是分散加载文件。有些STM32工程为了调整内存布局会自定义.sct文件。这时候如果.sct文件只定义了常规的RW、ZI区没有专门为RTX5的.bss.os.rtos.c段预留位置即使符号保留了也会被链接器安排到一个预期外的地方轻则调试窗口数据不对重则一跑就进HardFault。我通常的建议是能不用自定义分散加载就别用RTX5自己默认的布局很成熟实在要自定义务必在map文件里检查所有os.开头的section都被放置到合法RAM区域。第三个坑是关于多核或虚拟化工程。如果你在调试一个包含多个RTOS实例的工程每个核都有自己的osRtxInfo那这个排查思路要稍微调整一下你要找的是当前调试核对应的那个osRtxInfo符号而链接器保留时也注意符号名冲突。这种情况下map文件可能同时出现osRtxInfo和osRtxInfo_1调试插件未必能自动识别最稳妥的是按核切换调试窗口前先确认当前ELF文件里符号表的完整性。最后再说一个实用的小技巧。哪怕osRtxInfo not found的提示一直挥之不去你其实还可以在调试模式的Watch窗口里手动添加表达式比如输入(uint32_t)osRtxInfo。如果这时表达式能计算出值说明符号其实存在只是调试插件没有正确解析如果表达式直接报错那才说明符号彻底丢了。这个小细节能帮你快速区分“符号缺失”和“插件识别问题”排查方向完全不一样。RTX5的调试窗口问题说难不难说简单也不简单。我在实际项目里见过的这类问题九成以上都能通过“先看map、再调链接、最后改源码”这个顺序解决。调不出来的时候别急着怀疑玄学先把map文件打开把osRtxInfo搜一遍这一步能帮你过滤掉一半的无效操作。希望这篇文章能帮你少走几步弯路早点看到完整的线程状态列表。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →