精华内容
下载资源
问答
  • 用trace32分析内核死机

    2021-03-03 17:17:05
    因为ARM64内核的虚拟地址空间范围是0xFFFF_0000_0000_0000 =>0xFFFF_FFFF_FFFF_FFFF,很明显这个值0x0000000000000008不在范围内,它属于用户空间的虚拟地址空间,肯定会被MMU拦截掉上报data abort异常,所以此题的...

    dmesg 初步分析

    [  423.400073] Unable to handle kernel NULL pointer dereference at virtual address 00000008
    [  423.400075] [silead finger_interrupt_handler 505]:S IRQ 19 , GPIO 12 state is 0
    [  423.400083] [silead finger_interrupt_handler 506]:state is 0
    [  423.400096] pgd = ffffffc0017eb000
    [  423.400103] [00000008] *pgd=000000008ea0a003, *pud=000000008ea0a003, *pmd=000000008ea0b003, *pte=006000000b000707
    [  423.400124] Internal error: Oops: 96000046 [#1] PREEMPT SMP
    [  423.400132] Modules linked in: wlan(O)
    [  423.400148] CPU: 4 PID: 0 Comm: swapper/4 Tainted: G        W  O   3.18.31-perf #1
    [  423.400155] Hardware name: Qualcomm Technologies, Inc. MSM8940-PMI8950 MTP (DT)
    [  423.400164] task: ffffffc04eae4980 ti: ffffffc0b28bc000 task.ti: ffffffc0b28bc000
    [  423.400182] PC is at run_timer_softirq+0x4ac/0x5ec
    [  423.400192] LR is at run_timer_softirq+0x324/0x5ec
    [  423.400199] pc : [<ffffffc0000feb98>] lr : [<ffffffc0000fea10>] pstate: 600001c5
    [  423.400204] sp : ffffffc0b28bfb60
    ...
    [  423.401490] Process swapper/4 (pid: 0, stack limit = 0xffffffc0b28bc058)
    [  423.401496] Call trace:
    [  423.401510] [<ffffffc0000feb98>] run_timer_softirq+0x4ac/0x5ec
    [  423.401523] [<ffffffc0000a6864>] __do_softirq+0x178/0x350
    [  423.401532] [<ffffffc0000a6c8c>] irq_exit+0x74/0xb0
    [  423.401543] [<ffffffc0000edf18>] __handle_domain_irq+0xb4/0xec
    [  423.401553] [<ffffffc00008254c>] gic_handle_irq+0x54/0x84
    [  423.401560] Exception stack(0xffffffc0b28bfd40 to 0xffffffc0b28bfe60)
    ...
    [  423.401671] [<ffffffc000085da8>] el1_irq+0x68/0xd4
    [  423.401685] [<ffffffc000851480>] cpuidle_enter_state+0xd0/0x224
    [  423.401695] [<ffffffc0008516ac>] cpuidle_enter+0x18/0x20
    [  423.401706] [<ffffffc0000e1cc0>] cpu_startup_entry+0x288/0x384
    [  423.401717] [<ffffffc000091d5c>] secondary_start_kernel+0x108/0x114
    [  423.401728] Code: b90052a0 34000840 f9400321 f9400720 (f9000420) 
    [  423.401736] ---[ end trace d0daa1892c14378b ]---
    [  423.401753] Kernel panic - not syncing: Fatal exception in interrupt
    [  423.401774] CPU7: stopping
    

    连上trace32,load vmlinux后通过list source看下汇编源码混合显示,如下:

    • FFFFFFC0000FE968: 当前汇编指令的虚拟地址

    • F9000760: 汇编机器码,ARM/ARM64的指令机器码都是32位固定长度

    • str x0,[x27, #0x8]: 汇编指令,;后的是注释

    根据AAPCS(ARM二进制过程调用标准)参数传递规则,ARM64的 v0 - v7 参数直接由 x0 - x7 传递,其他参数由压栈传递,子程序返回结果保存到x0。

    那么这里可推导如下:

    x0 == prev, x1 == next

    指令:str x0 ,[x1,#0x8]
    x1+0x8 其实就是next+8个字节的偏移,看下:

    struct list_head {
        struct list_head *next, *prev;
    };
    

    ARM体系结构中,ARM64一个指针占8个字节内存,也就是: [x1+0x8] == prev

    所以这个str指令就是对应上面的next->prev = prev

    我们根据异常栈的寄存器值来看下:

    [  423.400182] PC is at run_timer_softirq+0x4ac/0x5ec
    [  423.400192] LR is at run_timer_softirq+0x324/0x5ec
    [  423.400199] pc : [<ffffffc0000feb98>] lr : [<ffffffc0000fea10>] pstate: 600001c5
    [  423.400204] sp : ffffffc0b28bfb60
    [  423.400210] x29: ffffffc0b28bfb60 x28: ffffffc0b2619038 
    [  423.400219] x27: ffffffc000c9a000 x26: 0000000000000000 
    [  423.400228] x25: ffffffc001741120 x24: ffffffc0006e277c 
    [  423.400237] x23: ffffffc0b2619000 x22: ffffffc0b28bfbf8 
    [  423.400246] x21: ffffffc0b28bc000 x20: ffffffc0013d2000 
    [  423.400254] x19: ffffffc0b2618000 x18: 0000007f9588e080 
    [  423.400263] x17: 0000007f9a36d4b4 x16: ffffffc0001e4f6c 
    [  423.400272] x15: 003b9aca00000000 x14: 0000000000000001 
    [  423.400280] x13: 0000000000000000 x12: 0000000000000001 
    [  423.400289] x11: 000000000000000f x10: ffffffc000c9c3f4 
    [  423.400297] x9 : 0000000000000000 x8 : 0000000000000005 
    [  423.400305] x7 : 0000000000000000 x6 : 000000000001451c 
    [  423.400314] x5 : ffffffc0b2ae8000 x4 : 00135f1aa15bb200 
    [  423.400323] x3 : 0000000000000018 x2 : 0000000000000000 
    [  423.400331] x1 : 0000000000000000 x0 : ffffffc0b28bfbf8
    

    上面可以看到,x1+0x8 ==0x0000000000000000+0x8==0x0000000000000008,这个和出错时候报的地址一致“Unable to handle kernel NULL pointer dereference at virtual address 00000008”

    因为ARM64内核的虚拟地址空间范围是0xFFFF_0000_0000_0000 =>0xFFFF_FFFF_FFFF_FFFF,很明显这个值0x0000000000000008不在范围内,它属于用户空间的虚拟地址空间,肯定会被MMU拦截掉上报data abort异常,所以此题的真正原因是程序跑飞访问非法地址所致。

    目前看来从kernel log上的信息无法直接分析出导致问题的具体源代码,从dmesg的这些信息我们已经知道出问题的是这个prev指针,但是比较难直接抓到导致异常的真凶源码位置。

    Trace32 分析

    利用dmesg我们分析了产生问题时候的来龙去脉,但是想要彻底解决还需要trace32进一步分析。

    输入v.f,调出当前的调用栈关系:

    可以看到,异常时候的各种参数都显示出来了,这样就非常有利于我们debug了,这也是单纯从dmesg无法得到的重要信息!注意inline类型的函数会被编译器默认优化掉,所以inline类型的函数的参数不可见,需要通过读汇编代码,分析寄存器传参推导。

    输入d.list 查看PC停止的位置,如下高亮:

    分析Call Stack:

    为方便查看,把调用栈信息复制出来,如下:

     1. ...
    -007|die(
        |  ?,
        |    regs = 0xFFFFFFC0B28BFA40 -> (
        |      user_regs = (regs = (0xFFFFFFC0B28BFBF8, 0x0, 0x0, 0x18, 0x00135F1AA15BB200, 0xFFFFFFC0B2AE800
        |      regs = (0xFFFFFFC0B28BFBF8, 0x0, 0x0, 0x18, 0x00135F1AA15BB200, 0xFFFFFFC0B2AE8000, 0x0001451C
        |      sp = 0xFFFFFFC0B28BFB60,
        |      pc = 0xFFFFFFC0000FEB98,
        |      pstate = 0x600001C5,
        |      orig_x0 = 0xFFFFFFC0B2618000,
        |      syscallno = 0xFFFFFFC0000FE7D0),
        |    err = 0x96000046)
        |  flags = 0x01C0
        |  ret = 0x1
        |  tsk = 0xFFFFFFC04EAE4980
        |  die_counter = 0x1
    -008|__do_kernel_fault.part.5(
        |    mm = 0x0,
        |    addr = 0x8,
        |    esr = 0x96000046,
        |    regs = 0xFFFFFFC0B28BFA40)
    -009|do_page_fault(
        |    addr = 0x8,
        |    esr = 0x96000046,
        |    regs = 0xFFFFFFC0B28BFA40)
        |  tsk = 0xFFFFFFC04EAE4980
        |  mm = 0x0
        |  vm_flags = 0xFFFFFFC000C9A000
        |  vma = 0xFFFFFFC0B28BFA40
    -010|do_translation_fault(
        |    addr = 0x0A44,
        |    esr = 0x0124F800,
        |  ?)
    -011|do_mem_abort(
        |    addr = 0x8,
        |    esr = 0x96000046,
        |    regs = 0xFFFFFFC0B28BFA40)
        |  inf = 0xFFFFFFC0013DC790 -> (
        |    fn = 0xFFFFFFC000099A74,
        |    sig = 0x0B,
        |    code = 0x00030001,
        |    name = 0xFFFFFFC0010DF250 -> 0x6C)
        |  info = (
        |    si_signo = 0x0032D110,
        |    si_errno = 0xFFFFFFC0,
        |    si_code = 0x01C0,
        |    _sifields = (_pad = (0x7, 0x0, 0xB28BF9E0, 0xFFFFFFC0, 0x000A6D78, 0xFFFFFFC0, 0xB28BF9F0, 0xFFF
    -012|el1_da(asm)
     -->|exception
    -013|__list_del(inline)
    -013|detach_timer(inline)
    -013|detach_expired_timer(inline)
    -013|__run_timers(inline)
    -013|run_timer_softirq(
        |  ?)
        |  base = 0xFFFFFFC0B2618000 -> (
        |    lock = (rlock = (raw_lock = (owner = 0x6FCD, next = 0x6FCE))),
        |    running_timer = 0xFFFFFFC001741120 -> (
        |      entry = (next = 0xFFFFFFC0B27BC9B8, prev = 0xFFFFFFC0B27BC9B8),
        |      expires = 0x0000000100003098,
        |      base = 0xFFFFFFC0B27BC000,
        |      function = 0xFFFFFFC0006E277C -> ,
        |      data = 0x0,
        |      slack = 0xFFFFFFFF,
        |      start_pid = 0xFFFFFFFF,
        |      start_site = 0x0,
        |      start_comm = (0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0))
        |    timer_jiffies = 0x0000000100003035,
        |    next_timer = 0x0000000100003034,
        |    active_timers = 0x7,
        |    all_timers = 0x7,
        |    cpu_=_0x4,
        |    tv1 = (vec = ((next = 0xFFFFFFC0B2618038, prev = 0xFFFFFFC0B2618038), (next = 0xFFFFFFC0B2618048
        |    tv2 = (vec = ((next = 0xFFFFFFC0B2619038, prev = 0xFFFFFFC0B2619038), (next = 0xFFFFFFC0B2619048
        |    tv3 = (vec = ((next = 0xFFFFFFC0B2619438, prev = 0xFFFFFFC0B2619438), (next = 0xFFFFFFC0B2619448
        |    tv4 = (vec = ((next = 0xFFFFFFC0B2619838, prev = 0xFFFFFFC0B2619838), (next = 0xFFFFFFC0B2619848
        |    tv5 = (vec = ((next = 0xFFFFFFC0B2619C38, prev = 0xFFFFFFC0B2619C38), (next = 0xFFFFFFC0B2619C48
        |  fn = 0xFFFFFFC0006E277C ->
        |  data = 0x0
        |  it_func_ptr = 0x0
    ...
    

    看到这里,我们可以猜想是不是run_timer_softirq的参数出现了问题导致后面发生的一系列异常?可以从这个方向开始思考,我们先来看下这个函数的实现:

    static void run_timer_softirq(struct softirq_action *h)
    {
        struct tvec_base *base = __this_cpu_read(tvec_bases);
        hrtimer_run_pending();
        __run_deferrable_timers();
        if (time_after_eq(jiffies, base->timer_jiffies))
            __run_timers(base);
    }
    

    我们看到这个函数最重要的参数变量就是这个base,传入的h没有使用,继续来看下base的结构tvec_base :

    struct tvec_base {
        spinlock_t lock;
        struct timer_list *running_timer;
        unsigned long timer_jiffies;
        unsigned long next_timer;
        unsigned long active_timers;
        unsigned long all_timers;
        int cpu;  // 跟踪所在的CPU是哪个核,这里是CPU 4
        struct tvec_root tv1;
        struct tvec tv2;
        struct tvec tv3;
        struct tvec tv4;
        struct tvec tv5;
    } ____cacheline_aligned;
    

    这里就看到 tvec_base 的结构里面有个 struct timer_list * 的结构,我们继续看它的结构是怎么样的:

    struct timer_list {
        /*
         * All fields that change during normal runtime grouped to the
         * same cacheline
         */
        struct list_head entry;
        unsigned long expires;
        struct tvec_base *base;
        void (*function)(unsigned long);
        unsigned long data;
        int slack;
    ...
    

    首先我们查看 running_timer 的数据内容,

    工具栏调出:view -> Watch,输入:(struct timer_list *)0xffffffc001741120

    这个就是发生异常的那个timer的数据结构实例,我们最希望的就是希望可以通过这里的数据信息找到它在源码的位置,然后进一步分析它,使用Trace32的 dump 分析功能就可以做到这点。

    菜单栏调出:view -> dump

    输入地址 0xffffffc001741120 然后点OK

    右击高亮,选择view info:

    同理,还可以看function的位置(0xFFFFFFC0006E277C):

    上面所示,出异常的timer实例就是:fp_drv/m_timer, callback = timer_out_handle,源码位置也给出来了,那么就可以着手修复问题了。

    转自https://blog.csdn.net/forever_2015/article/details/77434580

    5T技术资源大放送!包括但不限于:C/C++,Arm, Linux,Android,人工智能,单片机,树莓派,等等。在公众号内回复「peter」,即可免费获取!!

     记得点击分享在看,给我充点儿电吧

    展开全文
  • 远程监控内核死机的一种方法

    千次阅读 2009-09-22 21:53:00
    开发背景:最近开发一个内核项目时,遇到一个服务器内核维护的问题: 服务器存放在很远的电信机房内,只能通过ssh连接上服务器,当服务器的内核死机时,没有办法看到死机时内核打印的调试信息。因此需要开放一个内核...

    开发背景:

    最近开发一个内核项目时,遇到一个服务器内核维护的问题: 服务器存放在很远的电信机房内,只能通过ssh连接上服务器,当服务器的内核死机时,没有办法看到死机时内核打印的调试信息。因此需要开放一个内核维护模块。

     

           通过查找,发现当前内核已经存在几个模块用于debug内核,如LKCD netconsole模块,还有kexec模块,KDB等模块。 其实,比较贴近需求的是netconsole模块,该模块可以把内核的debug信息发送给远端主机,但一但启用,所有的信息都会马上发送到网络远端,而我的目的是:内核Crash时,才把debug信息,包含Oops, panic信息,以及开发模块的诊断信息发送给远端。因此我决定写一个Debug模块。

     

    技术要点:

    1. 通过netpoll实现低层发送UDP数据报文。

    2. 注册panic notifier实例,当内核挂机之前,会回调实例函数,这样就可以在挂起前发送被debug模块的诊断信息以及Panic相关信息。

    3. 替换内核dump回调函数dump_function_ptr为自定义的dump回调函数,内核Oops时会调用dump函数,参考LKCDdump()函数,修改内核include/linux/dump.h的默认dump函数。

     

    这样,当内核Crash发生时,会通过printk打印出内核出错信息,然后回调自定义的回调函数2或者3,在回调函数中注册一个console实例,就会调用consolewrite函数,write函数再通过netpoll把内核的log buffer的信息全部发送给远端主机输出到中。

     

    实测过程:

    远端主机使用netcat来侦听coredump消息端口。

    netcat -l -u -p 51002

    当内核crash后,远端主机终端可以看到如下信息:

     

    Unable to handle kernel paging request at 0000000098761111 RIP:

    <ffffffff880074c0>{:kccd:kccd_kmq_event_proc+97}

    PGD d6b4067 PUD 0

    Oops: 0002 [1]

    last sysfs file:

    CPU 0

    Modules linked in: kccd mque

    Pid: 622, comm: kccd Tainted: PF    U 2.6.16.60-0.21-default #25

    RIP: 0010:[<ffffffff880074c0>] <ffffffff880074c0>{:kccd:kccd_kmq_event_proc+97}

    RSP: 0000:ffff81000c2ddda8  EFLAGS: 00010046

    RAX: 0000000000000000 RBX: 00007fffffc094f0 RCX: 000000000000000c

    RDX: ffff81000f5c4400 RSI: ffffffff8167c950 RDI: 0000000098761111

    RBP: 0000000000000001 R08: 0000000023bdcff2 R09: ffff81000fb726c0

    R10: 0000000000000000 R11: 0000000000000002 R12: 00007fffffc094f0

    R13: ffff81000d793f50 R14: 0000000000000000 R15: 000000000050e6b9

    FS:  00002b5528878e30(0000) GS:ffffffff81611000(0000) knlGS:00000000082dc840

    CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b

    CR2: 0000000098761111 CR3: 000000000f5fd000 CR4: 00000000000006e0

    Process kccd (pid: 622, threadinfo ffff81000c2dc000, task ffff81000f9cf0c0)

    Stack: 00000000000b8494 0000000000000000 ffff81000f5c4400 ffff81000f8e4340

           00000000045d8000 0000000100000000 ffff81000c2dde18 0000000000000096

           0000000000000002 ffff81000f5c4400

    Call Trace: <ffffffff8102684e>{__wake_up_common+61}

           <ffffffff88007b3d>{:kccd:kccd_thread+265} <ffffffff8100b5ae>{child_rip+8}

           <ffffffff88007a34>{:kccd:kccd_thread+0} <ffffffff8100b5a6>{child_rip+0}

     

    Code: f3 ab 48 8d 9c 24 9c 00 00 00 48 8d bc 24 90 00 00 00 48 c7

    =======kccd dump happend!!! dump_str:Oops

    =======

    展开全文
  • Linux内核死机调试方法总结

    千次阅读 2017-11-25 16:33:35
     4、通过cat /proc/modules获得模块内核链接基地址,用死机地址减去链接基地址得到模块内偏移,再反汇编,找该偏移对应的函数就找到了死机函数。 用objdump -d test.ko > test.asm的话。可以将模块文件反汇编。...
    

    使用空指针和缓冲区溢出是产生oops的两个最常见原因。

    1、直接查看oops信息,首先查找源代码发生oops的位置,通过查看指令寄存器EIP的值,可以找到位置。再查找函数调用栈可以得到更多的信息。从函数调用栈可辨别出局部变量,全局变量和函数参数。较为重要的信息就是指令指针(EIP),即出错指令的地址。

    例如:在函数faulty_read的oops信息的函数调用栈中,栈顶为ffffffff,栈顶值应为一个小于ffffffff的值,为此值,说明再找不回调用函数地址,说明有可能因缓冲区溢出等原因造成指针错误。

    如果oops信息显示触发oops的地址为0xa5a5a5a5,则说明很可能是因为没有初始化动态内存引起的。

    2、使用\prebuilts\gcc\linux-x86\arm\arm-eabi-4.7\bin\arm-eabi-addr2line命令找到地址对应的程序位置,显示对应的程序文件名和行号。

    1.arm-eabi-addr2line 将类似libxxx.so 0x00012345的调用栈16进制值翻译成文件名和函数名

      arm-eabi-addr2line -e libxxx.so 0x00012345

    2.arm-eabi-nm 列出文件的符号信息

      arm-eabi-nm -l -C -n -S libdvm.so > dvm.data

    3.arm-eabi-objdump 列出文件的详细信息

      arm-eabi-objdump -C -d libc.so > libc.s

    通过以上工具的分析 ,我们可以得到较完整的调用栈以及调用逻辑的汇编码。

    addr2line -e -f libc.so 0001173c 

     

    objdump -S -D libc.so > deassmble_libc.txt

     

      打开这个反汇编过后的重定向文件,在查询的时候输入1173c这个偏移地址,你会看到在茫茫人海中

      00011684 <pthread_create>:
       11684:       e92d4ff0        push    {r4, r5, r6, r7, r8, r9, sl, fp, lr}
       11688:       e24dd01c        sub     sp, sp, #28     ; 0x1c
       1168c:       e1a06001        mov     r6, r1
       11690:       e1a08002        mov     r8, r2
       11694:       e1a09003        mov     r9, r3
       11698:       e3a04001        mov     r4, #1  ; 0x1
       1169c:       e59f521c        ldr     r5, [pc, #540]  ; 118c0 <pthread_create+0x23c>
       116a0:       e58d000c        str     r0, [sp, #12]
       116a4:       eb009a35        bl      37f80 <strncmp+0x20>
       116a8:       e59f2214        ldr     r2, [pc, #532]  ; 118c4 <pthread_create+0x240>
       116ac:       e1a03000        mov     r3, r0
       116b0:       e1a01004        mov     r1, r4
       116b4:       e593c000        ldr     ip, [r3]
       116b8:       e3a0003c        mov     r0, #60 ; 0x3c
       116bc:       e08f3005        add     r3, pc, r5
       116c0:       e7933002        ldr     r3, [r3, r2]
       116c4:       e5834000        str     r4, [r3]
       116c8:       e58dc010        str     ip, [sp, #16]
       116cc:       eb009a3b        bl      37fc0 <strncmp+0x60>
       ...

     

       1173c:       ebffec2b        bl      c7f0 <__pthread_clone>-->就是他了,对你成功了。

     

       ...

     

    3、在分析转储映像之前,用户应重启动进入一个稳定的内核。用户可以用GDB对拷贝出的转储进行有限分析。编译vmlinux时应加上-g选项,才能生成调试用的符号,然后,用下面的命令调试vmlinux:

    gdb vmlinux <dump-file>
    首先 objdump -D vmlinx 反汇编你的内核
    然后 你可以通过以下几个寄存器来判断: 
    1. epc    挂在哪个函数里
    2. ra     函数的返回地址,
    3. Cause  通过这个寄存器可以分析是什么类型的异常.
    

     4、通过cat /proc/modules获得模块内核链接基地址,用死机地址减去链接基地址得到模块内偏移,再反汇编,找该偏移对应的函数就找到了死机函数。

    用objdump -d test.ko > test.asm的话。可以将模块文件反汇编。但是因为模块是目标文件,所以会看到,text段的地址是从0开始的。而该模块在内核在运行的时候,该模块的代码段显然不是在0地址。另外,该代码段中你会看到函数间调用,以及函数内部跳转都是用的b开头的分支指令(仅限于mips和arm的体系结构的讨论),分支指令跳转是以pc为基准值前后跳转的。除非,跳转符号不属于这个模块,则需要32位的跳转。实际上,模块链接到内核的时候,模块的代码段是作为一个整体链接到内核,所以我们只需要知道模块链接到的基地址,再用死机的地址减去这个基地址这就得到了,该地址在模块中代码段的偏移,再通过刚才的反汇编文件就找到了是死在那个函数中。而要得到各个模块的链接地址就很简单了,直接cat /proc/modules就得到了。需要注意的是用__init修饰了的模块初始化函数,是放在单独的段的,通常叫.init.text 。该段会在模块初始化完成后内存就释放掉了

     5、google提供了一个python脚本,可以从 http://code.google.com/p/android-ndk-stacktrace-analyzer/ 下载这个python脚本,然后使用
    adb logcat -d > logfile 导出 crash 的log,
    使用 arm-eabi-objdump (位于build/prebuilt/linux-x86/arm-eabi-4.2.1/bin下面)把so或exe转换成汇编代码,如:
    arm-eabi-objdump -S mylib.so > mylib.asm,
    然后使用脚本
    python parse_stack.py <asm-file> <logcat-file>

     

     

     

    http://blog.csdn.net/lickylin/article/details/19172725

    如上崩溃信息,可知发生崩溃的函数为rb_init_debugfs崩溃的地址为0x804386f8

     1>linux下,到工程的如下目录下:kernel/linux,找到文件vmlinux,执行命令gdb vmlinux

     在gdb命令下执行如下命令即可查找到出错函数所在的文件与行数

     (gdb) b *0x804386f8

     2>如果不确定崩溃的地址是否是0x804386f8,可以在文件System.map中

    查找函数rb_init_debugfs获取该函数的地址,然后加上偏移地址(本例中偏移地址为0x14 rb_init_debugfs+0x14/0x70)即可。

     3>直接函数名加偏移量也可以

     (gdb) b *rb_init_debugfs+0x14

     上面是出错模块是编译进内核的,对于编译进内核的模块可以通过gdb vmlinux来确定出错函数所在的文件与行数。

     那如果出错模块是动态加载进内核的该怎么办呢?

     这就需要使用objdump进行反汇编操作了,使用如下命令,就会将C语言与汇编语言同时显示(需要加-g命令)

     #objdump -S  **.o -g

     如果使用上面命令,还是只显示汇编,而没有c语言的话,不用担心,在你编译驱动模块的Makefile中,编译成.o文件时,增加-g选项,

    对于新生成的.o文件再使用上面的命令就 可以看到汇编与c语言共存了。然后根据kernel panic提示中显示的函数名加上偏移量就能找到出错行了。

     http://blog.csdn.net/wuruixn/article/details/38320643

    1. 为了测试GDB操作,故意在kernel/linux/fs/ioctl.c文件的do_vfs_ioctl方法中加入空指针操作代码,然后编译image烧入单板,启动单板,内核crash,部分log如下:
     
    CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 800a73b8, ra == 800a793c
    Oops[#1]:
    Cpu 0
    $ 0   : 00000000 10008d00 00000000 ffffffea
    $ 4   : fffffdfd 10008d01 00000001 00000000
    $ 8   : 00000000 7fed2e40 00001cb2 00000b3b
    $12   : 00031c7f 2ab5ead7 2aaac7c9 15010000
    $16   : 7fed2e18 878ca5a0 00000000 00000001
    $20   : 2ab84980 00000000 00000007 00000000
    $24   : 00000000 2ab62090                 
    $28   : 8782c000 8782fe98 7fed2fc8 800a793c
    Hi    : 0000002a
    Lo    : 000311fc
    epc   : 800a73b8 do_vfs_ioctl+0x88/0x5c8
        Not tainted
    ra    : 800a793c sys_ioctl+0x44/0x98
    Status: 10008d03    KERNEL EXL IE
    Cause : 00000008
    BadVA : 00000000
    PrId  : 0002a080 (Broadcom4350)
    Modules linked in:

    Process init (pid: 1, threadinfo=8782c000, task=8782bb68, tls=00000000)
    Stack : 878ca1a0 00000004 00000000 10008d00 00000603 2aabcfff 87b0bea8 00000001
            87beeaf0 2aabc000 2aabd000 87aa9cb0 2aabd000 2aabd000 8782ff08 fffffff8
            00000001 7fed3258 00000007 00000000 878ca5a0 0000540d 00000000 00000001
            2ab84980 800a793c 08100871 00000001 87bea41c 0000fff2 00000000 2abbdff0
            7fed2e18 00000001 7fed2e60 2abbdff0 00000120 8001ba7c 00000000 00000000
            ...
    Call Trace:(--Raw--
    [<800a793c>] sys_ioctl+0x44/0x98
    [<8001ba7c>] stack_done+0x20/0x3c

    Call Trace:
    [<800a73b8>] do_vfs_ioctl+0x88/0x5c8
    [<800a793c>] sys_ioctl+0x44/0x98
    [<8001ba7c>] stack_done+0x20/0x3c

    Code: 0c029c9f  02003021  8fbf0064 <8c020000> 8fb40060  8fb3005c  8fb20058  8fb10054  8fb00050
    Disabling lock debugging due to kernel taint
    Kernel panic - not syncing: Attempted to kill init!
    Rebooting in 1 seconds..<6>
    stopping CPU 1
    kerSysMipsSoftReset: called on cpu 0
        

    2. 启动GDB, 直接在主机(开发机)控制台运行gdb工具(或./mips-linux-uclibc-gdb),然后敲入 file  ...../vmlinux启动带调试信息的内核,注意此时要配置内核debug开关重新编译内核生成文件vmlinux(比之前的文件大10倍左右,50M以上),配置内核debug开关如下,

    Kernel hacking  --->
        [*] Kernel debugging
        [*] Compile the kernel with debug info
    编译内核命令:make kernelbuild,要在project的根目录下运行该命令进行编译。
    启动GDB命令如下:
     
    3. GDB调试定位
    Checked call trace log, the most important part in log is “epc” (exception program counter), it is where the crash happened. In this example, the “epc” is 0xc0d1d488. For X1000 and X3500, the address like 0x8XXXXXXXX is in kernel, and the address like 0xcXXXXXXX is in some module.
    地址0x800a73b8就是对应于地址(do_vfs_ioctl+0x88),后者表示位于函数do_vfs_ioctl的偏移地址0x88处。
    调试过程如下:
     
    (gdb) list *(0x800a73b8)
    0x800a73b8 is in do_vfs_ioctl (fs/ioctl.c:569).
    564                             error = vfs_ioctl(filp, cmd, arg);
    565                     break;
    566             }
    567             error = *test;
    568             return error;
    569     }
    570
    571     SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
    572     {
    573             struct file *filp;
    (gdb) list*(do_vfs_ioctl+0x88)
    0x800a73b8 is in do_vfs_ioctl (fs/ioctl.c:569).
    564                             error = vfs_ioctl(filp, cmd, arg);
    565                     break;
    566             }
    567             error = *test;
    568             return error;
    569     }
    570
    571     SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
    572     {
    573             struct file *filp;
    (gdb) list*(sys_ioctl+0x44)
     
     
    可以分析该函数附近代码发现错误位置在line567,test为空指针(故意在前面赋值NULL)。

     

     

    注:如果list*(0x80xxxxxx)命令提示如下信息:No source file for address 0x80xxxxxx. 原因是没有在make menuconfig中打开对应的调试开关进行编译。


    转自:https://www.cnblogs.com/thjfk/p/4383803.html

    展开全文
  • linux内核死机2-smp

    千次阅读 2017-01-16 15:32:45
    另一个常用的检测方式是把内核的lockdep检测打开,这样错误基本是无所遁形的(O_O)。  3. 触发NMI,一般是cpu卡死,如死锁,也有如系统异常时,巨量的prinrk(打印全开)。 I have disabled the ...


    问题:程序跑一段时间之后会报告:
            INFO: rcu_sched_state detected stalls on CPUs/tasks: { 1} (detected by 0, t=15002 jiffies)。意思是CORE0检测到CORE1挂了。

    1.cpu执行的指令和数据是从L1高速缓存的指令缓存和数据缓存中获取,一旦cpu要执行的指令或数据无法从高速缓存中获取,就会产生cpu stall。你这种情况是程序要求的cpu性能要高于你现在使用的cpu,你得考虑升级设备才能运行此庞大程序。


    2.再补充一点,当cpu无法从高速缓存中获取指令或数据,那么只有从内存中获取,而这种会浪费很长时间的,所以你的程序会hang住,考虑玩个小程序吧,或者非要玩这个大程序,换个牛逼手机吧。


    http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3658441如题,求指点

    Dec 30 15:12:14 T206 kernel: [ 1196.284001] INFO: rcu_sched_state detected stall on CPU 0 (t=15000 jiffies)
    Dec 30 15:12:14 T206 kernel: [ 1196.284001] sending NMI to all CPUs:

    提示这个错误是什么原因引起的?


    1.某个核调度出了问题,跟softlockup有点像。可能是spinlock关抢占。或者fifo死循环。
          如果是前者,得查死锁回溯;
          我们的业务模型会在某几个cpu上fifo死循环,没办法,目前的临时解决方法是配置了CONFIG_NO_HZ_FULL 。
    CONFIG_NO_HZ_FULL的好处是,如果运行的进程只有一个,RCU也会认为该cpu经过了一个grace period,不会出死锁。


    2.一般是死锁了,由于提示是cpu0死了,看下“sending nmi”下一行开始的cpu0的栈,一般最后能看到某个spin lock irqsave类似的锁操作,然后看下这个锁哪里用到。另一个常用的检测方式是把内核的lockdep检测打开,这样错误基本是无所遁形的(O_O)。

     3.   触发NMI,一般是cpu卡死,如死锁,也有如系统异常时,巨量的prinrk(打印全开)。


    I have disabled the Frequency scaling and this issue is not reproduce.






    展开全文
  • 内核调试死机排查

    千次阅读 2018-02-16 23:09:57
    内核调试死机排查 标签(空格分隔): 内核调试 http://blog.csdn.net/kangear/article/details/8217329 一版出现Unable to handle kernel NULL pointer dereference at virtual address 0xxxxxxx多是空指针...
  • 内核模块死机调试

    千次阅读 2011-11-14 19:20:32
    介绍一种内核模块死机调试的方法。在程序中,通常必现的死机很好解决,但是如果是拷机死机的话,则如果有好的方法和工具借助往往会极大的提高解决问题的速度。在linux中,应用空间程序死机通常可以借助GDB、addr2...
  • 通常在内核中死掉的话,可以根据死机地址再加反汇编,或者是addr2line找到死机的函数或者是那一行,但是对于动态插入的模块却不行。这是因为,内核在编译的时候就把地址链接好了,运行的时候代码段的地址空间在链接...
  • linux 内核出现CPU 死机

    千次阅读 2016-08-10 23:04:28
    linux 异常分析工具(一) linux 内核OOPS(二) linux 内核出现CPU stall
  • 从操作系统内核解释电脑死机原理

    千次阅读 2014-03-22 22:39:13
    关于电脑死机的原因或者说原理,即电脑为什么会死机,电脑死机时计算机底层都发生了什么。一直不太明白,在网上也查过相关的资料,但是... 最近在学习Linux内核,自从大一的时候读了一本《计算机的心智---操作系统之哲
  • 19.7 案例7:Fuse内核死锁导致的系统死机问题 1. 问题现象 问题发生的Android系统版本是7.1(Nougat); 界面定住,没有任何刷新,所有输入事件无效,包括电源键; watchdog没有重启system_server; 问题现场可以...
  • 1.驱动中栈的使用最大限制范围4k;如果使用的数组大小超过4096,申请为全局变量就可以了;
  • 建议先编译好内核 https://source.android.com/setup/build/building-kernels 第二步 查看里面的内核版本 strings 看 Image.lz4 第三步 去下在对应的源码 1)去这https://android.googlesource.com/ 2)然后...
  • 本系列主要介绍Linux内核死机、异常重启类稳定性问题的调试方法。 在Linux系统中,一切皆为文件,而系统运行的载体,是一类特殊的文件,即进程。因此,我尝试从进程的角度分析Linux内核的死机、异常重启等问题。在...
  • 下面是代码.... #include <linux/module.h>...static ssize_t twrite(struct file *pfile, const char __user *buff, size_t count, loff_t *f_pos) ...但是加载了就会导致oops......顺便问一下.....
  • 此方法用于死机故障出现间隔很长,而且不是空指针导致的死机问题.用于查找出现问题的函数....内核死机前的有用的信息主要有下面下个:CallTrace:[<f89ef137>][<f89eed7e>][<c0235ed0>][<c01f31...
  • #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h>...asmlinkage long (*g_old_sys_write)(unsigned int fd, const char __user *buf, size_t count)=NULL;...
  • 写了一个驱动程序,read/write函数实现如下,number是一个全局变量,读/写该变量之前都加上锁。程序大意是为了保证每次读完了才能继续写或者每次写结束以后才能继续读,但是我为了测试并发,在读函数中增加了一个10...
  • 单处理器系统的内核文件是Ntoskml.exe,而多处理器系统的内核文件是Ntkrnlmp.exe,但是,这些文件要与安装媒体上的文件相对应;在安装完Windows2000和,不论使用的是哪个原文件,都会被重命名为Ntoskrnl.exe文件。...
  • 下述为UCloud资深工程师邱模炯在InfoQ架构师峰会上的演讲——《UCloud...对于一个拥有成千上万台服务器的公司,Linux内核缺陷导致的死机屡见不鲜。让工程师们纠结的是,到底要不要通过给服务器升级内核来修复缺陷?...
  • 通常所说的死机是指操作没有响应了,但是操作系统的核心仍然在工作...要理解这个并不难,windows的界面和Linux的tty-tty7都是shell,使得用户能够与内核交互。在启动时,系统会默认启动shell。在Linux中尤为强调shel...
  • Linux内核问题分析方法

    万次阅读 2020-03-30 11:18:45
    死机没有现场或信息不全,有信息无法进一步分析; 调试困难,gdb只能作为辅助; 内核庞杂,系统代码量大,无从下手; 问题的表现和问题的原因不一定直接关联。linux内核堆栈大多是我们开发的模块问题。 Linux内核...
  • Linux 内核虽然号称“不死族”,几乎不会崩溃或者死机,但是特殊情况下,还是有一定几率会宕机的。因为 Linux 广泛用于生产环境,所以每一次宕机都会引起相当大的损失。它 Uptime 达到上百天也许你习以为常,但是...
  • 内核调试工具 — kdump & crash

    万次阅读 2014-10-23 11:43:21
    kdump是系统崩溃、死锁或者死机的时候用来转储内存运行参数的一个工具和服务。 如果系统一旦崩溃,那么正常的内核就没办法工作了,这个时候将由kdump产生一个用于capture 当前运行信息的内核,该内核会将此时的...
  • 一、内核调试方法简单分析 1、addr2line: 解决oops错误 a -- oops消息 oops(也称 panic),称程序...应用程序或内核线程的崩溃都会产生oops消息,通常发生oops时,系统不会发生死机,而在终端或日志中打印oops信息。
  • Linux内核kernel panic机制浅析

    千次阅读 2015-05-06 16:55:03
     内核错误(Kernel panic)是指操作系统在监测到内部的致命错误,并无法安全处理此错误时采取的动作。一旦到这个情况,kernel就尽可能把它此时能获取的全部信息都打印出来,至于能打印出多少信息,那就看是哪种情况...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 500
精华内容 200
关键字:

内核死机