1 / 32

偵錯技術

偵錯技術. Reporter:Ko-Wei,Chang 601430074. Outline. 介紹一系列專門用來對付核心程式的監視技術,以及追查錯誤的技巧 訊息除錯法 查詢除錯法 觀測除錯法 排除重大系統失誤 除錯工具. 訊息除錯法. Printk() 讓我們能指定訊息的”登載等級” 定義在 <linux/kernel.h> 所宣告的八個巨集中 下述代號展開之後,會分別成為 <0><1><2>…<7> 之類的字串,數字越低,表示嚴重程度越高

jill
Download Presentation

偵錯技術

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 偵錯技術 Reporter:Ko-Wei,Chang 601430074

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

  3. 訊息除錯法 • Printk()讓我們能指定訊息的”登載等級” • 定義在<linux/kernel.h>所宣告的八個巨集中 • 下述代號展開之後,會分別成為<0><1><2>…<7>之類的字串,數字越低,表示嚴重程度越高 • 如果沒在printk()註明分類代碼,會以DEFAULT_MESSAGE_LOGLEVEL為預設的等級,此變數值是4(相當於KERN_WARING) (參閱cd /usr /src /kernel /printk.c)

  4. P82 • KERN_EMERG • KERN_ALERT • KERN_CRIT • KERN_ERR • KERN_WARING • KERN_NOTICE • KERN_INFO • KERN_DEBUG

  5. Console_loglevel變數初值為default_console_loglevel,可用sys_syslog系統呼叫來改變此值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. 核心訊息輸出流程 • printk()將訊息寫入一個環形佇列,然後喚醒正在等待的行程—也就是被syslog()系統呼叫推入修眠狀態或是正在讀取/proc/kmsg • 日誌記錄引擎(syslogd和klogd),這兩種是等效的,但是直接讀取/proc/kmsg會消耗掉緩衝區裡的訊息,不會留給其他行程讀取;syslog()能讓我決定是否要將訊息留在緩衝區,也讓其他行程可以讀取。

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

  8. P86_scull.h

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

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

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

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

  13. 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 <= limit; d = d->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 < d->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; }

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

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

  16. 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)建立新入口點

  17. 建立新的/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); }

  18. 在模組被載卸之前必須先移除相關的/proc入口點,使用remove_proc_entry()在模組被載卸之前必須先移除相關的/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);

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

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

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

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

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

  24. 範例: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不是合理指標值

  25. oops訊息包括 : fault當時CPU的狀態,包括各暫存器的值及一些匪夷所思的資訊 • 但是~~看不懂那些十六進位的數字訊息,要想辦法把數字轉換成有意義的符號

  26. 除錯工具 • gdb • #gdb /usr/src/linux/vmlinux /proc/kcore • 第一個引數是核心映像檔 • 第二個引數是core檔的位置 • 可用還檢驗模組裡的變數。 • 反組譯: (gdb) x/i <addr> • Ex: (gdb) x/20i 0xc8002060

  27. #gdb /usr/src/linux/vmlinux /proc/kcore

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

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

  30. MEMO

More Related