一、情景引入
我们在分析linux或者安卓系统的coredump文件时,经常碰见SIGSEGV(段错误)、SIGBUS(总线错误)。那么这些错误和arm内核的各种硬件fault有什么关联呢?
二、基本概念
Signal Fault:这是 Linux 系统通过信号机制通知进程发生错误的一种方式。例如,SIGSEGV(段错误)、SIGBUS(总线错误)、SIGILL(非法指令)等信号都属于 Signal Fault。
ARM 内核定义了多种异常类型,用于处理硬件层面的错误情况,常见的 ARM 内核 Fault 包括:
- Data Abort:在数据访问(读取或写入)出错时触发。
- Prefetch Abort:指令预取失败时会引发该异常。
- Undefined Instruction:遇到无法识别的指令时产生。
- Bus Fault:总线访问失败,比如地址对齐错误或者外设响应超时。
三、关联机制
当 ARM 内核检测到硬件 Fault 时,会触发相应的异常处理流程。Linux 内核中的异常处理程序会捕获这些硬件异常,并将其转换为用户空间的 Signal,具体对应关系如下:
ARM 内核 Fault | Linux Signal | 常见原因 |
---|---|---|
Data Abort | SIGSEGV 或 SIGBUS | - SIGSEGV:访问未映射的内存地址 - SIGBUS:访问的地址有效,但总线传输失败(如非对齐访问) |
Prefetch Abort | SIGILL | 指令地址无效或指令格式错误 |
Undefined Instruction | SIGILL | 执行了 ARM 架构不支持的指令 |
Bus Fault | SIGBUS | 总线访问错误,例如地址未对齐、外设故障 |
SIGSEGV vs SIGBUS
这两个信号都与内存访问错误有关,但具体场景不同:
- SIGSEGV(段错误) :通常是因为访问了未映射的虚拟地址。比如,解引用空指针(
*NULL
)或者访问越界的数组元素。 - SIGBUS(总线错误) :更多是硬件层面的问题,例如:
- 非对齐访问(在 ARMv7-M 等架构中,某些指令要求数据地址必须对齐)。
- 访问物理设备地址时,外设响应错误。
四、映射源码解读
1. ARM 架构的异常处理核心逻辑
-
文件路径 :
arch/arm/kernel/traps.c
-
关键函数 :
do_DataAbort()
、do_PrefetchAbort()
、do_BusFault()
-
信号映射示例 :
cpp// 处理数据中止异常 static void do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { struct siginfo info; ... // 根据错误类型设置不同的信号 if (user_mode(regs)) { info.si_signo = SIGSEGV; // 默认发送SIGSEGV info.si_code = SEGV_MAPERR; // 映射错误 ... force_sig_info(SIGSEGV, &info, current); // 向当前进程发送信号 } else { die("Oops", regs, fault_code); } }
2. Bus Fault 的具体处理
-
文件路径 :
arch/arm/mm/fault.c
-
关键函数 :
do_bad_area()
、do_translation_fault()
-
信号映射逻辑 :
cpp// 处理无效地址访问 static int do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { if (user_mode(regs)) { // 对用户空间地址,发送SIGSEGV kill_faulted_task(current, addr, fsr, regs, SIGSEGV); return 0; } ... }
3. 非对齐访问的特殊处理
-
文件路径 :
arch/arm/mm/alignment.c
-
配置选项 :通过
CONFIG_ARM_UNALIGNED_ACCESS
控制是否允许非对齐访问 -
信号映射 :
cpp// 非对齐访问错误处理 static void __do_unaligned_access(struct pt_regs *regs, unsigned long addr) { if (user_mode(regs)) { // 发送SIGBUS信号 force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr, current); return; } ... }
4. ARMv7-M 架构的特殊处理
-
文件路径 :
arch/arm/mach-cortexm/exception.c
-
关键函数 :
hard_fault_handler()
、bus_fault_handler()
-
信号映射 :
cpp// Cortex-M的总线错误处理 void bus_fault_handler(struct pt_regs *regs) { // 通常通过系统调用向用户空间发送SIGBUS send_sig(SIGBUS, current, 0); ... }
总结
- 主要映射逻辑 :
arch/arm/kernel/traps.c
和arch/arm/mm/fault.c
- 架构差异:ARMv7-M 与 ARMv7-A/R 的处理略有不同,具体取决于内核配置和硬件特性。