Kernel Exception 问题分析

深入理解Kernel异常
和你一起终身学习,这里是程序员Android

本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

一、Kernel Exception概述
二、Kernel空间布局
三、printk 概述
四、AEE db log机制
五、前期异常处理
六、die()流程
七、panic()流程
八、nested panic

一、Kernel Exception(KE)概述

Android OS由3层组成,最底层是Kernel,上面是Native bin/lib,最上层是Java层:

Android OS 3层结构

任何软件都有可能发生异常,比如野指针,跑飞、死锁等等。
当异常发生在kernel层,我们就叫它为KE(kernel exception),同理,发生在Native就是NE,Java层就是JE。这篇文章仅关注底层的KE。

1. KE类别

kernel有以下2种(oops、panic)崩溃类别

  • 1.oops (类似assert,有机会恢复)

oops是美国人比较常有的口语。就是有点意外,吃惊,或突然的意思。内核行为表现为通知感兴趣模块,打印各种信息,如寄存器值,堆栈信息…
当出现oops时,我们就可以根据寄存器等信息调试并解决问题。
/proc/sys/kernel/panic_on_oops为1时导致panic。我们默认设置为1,即oops会发生panic。

  • 2.Panic – 困惑,恐慌,它表示Linux kernel遇到了一个不知道该怎么继续的情况。内核行为表现为通知感兴趣模块,死机或者重启。
    在kernel代码里,有些代码加了错误检查,发现错误可能直接调用了panic(),并输出信息提供调试

2. KE常用调试方法

凡是程序就有bug。bug总是出现在预料之外的地方。据说世界上第一个bug是继电器式计算机中飞进一只蛾子,倒霉的飞蛾夹在继电器之间导致了计算机故障。由于这个小虫子,程序中的错误就被称为了bug。

有Bug就需要Debug,而调试是一种很个性化的工作,十个人可能有十种调试方法。但从手段上来讲,大致可分为两类,在线调试 (Online Debug) 和离线调试 (Offline Debug).

3.在线调试

Online debug, 指的是在程序的运行过程中监视程序的行为,分析是否符合预期。通常会借助一些工具,如GDB和Trace32等。有时候也会借助一些硬件设备的协助,如仿真器/JTAG,但是准备环境非常困难,而且用起来也很麻烦,除非一些runtime问题需要外很少使用。

4.离线调试,

Offline debug, 指的是在程序的运行中收集需要的信息,在Bug发生后根据收集到的信息来分析的一种手段。通常也分为两种方式,一种是Logging,一种是Memory Dump。

Logging
日志或者相关信息的收集,可以比较清晰的看到代码的执行过程,对于逻辑问题是一种有效的分析手段,由于其简单易操作,也是最为重要的一种分析手法。

Memory Dump
翻译过来叫做内存转储,指的是在异常发生的时刻将内存信息全部转储到外部存储器,即将异常现场信息备份下来以供事后分析。是针对CPU执行异常的一种非常有效的分析手段。在Windows平台,程序异常发生之后可以选择启动调试器来马上调试。在Linux平台,程序发生异常之后会转储core dump,而此coredump可以用调试器GDB来进行调试。而内核的异常也可以进行类似的转储。

二、Kernel空间布局

在分析KE前,你要了解kernel内存布局,才知道哪些地址用来做什么,可能会是什么问题。

在内核空间中存在如下重要的段:

1. vmlinux代码/数据段:

任何程序都有TEXT(可执行代码),RW(数据段),ZI段(未初始化数据段),kernel也有,对应的是.text,.data,.bss

2.module区域:

kernel可以支持ko(模块),因此需要一段空间用于存储代码和数据段。

3. vmalloc区域:

kernel除了可以申请连续物理地址的内存外,还可以申请不连续的内存(虚拟地址是连续的),可以避免内存碎片化而申请不到内存。

4. io map区域:

留给io寄存器映射的区域,有些版本没有io map区域而是直接用vmalloc区域了。

5.memmap:

kernel是通过page结构体描述内存的,每一个页框都有对应的page结构体,而memmap就是page结构体数组。

还有其他段小的段没有列出来,可能根据不同的版本而差别。

6. ARM64bit kernel布局

目前智能机已进入64bit,因此就存在32bit布局和64bit布局,下面一一讲解。

ARM64可以使用多达48bit物理、虚拟地址(扩充成64bit,高位全为1或0)。对linux kernel来讲,目前配置为39bit的kernel空间。

由于多达512GB的空间,因此完全可以将整个RAM映射进来,0xFFFFFFC000000000之后就是一一映射了,就无所谓high memory了。

<think>首先,用户查询的是解决 'Unexpected kernel BRK exception at EL1' 错误的方案。用户提供了几个引用,我需要参考这些内容来构建答案。 关键引用内容: - 引用[1]:关于内核panic的解释,表示内核遇到无法处理的情况,可能导致死机或重启。提到了内核代码中的错误检查和调用panic()。 - 引用[2]:描述Linux内核的启动过程,包括stext代码的步骤:关中断、设置svc模式、校验参数、创建页表、开启MMU、跳转到C代码等。特别提到了校验cpuid、machid、atag传参的重要性。 - 引用[3]:讨论错误处理时写日志的重要性。 用户的问题是关于具体的错误:'Unexpected kernel BRK exception at EL1'。这似乎是一个内核级别的异常,涉及EL1(Exception Level 1),通常在ARM架构中使用。 理解错误: - 'BRK exception':在ARM语境中,BRK指令用于软件断点或调试异常。 - 'EL1':Exception Level 1,是ARMv8架构中的内核模式级别。 - 所以,这个错误可能表示内核在执行过程中遇到了一个意外的调试断点异常。 根据引用[1],panic可能由错误检查触发。引用[2]描述了启动过程中的参数校验,如果校验失败可能导致错误。引用[3]强调日志的重要性。 我的回答需要结构化,逐步解决问题,并参考这些引用。 回答结构: 1. **理解错误**:先解释这个错误是什么,可能的原因。 2. **解决方案**:提供逐步的解决建议。 3. **参考引用**:自然地融入引用内容,末尾添加引用标识。 4. **生成相关问题**:根据系统指令,我需要生成相关问题。 5. **格式要求**: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式。 - LaTeX语法正确。 - 使用中文回答。 - 回答真实可靠。 在这个上下文中,可能不需要数学表达式,但如果涉及计算或公式,我会遵守格式。 可能的解决方案: - 检查启动参数:如引用[2]所说,启动时校验cpuid、machid、atag传参,如果不合法会导致问题。 - 日志分析:如引用[3]强调,查看内核日志(dmesg)获取更多错误细节。 - 调试工具:使用调试器如GDB分析core dump。 - 硬件兼容性:可能是内核不支持当前的硬件配置。 - 内核配置:检查内核编译选项是否错误。 - 更新或补丁:确保内核是最新版本或应用相关补丁。 参考引用: - 在回答中,提到校验参数时,引用引用[2]。 - 提到panic和错误检查时,引用引用[1]。 - 强调日志时,引用引用[3]。 生成相关问题:在回答末尾,添加相关问题部分,如“§§相关问题§§”,然后列出几个问题。 步骤: 1. 引言:确认错误并简要解释。 2. 解决方案步骤: - 步骤1: 检查启动日志和参数。 - 步骤2: 分析内核日志。 - 步骤3: 调试和硬件检查。 - 步骤4: 考虑内核更新或配置更改。 3. 结论:总结关键点。 4. 相关问题。 确保回答清晰、逐步。 </think>### 解决 'Unexpected kernel BRK exception at EL1' 错误的方法 'Unexpected kernel BRK exception at EL1' 错误是 Linux 内核在 ARM 架构中遇到的严重异常。EL1(Exception Level 1)表示内核运行级别,而 BRK(Breakpoint)异常通常涉及调试中断或意外软件断点。这可能导致系统 panic、死机或重启,严重影响系统稳定性[^1]。常见原因包括内核启动参数错误、硬件不兼容、内核代码缺陷或调试配置问题。以下基于参考引用内容,提供逐步解决方案。每个步骤均参考内核启动和错误处理机制,确保方法真实可靠。 #### 步骤 1: **检查内核启动参数和校验过程** 内核启动时,会严格校验参数如 CPU ID(cpuid)、机器 ID(machid)和 ATAG 传参。如果这些参数非法或不兼容,可能触发异常。引用[2]中指出,在 `stext` 代码阶段,内核执行 `__lookup_processor_type` 和 `__lookup_machine_type` 校验 cpuid 和 machid 的合法性,同时 `__vet_atags` 检查 ATAG 传参的头部是否为 `ATAG_CORE`。如果任一校验失败,内核可能抛出类似 BRK 异常的错误。 - **操作建议**: - 检查 bootloader(如 U-Boot)的启动参数。确保 `cpuid` 和 `machid` 与内核支持的硬件列表匹配。可以通过 U-Boot 命令行查看参数: ```bash printenv machid # 显示机器 ID printenv cpuid # 显示处理器 ID ``` - 验证 ATAG 传参:确保 ATAG 数据结构正确,例如使用 `atags` 命令检查首地址是否为 `ATAG_CORE`。 - 如果使用 Device Tree(DTB),确认 DTB 文件正确编译且与内核版本兼容。 - 如果参数错误,更新 bootloader 配置或内核源码中的硬件支持列表。 - **预期结果**:修复参数错误后,异常可能消失。如果校验失败,内核会提前报错,避免后续异常[^2]。 #### 步骤 2: **分析内核日志以获取错误细节** 错误日志是诊断的关键。引用[3]强调,内核错误应写入日志以便调试,否则难以定位问题。引用[1]提到,内核调用 `panic()` 时会输出调试信息,包括 BRK 异常的堆栈跟踪。 - **操作建议**: - 如果系统能部分启动,使用 `dmesg` 命令查看内核日志: ```bash dmesg | grep "BRK exception" # 过滤相关错误 dmesg -T # 显示完整日志带时间戳 ``` - 如果系统无法启动,通过串口控制台或 JTAG 调试器捕获启动日志。错误日志通常显示异常地址、寄存器状态和调用栈,例如: ``` [ 0.000000] Unexpected kernel BRK exception at EL1: [address] [ 0.000000] Call trace: ... ``` - 引用日志中的错误代码或地址,在内核源码中搜索匹配的调试点(如 `arch/arm64/kernel/entry.S` 中的 BRK 处理代码)。 - 确保日志保存机制启用:在内核配置中启用 `CONFIG_PRINTK` 和 `CONFIG_EARLY_PRINTK`。 - **预期结果**:日志能揭示具体原因,如特定驱动或模块失败。例如,错误可能源于内存管理错误(如页表问题),引用[2]提到内核启动时建立段式页表(页表项大小为 $4 \times 10^3$ 字节)可能导致问题[^3]。 #### 步骤 3: **调试和硬件兼容性检查** BRK 异常常由内核代码缺陷或硬件问题引起。引用[1]指出,内核的错误检查可能直接调用 `panic()`,表明内部逻辑错误。 - **操作建议**: - **软件调试**: - 使用 KGDB(内核调试器)或 GDB with QEMU 模拟环境,加载内核镜像并设置断点。例如: ```bash qemu-system-aarch64 -kernel zImage -append "kgdboc=ttyS0,115200" -machine virt ``` 然后分析异常点的寄存器值和内存状态。 - 检查是否有内核模块冲突:尝试以最小配置启动(`init=/bin/sh`),逐步加载模块测试。 - **硬件检查**: - 确认 CPU 和 SoC 兼容性:ARMv8 架构的处理器必须支持 EL1 模式。运行 `cat /proc/cpuinfo` 检查处理器特性。 - 测试内存和时钟:使用 `memtester` 工具检测 RAM 错误,或检查时钟配置(不稳定时钟可能触发异常)。 - 如果使用自定义内核,确保内核配置(`.config`)正确:启用 `CONFIG_ARM64_ERRATUM` 补丁以修复已知硬件缺陷。 - **回退或更新内核**: - 如果问题在新内核版本中出现,回退到稳定版本(如 Linux LTS)。 - 应用相关补丁:搜索内核邮件列表(如 LKML)中的类似错误报告。 - **预期结果**:硬件问题需更换组件;软件问题可通过补丁或配置修复。调试工具能提供堆栈信息,定位到源码函数[^1]。 #### 步骤 4: **优化内核配置和预防措施** 预防此类错误,需强化内核的健壮性。引用[3]建议,错误处理应优先写入日志。 - **操作建议**: - 在内核编译时启用更多调试选项:如 `CONFIG_DEBUG_BUGVERBOSE`(详细错误报告)和 `CONFIG_DEBUG_LL`(底层调试输出)。 - 更新启动脚本:添加 `panic=10` 参数到内核命令行,使系统在 panic 后自动重启,避免死机。 - 定期监控:使用工具如 `kernelshark` 分析内核事件。 - 如果错误发生在特定驱动中,禁用或更新该驱动(检查内核源码中的 `.brk` 指令使用点)。 - **预期结果**:减少异常发生概率;日志完善后,便于快速修复[^3]。 ### 总结 解决 'Unexpected kernel BRK exception at EL1' 错误的核心是:验证启动参数(如 cpuid 和 machid)[^2]、分析内核日志定位细节[^3]、并结合调试工具检查代码或硬件[^1]。多数情况下,参数错误或内存问题是根本原因。确保内核版本最新,并启用详细日志。如果问题持续,提供更多日志细节以便进一步分析
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值