• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

      Linux 內(nèi)核調(diào)試技術(shù)的方法研究

      2012-09-12 03:22:42洪永學(xué)余紅英姜世杰林麗蓉
      電子測試 2012年11期
      關(guān)鍵詞:驅(qū)動程序內(nèi)核寄存器

      洪永學(xué), 余紅英, 姜世杰, 林麗蓉

      (中北大學(xué)信息與通信工程學(xué)院, 山西太原 030051)

      0 引言

      Linux操作系統(tǒng)最大的優(yōu)勢在于其源碼的開放性,人們可以根據(jù)應(yīng)用的需要對其內(nèi)核驅(qū)動進(jìn)行必要的裁剪或修改,但是由于內(nèi)核是整個計算機(jī)軟件系統(tǒng)的基礎(chǔ),其與無操作系統(tǒng)的調(diào)試有著很大的差異。調(diào)試中所獲得的錯誤信息也不同,尤其是涉及到Oops信息的段錯誤。為了能有效地調(diào)試Linux內(nèi)核,人們采用了很多方法,下面介紹兩種常用的Linux內(nèi)核調(diào)試方法。

      1 內(nèi)核打印函數(shù)printk調(diào)試

      1.1 printk函數(shù)的記錄級別

      調(diào)試內(nèi)核、驅(qū)動是最簡單,最常用,也是效率較高的方法,是使用printk函數(shù)打印信息。printk函數(shù)與用戶空間的printf函數(shù)的格式完全相同,它所打印的字符串頭部可以加入""樣式的字符,其中n為0~7,表示這條信息的記錄級別。

      在內(nèi)核代碼include/linux/kernel.h中,下面幾個宏控制了printk函數(shù)所輸出的信息記錄級別。

      #define console_loglevel (console_printk[0])#define default_message_loglevel (console_printk[1])

      #define minimum_console_loglevel (console_printk[2])

      #define default_console_loglevel (console_printk[3])

      1.2 在用戶空間修改printk函數(shù)的記錄級別

      掛接在proc文件系統(tǒng)后,讀取/proc/sys/kernel/printk文件可以得知console_loglevel,fault_message_loglevel,minimum_console_loglevel 和default_console_loglevel這個4個值。

      可以修改/proc/sys/kernel/printk文件來改變這4個值,比如:

      # echo "1 4 1 7" > /proc/sys/kernel/printk

      這使得console_loglevel被改為1,于是所有的printk信息都不會被打印。

      1.3 printk函數(shù)記錄級別的名稱及使用

      在內(nèi)核代碼include/linux/kernel.h中有如下代碼,它們表示0~7這個8個記錄級別的名稱。

      #define KERN_EMERG "<0>" /* system is unusable */

      #define KERN_ALERT "<1>" /* action must be taken immediately */

      #define KERN_CRIT "<2>" /* critical conditions */

      #define KERN_ERR "<3>" /* error conditions */

      #define KERN_WARNING "<4>" /*warning conditions */

      #define KERN_NOTICE "<5>" /*normal but significant condition */

      #define KERN_INFO "<6>" / *informational */

      #define KERN_DEBUG "<7>" /* debuglevel messages */

      在使用printk函數(shù)時,可以這樣的使用記錄級別。

      printk(KERN_WARNING"there is a warning here ! ")

      在被調(diào)試的內(nèi)核中相應(yīng)的位置加入printk函數(shù),可以根據(jù)串口中打印出的信息獲得其錯誤的位置從而實(shí)施相應(yīng)的解決方法。

      2 Oops信息及棧回溯的調(diào)試

      在進(jìn)行Linux內(nèi)核驅(qū)動調(diào)試時,經(jīng)常會出現(xiàn)Segmentation fault錯誤信息,其大部分都是NULL指針引用或使用其他不正確的指針數(shù)值。這些錯誤通常會導(dǎo)致一個Oops消息。由于處理器使用的地址都是“虛”地址,而且通過一個復(fù)雜的稱為頁表的結(jié)構(gòu)映射為物理地址。當(dāng)引用一個非法指針時,頁面映射機(jī)制就不能將”虛”地址映射到物理地址,因此處理器向操作系統(tǒng)發(fā)出一個“頁面失效”。如果地址確實(shí)是非法的,內(nèi)核就無法從失效地址上“換頁”;如果此時處理器工作在超級用戶態(tài),系統(tǒng)就會產(chǎn)生一個“Oops”消息。Oops顯示故障時的處理器狀態(tài),模塊CPU寄存器內(nèi)容,頁描述符表的位置,以及其他較為難以理解的信息。利用ksymoopsJ工具可以將這些十六進(jìn)制數(shù)據(jù)解析為內(nèi)核符號,然后再進(jìn)一步判斷錯誤的所在。

      2.1 Oops信息來源及格式

      Oops這個單詞含義為“驚訝”,當(dāng)內(nèi)核出錯時(比如訪問非法地址)打印出來的信息被稱為Oops信息。 Oops信息包含以下幾部分內(nèi)容:

      (1)一段文本描述信息。比如類似”Unable to handle kernel NULL pointer dereference at virtual address 00000000”的信息,他說明了發(fā)生的是哪類錯誤。

      (2)Oops信息的序號。比如是第幾次等。這些信息與下面類似,括號內(nèi)的數(shù)據(jù)表示序號。

      Internal error: Oops: 806 [#1]

      (3)內(nèi)核中加載的模塊名稱,也可能沒有,以下面字樣開頭。

      Modules linked in:

      (4)發(fā)生錯誤的CPU的序號,對于單處理器系統(tǒng),序號為0,如:

      CPU: 0 Not tainted (2.6.22.6 #36)

      (5)發(fā)生錯誤時CPU的各個寄存器值。

      (6)當(dāng)前進(jìn)程的名字及進(jìn)程ID,比如:

      Process swapper (pid: 1, stack limit =0xc0480258)

      這并不是說發(fā)生錯誤的是這個進(jìn)程,而是表示發(fā)生錯誤時,當(dāng)前進(jìn)程是它。錯誤可能發(fā)生在內(nèi)核代碼、驅(qū)動程序,也可能就是這個進(jìn)程的錯誤。

      (7)棧信息。

      (8)?;厮菪畔?,可以從中看出函數(shù)調(diào)用關(guān)系,形式如下:

      Backtrace:

      [](s3c2410fb_probe+0x0/0x560)from [](platform_drv_probe+0x20/0x24)

      (9)出錯指令附近的指令機(jī)器碼,比如(出錯指令在小括號內(nèi)):

      Code: e24cb004 e24dd010 e59f34e0 e3a07000(e5873000)

      2.2 使用 Oops 的棧信息手工進(jìn)行?;厮?/h3>

      從 Oops 信息的 PC寄存器值可知得知崩潰發(fā)生時的函數(shù)、出錯指令。但是錯誤有可能是它的調(diào)用者引入的,所以還要找出函數(shù)的調(diào)用關(guān)系。由于內(nèi)核配置了 CONFIG_FRAME_POINTER,當(dāng)出現(xiàn) Oops 信息時,會打印?;厮菪畔?。如果內(nèi)核沒有配置 CONFIG_FRAME_POINTER,這時可以自己分析棧信息,找到函數(shù)的調(diào)用關(guān)系。

      2.3 棧的作用

      一個程序包含代碼段、數(shù)據(jù)段、BSS 段、堆、棧;其中數(shù)據(jù)段用來中存儲初始值不為 0 的全局?jǐn)?shù)據(jù),BSS 段用來存儲初始值為 0 的全局?jǐn)?shù)據(jù),堆用于動態(tài)內(nèi)存分配,棧用于實(shí)現(xiàn)函數(shù)調(diào)用、存儲局部變量。被調(diào)用函數(shù)在執(zhí)行之前,它會將一些寄存器的值保存在棧中,其中包括返回地址寄存器lr。如果知道了所保存的 lr 寄存的值,那么就可以知道它的調(diào)用者是誰。在棧信息中,一個函數(shù)一個函數(shù)地往上找出所有保存的 lr 值,就可以知道各個調(diào)用函數(shù),這就是?;厮莸脑怼?/p>

      3 ?;厮輰?shí)例分析

      故意修改 LCD 驅(qū)動程序 drivers/video/s3c2410fb.c,加入錯誤代碼:在 s3c2410fb_ probe函數(shù)的開頭增加下面兩條代碼:

      根據(jù) pc 寄存器值找到第一個函數(shù),確定它的棧大小,確定調(diào)用函數(shù)。

      從 Oops 信息 :

      可知 pc 值為 c0018f78,使用它在內(nèi)核反匯編程序 vmlinux.dis 中可以知道它位于 s3c2410fb_probe 函數(shù)內(nèi)。

      lr存放的是函數(shù)返回值地址,為c01d3f88,根據(jù)這個地址,搜索內(nèi)核反匯編程序 vmlinux.dis ,可知它位于:

      也就是說,函數(shù)s3c2410fb_probe() 被platform_drv_probe()調(diào)用。再看platform_drv_probe()的反匯編代碼,其中c01d3f70: e92d4010 push {r4, lr} ,棧中存放的是 r4, lr 對應(yīng)(查看上文中的棧的信息) ,其中,lr對應(yīng)的值為c01d2e7c,用此值檢索vmlinux.dis,位于

      可知,platform_drv_probe()被driver_probe_device()調(diào)用,再用同樣的方法就可以找出所有函數(shù)調(diào)用關(guān)系。 從而就能找到導(dǎo)致Segmentation fault錯誤的語句。

      4 結(jié)論

      在Linux內(nèi)核調(diào)試技術(shù)中,由于printk函數(shù)調(diào)試的使用方法簡單,分析問題效率較高,因此內(nèi)核打印函數(shù)printk是眾多開發(fā)者所最喜愛的一種調(diào)試技術(shù)。但在驅(qū)動開發(fā)的情況下出現(xiàn)的錯誤幾乎都會涉及到段錯誤,所以掌握通過Oops信息使用?;厮菁夹g(shù)在Linux嵌入式驅(qū)動開發(fā)中變得不可或缺的一項(xiàng)調(diào)試技能。

      [1]毛德操,胡希明.LINUX內(nèi)核代碼情景分析[M].杭州:浙江大學(xué)出版社,2001.

      [2]Rubimi A.Linux設(shè)備驅(qū)動程序[M].聊鴻斌譯.北京:中國電力出版社,1999.

      [3]宋寶華.Linux設(shè)備驅(qū)動開發(fā)詳解[M].北京:人民郵電出版社,2010.

      [4]何紹然,史海濱,吳國成,宋寶華.精通linux設(shè)備驅(qū)動程序開發(fā)[M].北京:人民郵電出版社,2010.

      [5]李紅衛(wèi),李翠萍.kgdb調(diào)試Linux內(nèi)核的剖析與改進(jìn)[J].微型機(jī)與應(yīng)用,2004(10):7-10.

      [6]張磊,王學(xué)慧.Linux內(nèi)核調(diào)試技術(shù)[J].計算機(jī)工程,2003,29(10):8l-83.

      [7]孫悅紅.編譯原理及實(shí)現(xiàn)[M].北京:清華大學(xué)出版社,2005:14-17.

      [8]李善平,劉文峰.Linux內(nèi)核2.4版源代碼分析大全[M].北京:機(jī)械工業(yè)出版社,2002.

      猜你喜歡
      驅(qū)動程序內(nèi)核寄存器
      萬物皆可IP的時代,我們當(dāng)夯實(shí)的IP內(nèi)核是什么?
      強(qiáng)化『高新』內(nèi)核 打造農(nóng)業(yè)『硅谷』
      Lite寄存器模型的設(shè)計與實(shí)現(xiàn)
      基于嵌入式Linux內(nèi)核的自恢復(fù)設(shè)計
      Linux內(nèi)核mmap保護(hù)機(jī)制研究
      分簇結(jié)構(gòu)向量寄存器分配策略研究*
      高速數(shù)模轉(zhuǎn)換器AD9779/AD9788的應(yīng)用
      一種可重構(gòu)線性反饋移位寄存器設(shè)計
      驅(qū)動程序更新與推薦
      驅(qū)動程序更新與推薦
      龙州县| 塔城市| 扬州市| 台前县| 阿拉善左旗| 安西县| 卢湾区| 招远市| 日土县| 双鸭山市| 融水| 西吉县| 本溪| 新竹县| 区。| 五莲县| 礼泉县| 仁布县| 和静县| 吐鲁番市| 湾仔区| 京山县| 峨眉山市| 东莞市| 万盛区| 崇阳县| 抚远县| 鄂伦春自治旗| 廉江市| 永德县| 晋城| 仪征市| 威海市| 阜城县| 桂阳县| 萨嘎县| 明水县| 江安县| 日土县| 周宁县| 宜宾市|