oops的解读方法-----怎么通过oops查找源码行

来源:互联网 发布:剑三遗失的尊敬淘宝 编辑:程序博客网 时间:2024/05/21 08:46

-----------------------------------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:http://blog.csdn.net/android_huber
交流邮箱:dp.shao@gmail.com
-----------------------------------------------------------------------

    今天很郁闷的遇到了一个oops,以前碰到这类事情我就会退缩的,今天刚好没有任务,就想要不就分析一下,这个还是很重要的,我不能总是逃避这类问题啊,果断开始分析了。

    先把oops亮出来给大伙看看,

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

    从上面很明显的可以看出是一个dhd模块出错了,在我的这个板子上是一个wifi的驱动,

    这么一大串,吓到了。。。。

    乍看是在dhdsdio_htclk这个函数中出错了,因为有这么一个片段的log啊

[cpp] view plaincopy
  1. PC is at dhdsdio_htclk+0x28/0x438 [dhd]  

此是pc的值是在dhdsdio_htclk这个函数的范围内(啥,,你不知道pc是啥玩意,,那这个就靠你自己去google一下啦)

下面我要做的事情就是要将这个函数所对应的c文件产生的.o文件反汇编一下,如下:

[cpp] view plaincopy
  1. ./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啦,哈哈哈)

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

[cpp] view plaincopy
  1. static int  
  2. dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)  
  3. {  
  4.     int err;  
  5.     uint8 clkctl, clkreq, devctl;  
  6.     bcmsdh_info_t *sdh;  
  7.   
  8.     DHD_TRACE(("%s: Enter\n", __FUNCTION__));  
  9.   
  10. #if defined(OOB_INTR_ONLY)  
  11.     pendok = FALSE;  
  12. #endif  
  13.     clkctl = 0;  
  14.     sdh = bus->sdh;  
  15.   
  16.   
  17.     if (on) {  
  18.         /* Request HT Avail */  
  19.         clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;  
  20.   
  21.         if ((bus->sih->chip == BCM4329_CHIP_ID) && (bus->sih->chiprev == 0))  
  22.             clkreq |= SBSDIO_FORCE_ALP;  
  23.   
  24.   
  25.   
  26.   
  27.         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);  
  28.         if (err) {  
  29.             DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));  
  30.             return BCME_ERROR;  
  31.         }  
  32.     ........(下面省略一大段)  

[cpp] view plaincopy
  1. PC is at dhdsdio_htclk+0x28/0x438 [dhd]  
可知问题出在 从dhdsdio_htclk+0x28的代码处,由反汇编代码知dhdsdio_htclk在124位置处,加上0x28的话,就是0x14c处,我们找到0x14c对应的汇编代码

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

对于这段汇编代码,我在上面已经大概做出注释了,

[cpp] view plaincopy
  1. 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的结构定义,如下

[cpp] view plaincopy
  1. typedef struct dhd_bus {  
  2.     dhd_pub_t   *dhd;  
  3.   
  4.     bcmsdh_info_t   *sdh;           /* Handle for BCMSDH calls */  
  5.     si_t        *sih;           /* Handle for SI calls */  
  6.     char        *vars;          /* Variables (from CIS and/or other) */  
  7.     ...... dhd_bus的定义,下面省略,只需关注sih这个成员变量  
接着来看看sih的定义(即si_t)

[cpp] view plaincopy
  1. struct si_pub {  
  2.     uint    socitype;         
  3.       
  4.     uint    bustype;       
  5.     uint    buscoretype;  
  6.     uint    buscorerev;   
  7.     uint    buscoreidx;  
  8.     int ccrev;         
  9.     uint32  cccaps;  
  10.     int pmurev;         
  11.     uint32  pmucaps;  
  12.     uint    boardtype;        
  13.     uint    boardvendor;  
  14.     uint    boardflags;  
  15.     uint    chip;  
  16.     uint    chiprev;       
  17.     uint    chippkg;   
  18.     uint32  chipst;     
  19.     bool    issim;      
  20.     uint    socirev;     
  21.     bool    pci_pr32414;  
  22. };  
  23.       
  24. #if defined(WLC_HIGH) && !defined(WLC_LOW)  
  25. typedef struct si_pub si_t;  
  26. #else  
  27. typedef const struct si_pub si_t;  
  28. #endif  

这样就方便看汇编啦,

从上面的分析可知,我们的代码是在读取r2+48(即r2+0x30)这个地址所对应的值,然后保存到r0中的时候出错的,

下面来验证我上面的分析。

-------------------------------------------------------验证---------------------------------------------------------

[cpp] view plaincopy
  1. [ 231.043450] r10: 35c61ef0 r9 : 9ae40000 r8 : 00000001  
  2. [ 231.048681] r7 : 00000000 r6 : 00000000 r5 : 9c096000 r4 : 9c09f000  
  3. [ 231.055217] r3 : 00000000 r2 : 9c0d5000 r1 : 00004329 r0 : 9c09f000  
oops提供的信息中包含了各个寄存器的值,让我们来看看r2,r2=0x9c0d5000,

那么r2+0x30=0x9c0d5030

好了,我们知道是在读取0x9c0d5030这个地址处的值,然后保存到r0的时候出现oops的,那么到底是读取的时候出错了,还是保存的时候出错了呢,

下面我们再来看一句可以验证我们想法的log信息,那就是oops的第一句,如下

[cpp] view plaincopy
  1. Unable to handle kernel paging request at virtual address 9c0d5030  
    注意看这个地址,,注意看最后的这个地址啊,,,,,,9c0d5030,哇,,好熟悉啊,不就是我们上面算出来的值么,,,,怎么验证了吧,是在读取这个地址的值的时候出错的。。。瓦咔咔,,,分析出来了,,


------------------------------------------------------后续--------------------------------------------------------

    上面好像一片和谐的景象啊,,结果有了,哈哈哈,可是不要高兴的太早喔,,结果是有了,可是该怎么解决呢,,毕竟我们分析问题的目的就是为了解决问题啊。。

单从该问题来说,我觉得可能是因为sih这个变量已经被deatch了,但是还没有验证,问题比较偶现,,唉,,最烦偶现的bug了,,

    其实写这篇文章的目的也主要是为了讲述怎么从oops信息中去查找对应c代码中的错误行的,在linux内核调试中还是很有用的。

    

[cpp] view plaincopy
  1. Unable to handle kernel paging request at virtual address  
   

    其实对于这句话我还是没有能够理解到底是怎么了,怎么会出现这种错误,

    如果哪位朋友对这个比较了解的话,希望能不吝赐教,多多回帖帮我解惑,再此先感谢了。

 

关于oops定位处理的一些收集整理


(
来自Linus Torvalds的讨论:
[url]https://groups.google.com/group/linux.kernel/browse_thread/thread/b70bffe9015a8c41/ed9c0a0cfcd31111[/url]
又,[url]http://kerneltrap.org/Linux/Further_Oops_Insights[/url]
)
     
        例如这样的一个Oops:
                Oops: 0000 [#1] PREEMPT SMP  
                Modules linked in: capidrv kernelcapi isdn slhc ipv6 loop dm_multipath snd_ens1371 gameport snd_rawmidi snd_ac97_codec ac97_bus snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd parport_pc floppy parport pcnet32 soundcore mii pcspkr snd_page_alloc ac i2c_piix4 i2c_core button power_supply sr_mod sg cdrom ata_piix libata dm_snapshot dm_zero dm_mirror dm_mod BusLogic sd_mod scsi_mod ext3 jbd mbcache uhci_hcd ohci_hcd ehci_hcd

                Pid: 1726, comm: kstopmachine Not tainted (2.6.24-rc3-module #2)
                EIP: 0060:[<c04e53d6>] EFLAGS: 00010092 CPU: 0
                EIP is at list_del+0xa/0x61
                EAX: e0c3cc04 EBX: 00000020 ECX: 0000000e EDX: dec62000
                ESI: df6e8f08 EDI: 000006bf EBP: dec62fb4 ESP: dec62fa4
                 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 
                Process kstopmachine (pid: 1726, ti=dec62000 task=df8d2d40 task.ti=dec62000)
                Stack: 000006bf dec62fb4 c04276c7 00000020 dec62fbc c044ab4c dec62fd0 c045336c
                       df6e8f08 c04532b4 00000000 dec62fe0 c043deb0 c043de75 00000000 00000000
                       c0405cdf df6e8eb4 00000000 00000000 00000000 00000000 00000000
                Call Trace:
                 [<c0406081>] show_trace_log_lvl+0x1a/0x2f
                 [<c0406131>] show_stack_log_lvl+0x9b/0xa3
                 [<c04061dc>] show_registers+0xa3/0x1df
                 [<c0406437>] die+0x11f/0x200
                 [<c0613cba>] do_page_fault+0x533/0x61a
                 [<c06123ea>] error_code+0x72/0x78
                 [<c044ab4c>] __unlink_module+0xb/0xf
                 [<c045336c>] do_stop+0xb8/0x108
                 [<c043deb0>] kthread+0x3b/0x63
                 [<c0405cdf>] kernel_thread_helper+0x7/0x10
                 =======================
                Code: 6b c0 e8 2e 7e f6 ff e8 d1 16 f2 ff b8 01 00 00 00 e8 aa 1c f4 ff 89 d8 83 c4 10 5b 5d c3 90 90 90 55 89 e5 53 83 ec 0c 8b 48 04 <8b> 11 39 c2 74 18 89 54 24 08 89 44 24 04 c7 04 24 be 32 6b c0  
                EIP: [<c04e53d6>] list_del+0xa/0x61 SS:ESP 0068:dec62fa4
                note: kstopmachine[1726] exited with preempt_count 1
     
        1, 有自己编译的vmlinux: 使用gdb
     
           编译时打开complie with debug info选项。 

           注意这行: 
     
                EIP is at list_del+0xa/0x61
     
           这告诉我们,list_del函数有0x61这么大,而Oops发生在0xa处。 那么我们先看一下list_del从哪里开始: 

                # grep list_del /boot/System.map-2.6.24-rc3-module
                c10e5234 T plist_del
                c10e53cc T list_del
                c120feb6 T klist_del
                c12d6d34 r __ksymtab_list_del
                c12dadfc r __ksymtab_klist_del
                c12e1abd r __kstrtab_list_del
                c12e9d03 r __kstrtab_klist_del

           于是我们知道,发生Oops时的EIP值是:

                c10e53cc + 0xa  == c10e53d6

           然后用gdb查看:

                # gdb /home/arc/build/linux-2.6/vmlinux
                (gdb) b *0xc10e53d6
                Breakpoint 1 at 0xc10e53d6: file /usr/src/linux-2.6.24-rc3/lib/list_debug.c, line 64.

           看,gdb直接就告诉你在哪个文件、哪一行了。

           gdb中还可以这样:

                # gdb Sources/linux-2.6.24/vmlinux
                (gdb) l *do_fork+0x1f
                0xc102b7ac is in do_fork (kernel/fork.c:1385).
                1380
                1381    static int fork_traceflag(unsigned clone_flags)
                1382    {
                1383            if (clone_flags & CLONE_UNTRACED)
                1384                    return 0;
                1385            else if (clone_flags & CLONE_VFORK) {
                1386                    if (current->ptrace & PT_TRACE_VFORK)
                1387                            return PTRACE_EVENT_VFORK;
                1388            } else if ((clone_flags & CSIGNAL) != SIGCHLD) {
                1389                    if (current->ptrace & PT_TRACE_CLONE)
                (gdb)

            也可以直接知道line number。

            或者:

                (gdb) l *(0xffffffff8023eaf0 + 0xff)  /* 出错函数的地址加上偏移 */



        2, 没有自己编译的vmlinux: TIPS

           如果在lkml或bugzilla上看到一个Oops,而自己不能重现,那就只能反汇编以"Code:"开始的行。 这样可以尝试定位到
           源代码中。

           注意,Oops中的Code:行,会把导致Oops的第一条指令,也就是EIP的值的第一个字节, 用尖括号<>括起来。 但是,有些
           体系结构(例如常见的x86)指令是不等长的(不一样的指令可能有不一样的长度),所以要不断的尝试(trial-and-error)。

           Linus通常使用一个小程序,类似这样:

                const char array[] = "\xnn\xnn\xnn...";
                int main(int argc, char *argv[])
                {
                        printf("%p\n", array);
                        *(int *)0 = 0;
                }

e.g. /*{{{*/ /* 注意, array一共有从array[0]到array[64]这65个元素, 其中出错的那个操作码<8b> == arry[43] */
#include <stdio.h>
#include <stdlib.h>


const char array[] ="\x6b\xc0\xe8\x2e\x7e\xf6\xff\xe8\xd1\x16\xf2\xff\xb8\x01\x00\x00\x00\xe8\xaa\x1c\xf4\xff\x89\xd8\x83\xc4\x10\x5b\x5d\xc3\x90\x90\x90\x55\x89\xe5\x53\x83\xec\x0c\x8b\x48\x04\x8b\x11\x39\xc2\x74\x18\x89\x54\x24\x08\x89\x44\x24\x04\xc7\x04\x24\xbe\x32\x6b\xc0";
int main(int argc, char *argv[])
{
        printf("%p\n", array);
        *(int *)0 = 0;
}
/*}}}*/



           用gcc -g编译,在gdb里运行它:

                [arc@dhcp-cbjs05-218-251 ~]$ gdb hello
                GNU gdb Fedora (6.8-1.fc9)
                Copyright (C) 2008 Free Software Foundation, Inc.
                License GPLv3+: GNU GPL version 3 or later <[url]http://gnu.org/licenses/gpl.html[/url]>
                This is free software: you are free to change and redistribute it.
                There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
                and "show warranty" for details.
                This GDB was configured as "x86_64-redhat-linux-gnu"...
                (no debugging symbols found)
                (gdb) r
                Starting program: /home/arc/hello
                0x80484e0

                Program received signal SIGSEGV, Segmentation fault.

           注意,这时候就可以反汇编0x80484e0这个地址:

                (gdb) disassemble 0x80484e0
                Dump of assembler code for function array:
                0x080484e0 <array+0>:   imul   $0xffffffe8,%eax,%eax
                0x080484e3 <array+3>:   jle,pn 0x80484dc <__dso_handle+20>
                0x080484e6 <array+6>:   ljmp   *<internal disassembler error>
                0x080484e8 <array+8>:   rcll   (%esi)
                0x080484ea <array+10>:  repnz (bad)
                0x080484ec <array+12>:  mov    $0x1,%eax
                0x080484f1 <array+17>:  call   0x7f8a1a0
                0x080484f6 <array+22>:  mov    %ebx,%eax
                0x080484f8 <array+24>:  add    $0x10,%esp
                0x080484fb <array+27>:  pop    %ebx
                0x080484fc <array+28>:  pop    %ebp
                0x080484fd <array+29>:  ret
                0x080484fe <array+30>:  nop
                0x080484ff <array+31>:  nop
                0x08048500 <array+32>:  nop
                0x08048501 <array+33>:  push   %ebp
                0x08048502 <array+34>:  mov    %esp,%ebp
                0x08048504 <array+36>:  push   %ebx
                0x08048505 <array+37>:  sub    $0xc,%esp
                0x08048508 <array+40>:  mov    0x4(%eax),%ecx
                0x0804850b <array+43>:  mov    (%ecx),%edx
                0x0804850d <array+45>:  cmp    %eax,%edx
                0x0804850f <array+47>:  je     0x8048529
                0x08048511 <array+49>:  mov    %edx,0x8(%esp)
                0x08048515 <array+53>:  mov    %eax,0x4(%esp)
                0x08048519 <array+57>:  movl   $0xc06b32be,(%esp)
                0x08048520 <array+64>:  add    %ah,0xa70
                End of assembler dump.
                (gdb)

          OK, 现在你知道出错的那条指令是array[43],也就是mov    (%ecx),%edx,也就是说,(%ecx)指向了一个错误内存地址。

补充:

为了使汇编代码和C代码更好的对应起来, Linux内核的Kbuild子系统提供了这样一个功能: 任何一个C文件都可以单独编译成汇编文件,例如:

make path/to/the/sourcefile.s

例如我想把kernel/sched.c编译成汇编,那么:

make kernel/sched.s V=1

或者:

make kernel/sched.lst V=1

         编译出*.s文件
           
           有时侯需要对*.s文件进行分析,以确定BUG所在的位置。 对任何一个内核build目录下的*.c文件,都可以
           直接编译出*.s文件。

                   # make drivers/net/e100.s V=1
           
           而对于自己写的module,就需要在Makefile中有一个灵活的target写法:
                   
                # cat Makefile
                obj-m := usb-skel.o
                KDIR := /lib/modules/`uname -r`/build
                traget := modules

                default:
                        make -C $(KDIR) M=$(shell pwd) $(target)
                clean:
                        rm -f *.o *.ko .*.cmd *.symvers *.mod.c
                        rm -rf .tmp_versions


                # make target=usb-skel.s V=1
           
           这样,kbuild系统才知道你要make的目标不是modules,而是usb-skel.s。




另外, 内核源代码目录的./scripts/decodecode文件是用来解码Oops的:

./scripts/decodecode < Oops.txt



其它收集


http://bbs.chinaunix.net/thread-3744197-1-1.html