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

转载地址:https://blog.csdn.net/LinSeeker85/article/details/86597145 

刚刚接触内核,在调试过程中用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 <linux/module.h>
#include <linux/init.h>
#include <linux/kprobes.h>
#include <asm/traps.h>
         
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()要加上这两个头文件

#include <linux/kprobes.h>

#include <asm/traps.h>

然后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]  [<f80ff017>] hello_init+0x17/0x27 [hello]

[  452.785218]  [<c0101124>] do_one_initcall+0x34/0x170

[  452.785233]  [<c0195c8c>] do_init_module+0x3c/0x1a0

[  452.785237]  [<c0198571>] load_module+0x1551/0x15f0

[  452.785243]  [<c019872b>] sys_init_module+0x9b/0xb0

[  452.785266]  [<c0653dd9>] 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从而打印出错误的调用关系。
 

对于调用关系比较复杂的函数,在目标函数里面调用dump_stack()可以查看目标函数的调用链

但是如果情况更复杂,涉及到很多函数指针的传递和钩子函数,那么dump_stack的作用也是有限

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值