Debugging 如何在SystemTap中获取内核函数的参数并将void指针强制转换为char?

Debugging 如何在SystemTap中获取内核函数的参数并将void指针强制转换为char?,debugging,systemtap,Debugging,Systemtap,我有一个探测内核函数“memcpy”的系统tap脚本。我想根据src缓冲区的内容打印堆栈跟踪,src缓冲区是一个空指针 我的代码: %{ #include <linux/string.h> %} probe begin { printf("Begin\n"); } probe kernel.function("memcpy") { buffer = @cast($src, "char"); if (isinstr(buf

我有一个探测内核函数“memcpy”的系统tap脚本。我想根据src缓冲区的内容打印堆栈跟踪,src缓冲区是一个空指针

我的代码:

%{
        #include <linux/string.h>
%}
probe begin
{
        printf("Begin\n");
}
probe kernel.function("memcpy")
{
        buffer = @cast($src, "char");
        if (isinstr(buffer, "some pattern") != NULL) {
                printf("Found\n");
                print_backtrace();
        }
}
语义错误:首先在此处推断类型(长):标识符“缓冲区”位于:30:2

   source:         buffer = @cast($src, "char");
                    ^
通过2:分析失败。[人工错误::pass2]

我在linux内核代码中看到了memcpy的函数定义,参数名为src only。我无法解析变量名。我尝试了不同的名称
$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
  • kernel-3.10.0-514.el7.x86_64
  • kernel-headers-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");
这应该是一个字符指针而不是一个字符吗


更新1:从

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

在无法解析的探测处理程序中引用了目标变量。或者,目标变量在脚本函数等上下文中根本无效。这个变量可能被优化编译器省略了,或者可能没有合适的类型,或者可能只是某个地方有一个恼人的bug。请使用稍微不同的探测点(使用语句()而不是函数())重试,以在同一区域中搜索更合作的邻居


原创漫谈

变量的概念是一个友好的东西,称为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的每个位置保留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

。。。因此,stap代码必须能够容忍这个范围。

我认为您所需要的就是
buffer=kernel\u string($src),但如果您能解释为什么要将void*强制转换为char-也许您只需要一个字节首先,我得到一个错误,说变量src是不可解析的。我不知道为什么会产生这个错误,即使memcpy将src作为参数。现在,关于您的问题@MarkPlotnick,我想读取传递给memcpy的缓冲区的内容,并想将其与预定义模式进行比较,这就是我想将其转换为char*的原因。在您修订的问题中,您说systemtap无法解析
$src
。您可以编辑您的问题,说明您正在运行哪个发行版,以及您安装了哪些内核开发、内核调试和内核调试信息包吗?@MarkPlotnick,添加了所有配置详细信息。使用stap-L'kernel.function(“memcpy”)'查看在该探测点有哪些变量可用。使用反汇编,我仍然无法找到函数memcpy的参数名。你有什么建议来解决这个问题?另外,“buffer=@cast($src,“char”);”这里cast操作符返回一个“long”作为数据类型,而不是我需要的字符串或字符指针。
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