linxu内核的signal fault和arm内核的flault

一、情景引入

我们在分析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.carch/arm/mm/fault.c
  • 架构差异:ARMv7-M 与 ARMv7-A/R 的处理略有不同,具体取决于内核配置和硬件特性。