AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 605946
Accepted
tylerl
tylerl
Asked: 2014-06-18 22:08:39 +0800 CST2014-06-18 22:08:39 +0800 CST 2014-06-18 22:08:39 +0800 CST

内核堆栈跟踪到源代码行

  • 772

给定如下的内核堆栈跟踪,您如何确定发生问题的特定代码行?

kernel:  [<ffffffff80009a14>] __link_path_walk+0x173/0xfb9
kernel:  [<ffffffff8002cbec>] mntput_no_expire+0x19/0x89
kernel:  [<ffffffff8000eb94>] link_path_walk+0xa6/0xb2
kernel:  [<ffffffff80063c4f>] __mutex_lock_slowpath+0x60/0x9b
kernel:  [<ffffffff800238de>] __path_lookup_intent_open+0x56/0x97
kernel:  [<ffffffff80063c99>] .text.lock.mutex+0xf/0x14
kernel:  [<ffffffff8001b222>] open_namei+0xea/0x712
kernel:  [<ffffffff8006723e>] do_page_fault+0x4fe/0x874
kernel:  [<ffffffff80027660>] do_filp_open+0x1c/0x38
kernel:  [<ffffffff8001a061>] do_sys_open+0x44/0xbe
kernel:  [<ffffffff8005d28d>] tracesys+0xd5/0xe0

虽然我很容易找到函数调用——但是将__link_path_walk加上偏移量转换为实际的行号是困难的部分。

假设这是针对我知道确切版本和内部版本号的标准发行版提供的内核,那么获取必要的元数据并进行相应查找的过程是什么?

linux
  • 5 5 个回答
  • 30349 Views

5 个回答

  • Voted
  1. dawud
    2014-06-19T02:17:17+08:002014-06-19T02:17:17+08:00

    我手头没有 ~= RHEL5,所以显示的输出来自 Fedora 20,尽管过程应该基本相同(函数名称已更改)。

    您需要kernel-debug-debuginfo为您的内核安装适当的软件包(假设 RHEL 或衍生发行版)。这个包提供了一个vmlinux镜像(一个未压缩的未剥离的内核版本):

    # rpm -ql kernel-debug-debuginfo | grep vmlinux
    /usr/lib/debug/lib/modules/3.14.7-200.fc20.x86_64+debug/vmlinux
    

    该图像可以直接与gdb

    # gdb /usr/lib/debug/lib/modules/3.14.7-200.fc20.x86_64+debug/vmlinux
    GNU gdb (GDB) Fedora 7.7.1-13.fc20
    Copyright (C) 2014 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    ...
    Reading symbols from /usr/lib/debug/lib/modules/3.14.7-200.fc20.x86_64+debug/vmlinux...done.
    (gdb) disassemble link_path_walk
    Dump of assembler code for function link_path_walk:
       0xffffffff81243d50 <+0>:     callq  0xffffffff817ea840 <__fentry__>
       0xffffffff81243d55 <+5>:     push   %rbp
       0xffffffff81243d56 <+6>:     mov    %rsp,%rbp
       0xffffffff81243d59 <+9>:     push   %r15
       0xffffffff81243d5b <+11>:    mov    %rsi,%r15
       0xffffffff81243d5e <+14>:    push   %r14
       0xffffffff81243d60 <+16>:    push   %r13
       0xffffffff81243d62 <+18>:    push   %r12
       0xffffffff81243d64 <+20>:    push   %rbx
       0xffffffff81243d65 <+21>:    mov    %rdi,%rbx
       0xffffffff81243d68 <+24>:    sub    $0x78,%rsp
       0xffffffff81243d6c <+28>:    mov    %gs:0x28,%rax
       0xffffffff81243d75 <+37>:    mov    %rax,0x70(%rsp)
       0xffffffff81243d7a <+42>:    xor    %eax,%eax
       0xffffffff81243d7c <+44>:    movzbl (%rdi),%eax
       0xffffffff81243d7f <+47>:    cmp    $0x2f,%al
       ....
    

    您还可以objdump(1)在vmlinux图像上使用:

    # objdump -rDlS /usr/lib/debug/lib/modules/3.14.7-200.fc20.x86_64+debug/vmlinux > vmlinux.out
    

    标志是:

       -D
       --disassemble-all
           Like -d, but disassemble the contents of all sections, not just those expected to contain instructions.
       -r
       --reloc
           Print the relocation entries of the file.  If used with -d or -D, the relocations are printed interspersed with the
           disassembly.
       -S
       --source
           Display source code intermixed with disassembly, if possible.  Implies -d.
       -l
       --line-numbers
           Label the display (using debugging information) with the filename and source line numbers corresponding to the object
           code or relocs shown.  Only useful with -d, -D, or -r.
    

    你可以在那里查找函数:

    ffffffff81243d50 <link_path_walk>:
    link_path_walk():
    /usr/src/debug/kernel-3.14.fc20/linux-3.14.7-200.fc20.x86_64/fs/namei.c:1729
     *
     * Returns 0 and nd will have valid dentry and mnt on success.
     * Returns error and drops reference to input namei data on failure.
     */
    static int link_path_walk(const char *name, struct nameidata *nd)
    {
    ffffffff81243d50:       e8 eb 6a 5a 00          callq  ffffffff817ea840 <__entry_text_start>
    ffffffff81243d55:       55                      push   %rbp
    ffffffff81243d56:       48 89 e5                mov    %rsp,%rbp
    ffffffff81243d59:       41 57                   push   %r15
    ffffffff81243d5b:       49 89 f7                mov    %rsi,%r15
    ffffffff81243d5e:       41 56                   push   %r14
    ffffffff81243d60:       41 55                   push   %r13
    ffffffff81243d62:       41 54                   push   %r12
    ffffffff81243d64:       53                      push   %rbx
    ffffffff81243d65:       48 89 fb                mov    %rdi,%rbx
    ffffffff81243d68:       48 83 ec 78             sub    $0x78,%rsp
    ffffffff81243d6c:       65 48 8b 04 25 28 00    mov    %gs:0x28,%rax
    ffffffff81243d73:       00 00
    ffffffff81243d75:       48 89 44 24 70          mov    %rax,0x70(%rsp)
    ffffffff81243d7a:       31 c0                   xor    %eax,%eax
    /usr/src/debug/kernel-3.14.fc20/linux-3.14.7-200.fc20.x86_64/fs/namei.c:1733
            struct path next;
            int err;
    
            while (*name=='/')
    ffffffff81243d7c:       0f b6 07                movzbl (%rdi),%eax
    ffffffff81243d7f:       3c 2f                   cmp    $0x2f,%al
    ffffffff81243d81:       75 10                   jne    ffffffff81243d93 <link_path_walk+0x43>
    ffffffff81243d83:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
    /usr/src/debug/kernel-3.14.fc20/linux-3.14.7-200.fc20.x86_64/fs/namei.c:1734
                    name++;
    ffffffff81243d88:       48 83 c3 01             add    $0x1,%rbx
    /usr/src/debug/kernel-3.14.fc20/linux-3.14.7-200.fc20.x86_64/fs/namei.c:1733
    static int link_path_walk(const char *name, struct nameidata *nd)
    {
            struct path next;
            int err;
    
            while (*name=='/')
    ....
    

    并将偏移量与实际的代码行匹配。

    • 17
  2. Best Answer
    Lekensteyn
    2014-06-19T06:02:22+08:002014-06-19T06:02:22+08:00

    给定一个未剥离vmlinux的调试符号(通常包含在与您的内核版本匹配的“linux-devel”或“linux-headers”包中),您可以使用addr2linebinutils 中包含的程序将地址转换为源文件中的行。

    考虑这个调用跟踪:

    Call Trace:
     [<ffffffff8107bf5d>] ? finish_task_switch+0x3d/0x120
     [<ffffffff815f3130>] __schedule+0x3b0/0x9d0
     [<ffffffff815f3779>] schedule+0x29/0x70
     [<ffffffff815f2ccc>] schedule_hrtimeout_range_clock.part.24+0xdc/0xf0
     [<ffffffff81076440>] ? hrtimer_get_res+0x50/0x50
     [<ffffffff815f2c6f>] ? schedule_hrtimeout_range_clock.part.24+0x7f/0xf0
     [<ffffffff815f2cf9>] schedule_hrtimeout_range_clock+0x19/0x60
     [<ffffffff815f2d53>] schedule_hrtimeout_range+0x13/0x20
     [<ffffffff811a8aa9>] poll_schedule_timeout+0x49/0x70
     [<ffffffff811aa203>] do_sys_poll+0x423/0x550
     [<ffffffff814eaf8c>] ? sock_recvmsg+0x9c/0xd0
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811a8c50>] ? poll_select_copy_remaining+0x140/0x140
     [<ffffffff811aa3fe>] SyS_poll+0x5e/0x100
     [<ffffffff816015d2>] system_call_fastpath+0x16/0x1b
    

    然后poll_select_copy_remaining可以通过以下方式找到调用者的地址:

    $ addr2line -e /tmp/vmlinux ffffffff811a8c50
    /tmp/linux-3.15-rc8/fs/select.c:209
    
    • 15
  3. wenjianhn
    2018-03-14T22:24:49+08:002018-03-14T22:24:49+08:00
    1. 安装内核调试信息

    2. 下载内核源代码树中的decode_stacktrace.sh 。

    3. 使堆栈转储输出再次有用。

       # ./decode_stacktrace.sh /usr/lib/debug/lib/modules/`uname -r`/vmlinux /usr/lib/debug/lib/modules/4.1.12-112.14.14.el7uek.x86_64/ < ./trace > out
       # cat out
       [102820.087367] Call Trace:
       [102820.087371] dump_stack (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/lib/dump_stack.c:53)
       [102820.087375] warn_slowpath_common (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/kernel/panic.c:499)
       [102820.087378] warn_slowpath_null (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/kernel/panic.c:533)
       [102820.087380] af_alg_accept (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/include/net/sock.h:1689 /usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/crypto/af_alg.c:287)
       [102820.087382] alg_accept (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/crypto/af_alg.c:326)
       [102820.087385] SYSC_accept4 (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/net/socket.c:1485)
       [102820.087388] ? release_sock (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/net/core/sock.c:2415)
       [102820.087390] ? alg_setsockopt (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/crypto/af_alg.c:264)
       [102820.087393] SyS_accept (/usr/src/debug/kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/net/socket.c:1515)
       [102820.087395] system_call_fastpath (/usr/src/debug////////kernel-4.1.12/linux-4.1.12-112.14.14.el7uek/arch/x86/kernel/entry_64.S:277)
       [102820.087397] ---[ end trace 1315ff0b8d6ff7d8 ]---
      
    4. 对于少数函数偏移,请尝试faddr2line内核源代码中的。

       $ wget https://raw.githubusercontent.com/torvalds/linux/master/scripts/faddr2line
       $ bash faddr2line /usr/lib/debug/lib/modules/`uname -r`/vmlinux __do_softirq+0x92/0x320
       __do_softirq+0x92/0x320:
       ffs at arch/x86/include/asm/bitops.h:410
       (inlined by) __do_softirq at kernel/softirq.c:261
      
    • 8
  4. Johannes Thoma
    2016-10-06T09:08:06+08:002016-10-06T09:08:06+08:00

    如果 addr2line 应该打印行号的问号或 objdump 无法内联源代码并且您有自定义内核,请务必使用 CONFIG_DEBUG_INFO 设置重新编译内核。您可能需要使用刚刚构建的内核重现错误。

    • 1
  5. accessory
    2021-06-15T19:03:49+08:002021-06-15T19:03:49+08:00

    使用 gdb,您还可以使用此命令快速查找行号:

    (gdb) 列表 *(some_function+0x12c)

    • 0

相关问题

  • Linux 主机到主机迁移

  • 如何在 Linux 机器上找到有关硬件的详细信息?

  • 如何在 Linux 下监控每个进程的网络 I/O 使用情况?

  • 在 RHEL4 上修改 CUPS 中的现有打印机设置

  • 为本地网络中的名称解析添加自定义 dns 条目

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve