LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

RISCV Linux下Illegal Instruction解析定位

 一个非法指令的日志和产生日志的代码流程分析。

1 非法指令log

一个非法指令异常的log如下:

[   27.111085] Oops - illegal instruction [#1]
[   27.111108] Modules linked in: xxx(O)--tainted信息参考下面。
[   27.111136] CPU: 0 PID: 947 Comm: netifd Tainted: G           O       6.6.69-gbe5cdcb68ab7 #1--这部分的错误参考《RISC-V Linux下Trap日志解析 - ArnoldLu - 博客园》。
[ 27.111151] Hardware name: yyy (DT) [ 27.111156] epc : fib_check_nh+0xa/0x394--显示epc/ra寄存器对应的符号信息。
[ 27.111188] ra : fib_create_info+0x704/0xb04
[ 27.111208] epc : c048b5f8 ra : c048c144 sp : c0b678d0 [ 27.111218] gp : c186b150 tp : c0b11800 t0 : c464c278 [ 27.111227] t1 : ffffffff t2 : 0000017a s0 : c0b679a0 [ 27.111236] s1 : 00000000 a0 : c1895140 a1 : c34ac4d0 [ 27.111244] a2 : 000000ff a3 : 000000fd a4 : 00000000
[ 27.111252] a5 : 000000fe a6 : 00000000 a7 : 00000002
[ 27.111260] s2 : 00000000 s3 : c1895140 s4 : c104a230 [ 27.111268] s5 : c186ce68 s6 : 00000001 s7 : c186ce60 [ 27.111277] s8 : c0b67a2c s9 : c103b064 s10: c34ac480 [ 27.111286] s11: 000000ff t3 : 00000400 t4 : 000fffff [ 27.111294] t5 : 00000400 t6 : 00000000
[ 27.111300] status: 00000120 badaddr: 0100de07 cause: 00000002
[ 27.111310] [<c048b5f8>] fib_check_nh+0xa/0x394--栈回溯,后面给出函数内部的偏移,方便明确定位。
[ 27.111333] [<c048ecec>] fib_table_insert+0x86/0x544
[ 27.111357] [<c0489020>] fib_magic.isra.0+0xe8/0xea
[ 27.111376] [<c048a33e>] fib_add_ifaddr+0xe0/0x13a
[ 27.111397] [<c048a990>] fib_inetaddr_event+0x64/0x9e
[ 27.111417] [<c0021b80>] blocking_notifier_call_chain+0x4c/0x78
[ 27.111447] [<c0480892>] __inet_insert_ifa+0x1c0/0x296
[ 27.111462] [<c0480df8>] inet_rtm_newaddr+0x2d6/0x498
[ 27.111477] [<c038126e>] rtnetlink_rcv_msg+0x216/0x2ce
[ 27.111500] [<c03b2d36>] netlink_rcv_skb+0x3c/0xbe
[ 27.111516] [<c037ff58>] rtnetlink_rcv+0x14/0x1c
[ 27.111533] [<c03b25c4>] netlink_unicast+0x126/0x1b6
[ 27.111547] [<c03b28c4>] netlink_sendmsg+0x270/0x39a
[ 27.111561] [<c03559c4>] ____sys_sendmsg+0x140/0x198
[ 27.111576] [<c0357386>] ___sys_sendmsg+0x74/0x9a
[ 27.111592] [<c0357710>] __sys_sendmsg+0x4c/0x78
[ 27.111607] [<c0357750>] __riscv_sys_sendmsg+0x14/0x1c
[ 27.111623] [<c056c008>] do_trap_ecall_u+0xb6/0xfc
[ 27.111641] [<c05734fe>] ret_from_exception+0x0/0x66
[ 27.111674] Code: bf59 4501 54d2 5942 b76d 7119 dca2 daa6 d8ca d6ce (de07) 0100 --dump epc附近的代码二进制,其中括号中的内容为epc指向的指令值。大概率括号中或者前后就是错误的指令。 [ 27.111684] ---[ end trace 0000000000000000 ]---
[ 27.111693] Kernel panic - not syncing: Fatal exception in interrupt [ 27.319357] Rebooting in 3 seconds..

通过objdump -S vmlinux反汇编vmlinux得到汇编以及机器码,跳转到epc处,比对二进制。

在架构和编译配置正确的情况下,出现Illegal Instruction的可能情况包括:

  • SoC中NoC其他Master(CPU、DMA等)误写踩到指令。这时候如果有现场,可以通过JTAG查看DDR中内存和elf反汇编不一致,则可以断定内存被踩。
  • 可以通过JTAG,绕过CPU从总线直接读取DDR对应数据。如果数据正确,但是执行的指令不正确,说明从DDR读取指令,到取指执行。结合下面流程图(让DeepSeek生成从DDR颗粒到CPU执行指令的完整流程):
    • 最可能出问题在Memory Subsystem的DDR初始化训练部分。DDR初始化训练完成度不好,则某些情况下出现bit翻转。
    • 对于一个成熟的CPU,Cache/Memory和AXI交互出问题的概率很小。
    • 更甚CPU Core和Cache/Memory之间出问题,或者CPU Core内部执行出问题更小。

 所以重点怀疑内存被踩和DDR训练结果不稳定。

2 非法指令异常处理流程

非法指令异常的处理流程如下:

do_trap_insn_illegal
  ->do_trap_error
    ->fixup_exception
    ->die
      ->oops_enter
      ->spin_lock_irqsave
      ->console_verbose
      ->bust_spinlocks
      ->pr_emerg--输出die提示,并在[]中输出进入die的计数。
      ->print_modules--输出内核中通过insmod插入的module列表。
      ->show_regs--显示epc到scause寄存器的值。
        ->__show_regs
          ->show_regs_print_info
            ->dump_stack_print_info--输出进程、模块、硬件名称等信息。
              ->print_worker_info--打印内核worker信息。
              ->print_stop_info--打印内核中cpu_stopper信息。
          ->user_mode--如果是非用户态,输出epc和ra对应的符号信息。
        ->dump_backtrace--如果非用户态,输出栈回溯。
          ->walk_stackframe--按照调用关系输出栈指针指向的符号信息:[<符号地址>] 符号名称+偏移/函数大小。       
->dump_kernel_instr--打印16位数据,共打印12个:epc前10个,epc指向1个,epc后1个。
        ->instruction_pointer--从struct pt_regs中获取epc的值。

      ->notify_die
      ->bust_spinlocks
      ->add_taint
      ->spin_unlock_irqrestore
      ->oops_exit
      ->panic--当oops后,调用panic。

tainted-kernels.rst中对tainted状态进行了详细解释,总结如下:

位编号状态名称True 时的含义及打印字符False 时的含义及打印字符
0 TAINT_PROPRIETARY_MODULE 加载专有模块(无 GPL或兼容许可证)
打印字符: P
未加载专有模块
打印字符:G
1 TAINT_FORCED_MODULE 强制加载模块(如insmod -f)
打印字符: F
未强制加载模块
打印空格
2 TAINT_UNSAFE_SMP 在不支持的 SMP 系统运行(如非官方 CPU)
打印字符: S
在支持的硬件运行
打印空格
3 TAINT_FORCED_RMMOD 强制卸载正在使用的模块
打印字符: R
未强制卸载模块
打印空格
4 TAINT_MACHINE_CHECK 处理器报告机器检查异常(MCE)
打印字符: M
无 MCE 错误
打印空格
5 TAINT_BAD_PAGE 内核检测到坏页/非法内存访问
打印字符: B
无内存页错误
打印空格
6 TAINT_USER 用户手动请求污染(写 /proc/sys/kernel/tainted
打印字符: U
用户未主动污染
打印空格
7 TAINT_DIE 内核发生OOPS或BUG
打印字符: D
未触发致命错误
打印空格
8 TAINT_OVERRIDDEN_ACPI_TABLE ACPI表被覆盖(如 acpi_rsdp 启动参数)
打印字符: A
未修改 ACPI 表
打印空格
9 TAINT_WARN 内核发出严重警告(已弃用)
打印字符: W
无相关警告
打印空格
10 TAINT_CRAP 加载staging驱动/未通过检查的模块
打印字符: C
所有模块通过检查
打印空格
11 TAINT_FIRMWARE_WORKAROUND 使用固件漏洞规避措施(如旧 CPU 微码补丁)
打印字符: I
未使用规避措施
打印空格
12 TAINT_OOT_MODULE 加载非官方构建模块(第三方/自定义编译)
打印字符: O
仅使用官方模块
打印空格
13 TAINT_UNSIGNED_MODULE 加载未签名模块(启用模块签名验证时)
打印字符: E
所有模块已签名
打印空格
14 TAINT_SOFTLOCKUP 检测到软死锁(CPU 长时间卡在内核)
打印字符: L
无软死锁事件
打印空格
15 TAINT_LIVEPATCH 实时内核补丁已加载
打印字符: K
未使用实时补丁
打印空格
16 TAINT_AUX 辅助污染位(通常由发行版设置)
打印字符: X
未使用
打印空格
17 TAINT_RANDSTRUCT 内核启用结构随机化(非污染原因,标记调试差异)
打印字符: T
未启用结构随机化
打印空格
18 TAINT_TEST 加载测试模块(含 MODULE_TEST 标识)
打印字符: N
未加载测试模块
打印空格
19-31 - 保留位(未定义)
无打印字符
-

posted on 2025-06-14 23:59  ArnoldLu  阅读(195)  评论(0)    收藏  举报

导航