Presentasjon lastes. Vennligst vent

Presentasjon lastes. Vennligst vent

1 偵錯技術. 2 Outline 介紹一系列專門用來對付核心程式的監視 技術,以及追查錯誤的技巧 訊息除錯法 查詢除錯法 觀測除錯法 排除重大系統失誤 除錯工具.

Liknende presentasjoner


Presentasjon om: "1 偵錯技術. 2 Outline 介紹一系列專門用來對付核心程式的監視 技術,以及追查錯誤的技巧 訊息除錯法 查詢除錯法 觀測除錯法 排除重大系統失誤 除錯工具."— Utskrift av presentasjonen:

1 1 偵錯技術

2 2 Outline 介紹一系列專門用來對付核心程式的監視 技術,以及追查錯誤的技巧 訊息除錯法 查詢除錯法 觀測除錯法 排除重大系統失誤 除錯工具

3 3 訊息除錯法 Printk() 讓我們能指定訊息的 ” 登載等級 ” 定義在 所宣告的八個巨集中 下述代號展開之後,會分別成為 … 之類的字串,數字越低,等級 越高 如果沒在 printk() 註明分類代碼,則訊息的預設分 類為 DEFAULT_MESSAGE_LOGLEVEL( 參閱 cd /usr /src /kernel /printk.c)

4 4 P102 KERN_EMERG KERN_ALERT KERN_CRIT KERNERP KERN_WARING KERN_NOTICE KERN_INFO KERN_DEBUG

5 5 Console_loglevel 變數初值為 default_console_loglevel ,可用 sys_syslog 系統呼叫來改變此值 (1. 先殺掉執行中的 klogd 再以 -c 選項啟動之 2. 自己寫一個程式 來觸發 書中範例 :misc-progs/setlevel.c) 當在控制台上工作,遭遇到 kernel fault ,想 調整 console_level 的現值可用簡單命令迫 使所有核心訊息都出現在操控台上 #echo 8 > /proc/sys/kernel/printk

6 6 核心訊息輸出流程 printk() 將訊息寫入一個環形佇列,然後喚 醒正在等待的行程 — 也就是被 syslog() 系統 呼叫推入修眠狀態或是正在讀取 /proc/kmsg 日誌記錄引擎 (syslogd 和 klogd) ,這兩種是 等效的,但是直接讀取 /proc/kmsg 會消耗掉 緩衝區裡的訊息,不會留給其他行程讀取; syslog() 能讓我決定是否要將訊息留在緩衝 區,也讓其他行程可以讀取。

7 7 訊息開關 研發驅動程式初期, printk() 很好用,可以輔助測試 ~ 除錯 程式碼,但是正式釋出驅動程式時,該如何亦切拿掉所有 除錯用途的 printk()? 1.. 修改巨集名稱,取消或恢復個別列印敘述 2.. 只要在編譯之前變更 cflags 變數值,就可以關閉所有除 錯訊息 3.. 同樣的列印敘述,要同時可用在 kernel-space 與 user- space 的程式裡,讓我們可以用一致方式來控制除錯訊息 P106 熟悉 C preprocessor 的人,甚至可以擴充巨集定義,做出 除錯等級的效果,例如以不同數值定義不同等級的程度

8 8 查詢除錯法 大量使用 printk() 的結果,將明顯拖慢系統效能,因為 syslogd 必須隨時將取得的核心訊息寫入日誌檔,美 印出一行訊息,就會引發一次磁碟動作 解決辦法 1 : 修改 /etc/syslog.conf ,在日誌檔的檔名之 前加一個減號 ( 魔術記號,它要求 syslogd 不必每次收 到新訊息就寫入磁碟 ) 解決辦法 2 : 以其他程式來替代 klogd(cat/proc/kmesg) 最佳辦法 : 是必要時才向系統查詢,Unix 提供許多 ps, netstat, vmstat 等取得系統資訊的工具 對 driver 設計時而言,查詢系統資訊的主要管道有 : 將資訊輸出到 /proc 檔案系統. 適用 ioctl 作業方式.

9 9 使用 /proc 檔案系統 /proc 是靠軟體模擬出來的特殊檔案系統,並 不實際存在於硬碟上,而是核心提供給 user- space 的資訊窗口 在 proc/ 下的每一個檔案,接聯繫到核心內的 專屬函式,這些函式在使用者讀取檔案時,及 時產生檔案的內容 以 /proc/modules 為例,當你讀取它時它會顯 示目前載入哪些模組,但此檔案系統的長度都 為 0.

10 10 Linux 許多系統工具,如 ps, top,uptime 等都是從 /proc 取得它們所需要的資訊 全功能的 /proc 檔案可以很複雜,不僅可被讀出資訊, 甚至容許使用者寫入一些值,藉此改變特定核心功能 的行為 任何欲支援 /proc 的模組,都必須引入 ,來定義適當的函式 建立 /proc 檔案 : 驅動程式必須製作一備查函式,讓它 在檔案被存取的時,及時供應資料,核心也會配置一 個記憶頁給它,核心會自動將我寫在該記憶頁的資料 傳回 user-space

11 11 備查函式介面 : int (*read_proc)(char *page,char **start,off_t offset,int count,int *eof,void *data); page 指標 : 指向核心預先配置的記憶頁 start: 用來表示有效資料的起點位置 eof: 指向一個整數值,驅動程式以此值讓核心知道它 沒有資料要傳回 offset: 若檔案超過一記憶頁大小, 可利用分批傳輸的方 式, 先將 *start 指向 page ,讓呼叫者知道新資料是放在 page 緩衝區的開頭,將 *start 指向 offset bytes 之後的 下一個位元組 skcull 程式中有對 read_proc 的實作 :

12 12 int scull_read_procmem(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int i, j, len = 0; int limit = count - 80; /* Don't print more than this */ for (i = 0; i < scull_nr_devs && len <= limit; i++) { Scull_Dev *d = &scull_devices[i]; if (down_interruptible(&d->sem)) return -ERESTARTSYS; len += sprintf(buf+len,"\nDevice %i: qset %i, q %i, sz %li\n", i, d->qset, d->quantum, d->size); for (; d && len next) { /* scan the list */ len += sprintf(buf+len, " item at %p, qset at %p\n", d, d->data); if (d->data && !d->next) /* dump only the last item - save space */ for (j = 0; j qset; j++) { if (d->data[j]) len += sprintf(buf+len," % 4i: %8p\n",j,d->data[j]); } up(&scull_devices[i].sem); } *eof = 1; return len; }

13 13 定義好 read_proc 作業方式後,必須為它在 /proc 下設置一個入口點, 使用 create_proc_read_entry() 若希望使用者能透過 /proc/scullmem 取得該函 式提供的資料,則 driver 需宣告如下 : static void scull_create_proc() { create_proc_read_entry(“scullmem”, 0 /* 預設模式 (0x444) */, NULL /* 上層目錄 (*proc_dir_entry)*/, scull_read_procmem, NULL /* 提供給 read_proc 使用的資料 */); } /proc 入口點名稱 檔案權限 入口點上層目錄 read_proc 作業 方法的指標 傳給 read_proc 的資 料的指標

14 14 第三引數的說明 : 在 /proc 檔案系統下的每一個子目錄,都有各 自專屬的 proc_dir_entry 結構來描述 描述 /proc/driver 子目錄的結構為 proc_root_driver ,描述 /proc/bus 子目錄的結構 為 proc_bus 若此引數設定為 NULL ,代表入口點設置在 /proc 目錄下

15 15 static void scull_create_proc() { create_proc_read_entry(“scullmem”, 0 /* 預設模式 (0x444) */, proc_root_driver/* 代表 /proc/driver 子目錄 */, scull_read_procmem, NULL /* 提供給 read_proc 使用的資料 */); } 在 /proc 子目錄下 ( /proc/driver) 建立新入口點

16 16 建立新的 /proc 子目錄,利用 proc_mkdir() struct proc_dir_entry *scull_procdir=NULL; static void scull_create_proc() { // 建立 /proc/scull 子目錄 scull_procdir=proc_mkdir(“scull”,NULL); create_proc_read_entry(“scullmem”,0,scull_procdir,scull_read_proc,NULL); }

17 17 在模組被載卸之前必須先移除相關的 /proc 入 口點,使用 remove_proc_entry() // 移除 /proc/scullmem; remove_pcor_entry(“scullmem”,NULL); // 移除 /proc/driver/scullmem; remove_proc_entry(“scullmem”,proc_root_driver); // 移除 /proc/scull/scullmem; remove_proc_entry(“scullmem”,scull_procdir);

18 18 Ioctl 作業方法 Ioctl() 是作用在檔案描述單元 (file descriptor) 的一種系 統呼叫,接受一個數值引數,一個可有可無的指標引 數 數值引數 --ioctl() 所要執行的命令 指標引數 -- 該命令的作業參數 使用 ioctl() 來取得資訊,比較困難,因為要另外寫一 個測試程式來發出呼叫,但是比讀取 /proc 的速度快 沒有單記憶頁的限制,不必將資料拆解成片段 不同於任何人都可見的 /proc 檔案, ioctl 能將擷取除錯 資訊的功能留在驅動程式裡面 ( 因為不會影響效能 ) 詳情請待第五章

19 19 觀測除錯法 有時候,對於一些不太嚴重的小問題,用 觀察 user-space 應用程式的行為,就可以察 覺出來 將程式交給 debugger 來逐步執行 在適當地方印出訊息 將程式交給 strace 來執行

20 20 strace 提供的除錯資訊,直接取自系統核心本 身,能顯示出由 user-space 程式所發出的所有 系統呼叫,輸入輸出資料是否一致 #strace ls /dev > /dev/scull0 strace 最有用之處,在於能讓我們從系統呼叫 中發現執行期的錯誤,一般應用程式中的 perror() 往往不夠詳細

21 21 排除重大系統錯誤 除了監視,除錯技術,驅動程式可能還是有很 多意料之外的 bug 存在,嚴重可能造成 system fault fault( 失誤 ) 不等於 panic( 死當 ) ,失誤通常會摧 毀目前的行程,但是系統本身功能正常 若 fault 發生在 process context 之外,或是破壞 系統的關鍵部分, 就有可能造成 panic oops 訊息 : 往往發生在不當的操作指標所引起, 如 dereference( 提領 ) 或者是誤用指標的值

22 22 page fault: 在 protect mode( 保護模式 ) 下,所使 用的是 virtual address( 虛擬記憶體 ) ,藉由 page table 換算出 physical address( 實體位置 ) , 若程式提領一個無效指標,分頁機制則沒有辦 法算出實體位置,因而發生 page fault 若在 user-space 發生提領無效,後果頂多是無 法 ”page in“ 該位址 但若發生在 kernel 則迫使核心發出 oops 訊息

23 23 範例 :misc-modules/faulty.c ssize_t faulty_write (struct file *filp, const char *buf, size_t count, loff_t *pos) { /* 提領一個 NULL 指標, 刻意製造簡單的 fault 狀況 */ *(int *)0 = 0; return 0; } 0 不是合理指標值

24 24 oops 訊息包括 : fault 當時 CPU 的狀態, 包括各 暫存器的值等 … 但是 ~~ 看不懂那些十六進位的數字訊息,要想 辦法把數字轉換成有意義的符號 klogd ( 自動轉換它所經手的核心訊息 ) ksymoops ( 必須靠使用者自己操作 )

25 25 klogd 必須先有目前核心的 system.map 符號表檔 案 ( /boot 下 ) -p 選項 ( paranoid 謹慎 ) 啟動 klogd ,讓他每 次收到 oops 訊息,都會重讀一次符號表

26 26 ksymoops system.map 檔 (-v) ( /usr/src/linux/system.map ) 模組清單 (-l): ( /proc/modules ) 核心符號表 (-k): ( /proc/ksyms ) 核心映像檔 (-v): 模組 object 檔存放位置 (-o):

27 27 指令 : #ksymoops -v /usr/src/linux /vmlinux -m /usr/src/linux /Systme.map oops.txt

28 28 >>EIP; df8a90e3 <===== Trace; c0145de3 Trace; c Code; df8a90e : Code; df8a90e3 <===== 0: c movl $0x0,0x0 <===== Code; df8a90ea 7: Code; df8a90ed a: 31 c0 xor %eax,%eax Code; df8a90ef c: c9 leave Code; df8a90f0 d: c3 ret Code; df8a90f1 e: 8d lea 0x0(%esi),%esi Code; df8a90f4 11: 55 push %ebp Code; df8a90f5 12: 89 e5 mov %esp,%ebp

29 29 除錯工具 GDB gdb /usr/src/linux/vmlinux /proc/kcore 反組譯 : (gdb) x/i Ex: (gdb) x/20i 0xc bin/info2html?(gdb)Top

30 30 0xc : push %ebp 0xc : mov %esp,%ebp 0xc : sub $0x8,%esp 0xc : sub $0x,%esp 0xc : push $0xc xc800206e: call 0xc0114e50 0xc : add $0x10,%esp

31 31 KGDB 補強程式 為了解決 gdb 在除錯核心時,不能發揮全部 功能的遺憾 準備兩台電腦。一台跑經過 kgdb 補強過的 受測核心,另一台跑 gdb ,兩台相連

32 32 CDA 分析當機狀態資料 Crash dump analyzers 讓系統發生故障時, 能記錄下當時的系統狀態,以便我們事後 分析故障原因 使用者不會抄寫 oops 訊息,我們可以事先 安裝這套在他們的機器上

33 33 User-mode Linux 移植版 ( 一種有趣的概念,並非在某種新型硬體平台上運 行,而是在一個具備 linux 系統呼叫介面的虛擬機 器上執行,適合讓設計師構思程式架構的雛形 ) Linux Trace Toolkit ( 回報時序資訊,可清楚某段時間內所發生的大小 事情 ) Dynamic Probes ( IBM ,特殊堆疊語法的探針,可回報訊息到 user- space ,改變暫存器內容 )

34 34 書中小錯誤 P104 倒數第五行 km”e”sg


Laste ned ppt "1 偵錯技術. 2 Outline 介紹一系列專門用來對付核心程式的監視 技術,以及追查錯誤的技巧 訊息除錯法 查詢除錯法 觀測除錯法 排除重大系統失誤 除錯工具."

Liknende presentasjoner


Annonser fra Google