驅動程式 - Linux Device Driver(LDD) - SystemTap - 解析Oneshot執行流程



參考資訊:
https://sourceware.org/systemtap/ftp/releases/
https://sourceware.org/systemtap/SystemTap_Beginners_Guide/index.html

main.stp

probe oneshot
{
    printf("hello, world!\n")
}

編譯成C語言

$ stap main.stp -p3 > main.c

module_init() runtime/linux/runtime.h

int init_module (void)
{
    int rc;
    /* With deliberate hash-collision-inducing data conceivably fed to
     stap, it is beneficial to add some runtime-random value to the
     map hash. */
    get_random_bytes(&stap_hash_seed, sizeof (stap_hash_seed));
    rc = systemtap_kernel_module_init();
    if (rc)
        return rc;
    rc = _stp_transport_init();
    if (rc)
        systemtap_kernel_module_exit();
    return rc;
}

SystemTap的init_module()會呼叫systemtap_kernel_module_init(),這個副程式是包含在main.stp編譯出來的*.ko檔案裡面

systemtap_kernel_module_init() main.c

static int systemtap_kernel_module_init (void)
{
    int rc = 0;
    int i=0, j=0;
    if (rc) {
        goto out;
    }
out:
    return rc;
}

_stp_transport_init() runtime/transport/transport.c

/**
 * _stp_transport_init() is called from the module initialization.
 *   It does the bare minimum to exchange commands with staprun
 */
static int _stp_transport_init(void)
{
    ...
    /* create control channel */
    ret = _stp_register_ctl_channel();
    if (ret < 0)
        goto err1;
    ...
}

由init_module()呼叫的第二個副程式是_stp_transport_init(),主要用來初始化SystemTap相關fs

_stp_register_ctl_channel() runtime/transport/control.c

static int _stp_register_ctl_channel(void)
{
    ...
    if (_stp_register_ctl_channel_fs() != 0) // procfs or debugfs decision time
        goto err0;
    ...
}

_stp_register_ctl_channel_fs() runtime/transport/transport.c

static int _stp_register_ctl_channel_fs(void)
{
    ...
    if (procfs_p)
        return _stp_procfs_register_ctl_channel_fs();
    ...
}

_stp_procfs_register_ctl_channel_fs()用來註冊staprun需要使用的fs

_stp_procfs_register_ctl_channel_fs() runtime/transport/procfs.c

static int _stp_procfs_register_ctl_channel_fs(void)
{
    ...
#ifdef STAPCONF_PROC_OPS
    de = proc_create(".cmd", 0600, _stp_procfs_module_dir, &_stp_ctl_proc_ops_cmd);
#else
    de = proc_create(".cmd", 0600, _stp_procfs_module_dir, &_stp_ctl_fops_cmd);
#endif
    ...
}

_stp_ctl_fops_cmd runtime/transport/control.c

static struct file_operations _stp_ctl_fops_cmd = {
    .owner = THIS_MODULE,
    .read = _stp_ctl_read_cmd,
    .write = _stp_ctl_write_cmd,
    .open = _stp_ctl_open_cmd,
    .release = _stp_ctl_close_cmd,
    .poll = _stp_ctl_poll_cmd
};
#ifdef STAPCONF_PROC_OPS
static struct proc_ops _stp_ctl_proc_ops_cmd = {
    .proc_read = _stp_ctl_read_cmd,
    .proc_write = _stp_ctl_write_cmd,
    .proc_open = _stp_ctl_open_cmd,
    .proc_release = _stp_ctl_close_cmd,
    .proc_poll = _stp_ctl_poll_cmd
};
#endif

_stp_ctl_write_cmd() runtime/transport/control.c

static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    ...
    switch (type) {
    case STP_START:
    {
        static struct _stp_msg_start st;
        if (count &lt; sizeof(st)) {
            rc = 0; // ?
            goto out;
        }
        if (copy_from_user(&amp;st, buf, sizeof(st))) {
            rc = -EFAULT;
            goto out;
        }
        _stp_handle_start(&st);
    }
    break;
    ...
}

_stp_handle_start() runtime/transport/transport.c

static void _stp_handle_start(struct _stp_msg_start *st)
{
    ...
    st->res = systemtap_module_init();
    ...
}

systemtap_module_init() main.c

static int systemtap_module_init (void)
{
    ...
    for (i=0; i&lt;1; i++) {
        struct stap_be_probe* stp = &amp;stap_be_probes[i];
        if (stp->type == 0)
            enter_be_probe(stp); /* rc = 0 */
    }
    ...
}

stap_be_probe main.c

static struct stap_be_probe {
    const struct stap_probe * const probe;
    int state, type;
} stap_be_probes[] = {
    { .probe=(&stap_probes[0]), .state=STAP_SESSION_STARTING, .type=0 },
};

static struct stap_probe stap_probes[] = {
  STAP_PROBE_INIT(0, &probe_6334, "begin", "oneshot", "main.stp:1:7", " from: oneshot from: oneshot"),
};

probe_6334 main.c

static void probe_6334(struct context * __restrict__ c)
{
    ...
    _stp_print("hello, world!\n");
    ...
}

STP_START是由staprun發起