Linux核心Crash分析 重要

2021-08-29 02:50:59 字數 2991 閱讀 2721

linux核心crash分析

每乙個程序的生命週期內,其生命週期的範圍為幾毫秒到幾個月。一般都是和核心有互動,例如使用者空間程式使用系統呼叫進入核心空間。這時使用的不再是使用者空間的棧空間,使用對應的核心棧空間。對每乙個程序來說,linux核心都會把兩個不同的資料結構緊湊的存放在乙個單獨為程序分配的儲存空間中:乙個是核心態的程序堆疊,另乙個是緊挨程序描述符的資料結構thread_info,叫執行緒描述符。核心的堆疊大小一般為8kb,也就是8192個位元組,占用兩個頁。在linux-2.6.32核心中thread_info.h檔案中有對核心堆疊的定義:

#define thread_size               8192

在linux核心中使用下面的聯合結構體表示乙個程序的執行緒描述符和核心棧,在核心中檔案include/linux/sched.h。

union thread_union ;

該結構是乙個聯合體,我們在c語言書上看到過關於union的解釋,在在c programming language 一書中對於聯合體是這麼描述的:

1) 聯合體是乙個結構;

2) 它的所有成員相對於基位址的偏移量都為0;

3) 此結構空間要大到足夠容納最"寬"的成員;

4) 其對齊方式要適合其中所有的成員;

通過上面的描述可知,thread_union結構體的大小為8192個位元組。也就是stack陣列的大小,型別是unsigned long類 型。由於聯合體中的成員變數都是占用同一塊記憶體區域,所以,在平時寫**時總有乙個概念,對乙個聯合體的例項只能使用其中乙個成員變數,否則會把原先變數 給覆蓋掉,這句話如果正確的話,必須要有乙個前提假設,成員占用的位元組數相同,當成員所佔的位元組數不同時,只會覆蓋相應的位元組。對於thread_union聯合體,我們是可以同時訪問這兩個成員,只要能夠正確獲取到兩個成員變數的位址。

在核心中的某乙個程序使用了過多的棧空間時,核心棧就會溢位到thread_info部分,這將導致嚴重的問題(系統重啟),例如,遞迴呼叫的層次太深;在函式內定義的資料結構太大。

圖:程序中thread_info    task_struct和核心棧中的關係

下面我們看一下thread_info的結構體:

struct thread_info ;

ps:(1)flag 用於儲存各種特定的程序標誌,最重要的兩個是:tif_sigpending,如果程序有待處理的訊號就置位,tif_need_resched表示程序應該需要排程器選擇另乙個程序替換本程序執行。

結合上面的知識,看下當核心列印堆疊資訊時,都列印了上面資訊。下面的列印資訊是工作中遇到的一種情況,列印了核心的堆疊資訊,pc指標在dev_get_by_flags中,不能訪問的核心虛位址為45685516,核心中一般可訪問的位址都是以0xc******x開頭的位址。

(1)首先,看看這段堆疊資訊是在核心中那個檔案中列印出來的,在fault.c檔案中,__do_kernel_fault函式,在上面的列印中unable to handle kernel paging request at virtual address 45685516,該位址是核心空間不可訪問的位址。

static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, struct pt_regs *regs)

(2) 對於下面的兩個資訊,在函式show_pte中進行了列印,下面的列印涉及到了頁全域性目錄,頁表的知識,暫時先不分析,後續補上。

pgd = c65a4000

[45685516] *pgd=00000000

void show_pte(struct mm_struct *mm, unsigned long addr)

(3) die函式中呼叫在die函式中取得thread_info結構體的位址。

struct thread_info *thread = current_thread_info();

static inline struct thread_info *current_thread_info(void)

sp: 0xc07e9c28    通過current_thread_info得到 thread_info的位址

(0xc07e9c28 & 0xffffe000) = 0xc07e8000(thread_info的位址,也就是棧底的位址)

(4)下面的列印資訊在__die函式中列印

下面是__die函式的定義:

#define task_stack_page(task)        ((task)->stack) ,該巨集根據task_struct得到棧底,也就是thread_info位址。

#define task_thread_info(task)       ((struct thread_info *)(task)->stack),該巨集根據task_struct得到thread_info指標。

(5)dump_backtrace函式

該函式用於列印函式的呼叫關係。fp為幀指標,用於追溯程式的方式,方向跟蹤呼叫函式。該函式主要是fp進行檢查,看看能否進行backtrace,如果可以就呼叫彙編的c_backtrace,在arch/arm/lib/backtrace.s函式中。

static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)

else if (tsk != current) else

if (!fp) else if (verify_stack(fp)) else if (fp < (unsigned long)end_of_stack(tsk))

printk("frame pointer underflow");

printk("\n");

if (ok)

c_backtrace(fp, mode);

}(6)dump_instr

根據pc指標和指令mode, 列印出當前執行的指令碼

code: 0a000008 e5944000 e2545000 0a000005 (e4153010)

核心中函式的呼叫關係

Linux核心Crash分析

每乙個程序的生命週期內,其生命週期的範圍為幾毫秒到幾個月。一般都是和核心有互動,例如使用者空間程式使用系統呼叫進入核心空間。這時使用的不再是使用者空間的棧空間,使用對應的核心棧空間。對每乙個程序來說,linux核心都會把兩個不同的資料結構緊湊的存放在乙個單獨為程序分配的儲存空間中 乙個是核心態的程序...

crash除錯核心模組

wifi 模組出現panic時,怎麼根據fulldump去分析wifi問題,以及怎麼除錯wlan的ko檔案?這裡介紹linux下的crash工具來分析fulldump,當然也可以用trace32,gdb等其他工具.1.安裝crash工具 編譯和安裝 make target arm64 make in...

Crash日誌分析

從crash檔案出發解決bug的一般步驟,分三步 a,獲取裝置上的崩潰日誌。b,分析崩潰日誌,找到報錯位置 定位到函式和 行數 c,開啟 改bug。1,獲取裝置日誌 2,解析日誌 2.1 在命令列輸入下面的命令獲取symbolicatecrash二進位制檔案,獲取到路徑後,copy乙份出來 2.3 ...