executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
re-rtosRTOS 结构分析:FreeRTOS/ThreadX/Zephyr/RT-Thread/VxWorks/QNX/RTEMS/NuttX/eCos/µC-OS/SYS-BIOS/SAFERTOS/CMSIS-RTX5/T-Kernel/TOPPERS/OSE/INTEGRITY/ARINC 653/PikeOS/Deos 运行模型判定、任务表与 TCB 定位、内核对象还原、按任务拆分反编译。触发词:RTOS、FreeRTOS、ThreadX、Zephyr、VxWorks、QNX、RTEMS、NuttX、eCos、µC/OS、Micrium、SYS/BIOS、SAFERTOS、CMSIS-RTX5、T-Kernel、TOPPERS、ITRON、OSE、OSEck、Nucleus、INTEGRITY、ARINC 6…
Independent GitHub snapshot · Automated classification · Original documentation governs
各内核形态不同(链表任务表 / 编译期设备图 / 全局符号环境 / 用户态 server / 构建期配置),但共性是:注册模型决定你能看到什么——一个函数"没有直接交叉引用",在不同 RTOS 上可能分别意味着"正常(linker 注册)"、"正常(装载时符号解析)"、"正常(用户态 server)"或"真的没被引用"。
所以顺序永远是:先判这个 RTOS 的运行与注册模型,再谈任务与内核对象。 </CORE RULE>
| 平台 | "驱动/服务"在哪 | 注册与发现机制 | 先判什么 |
|---|---|---|---|
| FreeRTOS / ThreadX / RT-Thread | 与内核同镜像;任务 + 内核对象表 | 显式创建 API + 静态对象实例 | 任务表/TCB(本主文档) |
| Zephyr | 与内核同镜像,但设备图在编译期生成 | devicetree + Kconfig + iterable sections、SYS_INIT | 是否 linker 注册([[zephyr]]) |
| VxWorks | 两种:DKM 内核态 / RTP 用户态 | DKM 动态加载 + 全局符号环境;RTP 走标准 ELF/.so | 先分 DKM 还是 RTP([[vxworks]]) |
| QNX | 用户态 server;网络驱动是 io-pkt 内的共享对象 | pathname 注册 + 消息传递 | 先判形态([[qnx]]) |
| RTEMS | 与内核/应用同处单一地址空间 | 构建期配置(confdefs.h)+ 设备驱动表 + 运行期链接器 | 配置与驱动表([[rtems]]) |
| INTEGRITY / ARINC 653 / VxWorks 653 / PikeOS | 分区(空间 + 时间 + 资源三域) | 静态配置;分区级 major frame / partition window + 分区内调度 | 先对齐分区窗口与分区模式([[partitioned-rtos]]) |
| NuttX | 与内核同镜像或分离,取决于构建方式 | 由构建模型决定:FLAT 直接调用 / PROTECTED 走 syscall proxy / KERNEL 走 MMU | 先判 FLAT / PROTECTED / KERNEL([[nuttx]]) |
| eCos | 与内核同镜像;中断处理分三层 | ISR → DSR → thread,各层同步机制不同 | 判断工作落在哪一层([[ecos]]) |
| ThreadX Modules | 常驻内核 + 可动态装载模块 | module preamble + request ID 经软件 dispatch | 先认 module ABI([[threadx-modules]]) |
| FreeRTOS(上下文) | 与内核同镜像;中断上下文特殊 | task API 与 FromISR API 分离 | 先判上下文([[freertos-context]]) |
| µC/OS、SYS/BIOS | 与内核同镜像;中断参与调度 | ISR 显式通知内核(进入/退出);分层线程 Hwi > Swi > Task | 调度时机要把中断进出算进去([[ucos-sysbios]]) |
| SAFERTOS、CMSIS-RTX5 | 与内核同镜像;带访问控制与安全等级 | per-task 区域/保护域、API 与对象访问策略、ISR 延迟队列 | 先判"谁能访问什么"([[safertos-rtx5]]) |
| T-Kernel、TOPPERS | 与内核同镜像;服务调用合法性取决于上下文 | 静态配置生成 task/handler;设备驱动以准任务部分运行 | 先恢复上下文类型与规格家族([[tkernel-toppers]]) |
| OSE / OSEck | 与内核同镜像但消息可跨节点 | 消息式 IPC + 分布式透明传输层(共享内存/DMA/互连) | 先判消息对端在不在本地([[ose-oseck]]) |
| Nucleus | 与内核同镜像;MMU/MPU 子系统隔离 + 线性内存映射 | 动态 reload/restart/update 应用与内核模块(不必停机) | "模块被替换但系统继续跑"与"隔离存在但 VA 不像每进程独立"都不是异常 |
当"找不到调用关系""这段代码像死的""模块加载不了"时,按这张表先怀疑、再排除:
| 症状 | 优先怀疑 | 处理方向 |
|---|---|---|
| 某个 init / 设备对象没有直接 xref | 注册机制:iterable section / SYS_INIT / DEVICE_DEFINE(Zephyr) | 到 linker section 与 map 文件里裁决,别标 dead code([[zephyr]]) |
| 一整段规则排列的函数指针或结构体 | 同上:linker 生成的注册表 | 先按注册表理解,再考虑 vtable / jump table / 混淆([[zephyr]]) |
| early init 里不调用内核服务 | PRE_KERNEL_* 阶段服务尚不可用(设计如此) | 别判"被裁剪";反之出现线程/互斥/睡眠应先怀疑阶段判错([[zephyr]]) |
| 一个进程没有内核模块却控制硬件 | QNX 用户态 resource manager | 找 resmgr_attach / dispatch_* / MsgReceive 与注册的 pathname([[qnx]]) |
| 网络驱动既不是进程也不是模块 | 被 io-pkt 加载的 devnp-*.so | 找加载它的 io-pkt,确认原生还是经 shim 的旧驱动([[qnx]]) |
| 线程优先级在采样中突然变化 | QNX 消息驱动的优先级继承 / server boost | 不是主动调 pthread_setschedparam([[qnx]]) |
| 线程长时间阻塞在 IPC | MsgSend 本就同步等待(正常状态) | 找"谁该 reply";pulse 才是非阻塞那类([[qnx]]) |
| 独立模块里大量 unresolved symbols | VxWorks DKM 链接到目标镜像的全局符号环境 | 先定位 image 与 VSB/VIP 配置,别判 malformed([[vxworks]]) |
| 模块在同版本 VxWorks 上不工作 | 具体 image configuration 不同 | 核对 VSB/VIP 而不是版本字符串([[vxworks]]) |
dlopen() 行为不像 Unix 动态库 | RTEMS 运行时链接器 | 重定位进当前地址空间;对象名可为 libfoo.a:bar.o([[rtems]]) |
找不到设备回调的 file_operations | RTEMS 设备驱动表(major = 表索引) | 恢复 rtems_driver_address_table 与 rtems_io_register_name([[rtems]]) |
| 任务数/调度器找不到运行期创建点 | RTEMS 构建期配置生成 | 找定义 CONFIGURE_INIT 的那个翻译单元([[rtems]]) |
| 高优先级线程不运行(分区系统) | 分区级调度:当前没有它所属分区的执行窗口 / 预算,或分区还没进 NORMAL | 先对齐 major frame 与 partition window,再看线程优先级([[partitioned-rtos]]) |
| "连写 A B C 只读到 C" | 采样端口的覆盖语义 | 对队列端口才是异常([[partitioned-rtos]]) |
| 固定地址函数表被当成混淆 | APEX 服务表一类的 ABI | 先当服务表核对([[partitioned-rtos]]) |
| 同一个 API 反编译结果在不同样本里完全不同 | NuttX 的 FLAT/PROTECTED/KERNEL 构建差异 | 先判构建模型;极短 API + 立即 trap 是自动生成的 syscall proxy([[nuttx]]) |
| 某地址"用户能访问 / 用户 fault" | 可能分别来自 malloc 与 kmalloc(双堆) | 分清 user heap 与 kernel heap([[nuttx]]) |
| 找不到真正操作硬件的地方 | NuttX 的 upper half / lower half 分层 | 硬件实现常在 arch/ 或 boards/,不在 drivers/([[nuttx]]) |
| ISR 里调用了 task 版 API | 上下文判定或符号识别有误(FreeRTOS) | 先判任务/ISR 上下文与 API 变体([[freertos-context]]) |
| 某地址"有时能访问、有时不能" | MPU 受限任务或运行期改了 MPU 区域(FreeRTOS-MPU) | 查区域配置与运行期改区调用([[freertos-context]]) |
| ISR 只清状态位就返回 | eCos 的 DSR 承担真正工作 | 查 ISR 返回值是否调度 DSR([[ecos]]) |
| 大量「填 request ID → 跳公共 dispatcher」 | ThreadX Module 的 ABI | 建 request ID → 服务名映射,别判混淆([[threadx-modules]]) |
| 代码地址不在模块内存区内 | XIP 模块(指令在 Flash、数据在 RAM) | 别判控制流劫持([[threadx-modules]]) |
| ISR 尾部发生切换 / task 已就绪却不切换 | 中断进出参与调度(µC/OS 的进入退出协议;SYS/BIOS 的 Swi_disable 连带禁用 Task 调度) | 把中断进出算进调度时机([[ucos-sysbios]]) |
| 同一地址在不同 task 下可访问性不同 | per-task MPU 区域 / 保护域(SAFERTOS、RTX5) | 查区域配置与安全等级,别判内存损坏([[safertos-rtx5]]) |
| 句柄不像内存指针 | 间接对象 ID + 交叉引用表(SAFERTOS ESM) | 别指望从它推出对象布局([[safertos-rtx5]]) |
| ISR 里调用的 API 没立即生效 | ISR FIFO 延迟队列(RTX5) | 对象状态在 IRQ 退出后才变化,属正常([[safertos-rtx5]]) |
| 服务调用"非法"或被拒 | 上下文类型(T-Kernel 任务/准任务/任务独立;TOPPERS 任务/非任务/ISR/循环/闹钟) | 对照规范的有效上下文表,别按 API 名推测([[tkernel-toppers]]) |
| 消息/信号的对端找不到 | 消息可跨 core / CPU / DSP / node(OSE 的分布式透明传输层) | 别假定对端在本地,也别只查本地 syscall([[ose-oseck]]) |
| 模块被替换但系统继续运行 | Nucleus 的动态 reload/update(线性内存映射 + MMU/MPU 子系统隔离) | 见运行模型表;别先判劫持 |
本技能以纯静态分析为主(免沙箱,[[re-analyze/platform-tips]] 最高原则);需要动态验证时转 [[re-fw-emulate]]。工具可替换,方法为核心。
NationalSecurityAgency/ghidra releases,解压即用(无需安装)apt install openjdk-21-jdk / dnf install java-21-openjdk / pacman -S jdk21-openjdkbrew install openjdk@21 或 brew install --cask temurinchoco install temurin21./ghidraRun(GUI)/ ./support/analyzeHeadless(无头)java -version(须 21+);./support/analyzeHeadless -help 正常输出binwalk --versionapt install python3 / dnf install python3 / pacman -S pythonchoco install pythonpython3 --version按顺序执行,每步结果存档(任务清单、内核对象表、Ghidra 工程)。
前置:镜像提取与格式识别(衔接 [[re-fw-extract]] 流程):
file + readelf -h 确认架构与字节序(大端 ARM/MIPS 固件常见)RTOS 识别:启动代码链 + 特征串/符号搜索:
xTaskCreate / osThreadNew / tx_thread_create / k_thread_create / rt_thread_create / VxWorks taskSpawn(6.x 及更早常用;7 中仍存在,内部实现为 taskCreate+taskActivate)或 taskCreate(7 起,创建挂起任务需显式 taskActivate)/ QNX ThreadCreate / INTEGRITY ARINC 653 APEX CREATE_PROCESS)→ 调度器启动(vTaskStartScheduler / osKernelStart / tx_kernel_enter / rt_system_scheduler_start / VxWorks kernelInit / QNX 启动脚本拉起系统进程 / INTEGRITY START 进入运行态)。调度器启动调用点之前的代码全是初始化,不属于任何任务nm / Ghidra Symbol Table:pxCurrentTCB、_tx_thread_created_list、_kernel、rt_thread_ready_priority_group)io-*/devb-*/devc-*);INTEGRITY 分区名/进程名与 ARINC 653 APEX 服务名tx_kernel_enter + TX_THREAD 魔数 ID(步骤 3)确认任务表定位(按内核选结构;用 Ghidra 定义结构体后逐字段还原优先级/状态/栈指针/任务名):
_tx_thread_created_list 全局双向链表(每个 TX_THREAD 经 created_next/created_previous 字段互链),配 _tx_thread_created_count 计数;TX_THREAD 关键字段——tx_thread_id(魔数 0x54485244 'THRD',用于确认结构)、tx_thread_name(任务名)、tx_thread_priority、tx_thread_state、tx_thread_stack_start/end/ptr(栈区)、tx_thread_entry(入口函数)_kernel 全局结构(新版本为 struct _cpu,老版本为 struct _kernel)——current(当前线程指针)、ready_q(就绪队列:优先级位图 + 按优先级索引的队列数组)、timeout_q(超时队列)、idle 线程指针;另有 slist 全局线程链链着所有 k_thread;k_thread 关键字段——base.prio(优先级)、stack_info.start/size(栈区)、name(线程名)ThreadCreate/MsgSend 等内核调用点定位线程,线程名串交叉引用回线程控制块;动态环境可用 /proc//ctl 的 DCMD_PROC_TIDSTATUS 读线程状态做侧信道任务栈识别:
内核对象(队列/信号量/互斥/定时器):
xQueueSend/xQueueReceive/xSemaphoreTake/xTimerCreate(FreeRTOS)、tx_queue_send/tx_semaphore_get/tx_mutex_put/tx_timer_create(ThreadX)、k_sem_take/k_mutex_lock/k_queue_get/k_timer_start(Zephyr)、rt_sem_take/rt_mutex_take/rt_mq_recv(RT-Thread)——调用点第一个参数就是对象指针,沿交叉引用回溯到对象定义处(.bss 静态实例或内存池)按任务拆分反编译:
以下四个平台的"驱动/服务模型"与通用任务表方法差异足够大,单独成篇——先读分支判定运行模型,再回到本主文档做任务与对象分析:
dispatch_create → resmgr_attach → dispatch_block/handler,底层是 MsgReceive)、connect/I/O 两张函数表与 iofunc_* 默认实现的区分、devctl 与 _IO_DEVCTL、io-pkt 与 devnp-*.so(含单线程栈上下文)、消息驱动的优先级继承与 server boost、MsgSend 同步阻塞 vs pulse.out,内核态)vs RTP(.vxe,用户态)、DKM 与全局符号环境的链接关系、undefined symbol 的真实成因(VIP 未含组件)、独立模块 unresolved 属常态、VSB/VIP 与"同版本不同 ABI 环境"DEVICE_DEFINE/DEVICE_DT_DEFINE 与 linker section、SYS_INIT 的 level/prio 与返回值后果、iterable sections(规则排列的结构体未必是混淆表)、/chosen 与 /aliases 不是硬件节点、map 文件裁决归属、LLEXT(导出符号表、llext_unload 后指针失效、User Mode 下需 llext_add_domain)confdefs.h 与 CONFIGURE_INIT 唯一性、rtems_driver_address_table 六入口与 major = 表索引、rtems_io_register_name、运行时链接器不是 Unix 共享库模型(libfoo.a:bar.o、懒/立即绑定等价、未解析不报错、重名即错误、基镜像需 rtems-syms)...FromISR() 版 API、pxHigherPriorityTaskWoken 与 portYIELD_FROM_ISR(真正的切换发生在中断退出后)、configMAX_SYSCALL_INTERRUPT_PRIORITY(更紧急的 ISR 一个 API 都不能调,且优先级数值方向相反);FreeRTOS-MPU 的受限任务与运行期改区OSIntEnter/OSIntExit 成对协议与"只有最后一个嵌套 ISR 退出才判断切换";SYS/BIOS 的 Hwi > Swi > Task 分层、Swi_disable() 连带禁用 Task 调度、Hwi/Swi 共用 ISR 栈NU_PARTITION_POOL 是固定块内存池(与隔离域同名的术语坑);NU_SUSPEND 下池空则任务本就挂起;模块可动态 reload/restart/update 而不停机