oops的解讀方法-----怎麼通過oops查找源碼行

-----------------------------------------------------------------------
本文系本站原創,歡迎轉載!
轉載請註明出處:http://blog.csdn.net/android_huber
交流郵箱:[email protected]
-----------------------------------------------------------------------

    今天很鬱悶的遇到了一個oops,以前碰到這類事情我就會退縮的,今天剛好沒有任務,就想要不就分析一下,這個還是很重要的,我不能總是逃避這類問題啊,果斷開始分析了。

    先把oops亮出來給大夥看看,

[ 230.893864] Unable to handle kernel paging request at virtual address 
9c0d5030
[ 230.959592] pgd = 9aaf8000
[ 230.962313] [9c0d5030] *pgd=aa003011, *pte=00000000, *ppte=00000000
[ 231.001197] Internal error: Oops: 7 [#1] PREEMPT
[ 231.005821] last sysfs file: 
/sys/devices/platform/wakeup_event-driver/wakeup_source
[ 231.013571] Modules linked in: dhd(-)
[ 231.017270] CPU: 0 Not tainted (2.6.35.3 #1)
[ 231.022037] PC is at dhdsdio_htclk+0x28/0x438 [dhd]
[ 231.026977] LR is at dhdsdio_clkctl+0x5c/0x108 [dhd]
[ 231.031950] pc : [<7f012d84>] lr : [<7f013490>] psr: 20000013
[ 231.031956] sp : 9ae41e30 ip : 00000000 fp : 2b3408f0
[ 231.043450] r10: 35c61ef0 r9 : 9ae40000 r8 : 00000001
[ 231.048681] r7 : 00000000 r6 : 00000000 r5 : 9c096000 r4 : 9c09f000
[ 231.055217] r3 : 00000000 r2 : 9c0d5000 r1 : 00004329 r0 : 9c09f000
[ 231.061754] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
[ 231.068898] Control: 10c5387d Table: aaaf8019 DAC: 00000015
[ 231.074652] Process WifiService (pid: 2580, stack limit = 0x9ae402e8)
[ 231.081100] Stack: (0x9ae41e30 to 0x9ae42000)
[ 231.085468] 1e20: 9ae41eb4 803f17d0 20000093 80814e28
[ 231.093659] 1e40: 94073900 80814e28 00000001 20000013 9c1dc714 
9c09f000 00000003 00000000
[ 231.101850] 1e60: 9c1dc03c 00000001 9ae40000 35c61ef0 2b3408f0 
7f013490 9c09f000 00000000
[ 231.110042] 1e80: 9ae636c0 7f0155b0 9c09f000 00000001 9ae41e68 
00000000 9c1dc000 9c1dc0a8
[ 231.118234] 1ea0: 9c1df000 9c1dc03c 8004c0c4 7f00142c 9c1dc000 
7f00159c 9c09f000 9ae636c0
[ 231.126426] 1ec0: 7f025240 67e04660 8004c0c4 7f014638 7f025228 
9c093000 7f025240 7f01b24c
[ 231.134617] 1ee0: 922df400 7f02337c 922df43c 802ebcd0 922df408 
7f02337c 922df43c 802178b0
[ 231.142809] 1f00: 922df408 7f02337c 922df43c 80217980 7f02337c 
00000000 80846374 80216c24
[ 231.151000] 1f20: 7f0233b0 00000000 9ae41f44 7f01b3d0 7f0233b0 
7f01b5b0 7f0233b0 8009b1d4
[ 231.159191] 1f40: 00000000 00646864 00000000 9ad9f8dc 00000001 
39c2a6d3 00015e23 00000000
[ 231.167382] 1f60: ffffffff 00000000 00000000 39dd6b48 00000003 
00000003 39dd6c10 00000107
[ 231.175573] 1f80: 7f0233b0 00000880 9ae41f8c 00000000 39dd6b48 
ffffffff 67e04544 00000009
[ 231.183764] 1fa0: 00000081 8004bf40 ffffffff 67e04544 67e04660 
00000880 35c61f34 33d63f1c
[ 231.191955] 1fc0: ffffffff 67e04544 00000009 00000081 39dd6b68 
35c61f04 35c61ef0 2b3408f0
[ 231.200147] 1fe0: 67e06288 39dd6b30 67e03f01 6fd0c44c 20000010 
67e04660 7fff6d67 fdf7f39f
[ 231.208458] [<7f012d84>] (dhdsdio_htclk+0x28/0x438 [dhd]) from 
[<7f013490>] (dhdsdio_clkctl+0x5c/0x108 [dhd])
[ 231.218497] [<7f013490>] (dhdsdio_clkctl+0x5c/0x108 [dhd]) from 
[<7f0155b0>] (dhd_bus_stop+0x48/0x2ac [dhd])
[ 231.228426] [<7f0155b0>] (dhd_bus_stop+0x48/0x2ac [dhd]) from 
[<7f00142c>] (dhd_bus_detach+0x2c/0x44 [dhd])
[ 231.238242] [<7f00142c>] (dhd_bus_detach+0x2c/0x44 [dhd]) from 
[<7f00159c>] (dhd_detach+0x158/0x1c0 [dhd])
[ 231.247993] [<7f00159c>] (dhd_detach+0x158/0x1c0 [dhd]) from 
[<7f014638>] (dhdsdio_release+0x40/0xcc [dhd])
[ 231.257861] [<7f014638>] (dhdsdio_release+0x40/0xcc [dhd]) from 
[<7f01b24c>] (bcmsdh_remove+0x1c/0x8c [dhd])
[ 231.267779] [<7f01b24c>] (bcmsdh_remove+0x1c/0x8c [dhd]) from 
[<802ebcd0>] (sdio_bus_remove+0x18/0x54)
[ 231.277116] [<802ebcd0>] (sdio_bus_remove+0x18/0x54) from [<802178b0>] 
(__device_release_driver+0x84/0xd0)
[ 231.286790] [<802178b0>] (__device_release_driver+0x84/0xd0) from 
[<80217980>] (driver_detach+0x84/0xac)
[ 231.296287] [<80217980>] (driver_detach+0x84/0xac) from [<80216c24>] 
(bus_remove_driver+0x90/0xb8)
[ 231.305324] [<80216c24>] (bus_remove_driver+0x90/0xb8) from 
[<7f01b3d0>] (sdio_function_cleanup+0xc/0x2c [dhd])
[ 231.315522] [<7f01b3d0>] (sdio_function_cleanup+0xc/0x2c [dhd]) from 
[<7f01b5b0>] (dhd_module_cleanup+0x8/0x14 [dhd])
[ 231.326140] unwind: Index not found 7f01b5b0
[ 231.330421] Code: 0a0000d5 e5902008 e3041329 e5d031d8 (e5920030)
[ 232.176926] ---[ end trace 23c706acef457857 ]---

    從上面很明顯的可以看出是一個dhd模塊出錯了,在我的這個板子上是一個wifi的驅動,

    這麼一大串,嚇到了。。。。

    乍看是在dhdsdio_htclk這個函數中出錯了,因爲有這麼一個片段的log啊

PC is at dhdsdio_htclk+0x28/0x438 [dhd]

此是pc的值是在dhdsdio_htclk這個函數的範圍內(啥,,你不知道pc是啥玩意,,那這個就靠你自己去google一下啦)

下面我要做的事情就是要將這個函數所對應的c文件產生的.o文件反彙編一下,如下:

./prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-objdump -D external/linux-bcm4329-wifi/src/dhd/linux/dhd-cdc-sdmmc-gpl-2.6.35/dhd_sdio.o > dhd_dump.text
    這樣dhd_sdio.c的反彙編代碼就保存在dhd_dump.txt裏面(注:這個是android環境下的代碼路徑)啦,我們找到dhdsdio_htclk這個函數的所在位置(我只貼相關部分,還附帶了我的註釋,彙編的註釋就是c啦,哈哈哈)

00000124 <dhdsdio_htclk>:
     124:   e3510000    cmp r1, #0  ; 0x0   ;r1=on
     128:   e92d4ff0    push    {r4, r5, r6, r7, r8, r9, sl, fp, lr}
     12c:   e1a04000    mov r4, r0  ;r4=r0=bus
     130:   e24dd024    sub sp, sp, #36 ; 0x24
     134:   e1a07002    mov r7, r2
     138:   e5905004    ldr r5, [r0, #4]    ; sdh = bus->sdh; r5=sdh    ;ok
     13c:   0a0000d5    beq 498 <dhdsdio_htclk+0x374>
     140:   e5902008    ldr r2, [r0, #8]    ; r0+8=bus->sih ; r2=bus->sih   ;ok sih's real address
     144:   e3041329    movw    r1, #17193  ; 0x4329        ;ok
     148:   e5d031d8    ldrb    r3, [r0, #472]  ;r3=r0+472=bus->alp_only ; r3 = clkreq = bus->alp_only = 0;
     14c:   e5920030    ldr r0, [r2, #48]   ;r0=r2+48=bus->sih->chip    ;XXXXXXX  NO
     150:   e3530000    cmp r3, #0  ; 0x0   ;clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
     154:   13a03008    movne   r3, #8  ; 0x8
     158:   03a03010    moveq   r3, #16 ; 0x10
     15c:   e1500001    cmp r0, r1
     160:   1a000002    bne 170 <dhdsdio_htclk+0x4c>
     164:   e5922034    ldr r2, [r2, #52]   ;;r2+52=bus->sih->chiprev
     168:   e3520000    cmp r2, #0  ; 0x0
     16c:   03833001    orreq   r3, r3, #1  ; 0x1   ;clkreq |= SBSDIO_FORCE_ALP; r3=clkreq
     170:   e1a00005    mov r0, r5
     174:   e3a01001    mov r1, #1  ; 0x1
     178:   e59f23a8    ldr r2, [pc, #936]  ; 528 <dhdsdio_htclk+0x404>
     17c:   e28dc01c    add ip, sp, #28 ; 0x1c
     180:   e58dc000    str ip, [sp]
     184:   ebfffffe    bl  0 <bcmsdh_cfg_write>
       ......(後面省略一大段)
下面再貼出c的代碼啦,別急喔,

static int
dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
{
    int err;
    uint8 clkctl, clkreq, devctl;
    bcmsdh_info_t *sdh;

    DHD_TRACE(("%s: Enter\n", __FUNCTION__));

#if defined(OOB_INTR_ONLY)
    pendok = FALSE;
#endif
    clkctl = 0;
    sdh = bus->sdh;


    if (on) {
        /* Request HT Avail */
        clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;

        if ((bus->sih->chip == BCM4329_CHIP_ID) && (bus->sih->chiprev == 0))
            clkreq |= SBSDIO_FORCE_ALP;




        bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
        if (err) {
            DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
            return BCME_ERROR;
        }
    ........(下面省略一大段)

PC is at dhdsdio_htclk+0x28/0x438 [dhd]
可知問題出在 從dhdsdio_htclk+0x28的代碼處,由反彙編代碼知dhdsdio_htclk在124位置處,加上0x28的話,就是0x14c處,我們找到0x14c對應的彙編代碼

 14c:   e5920030    ldr r0, [r2, #48]   ;r0=r2+48=bus->sih->chip    ;XXXXXXX  NO

對於這段彙編代碼,我在上面已經大概做出註釋了,

    140:   e5902008    ldr r2, [r0, #8]    ; r0+8=bus->sih ; r2=bus->sih   ;ok sih's real address
由上一行彙編得知r2保存的是bus->sih的地址,r2偏移48那就是sih中的chip成員啦,可以給出sih的結構定義,如下

typedef struct dhd_bus {
    dhd_pub_t   *dhd;

    bcmsdh_info_t   *sdh;           /* Handle for BCMSDH calls */
    si_t        *sih;           /* Handle for SI calls */
    char        *vars;          /* Variables (from CIS and/or other) */
    ...... dhd_bus的定義,下面省略,只需關注sih這個成員變量
接着來看看sih的定義(即si_t)

struct si_pub {
    uint    socitype;       
    
    uint    bustype;     
    uint    buscoretype;
    uint    buscorerev; 
    uint    buscoreidx;
    int ccrev;       
    uint32  cccaps;
    int pmurev;       
    uint32  pmucaps;
    uint    boardtype;      
    uint    boardvendor;
    uint    boardflags;
    uint    chip;
    uint    chiprev;     
    uint    chippkg; 
    uint32  chipst;   
    bool    issim;    
    uint    socirev;   
    bool    pci_pr32414;
};
    
#if defined(WLC_HIGH) && !defined(WLC_LOW)
typedef struct si_pub si_t;
#else
typedef const struct si_pub si_t;
#endif

這樣就方便看彙編啦,

從上面的分析可知,我們的代碼是在讀取r2+48(即r2+0x30)這個地址所對應的值,然後保存到r0中的時候出錯的,

下面來驗證我上面的分析。

-------------------------------------------------------驗證---------------------------------------------------------

[ 231.043450] r10: 35c61ef0 r9 : 9ae40000 r8 : 00000001
[ 231.048681] r7 : 00000000 r6 : 00000000 r5 : 9c096000 r4 : 9c09f000
[ 231.055217] r3 : 00000000 r2 : 9c0d5000 r1 : 00004329 r0 : 9c09f000
oops提供的信息中包含了各個寄存器的值,讓我們來看看r2,r2=0x9c0d5000,

那麼r2+0x30=0x9c0d5030

好了,我們知道是在讀取0x9c0d5030這個地址處的值,然後保存到r0的時候出現oops的,那麼到底是讀取的時候出錯了,還是保存的時候出錯了呢,

下面我們再來看一句可以驗證我們想法的log信息,那就是oops的第一句,如下

Unable to handle kernel paging request at virtual address 9c0d5030
    注意看這個地址,,注意看最後的這個地址啊,,,,,,9c0d5030,哇,,好熟悉啊,不就是我們上面算出來的值麼,,,,怎麼驗證了吧,是在讀取這個地址的值的時候出錯的。。。瓦咔咔,,,分析出來了,,


------------------------------------------------------後續--------------------------------------------------------

    上面好像一片和諧的景象啊,,結果有了,哈哈哈,可是不要高興的太早喔,,結果是有了,可是該怎麼解決呢,,畢竟我們分析問題的目的就是爲了解決問題啊。。

單從該問題來說,我覺得可能是因爲sih這個變量已經被deatch了,但是還沒有驗證,問題比較偶現,,唉,,最煩偶現的bug了,,

    其實寫這篇文章的目的也主要是爲了講述怎麼從oops信息中去查找對應c代碼中的錯誤行的,在linux內核調試中還是很有用的。

    

Unable to handle kernel paging request at virtual address <pre name="code" class="cpp">9c0d5030

   

    其實對於這句話我還是沒有能夠理解到底是怎麼了,怎麼會出現這種錯誤,

    如果哪位朋友對這個比較瞭解的話,希望能不吝賜教,多多回帖幫我解惑,再此先感謝了。

ps: 解答上面的問題

不能訪問的內核虛地址爲45685516,內核中一般可訪問的地址都是以0xCXXXXXXX開頭的地址。



//---------------------------------------------------------------------------------------------------------------------------------------------------------------------

Oops: 0002 [#1]

這裏面,0002表示Oops的錯誤代碼(寫錯誤,發生在內核空間),#1表示這個錯誤發生一次。

Oops的錯誤代碼根據錯誤的原因會有不同的定義,本文中的例子可以參考下面的定義(如果發現自己遇到的Oops和下面無法對應的話,最好去內核代碼裏查找):

 * error_code:

 *      bit 0 == 0 means no page found, 1 means protection fault

 *      bit 1 == 0 means read, 1 means write

 *      bit 2 == 0 means kernel, 1 means user-mode

 *      bit 3 == 0 means data, 1 means instruction


發佈了24 篇原創文章 · 獲贊 19 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章