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状态进行了详细解释,总结如下:
联系方式:arnoldlu@qq.com
浙公网安备 33010602011771号