从内核调用跟踪中获取行号

Mik*_*inz 1 debugging kernel backtrace debug-symbols linux-kernel

我正在尝试调试似乎是完成队列问题:

Apr 14 18:39:15 ST2035 kernel: Call Trace:
Apr 14 18:39:15 ST2035 kernel:  [<ffffffff8049b295>] schedule_timeout+0x1e/0xad
Apr 14 18:39:15 ST2035 kernel:  [<ffffffff8049a81c>] wait_for_common+0xd5/0x13c
Apr 14 18:39:15 ST2035 kernel:  [<ffffffffa01ca32b>]
ib_unregister_mad_agent+0x376/0x4c9 [ib_mad]
Apr 14 18:39:16 ST2035 kernel:  [<ffffffffa03058f4>] ib_umad_close+0xbd/0xfd
Run Code Online (Sandbox Code Playgroud)

是否可以将这些十六进制数字转换为接近行号的数字?

che*_*tan 5

不完全是,但是如果您有一个使用调试信息构建的 vmlinux 映像(例如,在 RHEL 中,您应该能够安装 kernel-debug 或 kernel-dbg 或类似的东西),您可以接近。所以假设你有那个 vmlinux 文件可用。请执行下列操作:

objdump -S vmlinux

这将尝试将目标代码与源代码的各个行进行匹配是最困难的。

例如对于以下 C 代码:

#include <stdio.h>
main() {
  int a = 1;
  int b = 2;

  // This is a comment

  printf("This is the print line %d\n", b);
} 
Run Code Online (Sandbox Code Playgroud)

编译:cc -g test.c

然后在生成的可执行文件上运行 objdump -S,我得到了一个大输出,描述了可执行文件的各个部分,包括以下部分:

00000000004004cc <main>:
#include <stdio.h>
main() {
  4004cc:   55                      push   %rbp
  4004cd:   48 89 e5                mov    %rsp,%rbp
  4004d0:   48 83 ec 20             sub    $0x20,%rsp
  int a = 1;
  4004d4:   c7 45 f8 01 00 00 00    movl   $0x1,-0x8(%rbp)
  int b = 2;
  4004db:   c7 45 fc 02 00 00 00    movl   $0x2,-0x4(%rbp)

  // This is a comment

  printf("This is the print line %d\n", b);
  4004e2:   8b 75 fc                mov    -0x4(%rbp),%esi
  4004e5:   bf ec 05 40 00          mov    $0x4005ec,%edi
  4004ea:   b8 00 00 00 00          mov    $0x0,%eax
  4004ef:   e8 cc fe ff ff          callq  4003c0 <printf@plt>
} 
Run Code Online (Sandbox Code Playgroud)

您可以将第一列中目标代码的地址与堆栈跟踪中的地址进行匹配。将它与汇编输出中交错的行号信息相结合......你就在那里。

现在请记住,这不会总是 100% 成功,因为 kenrel 通常是在 -O2 优化级别编译的,并且编译器会进行大量代码重新排序等。但是如果您熟悉您正在使用的代码尝试调试并在破译您正在处理的平台的程序集方面有一些安慰……您应该能够确定大多数崩溃等。