Linux Device Driver >> SystemTap
解析oneshot執行流程
參考資訊:
1. document
2. source code
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 < sizeof(st)) { rc = 0; // ? goto out; } if (copy_from_user(&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<1; i++) { struct stap_be_probe* stp = &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發起