我有一个测试
Linux kernel module
打印 dump_stack()
。但它打印的跟踪不完整,因为它没有打印函数地址。我使用带有 Ubuntu 16.04.7 LTS
内核的 4.15.0-142-generic
,并且 CONFIG_DEBUG_INFO=y
设置在 /boot/config-4.15.0-142-generic
中。
我的问题:
(1) 为什么不打印函数地址?我可以使用
objdump -t
转储符号表。
(2) 跟踪显示
dump_stack()
是从 module_level_init
调用的。然而它是module_level_init()->module_level_2()->module_level_3()
以下是
dmesg
输出:
[ 1347.807370] CPU: 7 PID: 13262 Comm: insmod Tainted: P OE 4.15.0-142-generic #146~16.04.1-Ubuntu
[ 1347.807371] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[29020.752090] Call Trace:
[29020.752096] dump_stack+0x6d/0x8b
[29020.752097] ? 0xffffffffc0730000
[29020.752099] module_level_init+0x1a/0x1000 [kern]
[29020.752102] do_one_initcall+0x55/0x1b0
[29020.752103] ? _cond_resched+0x1a/0x50
[29020.752105] ? kmem_cache_alloc_trace+0x165/0x1c0
[29020.752106] do_init_module+0x5f/0x222
[29020.752108] load_module+0x1894/0x1ea0
[29020.752111] ? ima_post_read_file+0x83/0xa0
[29020.752112] SYSC_finit_module+0xe5/0x120
[29020.752113] ? SYSC_finit_module+0xe5/0x120
[29020.752115] SyS_finit_module+0xe/0x10
[29020.752116] do_syscall_64+0x73/0x130
内核模块:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
int module_level_3(void)
{
dump_stack();
return 0;
}
int module_level_2(void)
{
module_level_3();
return 0;
}
static int __init module_level_init(void)
{
printk(KERN_INFO "Hello, world\n");
module_level_2();
return 0;
}
static void __exit module_level_exit(void)
{
printk(KERN_INFO "Goodbye, world\n");
}
module_init(module_level_init);
module_exit(module_level_exit);
MODULE_LICENSE("GPL");
生成文件:
obj-m += kern.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
obj转储
#objdump -Sdlr kern.ko
kern.ko: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <module_level_3>:
module_level_3():
0: e8 00 00 00 00 callq 5 <module_level_3+0x5>
1: R_X86_64_PC32 __fentry__-0x4
5: 55 push %rbp
6: 48 89 e5 mov %rsp,%rbp
9: e8 00 00 00 00 callq e <module_level_3+0xe>
a: R_X86_64_PC32 dump_stack-0x4
e: 31 c0 xor %eax,%eax
10: 5d pop %rbp
11: c3 retq
12: 0f 1f 40 00 nopl 0x0(%rax)
16: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
1d: 00 00 00
0000000000000020 <module_level_2>:
module_level_2():
20: e8 00 00 00 00 callq 25 <module_level_2+0x5>
21: R_X86_64_PC32 __fentry__-0x4
25: 55 push %rbp
26: 48 89 e5 mov %rsp,%rbp
29: e8 00 00 00 00 callq 2e <module_level_2+0xe>
2a: R_X86_64_PC32 dump_stack-0x4
2e: 31 c0 xor %eax,%eax
30: 5d pop %rbp
31: c3 retq
Disassembly of section .init.text:
0000000000000000 <init_module>:
module_level_init():
0: e8 00 00 00 00 callq 5 <init_module+0x5>
1: R_X86_64_PC32 __fentry__-0x4
5: 55 push %rbp
6: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
9: R_X86_64_32S .rodata.str1.1
d: 48 89 e5 mov %rsp,%rbp
10: e8 00 00 00 00 callq 15 <init_module+0x15>
11: R_X86_64_PC32 printk-0x4
15: e8 00 00 00 00 callq 1a <init_module+0x1a>
16: R_X86_64_PC32 dump_stack-0x4
1a: 31 c0 xor %eax,%eax
1c: 5d pop %rbp
1d: c3 retq
Disassembly of section .exit.text:
0000000000000000 <cleanup_module>:
module_level_exit():
0: 55 push %rbp
1: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
4: R_X86_64_32S .rodata.str1.1+0x10
8: 48 89 e5 mov %rsp,%rbp
b: e8 00 00 00 00 callq 10 <cleanup_module+0x10>
c: R_X86_64_PC32 printk-0x4
10: 5d pop %rbp
11: c3 retq
dump_stack在较旧的内核版本(如3.10)中将打印地址,而在较新的内核版本(如4.19)中,它不会打印地址