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

RISC-V Linux下Trap日志解析

作为日常RISC-V Linux Trap问题定位参考。

1 Trap输出日志解析

[ 220.441130] dddd[2177]: unhandled signal 11 code 0x1 at 0x000000a8 in dddd[10000+37000]

  • 表示进程 dddd(进程ID为2177)收到了一个未处理的信号11(SIGSEGV),信号11对应于段错误(Segmentation Fault),错误码为1(SEGV_MAPPER,表示这个地址未被映射)。epc指向的vma文件名为dddd,vma区间从0x10000开始,大小为0x37000。
  • 错误发生在dddd程序的地址空间的 0x000000a8 位置。

[ 220.451993] CPU: 0 PID: 2177 Comm: ddd Not tainted <kernel version> #1

  • 表示这个错误发生在CPU 0上,进程ID(PID)为2177,进程命令名称为dddd。"Not tainted" 表示内核没有因为此错误而被标记为“污染”(通常是由于某些不安全的操作导致的),内核版本为<kernel version>

[ 220.463629] Hardware name: xxx (DT)

  • 表示硬件平台的名称是xxx,这是从设备树(Device Tree,DT)中获取的信息。

[ 220.474064] epc: 000249b2 ra: 00017650 sp: 945fed50

  • epc(Exception Program Counter)是一个重要的寄存器,它用于保存发生异常时指令的地址。当发生陷阱(Trap)时,RISC-V会在csr_epc寄存器中保存程序计数器pc的值,因为pc会被mtvec覆盖。
  • 根据epc查找dddd的vma,然后给出对应vma的vm_start+(vm_end-vm_start)。即epc (0x000249b2) 发生在0x10000+0x37000之间。所以出问题的epc指向dddd文件的0x000149b2处。
  • b C:0669:000249b2 /onchip: 给进程0x669的代码0x000249b2打上断点。

[ 220.484998] gp: 00048800 tp: 945ff920 t0: 00001000

[ 220.495778] t1: 000134dc t2: 00000000 s0: 0004cea0

[ 220.503484] s1: 94700aa0 a0: 945fed90 a1: 00000000

[ 220.508735] a2: 0000003f a3: 945fee4c a4: 20000000

[ 220.513948] a5: 00000000 a6: 0004cfaa a7: 00000000

[ 220.519158] s2: 950ffbd8 s3: 00000010 s4: 00000000

[ 220.524383] s5: 94700c74 s6: 93dff000 s7: 00000000

[ 220.529595] s8: 945ff440 s9: 945ff440 s10: 00000001

[ 220.534814] s11: 00000001 t3: 955f9362 t4: 947003d0

[ 220.540024] t5: 00000008 t6: 950ff858

在RISC-V中,通用寄存器(GP寄存器)用于存储数据和地址。它们包括:

  • x0 别名 zero,硬件固定为零,用作源寄存器或目标寄存器。
  • x1 别名 ra,链接寄存器,保存函数返回地址。
  • x2 别名 sp,栈指针寄存器,指向栈的地址。
  • x3 别名 gp,全局寄存器,用于链接器优化。
  • x4 别名 tp,线程寄存器,通常在操作系统中用于保存指向进程控制块的指针。来源于CSR_SCRATCH。
  • x5 别名 t0,临时/备用链接寄存器,用作临时变量、备用链接寄存器。
  • x6-x7 别名 t1-t2,临时寄存器,用作一般的操作。
  • x8 别名 s0/fp,保存寄存器/帧指针,用于函数调用,被调用函数需保存数据。
  • x9 别名 s1/gp,保存寄存器/全局指针,用于函数调用,被调用函数需要保存的数据。
  • x10-x11 别名 a0-a1,函数参数/返回值,用于函数调用时传递参数和返回结果。
  • x12-x17 别名 a2-a7,函数参数,用于函数调用时传递参数。
  • x18-x27 别名 s2-s11,保存寄存器,用于函数调用,被调用函数需要保存的数据。
  • x28-x31 别名 t3-t6,临时寄存器,用于一般的操作。

[ 220.544018] status: 00004020 badaddr: 00000000a8 cause: 0000000f

  • status 表示异常状态,来源于CSR_STATUS。
  • badaddr 表示导致异常的“坏地址”(这里是 0x000000a8),来源于CSR_TVAL。
  • cause 表示异常的原因(这里是 0x000000f,对应于段错误),来源于CSR_CAUSE。

2 Trap打印处理流程

在RISC-V架构的Linux内核中,do_trap 是陷阱处理的核心函数,负责处理CPU产生的同步异常(如系统调用、页错误、非法指令等)和部分中断。

do_trap
  pr_info--按照此格式显示错误信息:<进程名>[<进程ID>]: unhandled signal <未处理信号> code <错误码> at 0x<错误指向地址>。
  instruction_pointer--获取epc的值。
  print_vma_addr--根据epc的值找到vma,进而找到vm_file。此时就获取到epc执行的vma区域和vma区域对应的文件。显示错误信息:in <vma对应文件>[16进制vma起始地址+16进制vma区域大小]。
  __show_regs
    show_regs_print_info
      dump_start_print_info--显示发生错误的进程相关信息:CPU: <CPU ID> PID: <进程ID> Comm: <进程名> <> <Tainted信息> <内核版本号> <>。
        printk--显示错误信息:Hardware name: <dump_stack_arch_desc_str>。
    user_mode--非内核显示epc和ra信息。
    pr_cont--显示一系列寄存器。
  force_sig_fault

 常见的signal有:

#define SIGHUP           1
#define SIGINT           2
#define SIGQUIT          3
#define SIGILL           4
#define SIGTRAP          5
#define SIGABRT          6
#define SIGIOT           6
#define SIGBUS           7
#define SIGFPE           8
#define SIGKILL          9
#define SIGUSR1         10
#define SIGSEGV         11
#define SIGUSR2         12
#define SIGPIPE         13
#define SIGALRM         14
#define SIGTERM         15
#define SIGSTKFLT       16
#define SIGCHLD         17
#define SIGCONT         18
#define SIGSTOP         19
#define SIGTSTP         20
#define SIGTTIN         21
#define SIGTTOU         22
#define SIGURG          23
#define SIGXCPU         24
#define SIGXFSZ         25
#define SIGVTALRM       26
#define SIGPROF         27
#define SIGWINCH        28
#define SIGIO           29
#define SIGPOLL         SIGIO
/*
#define SIGLOST         29
*/
#define SIGPWR          30
#define SIGSYS          31
#define SIGUNUSED       31

SIGILL的code有:

#define ILL_ILLOPC      1       /* illegal opcode */
#define ILL_ILLOPN      2       /* illegal operand */
#define ILL_ILLADR      3       /* illegal addressing mode */
#define ILL_ILLTRP      4       /* illegal trap */
#define ILL_PRVOPC      5       /* privileged opcode */
#define ILL_PRVREG      6       /* privileged register */
#define ILL_COPROC      7       /* coprocessor error */
#define ILL_BADSTK      8       /* internal stack error */
#define ILL_BADIADDR    9       /* unimplemented instruction address */
#define __ILL_BREAK     10      /* illegal break */
#define __ILL_BNDMOD    11      /* bundle-update (modification) in progress */
#define NSIGILL         11

SIGTRAP的code有:

/*
 * SIGTRAP si_codes
 */
#define TRAP_BRKPT      1       /* process breakpoint */
#define TRAP_TRACE      2       /* process trace trap */
#define TRAP_BRANCH     3       /* process taken branch trap */
#define TRAP_HWBKPT     4       /* hardware breakpoint/watchpoint */
#define TRAP_UNK        5       /* undiagnosed trap */
#define TRAP_PERF       6       /* perf event with sigtrap=1 */
#define NSIGTRAP        6

SIGBUS的code有:

#define BUS_ADRALN      1       /* invalid address alignment */
#define BUS_ADRERR      2       /* non-existent physical address */
#define BUS_OBJERR      3       /* object specific hardware error */
/* hardware memory error consumed on a machine check: action required */
#define BUS_MCEERR_AR   4
/* hardware memory error detected in process but not consumed: action optional*/
#define BUS_MCEERR_AO   5
#define NSIGBUS         5
 

SIGFPE的code有:

/*
 * SIGFPE si_codes
 */
#define FPE_INTDIV      1       /* integer divide by zero */
#define FPE_INTOVF      2       /* integer overflow */
#define FPE_FLTDIV      3       /* floating point divide by zero */
#define FPE_FLTOVF      4       /* floating point overflow */
#define FPE_FLTUND      5       /* floating point underflow */
#define FPE_FLTRES      6       /* floating point inexact result */
#define FPE_FLTINV      7       /* floating point invalid operation */
#define FPE_FLTSUB      8       /* subscript out of range */
#define __FPE_DECOVF    9       /* decimal overflow */
#define __FPE_DECDIV    10      /* decimal division by zero */
#define __FPE_DECERR    11      /* packed decimal error */
#define __FPE_INVASC    12      /* invalid ASCII digit */
#define __FPE_INVDEC    13      /* invalid decimal digit */
#define FPE_FLTUNK      14      /* undiagnosed floating-point exception */
#define FPE_CONDTRAP    15      /* trap on condition */
#define NSIGFPE         15

SIGSEGV的code有:

#define SEGV_MAPERR     1       /* address not mapped to object */
#define SEGV_ACCERR     2       /* invalid permissions for mapped object */
#define SEGV_BNDERR     3       /* failed address bound checks */
#ifdef __ia64__
# define __SEGV_PSTKOVF 4       /* paragraph stack overflow */
#else
# define SEGV_PKUERR    4       /* failed protection key checks */
#endif
#define SEGV_ACCADI     5       /* ADI not enabled for mapped object */
#define SEGV_ADIDERR    6       /* Disrupting MCD error */
#define SEGV_ADIPERR    7       /* Precise MCD exception */
#define SEGV_MTEAERR    8       /* Asynchronous ARM MTE error */
#define SEGV_MTESERR    9       /* Synchronous ARM MTE exception */
#define NSIGSEGV        9

3 Linux下信号特性列表

信号值信号名说明常见si_codes值(宏定义)可屏蔽导致Coredump
1 SIGHUP 终端连接断开或控制进程终止,常用于通知守护进程重载配置 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
2 SIGINT 交互式中断(Ctrl+C),请求进程终止 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
3 SIGQUIT 交互式退出(Ctrl+\),请求进程终止并生成核心转储 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
4 SIGILL 非法CPU指令,通常因执行无效或特权指令触发 ILL_ILLOPC (1) - 非法操作码
ILL_ILLOPN (2) - 非法操作数
ILL_ILLADR (3) - 非法寻址模式
ILL_PRVOPC (5) - 特权指令
ILL_PRVREG (6) - 特权寄存器访问
5 SIGTRAP 调试陷阱,用于断点和单步执行 TRAP_BRKPT (1) - 断点陷阱
TRAP_TRACE (2) - 跟踪陷阱
TRAP_UNK (5) - RISC-V未知陷阱
6 SIGABRT 进程中止信号,由abort()函数触发 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
SI_QUEUE (-1) - sigqueue()发送
7 SIGBUS 总线错误,内存访问违反硬件约束 BUS_ADRALN (1) - 地址未对齐
BUS_ADRERR (2) - 物理地址无效
BUS_OBJERR (3) - 硬件错误
8 SIGFPE 算术异常,如除零或浮点溢出 FPE_INTDIV (1) - 整数除零
FPE_INTOVF (2) - 整数溢出
FPE_FLTDIV (3) - 浮点除零
FPE_FLTOVF (4) - 浮点上溢
9 SIGKILL 强制终止信号,不可被捕获或忽略 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
10 SIGUSR1 用户自定义信号1,可用于进程间通信 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
SI_QUEUE (-1) - sigqueue()发送
11 SIGSEGV 段错误,无效内存访问(最常见信号之一) SEGV_MAPERR (1) - 地址未映射
SEGV_ACCERR (2) - 权限不足
SEGV_BNDERR (3) - 地址边界错误
12 SIGUSR2 用户自定义信号2,可用于进程间通信 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
SI_QUEUE (-1) - sigqueue()发送
13 SIGPIPE 管道破裂,向已关闭的管道或套接字写入 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
14 SIGALRM 实时定时器到期,由alarm()setitimer()设置 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
15 SIGTERM 终止请求(kill默认),请求进程正常退出 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
16 SIGSTKFLT 协处理器栈错误(历史遗留,现代系统很少使用) SI_USER (0) - 用户进程发送
17 SIGCHLD 子进程状态变更(终止/停止/继续) CLD_EXITED (1) - 子进程退出
CLD_KILLED (2) - 子进程被杀死
CLD_STOPPED (5) - 子进程停止
CLD_CONTINUED (6) - 子进程继续
18 SIGCONT 继续执行先前停止的进程 SI_USER (0) - 用户进程发送
19 SIGSTOP 强制停止信号,不可被捕获或忽略 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
20 SIGTSTP 终端停止请求(Ctrl+Z),请求进程停止 SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
21 SIGTTIN 后台进程尝试读取控制终端 SI_USER (0) - 用户进程发送
22 SIGTTOU 后台进程尝试写入控制终端 SI_USER (0) - 用户进程发送
23 SIGURG 紧急/带外数据到达(TCP套接字) SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
24 SIGXCPU CPU时间超限(超过RLIMIT_CPU限制) SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
可能
25 SIGXFSZ 文件大小超限(超过RLIMIT_FSIZE限制) SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
可能
26 SIGVTALRM 虚拟时间定时器到期(ITIMER_VIRTUAL) SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
27 SIGPROF 性能分析定时器到期(ITIMER_PROF) SI_USER (0) - 用户进程发送
SI_KERNEL (128) - 内核发送
28 SIGWINCH 终端窗口大小改变 SI_USER (0) - 用户进程发送
29 SIGPOLL 可轮询事件发生(System V信号名,等同SIGIO) POLL_IN (1) - 数据可读
POLL_OUT (2) - 输出缓冲可用
POLL_MSG (3) - 消息到达
POLL_ERR (4) - I/O错误
30 SIGPWR 电源故障/电池电量低,通常由UPS监控进程发送 SI_USER (0) - 用户进程发送
31 SIGSYS 无效系统调用/seccomp策略违规 SYS_SECCOMP (1) - seccomp过滤触发
SYS_USER_DISPATCH (2) - 用户调度机制触发
32-64 SIGRTMIN-
SIGRTMAX
实时信号,用于自定义事件,支持排队处理 SI_QUEUE (-1) - sigqueue()发送
SI_TIMER (-2) - 定时器到期
SI_ASYNCIO (-4) - 异步I/O完成

posted on 2025-05-24 23:59  ArnoldLu  阅读(199)  评论(0)    收藏  举报

导航