【问题标题】:How to access a process's kernel stack in linux kernel?如何在linux内核中访问进程的内核堆栈?
【发布时间】:2015-06-26 00:49:43
【问题描述】:

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

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

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

【问题讨论】:

  • 有了函数,你的意思是系统调用?或者只是您的代码调用的用户空间中的任何函数,也来自用户空间?
  • 由于我目前无法发表评论,您是否尝试过 manning /proc/ man7.org/linux/man-pages/man5/proc.5.html 和 strace 的流程?
  • 函数调用是指作为流程执行的一部分执行的所有可能的函数。例如,对于用户级别的文件读取操作,系统调用 read() 被调用,然后是内核函数,如 do_page_fault()、do_generic_file_read() 等。

标签: process linux-kernel stack kernel-module


【解决方案1】:

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

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

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

但是如果修补 all 指令,即使用 SystemTap 探测 kernel.function("*"),您将扼杀性能,并可能导致系统崩溃。所以,你不能测量每一个函数调用,但是你可以测量每Nth函数调用,希望你能得到相同的结果,但是你需要大的sample(即运行程序几分钟)——这称为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 探针,该探针附加到性能事件cpu-clock。为此,它生成、构建和加载内核模块。您可以通过stap -k -p 3 进行检查

【讨论】:

  • 感谢详尽的回复!您能否详细说明 SystemTap 输出的内容?要获得上述形式的输出(堆栈跟踪),内核代码 perf 或 SystemTap 实用程序在哪里进行更改/更新?
猜你喜欢
  • 1970-01-01
  • 2020-04-24
  • 2017-09-19
  • 2016-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多