为啥systemtap没找到函数

hon@station6:~/codebox/stap/net$ sudo stap -L 'kernel.function("sock_recvmsg_nosec")'
kernel.function("sock_recvmsg_nosec@/build/linux-Ay7j_C/linux-4.4.0/net/socket.c:710")

 710 static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
711 size_t size, int flags)
712 {
713 return sock->ops->recvmsg(sock, msg, size, flags);
714 }

这是很好的一个例子,函数中明明是有sock msg size flags,但是stap显示不了,这说明函数被优化过了,

但是没有变量信息,说明这个参数直接被优化掉了

难道不是edi/esi中存放的就不是第一个参数了?

gcc如何优化函数入参:windows和linux是不同的:

https://www.cnblogs.com/shangdawei/p/3323252.html

那么函数参数什么时候会被优化呢?

我ubuntu机器上vmlinux的路径是/usr/lib/debug/boot目录下面,我们看一下这段反汇编代码的样子:

  7 ffffffff816fb700 <sock_recvmsg_nosec>:
8 ffffffff816fb700: 48 8b 47 28 mov 0x28(%rdi),%rax
9 ffffffff816fb704: 55 push %rbp
10 ffffffff816fb705: 48 89 e5 mov %rsp,%rbp
11 ffffffff816fb708: ff 90 90 00 00 00 callq *0x90(%rax)
12 ffffffff816fb70e: 5d pop %rbp
13 ffffffff816fb70f: c3 retq

好好分析下这段汇编代码还真是有问题呢,首先我们通过gdb发现0x28(%rdi) 这个地方的值就是是:$sock->ops呢,也就是说rax寄存器中的值就是,

(gdb) p &((struct socket *)0)->ops
$2 = (const struct proto_ops **) 0x28 <irq_stack_union+40>
(gdb) p &((struct proto_ops *)0)->recvmsg
$3 = (int (**)(struct socket *, struct msghdr *, size_t,
    int)) 0x90 <irq_stack_union+144>
这段汇编代码中两个非常关键的常数:0x28,0x90我们就知道是啥了, 第一步是$sock->ops嘛,然后第二部就是($sock->ops)->recvmsg,然后取数值,就得到真正的recv_msg的地址咯,所以直到调用函数unix_stream_recvmsg,应该edi/esi都不变才对呢,为啥就变了呢,看下参数是怎么传递的:

来个普通的func(int a, int b)函数是怎么传递参数的

273 00000000004004d6 <func>:
274 4004d6: 55 push %rbp
275 4004d7: 48 89 e5 mov %rsp,%rbp
276 4004da: 89 7d fc mov %edi,-0x4(%rbp)
277 4004dd: 89 75 f8 mov %esi,-0x8(%rbp)
...................
281 4004e7: c3 retq
282
283 00000000004004e8 <main>:
..................
287 4004f0: be 02 00 00 00 mov $0x2,%esi
288 4004f5: bf 01 00 00 00 mov $0x1,%edi
289 4004fa: e8 d7 ff ff ff callq 4004d6 <func>
290 4004ff: 89 45 fc mov %eax,-0x4(%rbp)
291 400502: b8 01 00 00 00 mov $0x1,%eax
292 400507: c9 leaveq
293 400508: c3 retq
294 400509: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)

即便是优化了,参数也是放在了edi/esi中,那么我读取这个寄存器咋就不行呢?

程序为了优化,在sock_recvmsg_nosec上下文中根本就看不到edi/esi/edi,

710 static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
 711                      size_t size, int flags)
 712 {
 713     return sock->ops->recvmsg(sock, msg, size, flags); //
 714 }
 但是这里我觉得edi/esi/参数仍然是存在的于寄存器edi中,只不过在这个上下文中不存在,所以在这里我们用ktap中两种方法中第一个参数的值;

1)ulong_arg(1)

2) 直接读取寄存器edi register("edi")

结果发现惊人地相似:

regis: 0xffffffff81d5d210
ulong: 0xffffffff81d5d210
regis: 0xffffffff81d5d210
ulong: 0xffffffff81d5d210
regis: 0xffffffff81d5d210
ulong: 0xffffffff81d5d210
regis: 0xffffffff81d5d210
ulong: 0xffffffff81d5d210
发现大家指向的都是一样的 1) ulong_arg(1) 2) pointer_arg(1); (3) register("edi")

为啥子,在函数中遇到的值不是一样的咧。

在函数调用关系中sock_recvmsg->sock_recvmsg_nosec->unix_stream_recvmsg

发现在函数sock_recvmsg和函数unix_stram_recvmsg中得到的函数的变量是一致的!!只有在sock_recvmsg_nosec中得到的变量与他们相差好大,这是因为sock_recvmsg_nosec是inline函数吗?但是inline函数怎么/proc/kallsyms中也能看到呀,并且

ffffffff816fb700 t sock_recvmsg_nosec
ffffffff816fdb30 T sock_recvmsg

hello inline:0xffffffff816fdb55 sock_recvmsg
hello inline:0xffffffff816fdb55 sock_recvmsg
hello inline:0xffffffff816fdb55 sock_recvmsg
hello inline:0xffffffff816fdb55 sock_recvmsg
hello inline:0xffffffff816fdb55 sock_recvmsg
hello inline:0xffffffff816fdb55 sock_recvmsg
hello inline:0xffffffff816fdb55 sock_recvmsg
hello inline:0xffffffff816fdb55 sock_recvmsg
hello inline:0xffffffff816fdb55 sock_recvmsg

发现根本就不是函数sock_recvmsg_nosec,而是函数probefunc()

7 probe kernel.function("sock_recvmsg_nosec").inline {
  8     printf("hello inline:%p %s\n", addr(), probefunc())
  9 }

并且输出的地址也不是sock_recvmsg_nosec,直接就是函数sock_recvmsg了,根本就没有上下文信息,所以现在的问题是为啥inline函数有单独的程序块?

inline函数是有单独的程序块,但是真正程序执行时是不会跳到这个块里的,这个块就是为了将来直接嵌入到caller中去,看下caller的汇编码就可以了

反汇编函数的代码有:真正程序执行是调用的函数调用在0x816fdb55这个地方,

  7 ffffffff816fdb30 <sock_recvmsg>:
8 ffffffff816fdb30: e8 7b 90 12 00 callq ffffffff81826bb0 <__fentry__>
9 ffffffff816fdb35: 55 push %rbp
10 ffffffff816fdb36: 48 89 e5 mov %rsp,%rbp
11 ffffffff816fdb39: 41 56 push %r14
12 ffffffff816fdb3b: 41 55 push %r13
13 ffffffff816fdb3d: 41 54 push %r12
14 ffffffff816fdb3f: 53 push %rbx
15 ffffffff816fdb40: 49 89 f4 mov %rsi,%r12
16 ffffffff816fdb43: 48 89 fb mov %rdi,%rbx
17 ffffffff816fdb46: 49 89 d5 mov %rdx,%r13
18 ffffffff816fdb49: 41 89 ce mov %ecx,%r14d
19 ffffffff816fdb4c: e8 3f 18 c4 ff callq ffffffff8133f390 <security_socket_recvmsg>
20 ffffffff816fdb51: 85 c0 test %eax,%eax
21 ffffffff816fdb53: 75 16 jne ffffffff816fdb6b <sock_recvmsg+0x3b>
22 ffffffff816fdb55: 48 8b 43 28 mov 0x28(%rbx),%rax
23 ffffffff816fdb59: 44 89 f1 mov %r14d,%ecx
24 ffffffff816fdb5c: 4c 89 ea mov %r13,%rdx
25 ffffffff816fdb5f: 4c 89 e6 mov %r12,%rsi
26 ffffffff816fdb62: 48 89 df mov %rbx,%rdi
27
ffffffff816fdb65: ff 90 90 00 00 00 callq *0x90(%rax)
28 ffffffff816fdb6b: 5b pop %rbx
29 ffffffff816fdb6c: 41 5c pop %r12
30 ffffffff816fdb6e: 41 5d pop %r13
31 ffffffff816fdb70: 41 5e pop %r14
32 ffffffff816fdb72: 5d pop %rbp
33 ffffffff816fdb73: c3 retq
34 ffffffff816fdb74: 66 90 xchg %ax,%ax
35 ffffffff816fdb76: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
36 ffffffff816fdb7d: 00 00 00

在红色插入点的位置,可见,其实rdi/rsi/rdx/rcx的值可能已经被函数给换掉了,所以不能够使用了已经。

systemtap没找到函数变量的更多相关文章

  1. python note 10 函数变量

    1.命名空间 #内置命名空间 —— python解释器 # 就是python解释器一启动就可以使用的名字存储在内置命名空间中 # 内置的名字在启动解释器的时候被加载进内存里#全局命名空间 —— 我们写 ...

  2. Python基础3 函数 变量 递归 -DAY3

    本节内容 1. 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数 温故知新 1. 集合 主要作用: 去重 关系测 ...

  3. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  4. C++中函数变量布局小结

    把布局作为一种信仰(Layout as Religion).                                                                       ...

  5. 没找到Wkhtmltopdf,报表会被显示为html

    windows10 odoo 打印报表时提示 没找到Wkhtmltopdf,报表会被显示为html 现象 原因 没有安装Wkhtmltopdf,没有配置环境变量,odoo在电脑系统中找不到Wkhtml ...

  6. 函数变量作用域(python)

    收集参数:该参数个数不确定 >>> def test(*params): print('参数的长度是:', len(params)); print('第二个参数是:', params ...

  7. 创建 userSettings/Microsoft.SqlServer.Configuration.LandingPage.Properties.Settings 的配置节处理程序时出错: 未能加载文件或程序集“System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”或它的某一个依赖项。系统没找到指定的文件

    创建 userSettings/Microsoft.SqlServer.Configuration.LandingPage.Properties.Settings 的配置节处理程序时出错: 未能加载文 ...

  8. 解决SecureCRT中文版"数据库里没找到防火墙'无'"的错误提示

    问题描述: 最近从同事那拷贝到一个中文版的SecureCRT,但是每次打开都会有个防火墙的错误提示,“数据库里没找到防火墙“无”.此会话将尝试不通过防火墙进行连接. 出现这个错误的原因是在Secure ...

  9. day11.1函数进阶 列表集合 字典中的函数变量,函数作为形参

    函数进阶 1.函数作为变量 a=123 name="gao" nums=[1,2,3] data=nums#指向同一个内存地址 #查看内存地址篇章 def func(): prin ...

随机推荐

  1. 构建高可靠hadoop集群之2-机栈

    本文主要参考 http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-common/RackAwareness.html had ...

  2. 使用Linux命名将代码上传到GitHub

    GitHub代码上传教程 https://my.oschina.net/baishi/blog/520791 这篇文章讲得挺清楚的,但是在上传的时候出现了问题 ! [rejected] master ...

  3. Percona-Tookit工具包之pt-ioprofile

      Preface       As a matter of fact,disk IO is the most important factor which tremendously influenc ...

  4. ASP.NET安全验证

    一.为什么要用安全验证,使用安全验证有什么好处. 构造特殊的链接地址,导致文件内的数据泄露 数据库泄露 安全防范的首要策略:所有的HTTP访问都要经过IIS,所以限制IIS的安全性是关键 二.安全验证 ...

  5. pyqt5--学习资料

    http://zetcode.com/gui/pyqt5/ http://www.thehackeruniversity.com/2014/01/23/pyqt5-beginner-tutorial/ ...

  6. sql语句中#{}和${}的区别

    #---将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的 ...

  7. lnmp+phpmyadmin+laravel 环境配置

    腾讯云 Ubuntu16.04 添加用户 useradd 与 adduser Ubuntu下useradd不会在/home下自动创建与用户名同名的用户目录,而且不会自动选择shell版本,也没有设置密 ...

  8. 用友二次开发之科脉TOT3凭证接口

    按客户的要求,根据科脉导出的数据,开发一个工具,将凭证导入T3 这个科目导出的凭证格式. 选择账套登陆,你没看错,这个是我开发的登陆界面. 选择接口文件. 软件自动进数据分类,你可以看到数据了.但只是 ...

  9. JavaScript Shell学习分享

    目录 JavaScript Shell学习分享 简介 安装 使用原因 小结 JavaScript Shell学习分享 简介 JavaScript Shell是由Mozilla提供的综合JavaScri ...

  10. 【GUI】一、Swing外观框架BeautyEye使用

    一.Swing外观框架BeautyEye使用 1.1 导包 BeautyEye.jar 1.2 使用BeautyEye L&F public static void main(String[] ...