36.Linux驅動調試-根據oops定位錯誤代碼行

来源:http://www.cnblogs.com/lifexy/archive/2017/12/08/8006748.html
-Advertisement-
Play Games

1.當驅動有誤時,比如,訪問的記憶體地址是非法的,便會列印一大串的oops出來 1.1以LED驅動為例 將open()函數里的ioremap()屏蔽掉,直接使用物理地址的GPIOF,如下圖所示: 1.2然後編譯裝載26th_segmentfault並執行測試程式後,內核便列印了oops出來,如下圖所示 ...


1.當驅動有誤時,比如,訪問的記憶體地址是非法的,便會列印一大串的oops出來

1.1以LED驅動為例

將open()函數里的ioremap()屏蔽掉,直接使用物理地址的GPIOF,如下圖所示:

 

1.2然後編譯裝載26th_segmentfault並執行測試程式後,內核便列印了oops出來,如下圖所示:

 

 

2.接下來,我們便來分析oops:

Unable to handle kernel paging request at virtual address 56000050
      //無法處理內核頁面請求的虛擬地址56000050

pgd = c3850000
[56000050] *pgd=00000000

Internal error: Oops: 5 [#1]
        //內部錯誤oops

Modules linked in: 26th_segmentfault
        //表示內部錯誤發生在26th_segmentfault.ko驅動模塊里

CPU: 0    Not tainted  (2.6.22.6 #2)
PC is at first_drv_open+0x78/0x12c [26th_segmentfault]
        //PC值:程式運行成功的最後一次地址,位於first_drv_open()函數里,偏移值0x78,該函數總大小0x12c

LR is at 0xc0365ed8             //LR值

/*發生錯誤時的各個寄存器值*/
pc : [<bf000078>]    lr : [<c0365ed8>]    psr: 80000013
sp : c3fcbe80  ip : c0365ed8  fp : c3fcbe94
r10: 00000000  r9 : c3fca000  r8 : c04df960
r7 : 00000000  r6 : 00000000  r5 : bf000de4  r4 : 00000000
r3 : 00000000  r2 : 56000050  r1 : 00000001  r0 : 00000052

Flags: Nzcv  IRQs on  FIQs on  Mode SVC_32  Segment user
Control: c000717f  Table: 33850000  DAC: 00000015
Process 26th_segmentfau (pid: 813, stack limit = 0xc3fca258)
            //發生錯誤時,進程名稱為26th_segmentfault

Stack: (0xc3fcbe80 to 0xc3fcc000)                     //棧信息
be80: c06d7660 c3e880c0 c3fcbebc c3fcbe98 c008d888 bf000010 00000000 c04df960
bea0: c3e880c0 c008d73c c0474e20 c3fb9534 c3fcbee4 c3fcbec0 c0089e48 c008d74c
bec0: c04df960 c3fcbf04 00000003 ffffff9c c002c044 c380a000 c3fcbefc c3fcbee8
bee0: c0089f64 c0089d58 00000000 00000002 c3fcbf68 c3fcbf00 c0089fb8 c0089f40
bf00: c3fcbf04 c3fb9534 c0474e20 00000000 00000000 c3851000 00000101 00000001
bf20: 00000000 c3fca000 c04c90a8 c04c90a0 ffffffe8 c380a000 c3fcbf68 c3fcbf48
bf40: c008a16c c009fc70 00000003 00000000 c04df960 00000002 be84ce38 c3fcbf94
bf60: c3fcbf6c c008a2f4 c0089f88 00008588 be84ce84 00008718 0000877c 00000005
bf80: c002c044 4013365c c3fcbfa4 c3fcbf98 c008a3a8 c008a2b0 00000000 c3fcbfa8
bfa0: c002bea0 c008a394 be84ce84 00008718 be84ce30 00000002 be84ce38 be84ce30
bfc0: be84ce84 00008718 0000877c 00000003 00008588 00000000 4013365c be84ce58
bfe0: 00000000 be84ce28 0000266c 400c98e0 60000010 be84ce30 30002031 30002431

Backtrace:                                        //回溯信息
[<bf000000>] (first_drv_open+0x0/0x12c [26th_segmentfault]) from [<c008d888>] (chrdev_open+0x14c/0x164)
 r5:c3e880c0 r4:c06d7660
[<c008d73c>] (chrdev_open+0x0/0x164) from [<c0089e48>] (__dentry_open+0x100/0x1e8)
 r8:c3fb9534 r7:c0474e20 r6:c008d73c r5:c3e880c0 r4:c04df960
[<c0089d48>] (__dentry_open+0x0/0x1e8) from [<c0089f64>] (nameidata_to_filp+0x34/0x48)
[<c0089f30>] (nameidata_to_filp+0x0/0x48) from [<c0089fb8>] (do_filp_open+0x40/0x48)
 r4:00000002
[<c0089f78>] (do_filp_open+0x0/0x48) from [<c008a2f4>] (do_sys_open+0x54/0xe4)
 r5:be84ce38 r4:00000002
[<c008a2a0>] (do_sys_open+0x0/0xe4) from [<c008a3a8>] (sys_open+0x24/0x28)
[<c008a384>] (sys_open+0x0/0x28) from [<c002bea0>] (ret_fast_syscall+0x0/0x2c)
Code: bf000094 bf0000b4 bf0000d4 e5952000 (e5923000)
Segmentation fault

2.1上面的回溯信息,表示了函數的整個調用過程

比如上面的回溯信息表示:

  • sys_open()->do_sys_open()->do_filp_open()->nameidata_to_filp()->chrdev_open()->first_drv_open();

最終錯誤出在了first_drv_open();

 若內核沒有配置回溯信息顯示,則就不會列印函數調用過程,可以修改內核的.config文件,添加:

 //CONFIG_FRAME_POINTER,表示幀指針,用fp寄存器表示

 內核里,就會通過fp寄存器記錄函數的運行位置,並存到棧里,然後當出問題時,從棧里調出fp寄存器,查看函數的調用關係,就可以看到回溯信息.

(PS:若不配置,也可以直接通過棧來分析函數調用過程,在下章會分析到:http://www.cnblogs.com/lifexy/p/8011966.html)

2.2而有些內核的環境不同,opps也可能不會列印出上面的:

Modules linked in: 26th_segmentfault
PC is at first_drv_open+0x78/0x12c [26th_segmentfault]

這些相關信息, 只列印PC值,就根本無法知道,到底是驅動模塊出的問題,還是內核自帶的函數出的問題? 

所以oops里的最重要內容還是這一段: pc : [<bf000078>]

 

2.3那麼如何來確定,該PC值地址位於內核的函數,還是我們裝載的驅動模塊?

答:

可以在內核源碼的根目錄下通過的“vi System.map”來查看,該文件保存了內核里所有(符號、函數)的虛擬地址映射,比如下圖的內核函數root_dev_setup():

 

通過vi命令的:0和:$命令行,可以看到內核的虛擬地址是c0004000~c03cebf4

所以,pc值bf000078為的驅動模塊的地址值 

 

2.4當有多個驅動裝載時,又如何區分PC值是哪個驅動的函數的地址值?

答:通過/proc/kallsyms來查看:

#cat /proc/kallsyms  //(kernel all symbols)查看所有的內核標號(包括內核函數,裝載的驅動函數,變數符號等)的地址值

或者:

#cat  /proc/kallsyms> /kallsyms.txt    //將地址值放入kallsyms.txt中

如下圖所示,在kallsyms.txt里,找到pc值bf000078位於26th_segmentfault驅動里first_drv_open()函數下的bf000000+0x78

 

2.5然後將驅動生成反彙編:

arm-linux-objdump -D 26th_segmentfault.ko >26th_segmentfault.dis //反彙編

 

2.6打開反彙編:

如下圖所示,左邊是kallsyms.txt,右邊是26th_segmentfault.dis反彙編

 

顯然pc值bf000078,就位於反彙編的78地址處:

Disassembly of section .text:         //.text段起始地址為0x00
00000000 <first_drv_open>:

38: e59fc0e8   ldr   ip, [pc, #232]; 128 <.text+0x128> //ip=.text段+0x128里的內容
... ...

50: e585c000   str   ip, [r5]       //r5=.text段+0x128里的內容
... ...

74: e5952000   ldr   r2, [r5]           //r2=.text段+0x128里的內容
78: e5923000   ldr   r3, [r2]                  // r3=.text段+0x128里的內容
7c: e3c33c3f   bic   r3,  r3,   #16128    ;0x3f00  //清除0x56000050的bit8~13
... ...

128:  56000050  undefined                //.text段+0x128里的內容=0x56000050

(PS:其中, pc值78表示的是最後運行成功的地址,所以出錯地址在78+4上)

所以,找到了出錯地方位於first_drv_open ()函數下:

 

3.若發生錯誤的驅動位於內核的地址值時

3.1還是以26th_segmentfault.c為例,首先加入內核:

#cp 26th_segmentfault.c   /linux-2.6.22.6/drivers/char/  //將有問題的驅動複製到字元驅動目錄下

 

#vi Makefile

添加:

obj-y    += 26th_segmentfault.o                            //y:將該驅動放入內核中

 

3.2然後make uImage裝載新內核後,再運行測試程式,便會列印出opps信息

3.3在內核源碼的根目錄下通過:

# arm-none-linux-gnueabi-objdump -D vmlinux > vmlinux.dis

將整個內核反彙編, vmlinux:未壓縮的內核

3.4 vi vmlinux.dis,然後通過oops信息的PC值直接來查找地址即可

 

接下來下章便通過信息來分析函數調用過程:http://www.cnblogs.com/lifexy/p/8011966.html

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、配置centOS虛擬機網卡 先設置橋接模式 此處的address要和本機的vmware在同一個網段 2、重啟centOS網卡 3、關閉本機和虛擬機防火牆,防止ping不通 centOS命令: firewall-cmd --state #查看預設防火牆狀態(關閉後顯示notrunning,開啟後顯 ...
  • 虛擬機破解秘密碼步驟: 虛擬機(server)的登錄通常需要一個本地用戶,而本地用戶密碼假如不知道或者是已經忘記了,也是有辦法進入的,在Linux系統內就有可以提供這種可以進入的方案,而基本思路就是重置管理員(root)的登錄密碼,具體操作如下: 1、重啟虛擬機 server,出現 GRUB 啟動菜 ...
  • Linux上的文件系統一般來說就是EXT2或EXT3,但這篇文章並不准備一上來就直接講它們,而希望結合Linux操作系統並從文件系統建立的基礎——硬碟開始,一步步認識Linux的文件系統。## 1.機械硬碟的物理存儲機制現代電腦大部分文件存儲功能都是由機械硬碟這種設備提供的。(現在的SSD和快閃記憶體從... ...
  • 上章鏈接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我們分析了oops的PC值在哪個函數出錯的 本章便通過棧信息來分析函數調用過程 1.上章的oops棧信息如下圖所示: 9fe0: 代表最初的棧頂SP寄存器位置 9e80:代表函數出錯的 ...
  • Mysql實現企業級資料庫主從複製架構實戰 環境背景:公司規模已經形成,用戶數據已成為公司的核心命脈,一次老王一不小心把資料庫文件刪除,通過mysqldump備份策略恢復用了兩個小時,在這兩小時中,公司業務中斷,損失100萬,老王做出深刻反省,公司也因此對於資料庫的性能和可靠性提出更高要求。 要求對 ...
  • 原地址:http://blog.sina.com.cn/s/blog_9ba89b9901019bn9.html 用好Vmware Workstation 的克隆來簡化虛擬機的安裝配置: 好像是從Vmware5開始,增加了克隆的功能。在5.5中,克隆功能進一步強大了不少。充分利用好Vmware的克隆 ...
  • 本節主要介紹Linux基本服務的部署步驟,並以httpd服務的部署進行了詳細說明。 ...
  • 本節主要介紹Linux的文件系統,包括文件存儲結構,硬碟的分區、格式化、掛載,文件和目錄的軟鏈接、硬鏈接。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...