我有一个长期的项目,试图学习使用ftrace(Linux内核跟踪工具)。与往常一样,当我想了解更多信息时,我转向了Brendan Gregg的工具之一– Github上的perf-tools回购。
他有许多易于使用且易于理解的工具–例如,您可以使用execsnoop查看正在执行的每个程序。
还有一些需要……更多的工作。我对ftrace感兴趣,并且正在使用他的kprobe脚本跟踪系统调用及其参数。
我从sudo kernel/kprobe 'p:SyS_read'
每次read
系统调用发生时告诉我开始。这给我输出像
Chrome_ChildIOT-8978[000] d...7402.349880: SyS_read: (SyS_read+0x0/0xa0) Chrome_ChildIOT-4102[002] d...7402.349922: SyS_read: (SyS_read+0x0/0xa0) Xorg-1853[001] d...7402.349962: SyS_read: (SyS_read+0x0/0xa0) Xorg-1853[001] d...7402.349969: SyS_read: (SyS_read+0x0/0xa0) Chrome_IOThread-4092[003] d...7402.349974: SyS_read: (SyS_read+0x0/0xa0)
但是,它读取了什么文件?这一点都不好。
在该例子,他说,在开放的系统调用。
在这里,我猜测该模式位于寄存器%cx中,并将其强制转换为16位无符号整数(“:u16”)。您的平台和内核可能不同,并且模式可能在不同的寄存器中。如果摆弄这样的寄存器对您来说太痛苦或不可靠,请考虑安装内核debuginfo并将命名变量与perf_events“ perf probe”一起使用。
他怎么能猜测文件的模式在寄存器中%cx
?寄存器甚至是什么?这是没有道理的。
我部分地了解了这一点,并获得了有关read
系统调用的更多信息,所以现在我将告诉您!
我知道寄存器是CPU在计算事物时用来存储数据的东西。但是那里到底有几个呢?我怎么猜哪个是对的?
首先,我找到了描述x86寄存器的页面。告诉我有
General registersEAX EBX ECX EDXSegment registersCS DS ES FS GS SSIndex and pointersESI EDI EBP EIP ESP
从描述来看,段寄存器似乎可以忽略!指令指针和堆栈指针告诉我现在正在运行什么指令以及堆栈在哪里。我也不在乎。因此,我只需要担心7个寄存器(eax,ebx,ecx,edx,esi,edi和ebp)。
所以在我们跑步之前sudo kernel/kprobe 'p:SyS_read'
。我们还可以打印用于读取系统调用的寄存器!
sudo kernel/kprobe 'p:SyS_read ax=%ax bx=%bx cx=%cx dx=%dx si=%si di=%di' | grep chrome-4095 chrome-4095[001] d...7665.279404: SyS_read: (SyS_read+0x0/0xa0) ax=0 bx=2cb4726adec0 cx=0 dx=2 si=7fff1282f70e di=9 chrome-4095[001] d...7665.279562: SyS_read: (SyS_read+0x0/0xa0) ax=0 bx=2cb4726adec0 cx=0 dx=2 si=7fff1282f70e di=9 chrome-4095[002] d...7665.400594: SyS_read: (SyS_read+0x0/0xa0) ax=0 bx=2cb4726adec0 cx=0 dx=2 si=7fff1282f70e di=9
让我们将其与strace的输出进行比较:
sudo strace -e read -p 4095Process 4095 attached - interrupt to quitread(9, "!", 2) = 1read(9, "!", 2) = 1read(9, "!", 2) = 1
在的输出中strace
。我知道这9
是文件描述符,2是要读取的长度,中间值是字符串。这必须意味着这%di
是文件描述符,并且%dx
是要读取的数据量!
我现在可以贴上标签,成为布伦丹·格雷格(Brendan Gregg)这样的猜谜向导!
sudo kernel/kprobe 'p:julia_smart_read SyS_read fd=%di:u16 bytes_to_read=%dx' | grep chrome-4095 chrome-4095[003] d...7854.905089: julia_smart_read: (SyS_read+0x0/0xa0) fd=9 bytes_to_read=2 chrome-4095[003] d...7854.945585: julia_smart_read: (SyS_read+0x0/0xa0) fd=9 bytes_to_read=2 chrome-4095[002] d...7854.945852: julia_smart_read: (SyS_read+0x0/0xa0) fd=9 bytes_to_read=2
现在,我知道正在读取哪些文件描述符!
使用ftrace而不是strace的优点是开销要低得多:当我使用strace find
时,它的速度要慢20倍,但是使用ftrace时,它完全可以。我仍然不确定我们读取的字符串在哪里(不过我认为它在其中%si
!)
现在,我可以以更少的开销跟踪系统调用又近了一步。猜测寄存器确实很乏味,但似乎完全有可能!