用ftrace和kprobe捕获用户空间组合(通过使用虚拟地址转换)? [英] Capturing user-space assembly with ftrace and kprobes (by using virtual address translation)?

查看:1388
本文介绍了用ftrace和kprobe捕获用户空间组合(通过使用虚拟地址转换)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于长篇职位抱歉,我以较短的方式解决问题。此外,也许这更适合Unix& Linux Stack Exchange,但是我先在这里尝试一下,因为有一个 ftrace 标签。



无论如何 - 我想观察使用 ftrace function_graph 捕获的上下文中执行用户程序的机器指令>。一个问题是我需要一个较旧的内核:

  $ uname -a 
Linux mypc 2.6.38- 16-generic#67-Ubuntu SMP Thu Sep 6 18:00:43 UTC 2012 i686 i686 i386 GNU / Linux

...在这个版本中,没有 UPROBES - 其中,作为 3.5在[LWN.net] 中的Uprobes应该能够做这样的事情。 (只要我不需要修补原始内核,我会愿意尝试用树构建的内核模块,如用户空间探测器(uprobes)[chunghwan.com] 似乎证明;但是从 0:基于Inode的翻页[LWN.net] ,2.6可能需要一个完整的补丁



但是,在这个版本上,有一个 / sys / kernel / debug / kprobes / sys / kernel / debug / tracing / kprobe_events ;和 Documentation / trace / kprobetrace.txt 意味着可以直接在地址上设置kprobe;即使我无法找到任何关于如何使用这个例子的例子。



在任何情况下,我仍然不能确定要使用的地址 - 作为一个小例子,让我们说我想跟踪 wtest.c 程序(包括在下面)的 main 函数的开始。我可以这样做来编译并获得一个机器指令汇编列表:

  $ gcc -g -O0 wtest.c -o wtest 
$ objdump -S wtest | less
...
08048474< main> ;:
int main(void){
8048474:55 push%ebp
8048475:89 e5 mov%esp, %ebp
8048477:83 e4 f0和$ 0xfffffff0,%esp
804847a:83 ec 30 sub $ 0x30,%esp
804847d:65 a1 14 00 00 00 mov%gs:0x14, %eax
8048483:89 44 24 2c mov%eax,0x2c(%esp)
8048487:31 c0 xor%eax,%eax
char filename [] =/ tmp / wtest。文本;
...
return 0;
804850a:b8 00 00 00 00 mov $ 0x0,%eax
}
...

我将通过脚本设置ftrace记录:

  sudo bash -c'
KDBGPATH =/ sys / kernel / debug / tracing
echo function_graph> $ KDBGPATH / current_tracer
echo funcgraph-abstime> $ KDBGPATH / trace_options
echo funcgraph-proc> $ KDBGPATH / trace_options
echo 0> $ KDBGPATH / tracing_on
echo> $ KDBGPATH / trace
echo 1> $ KDBGPATH / tracing_on; ./wtest;回波0> $ KDBGPATH / tracing_on
cat $ KDBGPATH / trace> wtest.ftrace
'

您可以看到一部分(否则复杂) code> ftrace 登录调试 - 观察内核空间中的硬盘写入(带驱动程序/模块) - Unix& Linux堆栈交换(我从中得到例子)。



基本上,我想在这个 ftrace log,当 main 的第一条指令说,0x8048474,0x8048475,0x8048477,0x804847a,0x804847d,0x8048483和0x8048487的指令由(任何)CPU。问题是,据我所知,从解剖学的内存计划:Gustavo Duarte ,这些地址是虚拟地址,从进程本身的角度来看(我收集,同样的视角由 / proc / PID / maps )...显然,对于 krpobe_event 我需要一个物理地址?

因此,我的想法是:如果我可以找到与程序反汇编的虚拟地址相对应的物理地址(比如通过编码内核模块,这将接受pid和address,以及通过procfs返回物理地址),我可以通过上述脚本中的 / sys / kernel / debug / tracing / kprobe_events 将地址设置为tracepoints希望将它们放在 ftrace 日志中。这个工作原则上可以吗?



有一个问题,我发现在 Linux(ubuntu),C语言:虚拟到物理地址转换 - 堆栈溢出


在用户代码中,您不能知道与虚拟地址对应的物理地址。这是信息根本不会导出到内核之外。甚至可以随时更改,特别是如果内核决定更换部分进程的内存。

...

使用systemcall / procfs将虚拟地址传递给内核并使用vmalloc_to_pfn。通过procfs / register返回物理地址。


然而, vmalloc_to_pfn t似乎是微不足道的:



x86 64 - vmalloc_to_pfn在Linux 32系统上返回32位地址。为什么会切断较高位的PAE物理地址? - 堆栈溢出


VA:0xf8ab87fc PA使用vmalloc_to_pfn:0x36f7f7fc。但实际上我正在期待:0x136f7f7fc。

...

物理地址介于4到5 GB之间。但是我不能得到准确的物理地址,我只得到了32位地址。有没有另外一种获取真实地址的方法?


所以,我不知道我可以提取物理地址的可靠性,所以他们被kprobes追踪 - 特别是因为甚至可以随时改变。但是在这里,我希望,由于程序很小而且微不足道,所以程序在被跟踪时不会交换的合理机会,从而可以获得适当的捕获。 (所以即使我必须多次运行调试脚本,只要我希望获得一次正确捕获一次10次(甚至100次),我会很好



请注意,我想通过 ftrace 输出,以便时间戳在同一个域中(见可靠的Linux内核时间戳(或调整它)与usbmon和ftrace? - Stack Overflow ,以说明时间戳的问题)。因此,即使我可以想出一个 gdb 脚本,要从用户空间运行和跟踪程序(同时一个 ftrace capture获取) - 我想避免,因为 gdb 本身的开销将显示在 ftrace 日志。



总之:



查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆