如何在linux内核中访问进程的内核堆栈?

时间:2015-04-19 10:17:29

标签: process linux-kernel stack kernel-module

我正在尝试监视进程在执行过程中调用哪些函数。我的目标是知道一个过程在每个功能中花费了多少时间。函数被推送到堆栈并在函数调用返回时弹出。我想知道内核代码在推送和弹出实际发生的位置。

我在void *stack中找到了task_struct字段。我不确定这是否是我要找的领域。如果是,那么知道如何更新它的方法是什么?

我必须编写一个将使用此代码的模块。在这种情况下请帮助我。

1 个答案:

答案 0 :(得分:2)

  

函数被推送到堆栈并在函数调用返回时弹出。我想知道内核代码在推送和弹出实际发生的位置。

它不会发生在内核代码中,它由处理器完成。即当x86汇编CPU找到call指令时,它会将IP推送到堆栈,而ret指令将弹出该值。

您可以使用call修补内核中的每个retcall my_tracing_routine指令并在那里记录指令指针,而不是将控制传递给原始被调用者/调用者。有一些工具:LTTngSystemTap和内核接口,如kprobes,ftrace ......这种方法称为跟踪

但如果补丁所有指令,即使用SystemTap探测器kernel.function("*"),则会导致性能下降,并可能导致系统崩溃。所以,你不能测量每个函数调用,但你可以测量每个第N个函数调用,并希望你得到相同的结果,但是你需要大示例(即运行几分钟的程序) - 称为 profiling

Linux附带了分析器perf

# perf record -- dd if=/dev/zero of=/dev/null
...
^C

# perf report
9.75%  dd  [kernel.kallsyms]  [k] __clear_user
6.69%  dd  [kernel.kallsyms]  [k] __audit_syscall_exit
5.61%  dd  [kernel.kallsyms]  [k] fsnotify
4.73%  dd  [kernel.kallsyms]  [k] system_call_after_swapgs
4.37%  dd  [kernel.kallsyms]  [k] system_call
...

您也可以使用-g来收集呼叫链。默认情况下,perf使用CPU性能计数器,因此在N个CPU周期后,中断被引发,并且perf处理程序(它已嵌入到内核中)保存IP

如果您希望收集堆栈,可以使用SystemTap执行此操作:

# stap --all-modules -e '
    probe timer.profile { 
        if(execname() == "dd") { 
            println("----"); 
            print_backtrace(); } 
        }' -c 'dd if=/dev/zero of=/dev/null' 
...
    ----
0xffffffff813e714d : _raw_spin_unlock_irq+0x32/0x3c [kernel]
0xffffffff81047bb9 : spin_unlock_irq+0x9/0xb [kernel]
0xffffffff8104ac68 : get_signal_to_deliver+0x4f0/0x528 [kernel]
0xffffffff8100216f : do_signal+0x48/0x4b1 [kernel]
0xffffffff81002608 : do_notify_resume+0x30/0x63 [kernel]
0xffffffff813edd6a : int_signal+0x12/0x17 [kernel]

在此示例中,SystemTap使用timer.profile探针附加到perf事件cpu-clock。为此,它生成,构建和加载内核模块。您可以使用stap -k -p 3

进行检查