Linux内核调试之dump_stack的简单使用

创建于 2013-04-12

迁移自本人的百度空间

--------------------------------

刚刚接触内核,在调试过程中用printk打印信息当然是直接有效的办法,但当我们不知到一个函数或者一个模块到底在哪里出了问题时我们可以利用dump_stack有效的找到问题的根源,下面只是简单的给出了使用方法。

 

下面是使用例子

 

Makefile文件

obj-m := hello.o
KERNELBUILD :=/lib/modules/$(shell uname -r)/build
default: 
        make -C $(KERNELBUILD) M=$(shell pwd) modules 
clean: 
        rm -rf *.o *.ko *.mod.c *.cmd *.markers *.order *.symvers *.tmp_versions

hello.c文件

#include 
#include 
#include 
#include 
         
MODULE_LICENSE("Dual BSD/GPL");
          
static int __init hello_init(void)
{
     printk(KERN_ALERT "dump_stack start\n");
     dump_stack();
     printk(KERN_ALERT "dump_stack over\n");
     return 0;
 }
 static void __exit hello_exit(void)
 {
      printk(KERN_ALERT "test module\n");
 }
         
module_init(hello_init);
module_exit(hello_exit);

注意:使用dump_stack()要加上这两个头文件

  1. #include 

  2. #include 

然后make得到hello.ko
在运行insmod hello.ko把模块插入内核
运行查看内核启动信息的阿命令 dmesg
 

[  452.785164] dump_stack start

[  452.785177] Pid: 1874, comm: insmod Tainted: G           O 3.8.6 #2

[  452.785179] Call Trace:

[  452.785185]  [] hello_init+0x17/0x27 [hello]

[  452.785218]  [] do_one_initcall+0x34/0x170

[  452.785233]  [] do_init_module+0x3c/0x1a0

[  452.785237]  [] load_module+0x1551/0x15f0

[  452.785243]  [] sys_init_module+0x9b/0xb0

[  452.785266]  [] sysenter_do_call+0x12/0x28

[  452.785267] dump_stack over

 

上面打出运行这个模块时调用的函数


删除模rmmod hello

 

但是,使用dump_stack有不足之处

dump_stack的原理是遍历堆栈,把所有可能是内核函数的内容找出来,并打印对应的函数。因为函数调用时会把下一条指令的地址放到堆栈中。所以只要找到这些return address,就可以找到这些return address所在函数,进而打印函数的调用关系。

 

使用dump_stack可能不准确,可能的原因有三: 
         1.所有这些可以找到的函数地址,存在/proc/kallsyms中。它并不包括内核中所有的函数,而只包括内核中stext~etext和sinittext~einittext范围的函数,及模块中的函数。详细可参考scripts/kallsyms.c 
         2.一些函数在编译时进行了优化,把call指令优化为jmp指令,这样在调用时就不会把return address放到堆栈,导致dump_stack时在堆栈中找不到对应的信息。 
         3.堆栈中可能有一些数值,它们不是return address,但是在内核函数地址的范围里,这些数值会被误认为return address从而打印出错误的调用关系。

你可能感兴趣的:(Linux内核)