/usr/share/systemtap/runtime/linux
NameSizeModeActions
uprobes/-0755rm
uprobes2/-0755rm
access_process_vm.h43110644editdlrm
addr-map.c97490644editdlrm
alloc.c159000644editdlrm
arith.c167990644editdlrm
autoconf-514-panic.c680644editdlrm
autoconf-access_ok_2args.c900644editdlrm
autoconf-alloc-percpu-align.c1180644editdlrm
autoconf-asm-syscall.c510644editdlrm
autoconf-atomic_fetch_add_unless.c940644editdlrm
autoconf-bio-bi_opf.c8240644editdlrm
autoconf-blk-types.c3590644editdlrm
autoconf-compat-utimbuf.c530644editdlrm
autoconf-compat_sigaction.c4480644editdlrm
autoconf-constant-tsc.c630644editdlrm
autoconf-cpu-clock.c12770644editdlrm
autoconf-dpath-path.c1210644editdlrm
autoconf-files_lookup_fd_raw.c1360644editdlrm
autoconf-from_kuid_munged.c1910644editdlrm
autoconf-fs_supers-hlist.c3540644editdlrm
autoconf-generated-compile.c560644editdlrm
autoconf-genhd.c2010644editdlrm
autoconf-get-kretprobe.c1070644editdlrm
autoconf-get_user_pages-flags.c15490644editdlrm
autoconf-get_user_pages-notask_struct.c13010644editdlrm
autoconf-get_user_pages_remote-flags.c15500644editdlrm
autoconf-get_user_pages_remote-flags_locked.c13310644editdlrm
autoconf-get_user_pages_remote-notask_struct.c14380644editdlrm
autoconf-grsecurity.c2190644editdlrm
autoconf-hlist-4args.c2960644editdlrm
autoconf-hlist_add_tail_rcu.c1120644editdlrm
autoconf-hrtimer-getset-expires.c1260644editdlrm
autoconf-hrtimer-rel.c870644editdlrm
autoconf-hw_breakpoint_context.c3150644editdlrm
autoconf-inode-private.c1730644editdlrm
autoconf-inode-rwsem.c1720644editdlrm
autoconf-inode-uretprobes.c2640644editdlrm
autoconf-kernel_read-new-args.c10300644editdlrm
autoconf-kprobe-symbol-name.c900644editdlrm
autoconf-ktime-get-real.c980644editdlrm
autoconf-linux-sched_headers.c16780644editdlrm
autoconf-local-clock.c12820644editdlrm
autoconf-lockdown-debugfs.c1020644editdlrm
autoconf-lockdown-kernel.c900644editdlrm
autoconf-mm-context-vdso-base.c1170644editdlrm
autoconf-mm-context-vdso.c1140644editdlrm
autoconf-mm-shmempages.c720644editdlrm
autoconf-mmap_lock.c1750644editdlrm
autoconf-module-sect-attrs.c1580644editdlrm
autoconf-module_layout.c520644editdlrm
autoconf-mod_kallsyms.c510644editdlrm
autoconf-nameidata.c960644editdlrm
autoconf-netfilter-4_1.c7690644editdlrm
autoconf-netfilter-4_4.c14600644editdlrm
autoconf-netfilter-313b.c6020644editdlrm
autoconf-netfilter.c4220644editdlrm
autoconf-old-inode-uprobes.c3570644editdlrm
autoconf-oneachcpu-retry.c9570644editdlrm
autoconf-pagefault_disable.c1370644editdlrm
autoconf-pde_data.c2260644editdlrm
autoconf-perf-structpid.c4440644editdlrm
autoconf-procfs-owner.c1580644editdlrm
autoconf-proc_ops.c5660644editdlrm
autoconf-rcu_is_watching.c3850644editdlrm
autoconf-real-parent.c4270644editdlrm
autoconf-regset.c2390644editdlrm
autoconf-relay-umode_t.c7300644editdlrm
autoconf-relay_buf-per_cpu_ptr.c9200644editdlrm
autoconf-ring_buffer-flags.c1120644editdlrm
autoconf-ring_buffer_lost_events.c2960644editdlrm
autoconf-ring_buffer_read_prepare.c1810644editdlrm
autoconf-save-stack-trace-no-bp.c4980644editdlrm
autoconf-save-stack-trace.c5010644editdlrm
autoconf-set_fs.c2210644editdlrm
autoconf-smpcall-4args.c1660644editdlrm
autoconf-smpcall-5args.c1690644editdlrm
autoconf-stack-trace-save-regs.c1760644editdlrm
autoconf-stacktrace_ops-int-address.c4090644editdlrm
autoconf-stacktrace_ops-warning.c1880644editdlrm
autoconf-syscall_get_args_3args.c2390644editdlrm
autoconf-task-state.c5500644editdlrm
autoconf-task-uid.c1520644editdlrm
autoconf-task_work-struct.c2190644editdlrm
autoconf-time32-old.c520644editdlrm
autoconf-time32.c530644editdlrm
autoconf-timerfd.c2320644editdlrm
autoconf-trace-printk.c1510644editdlrm
autoconf-tracepoint-has-data.c4930644editdlrm
autoconf-tracepoint-strings.c2330644editdlrm
autoconf-uaccess.c280644editdlrm
autoconf-uapi-mount.c520644editdlrm
autoconf-udelay_simple.c900644editdlrm
autoconf-uidgid.c500644editdlrm
autoconf-unwind-stack-trace.c3260644editdlrm
autoconf-uprobe-get-pc.c3740644editdlrm
autoconf-utrace-regset.c2730644editdlrm
autoconf-utrace-via-tracepoints.c17120644editdlrm
autoconf-vm-area-pte.c1410644editdlrm
autoconf-walk-stack.c2170644editdlrm
autoconf-x86-fs.c900644editdlrm
autoconf-x86-gs.c900644editdlrm
autoconf-x86-uniregs.c1400644editdlrm
autoconf-x86-xfs.c910644editdlrm
common_session_state.h32490644editdlrm
compat_net.h8580644editdlrm
compat_structs.h44090644editdlrm
compat_unistd.h683840644editdlrm
copy.c27170644editdlrm
debug.h29780644editdlrm
io.c52910644editdlrm
itrace.c148740644editdlrm
kprobes.c251260644editdlrm
loc2c-runtime.h298740644editdlrm
map_list.h12200644editdlrm
map_runtime.h52660644editdlrm
namespaces.h71280644editdlrm
netfilter.c14100644editdlrm
perf.c75960644editdlrm
perf.h12720644editdlrm
perf_event_counter_context.c3360644editdlrm
perf_probe_handler_nmi.c2780644editdlrm
perf_read.h9590644editdlrm
print.c114020644editdlrm
probe_lock.h18070644editdlrm
regs-ia64.c37410644editdlrm
regs.c134900644editdlrm
runtime.h125910644editdlrm
runtime_context.h60890644editdlrm
runtime_defines.h10410644editdlrm
stap_mmap_lock.h3430644editdlrm
stat_runtime.h17740644editdlrm
stp_tls.h11810644editdlrm
stp_tracepoint.c114810644editdlrm
stp_tracepoint.h22700644editdlrm
syscalls-common.h9760644editdlrm
task_finder.c538600644editdlrm
task_finder2.c576400644editdlrm
task_finder_map.c51940644editdlrm
task_finder_stubs.c24420644editdlrm
task_work_compatibility.h12830644editdlrm
timer.c22000644editdlrm
timer.h13830644editdlrm
timer_compatibility.h23170644editdlrm
uprobes-common.c155730644editdlrm
uprobes-common.h16530644editdlrm
uprobes-inc.h4840644editdlrm
uprobes-inode.c340860644editdlrm
Edit: /usr/share/systemtap/runtime/linux/stp_tracepoint.c (11481B)
/* * stp_tracepoint.c * * SystemTap layer for registering various kernel tracepoint APIs. * * Copyright (C) 2014-2019 Red Hat Inc. * * Initially derived from lttng-tracepoints.c: * LTTng adaptation layer for Linux kernel 3.15+ tracepoints. * * Copyright (C) 2014 Mathieu Desnoyers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; only * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include "stp_tracepoint.h" /* * Protect the tracepoint table. stp_tracepoint_mutex nests within * kernel/tracepoint.c tp_modlist_mutex. kernel/tracepoint.c * tracepoint_mutex nests within stp_tracepoint_mutex. */ static DEFINE_MUTEX(stp_tracepoint_mutex); #define TRACEPOINT_HASH_BITS 6 #define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE]; /* * The tracepoint entry is the node contained within the hash table. It * is a mapping from the "string" key to the struct tracepoint pointer. */ struct tracepoint_entry { struct hlist_node hlist; struct tracepoint *tp; int refcount; struct list_head probes; char name[0]; }; struct stp_tp_probe { struct tracepoint_func tp_func; struct list_head list; }; static int add_probe(struct tracepoint_entry *e, void *probe, void *data) { struct stp_tp_probe *p; int found = 0; list_for_each_entry(p, &e->probes, list) { if (p->tp_func.func == probe && p->tp_func.data == data) { found = 1; break; } } if (found) return -EEXIST; p = _stp_kmalloc_gfp(sizeof(struct stp_tp_probe), STP_ALLOC_SLEEP_FLAGS); if (!p) return -ENOMEM; p->tp_func.func = probe; p->tp_func.data = data; list_add(&p->list, &e->probes); return 0; } static int remove_probe(struct tracepoint_entry *e, void *probe, void *data) { struct stp_tp_probe *p; int found = 0; list_for_each_entry(p, &e->probes, list) { if (p->tp_func.func == probe && p->tp_func.data == data) { found = 1; break; } } if (found) { list_del(&p->list); _stp_kfree(p); return 0; } else { return -ENOENT; } } /* * Get tracepoint if the tracepoint is present in the tracepoint hash table. * Must be called with stp_tracepoint_mutex held. * Returns NULL if not present. */ static struct tracepoint_entry *get_tracepoint(const char *name) { struct hlist_head *head; struct tracepoint_entry *e; u32 hash = jhash(name, strlen(name), 0); head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; hlist_for_each_entry(e, head, hlist) { if (!strcmp(name, e->name)) return e; } return NULL; } /* * Add the tracepoint to the tracepoint hash table. Must be called with * stp_tracepoint_mutex held. */ static struct tracepoint_entry *add_tracepoint(const char *name) { struct hlist_head *head; struct tracepoint_entry *e; size_t name_len = strlen(name) + 1; u32 hash = jhash(name, name_len - 1, 0); head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; hlist_for_each_entry(e, head, hlist) { if (!strcmp(name, e->name)) { return ERR_PTR(-EEXIST); /* Already there */ } } /* * Using kmalloc here to allocate a variable length element. Could * cause some memory fragmentation if overused. */ e = _stp_kmalloc_gfp(sizeof(struct tracepoint_entry) + name_len, STP_ALLOC_SLEEP_FLAGS); if (!e) return ERR_PTR(-ENOMEM); memcpy(&e->name[0], name, name_len); e->tp = NULL; e->refcount = 0; INIT_LIST_HEAD(&e->probes); hlist_add_head(&e->hlist, head); return e; } /* * Remove the tracepoint from the tracepoint hash table. Must be called * with stp_tracepoint_mutex held. */ static void remove_tracepoint(struct tracepoint_entry *e) { hlist_del(&e->hlist); _stp_kfree(e); } static void do_tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) { int ret = tracepoint_probe_register(tp, probe, data); if (ret) { dbug_tp(1, "error (%d) registering probe '%s'\n", ret, tp->name); } else { dbug_tp(2, "registered probe '%s'\n", tp->name); } } static void do_tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data) { int ret = tracepoint_probe_unregister(tp, probe, data); if (ret) { dbug_tp(1, "error (%d) unregistering probe '%s'\n", ret, tp->name); } else { dbug_tp(2, "unregistered probe '%s'\n", tp->name); } } int stp_tracepoint_probe_register(const char *name, void *probe, void *data) { struct tracepoint_entry *e; int ret = 0; might_sleep(); mutex_lock(&stp_tracepoint_mutex); e = get_tracepoint(name); if (!e) { e = add_tracepoint(name); if (IS_ERR(e)) { ret = PTR_ERR(e); goto end; } } /* add (probe, data) to entry */ ret = add_probe(e, probe, data); if (ret) { if (!e->refcount) remove_tracepoint(e); goto end; } e->refcount++; dbug_tp(2, "added probe on '%s'\n", name); if (e->tp) { do_tracepoint_probe_register(e->tp, probe, data); } end: mutex_unlock(&stp_tracepoint_mutex); if (ret) { dbug_tp(1, "error (%d) adding probe on '%s'\n", ret, name); } return ret; } int stp_tracepoint_probe_unregister(const char *name, void *probe, void *data) { struct tracepoint_entry *e; int ret = 0; might_sleep(); mutex_lock(&stp_tracepoint_mutex); e = get_tracepoint(name); if (!e) { ret = -ENOENT; goto end; } /* remove (probe, data) from entry */ ret = remove_probe(e, probe, data); if (ret) goto end; if (e->tp) { do_tracepoint_probe_unregister(e->tp, probe, data); } if (!--e->refcount) remove_tracepoint(e); dbug_tp(2, "removed probe on '%s'\n", name); end: mutex_unlock(&stp_tracepoint_mutex); if (ret) { dbug_tp(1, "error (%d) removing probe on '%s'\n", ret, name); } return ret; } #ifdef CONFIG_MODULES static int stp_tracepoint_coming(struct tp_module *tp_mod) { int i; might_sleep(); mutex_lock(&stp_tracepoint_mutex); for (i = 0; i < tp_mod->mod->num_tracepoints; i++) { struct tracepoint *tp; struct tracepoint_entry *e; struct stp_tp_probe *p; #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS tp = offset_to_ptr(&(((const int*)(tp_mod->mod->tracepoints_ptrs))[i])); #else tp = tp_mod->mod->tracepoints_ptrs[i]; #endif e = get_tracepoint(tp->name); if (!e) { e = add_tracepoint(tp->name); if (IS_ERR(e)) { dbug_tp(1, "error (%ld) adding %s:%s\n", PTR_ERR(e), tp_mod->mod->name, tp->name); continue; } } /* If already enabled, just check consistency */ if (e->tp) { if (e->tp != tp) { dbug_tp(1, "found duplicate '%s'\n", tp->name); } continue; } e->tp = tp; e->refcount++; dbug_tp(2, "added %s:%s\n", tp_mod->mod->name, tp->name); /* register each (probe, data) */ list_for_each_entry(p, &e->probes, list) { do_tracepoint_probe_register(e->tp, p->tp_func.func, p->tp_func.data); } } mutex_unlock(&stp_tracepoint_mutex); return NOTIFY_OK; /* may be more appropriate than NOTIFY_DONE=0; https://lkml.org/lkml/2019/6/24/880 */ } static int stp_tracepoint_going(struct tp_module *tp_mod) { int i; might_sleep(); mutex_lock(&stp_tracepoint_mutex); for (i = 0; i < tp_mod->mod->num_tracepoints; i++) { struct tracepoint *tp; struct tracepoint_entry *e; struct stp_tp_probe *p; #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS tp = offset_to_ptr(&(((const int*)(tp_mod->mod->tracepoints_ptrs))[i])); #else tp = tp_mod->mod->tracepoints_ptrs[i]; #endif e = get_tracepoint(tp->name); if (!e || !e->tp) continue; /* unregister each (probe, data) */ list_for_each_entry(p, &e->probes, list) { do_tracepoint_probe_unregister(e->tp, p->tp_func.func, p->tp_func.data); } e->tp = NULL; if (!--e->refcount) remove_tracepoint(e); dbug_tp(2, "removed %s:%s\n", tp_mod->mod->name, tp->name); } mutex_unlock(&stp_tracepoint_mutex); return 0; } static int stp_tracepoint_notify(struct notifier_block *self, unsigned long val, void *data) { struct tp_module *tp_mod = data; int ret = 0; switch (val) { case MODULE_STATE_COMING: ret = stp_tracepoint_coming(tp_mod); break; case MODULE_STATE_GOING: ret = stp_tracepoint_going(tp_mod); break; default: break; } return ret; } static struct notifier_block stp_tracepoint_notifier = { .notifier_call = stp_tracepoint_notify, .priority = 0, }; static int stp_tracepoint_module_init(void) { return register_tracepoint_module_notifier(&stp_tracepoint_notifier); } static void stp_tracepoint_module_exit(void) { (void)unregister_tracepoint_module_notifier(&stp_tracepoint_notifier); } #else /* #ifdef CONFIG_MODULES */ static int stp_tracepoint_module_init(void) { return 0; } static void stp_tracepoint_module_exit(void) { } #endif /* #else #ifdef CONFIG_MODULES */ static void stp_kernel_tracepoint_add(struct tracepoint *tp, void *priv) { struct tracepoint_entry *e; struct stp_tp_probe *p; int *ret = priv; might_sleep(); mutex_lock(&stp_tracepoint_mutex); e = get_tracepoint(tp->name); if (!e) { e = add_tracepoint(tp->name); if (IS_ERR(e)) { dbug_tp(1, "error (%ld) adding kernel:%s\n", PTR_ERR(e), tp->name); *ret = (int) PTR_ERR(e); goto end; } } /* If already enabled, just check consistency */ if (e->tp) { if (e->tp != tp) { dbug_tp(1, "found duplicate '%s'\n", tp->name); } goto end; } e->tp = tp; e->refcount++; dbug_tp(2, "added kernel:%s\n", tp->name); /* register each (probe, data) */ list_for_each_entry(p, &e->probes, list) { do_tracepoint_probe_register(e->tp, p->tp_func.func, p->tp_func.data); } end: mutex_unlock(&stp_tracepoint_mutex); } static void stp_kernel_tracepoint_remove(struct tracepoint *tp, void *priv) { struct tracepoint_entry *e; int *ret = priv; might_sleep(); mutex_lock(&stp_tracepoint_mutex); e = get_tracepoint(tp->name); if (!e || e->refcount != 1 || !list_empty(&e->probes)) { *ret = -EINVAL; goto end; } remove_tracepoint(e); dbug_tp(2, "removed kernel:%s\n", tp->name); end: mutex_unlock(&stp_tracepoint_mutex); } static int stp_tracepoint_init(void) { int error_ret = 0; int ret = 0; for_each_kernel_tracepoint(stp_kernel_tracepoint_add, &ret); if (!ret) ret = stp_tracepoint_module_init(); if (!ret) return 0; for_each_kernel_tracepoint(stp_kernel_tracepoint_remove, &error_ret); return ret; } static void stp_tracepoint_exit(void) { int i, ret = 0; stp_tracepoint_module_exit(); for_each_kernel_tracepoint(stp_kernel_tracepoint_remove, &ret); might_sleep(); mutex_lock(&stp_tracepoint_mutex); for (i = 0; i < TRACEPOINT_TABLE_SIZE; i++) { struct hlist_head *head = &tracepoint_table[i]; /* All tracepoints should be removed */ if (!hlist_empty(head)) { dbug_tp(1, "tracepoint_table[%d] is not empty!\n", i); } } mutex_unlock(&stp_tracepoint_mutex); }