在编译时将用户空间C函数代码下移到内核空间?

我可能无法立即回到这个问题上,但是现在我已经遇到了,我想我会记下来:

首先,我不确定用什么方法来调用它。 我已经试过在标题中“下降”和“解决”,但我想知道是否有一个更合适的术语。 从本质上讲,我想要得到的东西就像我从内核系统调用 – ar.linux.it获得的这个图像上显示的那样 :

ksys,如图一

这里是一个更具体的例子 – 考虑下面的小而不工作( 它只会导致“断言失败” ),但可编译的ALSA代码:

// atest.c #include <alsa/asoundlib.h> static snd_pcm_t *playbck_pcm_handle; static char wrsrcbuf[256] = {[0 ... 255] = 5}; // initialization gcc specific static snd_pcm_uframes_t period_frames = 32; static int ret; int main() { ret = snd_pcm_writei(playbck_pcm_handle, wrsrcbuf, period_frames); return 0; } 

我可以build立这个:

 gcc -Wall -g atest.c -lasound -o atest 

…然后,我可以用objdump观察程序集:

 $ objdump -d -M intel -S atest ... int main() { ... ret = snd_pcm_writei(playbck_pcm_handle, wrsrcbuf, period_frames); 804842d: 8b 15 40 a1 04 08 mov edx,DWORD PTR ds:0x804a140 ... 8048447: e8 0c ff ff ff call 8048358 <snd_pcm_writei@plt> ... return 0; 8048451: b8 00 00 00 00 mov eax,0x0 } ... 

…这只告诉我一个子程序<snd_pcm_writei@plt>会被调用 – 但是它并没有告诉我在哪个库目标文件(旁注:给定的编译通过,是否意味着gcc会知道库的位置作为当前系统上的对象文件?)

然后,我可以原则上运行程序(尽pipe不是这个),并且通过使用/sys/kernel/debug/tracing/trace的内置Linux跟踪( ftrace )function,获得运行时内核日志。 由于内核的抢占性和调度性,我们无法真正依靠执行顺序的任何恒定性,但原则上,我们可以得到类似的东西( 不是从上面的例子,因为它没有做任何适当的设备初始化 ):

 sys_ioctl() { ... do_vfs_ioctl() { snd_pcm_playback_ioctl() { snd_pcm_playback_ioctl1() { _cond_resched(); copy_from_user() { ... } snd_pcm_lib_write() { snd_pcm_lib_write1() { _raw_read_lock_irq(); _raw_spin_lock(); snd_pcm_update_hw_ptr() { snd_pcm_update_hw_ptr0() { azx_pcm_pointer() { ... 

所以,这告诉我,为了响应snd_pcm_writei命令 – 最终将调用sys_ioctl – > snd_pcm_playback_ioctl – > snd_pcm_lib_write ,这将是ALSA函数内置到内核中; 然而,像azx_pcm_pointer()这样的函数也会被调用,它们是设备驱动程序的一部分azx_pcm_pointerhda-intel驱动程序的一部分 )。

所以我的问题是 – 是否有一个应用程序可以输出程序的function“下降”树从用户空间到内核空间 – 无论是在编译时(这将是gcc本身,但有一些特殊的开关,如果他们为此目的而存在),还是后期编译(就像使用objdump ,但不是“运行时”,因为分析的程序本身没有运行)? 例如,对于这个例子,我希望输出如下所示:

 int main() { # atest ... ret = snd_pcm_writei(playbck_pcm_handle, wrsrcbuf, period_frames); # atest ... <snd_pcm_writei@plt> # libasound.so ?? ... sys_ioctl() { # ???.(k)o? ... snd_pcm_playback_ioctl() { # ???.(k)o? ... azx_pcm_pointer() { # /lib/modules/.../sound/pci/hda/snd-hda-intel.ko ... ... 

我明白,代码可能需要一些代码path – 所以希望这个工具能够解决所有的问题,或者允许设置variables,限制代码path的数量; 但一般来说,输出将是一棵树(然后可以用graphviz来显示)。

我也明白,parsing驱动程序可能不会进入运行时(因为设备及其驱动程序可以在运行时通过用户空间程序的命令行参数来指定)。 但我希望至less有一个通知告诉我像“这里一个未指定的驱动程序函数将被称为”。

旁注:给定编译通过,这是否意味着gcc会知道在当前系统上的库作为目标文件的位置?

是的,这正是为什么你必须指定-sound。 这个函数是由链接器找到的。 如果由于某些原因libasound没有它 – 你会得到链接错误。

所以我的问题是 – 是否有一个应用程序可以输出程序的功能“下降”树从用户空间到内核空间

我没有听说过。 这当然是可能的,但用户空间和内核空间之间的转换远不是单纯的函数调用。 实际上,用户空间库使用了syscall()函数,该函数将适当的系统调用号和参数设置到寄存器,并发出特殊的CPU中断,哪个内核捕获然后执行 – 所以gcc和任何对象代码解析工具都不能跟踪这个转换。 我最好的猜测是转储用户和内核空间,然后连接这个日志,但这将是棘手的。

顺便说一句,你为什么要这个?