2

我可能无法立即回到这个问题,但我想既然遇到了这个问题,我就会记下来:

首先,我不确定调用它的正确方法是什么;我在标题中尝试过“descend”和“resolve”,但我想知道是否有更合适的术语。从本质上讲,我想要的是获得像我从内核系统调用 - ar.linux.it获得的这张图片所示的东西:

ksys图1

这是一个更具体的示例 - 考虑以下小型且不工作(它只会导致“断言失败”),但可编译的 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;

}

我可以用:

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将知道库的位置为当前系统上的目标文件?)

然后,我原则上可以运行程序(虽然不是这个),并通过使用中内置的 Linux 跟踪(ftrace)功能/sys/kernel/debug/tracing/trace,获取运行时内核日志。由于内核的抢占性质和调度,我们不能真正指望执行顺序的任何恒定性,但原则上,我们可以得到这样的东西(虽然不是来自上面的例子,因为它没有做任何适当的设备初始化):

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_pointer的一部分(是hda-intel驱动程序的一部分)。

所以我的问题是 - 是否有一个应用程序可以将程序的函数“下降”树从用户空间输出到内核空间 - 无论是在编译时(这将是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
        ...
      ...

我知道代码可以采用许多代码路径 - 所以希望这个工具能够全部解决它们 - 或者允许设置变量,以限制代码路径的数量;但一般来说,输出将是一棵树(然后可以用,比如说,来可视化graphviz)。

我也明白,如果不进入运行时解析驱动程序可能是不可能的(因为设备 - 及其驱动程序 - 可以在运行时由用户空间程序的命令行参数指定);但我希望至少有一个通知告诉我“这里将调用一个未指定的驱动程序函数”。

4

1 回答 1

1

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

是的,这正是您必须指定 -lasound 的原因。这个函数是被链接器发现的。如果由于某些原因 libasound 没有它 - 你会得到链接错误。

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

我一个都没听说过。这当然是可能的,但是用户空间和内核空间之间的转换远非仅仅是函数调用。事实上,用户空间库使用 syscall() 函数,它为寄存器设置适当的系统调用号和参数,并发出特殊的 CPU 中断,内核捕获并执行该中断 - 因此 gcc 和任何目标代码解析工具都无法跟踪此转换。我最好的猜测是转储用户和内核空间并在之后连接这些日志,但这会很棘手。

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

于 2013-09-18T08:14:42.790 回答