Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 核心 Oops 錯誤訊息完整解讀:從空指標範例看 Call Trace、錯誤碼與 Tainted 旗標含義

編輯:Linux 教學

前言

Linux 核心發生嚴重錯誤(如空指標解參考)時,會輸出 Oops 訊息,包含當下 CPU 狀態、堆疊回溯、錯誤碼與 Tainted 旗標,是驅動開發除錯的關鍵線索。本文以故意製造 NULL pointer dereference 的核心模塊為例,示範如何結合 objdump 反組譯精確定位錯誤行,並完整解讀 Oops 各欄位含義。

一、觸發 Oops 的測試模塊


/* oops_demo.c */
#include 
#include 

static int __init oops_init(void) {
    int *p = 0;
    *p = 1;          // 故意解參考 NULL 指標
    return 0;
}
static void __exit oops_exit(void) {}
module_init(oops_init);
module_exit(oops_exit);
MODULE_LICENSE("GPL");

二、編譯載入觸發 Oops


make
insmod oops_demo.ko
# 系統輸出 Oops 訊息至 dmesg / 主控台

三、Oops 完整輸出範例與逐段解讀


[  100.243737] BUG: unable to handle kernel NULL pointer dereference at (null)
[  100.244985] IP: [] oops_init+0x5/0x11 [oops_demo]
[  100.262266] *pde = 00000000
[  100.288395] Oops: 0002 [#1] SMP
[  100.305468] last sysfs file: /sys/devices/virtual/sound/timer/uevent
[  100.325955] Modules linked in: oops_demo(+) ...
[  100.472178] Pid: 1586, comm: insmod Not tainted (2.6.32-21-generic #32-Ubuntu) VMware Virtual Platform
[  100.540018] EIP: 0060:[] EFLAGS: 00010246 CPU: 0
[  100.562844] EIP is at oops_init+0x5/0x11 [oops_demo]
[  100.584351] EAX: 00000000 EBX: fffffffc ECX: f82cf040 EDX: 00000001
[  100.609358] ESI: f82cf040 EDI: 00000000 EBP: f1b9ff5c ESP: f1b9ff5c
[  100.631467] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[  100.657664] Process insmod (pid: 1586, ti=f1b9e000 task=f137b340 task.ti=f1b9e000)
[  100.706083] Stack:
[  100.731783]  f1b9ff88 c0101131 f82cf040 c076d240 fffffffc f82cf040 0072cff4 f82d2000
[  100.759324] <0> fffffffc f82cf040 0072cff4 f1b9ffac c0182340 f19638f8 f137b340 f19638c0
[  100.811396] <0> 00000004 09cc9018 09cc9018 00020000 f1b9e000 c01033ec 09cc9018 00015324
[  100.891922] Call Trace:
[  100.916257]  [] ? do_one_initcall+0x31/0x190
[  100.943670]  [] ? oops_init+0x0/0x11 [oops_demo]
[  100.970905]  [] ? sys_init_module+0xb0/0x210
[  100.995542]  [] ? syscall_call+0x7/0xb
[  101.024087] Code:  05 00 00 00 00 01 00 00 00 5d c3 00 00 00 00 00 00 00 00 00 00
[  101.079592] EIP: [] oops_init+0x5/0x11 [oops_demo] SS:ESP 0068:f1b9ff5c
[  101.134682] CR2: 0000000000000000
[  101.158929] ---[ end trace e294b69a66d752cb ]---

關鍵欄位解讀

欄位含義本例數值
BUG 行錯誤類型描述kernel NULL pointer dereference at (null)
IP / EIP發生錯誤的指令指標oops_init+0x5 (模塊基址 f82d2000 + 0x5)
Oops: 0002錯誤碼 (十六進位)bit1=1 (Write)、bit2=0 (Kernel mode) → 核心態寫入導致頁面保護錯誤
[#1]此 CPU 發生第 1 次 Oops#1
Call Trace函數呼叫堆疊回溯insmod → sys_init_module → do_one_initcall → oops_init
Code錯誤指令附近機器碼c7 05 00 00 00 00 01 00 00 00 → movl $0x1, 0x0
CR2導致頁面錯誤的線性位址0x0 (NULL)
Tainted核心污染狀態Not tainted (GPL 模組、正常載入、無強制卸載、無 MCE)

四、結合 objdump 精確定位原始碼行


objdump -S oops_demo.o
# 輸出片段:
oops_demo.o: file format elf32-i386
Disassembly of section .init.text:
00000000 :
   0:   55                      push   %ebp
   1:   31 c0                   xor    %eax,%eax
   3:   89 e5                   mov    %esp,%ebp
   5:   c7 05 00 00 00 00 01    movl   $0x1,0x0    ← offset 0x5
   c:   00 00 00
   f:   5d                      pop    %ebp
  10:   c3                      ret
  • Oops 指出 oops_init+0x5,對應反組譯 offset 0x5 的 movl $0x1, 0x0。
  • 原始碼對應行:*p = 1; (第 7 行)。
  • 定位成功。

五、Oops 錯誤碼位元定義


/* arch/x86/mm/fault.c */
* error_code:
*  bit 0 = 0: 頁面不存在 (P=0)      1: 保護錯誤 (P=1, 權限不符)
*  bit 1 = 0: 讀取                   1: 寫入
*  bit 2 = 0: 核心模式               1: 用戶模式
*  bit 3 = 0: 資料存取               1: 指令擷取
*  bit 4 = 1: 保留位被設定 (PSE/ NX 等)

本例 0x2 = 0b0010 → 保護錯誤、寫入、核心模式、資料存取。

六、Tainted 旗標完整對照表

位置字元含義
1G / P所有模組 GPL 相容 / 有專有模組
2F / _曾用 insmod -f 強制載入 / 正常
3S / _SMP 核心跑在未認證硬體 / 正常
4R / _曾用 rmmod -f 強制卸載 / 正常
5M / _CPU 回報 Machine Check Exception / 無
6B / _頁面釋放發現壞頁面引用 / 無
7U / _用戶主動要求設定 Tainted / 無
8D / _核心近期曾死機 (Oops/BUG) / 無
9A / _ACPI 表被覆寫 / 無
10W / _核心曾發出警告 / 無
11C / _載入 staging 驅動 / 無
12I / _核心繞過平台韌體嚴重 Bug / 無

核心開發者收到 Oops 時,優先查看 Tainted 判斷環境乾淨度;自行除錯驅動可暫時忽略。

七、Oops 發生時系統可能狀態與資訊保全對策

  • 未死機:dmesg 完整保留,可直接分析。
  • 死機:訊息來不及落盤。對策:
    • Grub 加 vga=791 等高解析度參數,增加畫面顯示行數。
    • 雙機串口 Console:console=ttyS0,115200 將輸出導向宿主機記錄。
    • kdump / kexec:配置 crashkernel= 保留記憶體,Oops 觸發時自動轉儲 vmcore,事後用 crash 或 gdb 分析。

八、最佳實踐建議

  1. 模塊開發階段務必加 MODULE_LICENSE("GPL"),避免 Tainted 干擾核心開發者判斷。
  2. 遇到 Oops,先抓 IP/EIP + objdump -S 定位原始碼行,再結合 Call Trace 理解呼叫脈絡。
  3. 錯誤碼位元分析能快速判斷「讀/寫」、「核心/用戶」、「頁面不存在/保護錯誤」,縮小排查範圍。
  4. 生產環境部署 kdump,確保死機現場可事後複盤。
Copyright © Windows教程網 All Rights Reserved