如何获取内核函数的参数并在SystemTap中投入到char的空隙指针



我有一个系统点击脚本,该脚本探讨内核函数" memcpy"。我想根据SRC缓冲区的内容打印堆栈跟踪。

我的代码:

%{
        #include <linux/string.h>
%}
probe begin
{
        printf("Beginn");
}
probe kernel.function("memcpy")
{
        buffer = @cast($src, "char");
        if (isinstr(buffer, "some pattern") != NULL) {
                printf("Foundn");
                print_backtrace();
        }
}

当我运行脚本如下时,此脚本给了我一个错误:" stap -g stacktrace.stp"

未解决的目标符号表达式:标识符'$ src'

语义错误:键入不匹配(字符串):stacktrace.stp:31:14

的标识符"缓冲区"
 source:         if (isinstr(buffer, "shubham") != NULL) {
                                ^

语义错误:类型是在此处推断的(长):标识符"缓冲区":30:2

   source:         buffer = @cast($src, "char");
                    ^

通过2:分析失败。[MAN ERROR :: PASS2]

我已经看到了Linux内核代码中memcpy的函数定义,并且该参数仅命名为SRC。我无法解决可变名称。我尝试了不同的名称 $src$from$s,但是什么都没有。

机器的内核版本是:3.10.0-514.el7.x86_64(Rhel 7.3(Maipo))

上面安装了以下内核软件包:

  • kernel-debuginfo-common-x86_64-3.10.0-514.el7.x86_64
  • 内核-3.10.0-514.el7.x86_64
  • 内核头 - 3.10.0-514.el7.x86_64
  • kernel-debuginfo-3.10.0-514.el7.x86_64
  • kernel-devel-3.10.0-514.el7.x86_64

更新2:

buffer = @cast($src, "char");

应该是 char指针而不是 char


更新1 :来自SystemTap Docs

语义错误:未解决的目标符号表达式

在无法解析的探针处理程序中提到了一个目标变量。或者,目标变量在诸如脚本函数之类的上下文中根本无效。该变量可能是通过优化编译器来体现的,或者可能没有合适的类型,或者在某处可能只是一个烦人的错误。再次尝试使用略有不同的探针点(使用语句()而不是函数())在同一区域中搜索更合作的邻居。


原始杂物

变量作为友好事物的概念称为 src 仅存在于人类可读源代码中。环顾您的代码。您尚未声明任何名为 src 的变量。

我已经看到了Linux内核代码中的memcpy的函数定义,并且该参数命名为SRC

是的,但这再次是为了人类的利益。


您缺少的一部分是,当源代码被编译到应用程序中时,编译器将整理我们的所有人类结构并将其变成堆栈偏移。

警告:我完全忽略了为简单起见的函数。

如果您查看编译的二进制文件,则为您的平台,您可以看到一些更好的提示。假设您在X86系统上,您会看到这样的东西:

memcpy:
  push ebp
  mov ebp, esp
  sub esp, 8
  // The function body starts here and you will see references 
  // to what we recognize as the variable "src" with an instructions like
  mov edi, esp+0
  // That just loaded the EDI register with a reference to the location of src

您可以使用GDB看到平台的组件。

gcc debuginfo的内核可能不一致地在每个地方保存memcpy的内衬副本的形式参数可能不一致。

stap -vL 'kernel.function("memcpy").*'

应列出所有站点的个人或摘要。机会像

stap -e '
  probe kernel.function("memcpy") 
   { if (@defined($p) && @defined($q)) println($p, " ", $q) }'

可以做到这一点。它只会在定义这两个参数的那些探针位置发射println。在我最近的内核中,人们看到了...

之类的变体
kernel.function("memcpy@./include/linux/string.h:347").inline /* pc=_stext+0x68c6a */ $q:void const* $p:void*
kernel.function("memcpy@./include/linux/string.h:347").inline /* pc=_stext+0x178ec */ $size:__kernel_size_t $p:void*
kernel.function("memcpy@./include/linux/string.h:347").inline /* pc=_stext+0x15a31 */ $size:__kernel_size_t $q:void const* $p:void*
kernel.function("memcpy@./include/linux/string.h:347").inline /* pc=_stext+0x13f1f */ $size:__kernel_size_t $q:void const* $p:void* $p_size:size_t $q_size:size_t
kernel.function("memcpy@./include/linux/string.h:347").inline /* pc=_stext+0xc717 */ $size:__kernel_size_t $q:void const* $p:void* $p_size:size_t $q_size:size_t

...因此,订阅代码必须忍受范围。

最新更新