From 9ac44b1d057caacc72e980bd83876b77c42b2959 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 20 Feb 2009 13:11:34 -0600 Subject: Better header file inclusion. 2009-02-20 David Smith * debugfs.c: Added inclusion of linux/debugfs.h. * relayfs.h: Removed inclusion of linux/debugfs.h. --- runtime/transport/debugfs.c | 2 ++ runtime/transport/relayfs.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime') diff --git a/runtime/transport/debugfs.c b/runtime/transport/debugfs.c index dc651a56..85ee604d 100644 --- a/runtime/transport/debugfs.c +++ b/runtime/transport/debugfs.c @@ -9,6 +9,8 @@ * later version. */ +#include + #define STP_DEFAULT_BUFFERS 50 inline static int _stp_ctl_write_fs(int type, void *data, unsigned len) diff --git a/runtime/transport/relayfs.h b/runtime/transport/relayfs.h index c33e9b08..e984b05b 100644 --- a/runtime/transport/relayfs.h +++ b/runtime/transport/relayfs.h @@ -9,7 +9,6 @@ # include #elif defined (CONFIG_RELAY) # include -# include #else # undef STP_RELAYFS #endif -- cgit From 5780cc7f8208ebca519d6e076fe403b1220ab865 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 23 Feb 2009 14:22:38 -0800 Subject: Add selective use of _stp_time_init/kill (PR9822) Our gettimeofday runtime has frequent wakeups to stay in sync with kernel time, but this is wasted effort if gettimeofday is not used in the script. This patch moves the calls to _stp_time_init and _stp_time_kill into begin and end/error probes, which only get pulled in if one of the gettimeofday variants is called. --- runtime/time.c | 8 +++++++- runtime/transport/transport.c | 6 ------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'runtime') diff --git a/runtime/time.c b/runtime/time.c index ad7cef9d..58c23e57 100644 --- a/runtime/time.c +++ b/runtime/time.c @@ -223,6 +223,7 @@ _stp_kill_time(void) #endif _stp_free_percpu(stp_time); + stp_time = NULL; } } @@ -232,6 +233,8 @@ _stp_init_time(void) { int ret = 0; + _stp_kill_time(); + stp_time = _stp_alloc_percpu(sizeof(stp_time_t)); if (unlikely(stp_time == 0)) return -1; @@ -263,7 +266,7 @@ _stp_init_time(void) } } #endif - if (ret) + if (ret) _stp_kill_time(); return ret; } @@ -278,6 +281,9 @@ _stp_gettimeofday_ns(void) stp_time_t *time; int i = 0; + if (!stp_time) + return -1; + preempt_disable(); time = per_cpu_ptr(stp_time, smp_processor_id()); diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 0755781e..7fcebd42 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -188,7 +188,6 @@ static void _stp_transport_close() _stp_unregister_ctl_channel(); if (_stp_utt) utt_trace_remove(_stp_utt); - _stp_kill_time(); /* Go to a beach. Drink a beer. */ _stp_print_cleanup(); /* free print buffers */ _stp_mem_debug_done(); dbug_trans(1, "---- CLOSED ----\n"); @@ -244,10 +243,6 @@ static int _stp_transport_init(void) dbug_trans(1, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size); } - /* initialize timer code */ - if (_stp_init_time()) - return -1; - #if !defined (STP_OLD_TRANSPORT) || defined (STP_BULKMODE) /* open utt (relayfs) channel to send data to userspace */ _stp_utt = _stp_utt_open(); @@ -286,7 +281,6 @@ err1: if (_stp_utt) utt_trace_remove(_stp_utt); err0: - _stp_kill_time(); return -1; } -- cgit From 34309209f7b8f957125f34c263dcea870ea76c8e Mon Sep 17 00:00:00 2001 From: Wenji Huang Date: Tue, 3 Mar 2009 02:58:37 -0500 Subject: PR9875: Remove sduprobes Impact: cleanup Since sdt.h is in git tree, sduprobes is no longer needed. * Makefile.am: Remove sduprobes. * Makefile.in: Regenerated. * doc/Makefile.in: Ditto. * runtime/sduprobes.c: Removed. Signed-off-by: Wenji Huang --- runtime/sduprobes.c | 61 ----------------------------------------------------- 1 file changed, 61 deletions(-) delete mode 100644 runtime/sduprobes.c (limited to 'runtime') diff --git a/runtime/sduprobes.c b/runtime/sduprobes.c deleted file mode 100644 index 83bc8e72..00000000 --- a/runtime/sduprobes.c +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2005-2008 Red Hat Inc. -// Copyright (C) 2006 Intel Corporation. -// -// This file is part of systemtap, and is free software. You can -// redistribute it and/or modify it under the terms of the GNU General -// Public License (GPL); either version 2, or (at your option) any -// later version. - -#include -#define unused __attribute__ ((unused)) - -int -_stap_probe_0 (char* probe unused) -{ - return 1; -} - -int -_stap_probe_1 (char* probe unused, - size_t arg1 unused) -{ - return 1; -} - -int -_stap_probe_2 (char* probe unused , - size_t arg1 unused, - size_t arg2 unused) -{ - return 1; -} - -int -_stap_probe_3 (char* probe unused, - size_t arg1 unused, - size_t arg2 unused, - size_t arg3 unused) -{ - return 1; -} - -int -_stap_probe_4 (char* probe unused, - size_t arg1 unused, - size_t arg2 unused, - size_t arg3 unused, - size_t arg4 unused) -{ - return 1; -} - -int -_stap_probe_5 (char* probe unused, - size_t arg1 unused, - size_t arg2 unused, - size_t arg3 unused, - size_t arg4 unused, - size_t arg5 unused) -{ - return 1; -} -- cgit From 1324cc8267f44de856daa6aedd76d157e4259d28 Mon Sep 17 00:00:00 2001 From: Maynard Johnson Date: Tue, 3 Mar 2009 16:41:48 -0600 Subject: This patch updates the itrace code to support the new utrace interface. It also adds a private copy of access_process_vm to runtime/itrace.c since that function is not consistently exported by all distros. --- runtime/itrace.c | 146 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 117 insertions(+), 29 deletions(-) (limited to 'runtime') diff --git a/runtime/itrace.c b/runtime/itrace.c index df18a400..ed32b0bc 100644 --- a/runtime/itrace.c +++ b/runtime/itrace.c @@ -1,6 +1,6 @@ /* * user space instruction tracing - * Copyright (C) 2005, 2006, 2007, 2008 IBM Corp. + * Copyright (C) 2005, 2006, 2007, 2008, 2009 IBM Corp. * * This file is part of systemtap, and is free software. You can * redistribute it and/or modify it under the terms of the GNU General @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include "uprobes/uprobes.h" #ifndef put_task_struct @@ -65,10 +63,81 @@ static struct itrace_info *create_itrace_info( struct task_struct *tsk, u32 step_flag, struct stap_itrace_probe *itrace_probe); -static u32 usr_itrace_report_signal(struct utrace_attached_engine *engine, +/* + * The kernel's access_process_vm is not exported in kernel.org kernels, although + * some distros export it on some architectures. To workaround this inconsistency, + * we copied and pasted it here. Fortunately, everything it calls is exported. + */ +#include +#include +static int __access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct page *page; + void *old_buf = buf; + + mm = get_task_mm(tsk); + if (!mm) + return 0; + + down_read(&mm->mmap_sem); + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + int bytes, ret, offset; + void *maddr; + + ret = get_user_pages(tsk, mm, addr, 1, + write, 1, &page, &vma); + if (ret <= 0) + break; + + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + maddr = kmap(page); + if (write) { + copy_to_user_page(vma, page, addr, + maddr + offset, buf, bytes); + set_page_dirty_lock(page); + } else { + copy_from_user_page(vma, page, addr, + buf, maddr + offset, bytes); + } + kunmap(page); + page_cache_release(page); + len -= bytes; + buf += bytes; + addr += bytes; + } + up_read(&mm->mmap_sem); + mmput(mm); + + return buf - old_buf; +} + +static u32 usr_itrace_report_quiesce(enum utrace_resume_action action, + struct utrace_attached_engine *engine, + struct task_struct *tsk, + unsigned long event) +{ + int status; + struct itrace_info *ui; + + ui = rcu_dereference(engine->data); + WARN_ON(!ui); + + return (event == 0 ? ui->step_flag : UTRACE_RESUME); +} + + +static u32 usr_itrace_report_signal(u32 action, + struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs, - u32 action, siginfo_t *info, + siginfo_t *info, const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) { @@ -83,12 +152,10 @@ static u32 usr_itrace_report_signal(struct utrace_attached_engine *engine, WARN_ON(!ui); if (info->si_signo != SIGTRAP || !ui) - return UTRACE_ACTION_RESUME; - - /* normal case: continue stepping, hide this trap from other engines */ - return_flags = ui->step_flag | UTRACE_ACTION_HIDE | UTRACE_SIGNAL_IGN | - UTRACE_ACTION_NEWSTATE; + return UTRACE_RESUME; + /* normal case: continue stepping */ + return_flags = ui->step_flag | UTRACE_SIGNAL_IGN; #ifdef CONFIG_PPC if (ui->ppc_atomic_ss.step_over_atomic) { remove_atomic_ss_breakpoint(tsk, &ui->ppc_atomic_ss.end_bpt); @@ -99,8 +166,7 @@ static u32 usr_itrace_report_signal(struct utrace_attached_engine *engine, } if (handle_ppc_atomic_seq(tsk, regs, &ui->ppc_atomic_ss)) - return_flags = UTRACE_ACTION_RESUME | UTRACE_ACTION_NEWSTATE | - UTRACE_SIGNAL_IGN; + return_flags = UTRACE_RESUME | UTRACE_SIGNAL_IGN; #endif enter_itrace_probe(ui->itrace_probe, regs, (void *)&data); @@ -108,24 +174,26 @@ static u32 usr_itrace_report_signal(struct utrace_attached_engine *engine, return return_flags; } -static u32 usr_itrace_report_clone(struct utrace_attached_engine *engine, +static u32 usr_itrace_report_clone(enum utrace_resume_action action, + struct utrace_attached_engine *engine, struct task_struct *parent, unsigned long clone_flags, struct task_struct *child) { - return UTRACE_ACTION_RESUME; + return UTRACE_RESUME; } static u32 usr_itrace_report_death(struct utrace_attached_engine *e, - struct task_struct *tsk) + struct task_struct *tsk, bool group_dead, int signal) { struct itrace_info *ui = rcu_dereference(e->data); WARN_ON(!ui); - return (UTRACE_ACTION_NEWSTATE | UTRACE_ACTION_DETACH); + return (UTRACE_DETACH); } static const struct utrace_engine_ops utrace_ops = { + .report_quiesce = usr_itrace_report_quiesce, .report_signal = usr_itrace_report_signal, .report_clone = usr_itrace_report_clone, .report_death = usr_itrace_report_death @@ -137,6 +205,7 @@ static struct itrace_info *create_itrace_info( struct stap_itrace_probe *itrace_probe) { struct itrace_info *ui; + int status; if (debug) printk(KERN_INFO "create_itrace_info: tid=%d\n", tsk->pid); @@ -154,20 +223,34 @@ static struct itrace_info *create_itrace_info( /* push ui onto usr_itrace_info */ spin_lock(&itrace_lock); list_add(&ui->link, &usr_itrace_info); + spin_unlock(&itrace_lock); /* attach a single stepping engine */ - ui->engine = utrace_attach(ui->tsk, UTRACE_ATTACH_CREATE, &utrace_ops, ui); + ui->engine = utrace_attach_task(ui->tsk, UTRACE_ATTACH_CREATE, &utrace_ops, ui); if (IS_ERR(ui->engine)) { printk(KERN_ERR "utrace_attach returns %ld\n", PTR_ERR(ui->engine)); - ui = NULL; - } else { - utrace_set_flags(tsk, ui->engine, ui->engine->flags | - ui->step_flag | - UTRACE_EVENT(CLONE) | UTRACE_EVENT_SIGNAL_ALL | - UTRACE_EVENT(DEATH)); + return NULL; } - spin_unlock(&itrace_lock); + status = utrace_set_events(tsk, ui->engine, ui->engine->flags | + UTRACE_EVENT(QUIESCE) | + UTRACE_EVENT(CLONE) | UTRACE_EVENT_SIGNAL_ALL | + UTRACE_EVENT(DEATH)); + if (status < 0) { + printk(KERN_ERR "utrace_attach returns %d\n", status); + return NULL; + } + + status = utrace_control(tsk, ui->engine, UTRACE_STOP); + if (status == 0) { + status = utrace_control(tsk, ui->engine, step_flag); + if (status < 0) { + printk(KERN_ERR "utrace_control(%d) returns %d\n", + step_flag, status); + return NULL; + } + } + return ui; } @@ -193,7 +276,7 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe struct task_struct *tsk; rcu_read_lock(); - tsk = find_task_by_pid(tid); + tsk = find_task_by_vpid(tid); if (!tsk) { printk(KERN_ERR "usr_itrace_init: Cannot find process %d\n", tid); rcu_read_unlock(); @@ -203,7 +286,7 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe get_task_struct(tsk); ui = create_itrace_info(tsk, (single_step ? - UTRACE_ACTION_SINGLESTEP : UTRACE_ACTION_BLOCKSTEP), p); + UTRACE_SINGLESTEP : UTRACE_BLOCKSTEP), p); if (!ui) return 1; @@ -223,6 +306,7 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe void static remove_usr_itrace_info(struct itrace_info *ui) { struct itrace_info *tmp; + int status; if (!ui) return; @@ -232,7 +316,11 @@ void static remove_usr_itrace_info(struct itrace_info *ui) spin_lock(&itrace_lock); if (ui->tsk && ui->engine) { - (void) utrace_detach(ui->tsk, ui->engine); + status = utrace_control(ui->tsk, ui->engine, UTRACE_DETACH); + if (status < 0 && status != -ESRCH && status != -EALREADY) + printk(KERN_ERR + "utrace_control(UTRACE_DETACH) returns %d\n", + status); } list_del(&ui->link); spin_unlock(&itrace_lock); @@ -292,7 +380,7 @@ static void insert_atomic_ss_breakpoint (struct task_struct *tsk, cur_instr = get_instr(bpt->addr, "insert_atomic_ss_breakpoint"); if (cur_instr != BPT_TRAP) { bpt->instr = cur_instr; - WARN_ON(access_process_vm(tsk, bpt->addr, &bp_instr, INSTR_SZ, 1) != + WARN_ON(__access_process_vm(tsk, bpt->addr, &bp_instr, INSTR_SZ, 1) != INSTR_SZ); } } @@ -300,7 +388,7 @@ static void insert_atomic_ss_breakpoint (struct task_struct *tsk, static void remove_atomic_ss_breakpoint (struct task_struct *tsk, struct bpt_info *bpt) { - WARN_ON(access_process_vm(tsk, bpt->addr, &bpt->instr, INSTR_SZ, 1) != + WARN_ON(__access_process_vm(tsk, bpt->addr, &bpt->instr, INSTR_SZ, 1) != INSTR_SZ); } -- cgit From 8c5905d0b6c8206c5ed971a637077aa8ef5c1b02 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Wed, 4 Mar 2009 11:56:45 +0100 Subject: stap autoconf test for kernel stack trace support * buildrun.cxx (compile_pass): Add autoconf line for stack trace test, which defines STAPCONF_KERNEL_STACKTRACE. * runtime/autoconf-save-stack-trace.c: New file. * runtime/stack.c : Use STAPCONF_KERNEL_STACKTRACE instead of tests for kernel configuration and versions. * runtime/stack-i386.c : ditto * runtime/stack-x86_64.c : ditto --- runtime/autoconf-save-stack-trace.c | 22 ++++++++++++++++++++++ runtime/stack-i386.c | 2 +- runtime/stack-x86_64.c | 2 +- runtime/stack.c | 7 +++---- 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 runtime/autoconf-save-stack-trace.c (limited to 'runtime') diff --git a/runtime/autoconf-save-stack-trace.c b/runtime/autoconf-save-stack-trace.c new file mode 100644 index 00000000..39ded684 --- /dev/null +++ b/runtime/autoconf-save-stack-trace.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +void foo(struct task_struct *foo) +{ + struct stack_trace trace; + unsigned long backtrace[20]; + memset(&trace, 0, sizeof(trace)); + trace.entries = &backtrace[0]; + trace.max_entries = 20; + trace.skip = 0; + save_stack_trace_tsk(tsk, &trace); +} + +static const struct stacktrace_ops print_stack_ops; + +void dumper(struct task_struct *foo) +{ + dump_trace(foo, 0, 0, 0, &print_stack_ops, 0); +} diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index 206801d8..5a18c9d8 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -14,7 +14,7 @@ static int _stp_valid_stack_ptr(unsigned long context, unsigned long p) } /* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */ -#if ! (defined(CONFIG_STACKTRACE) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)) +#if !defined(STAPCONF_KERNEL_STACKTRACE) static void _stp_stack_print_fallback(unsigned long stack, int verbose, int levels) { unsigned long addr; diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index 183de0a0..03d88ef0 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -10,7 +10,7 @@ /* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */ -#if ! (defined(CONFIG_STACKTRACE) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)) +#if !defined(STAPCONF_KERNEL_STACKTRACE) static void _stp_stack_print_fallback(unsigned long stack, int verbose, int levels) { unsigned long addr; diff --git a/runtime/stack.c b/runtime/stack.c index aa0e6d65..f6b1cd08 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -27,8 +27,7 @@ #define MAXBACKTRACE 20 -#if defined(CONFIG_STACKTRACE) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) -// XXX: PR9866: hacky temporarily restriction to recent kernels +#if defined(STAPCONF_KERNEL_STACKTRACE) #include #include #endif @@ -51,7 +50,7 @@ static void _stp_stack_print_fallback(unsigned long, int, int); #error "Unsupported architecture" #endif -#if defined(CONFIG_STACKTRACE) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) +#if defined(STAPCONF_KERNEL_STACKTRACE) struct print_stack_data { @@ -161,7 +160,7 @@ static void _stp_ustack_print(char *str) void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels) { -#if defined(CONFIG_STACKTRACE) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) +#if defined(STAPCONF_KERNEL_STACKTRACE) int i; unsigned long backtrace[MAXBACKTRACE]; struct stack_trace trace; -- cgit From b1f85b93f4cdc5eaad45891399c30341d4d6ce93 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sun, 8 Mar 2009 22:28:03 -0400 Subject: Adapt to linux-next commit changing __alloc_percpu API. After linux-next commit f2a8205c, it takes two parameters again, so we autoconf for it rather than use KERNEL_VERSION ifdefs. --- runtime/alloc.c | 25 +++---------------------- runtime/autoconf-alloc-percpu-align.c | 6 ++++++ 2 files changed, 9 insertions(+), 22 deletions(-) create mode 100644 runtime/autoconf-alloc-percpu-align.c (limited to 'runtime') diff --git a/runtime/alloc.c b/runtime/alloc.c index 89d16612..439e8a7e 100644 --- a/runtime/alloc.c +++ b/runtime/alloc.c @@ -233,30 +233,14 @@ static void *_stp_vmalloc(unsigned long size) } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) static void *_stp_alloc_percpu(size_t size) { -#ifdef DEBUG_MEM +#ifdef STAPCONF_ALLOC_PERCPU_ALIGN void *ret = __alloc_percpu(size, 8); - if (likely(ret)) { - struct _stp_mem_entry *m = kmalloc(sizeof(struct _stp_mem_entry), STP_ALLOC_FLAGS); - if (unlikely(m == NULL)) { - free_percpu(ret); - return NULL; - } - _stp_mem_debug_percpu(m, ret, size); - _stp_allocated_memory += size * num_online_cpus(); - } - return ret; #else - return __alloc_percpu(size, 8); + void *ret = __alloc_percpu(size); #endif -} -#else -static void *_stp_alloc_percpu(size_t size) -{ #ifdef DEBUG_MEM - void *ret = __alloc_percpu(size); if (likely(ret)) { struct _stp_mem_entry *m = kmalloc(sizeof(struct _stp_mem_entry), STP_ALLOC_FLAGS); if (unlikely(m == NULL)) { @@ -266,12 +250,9 @@ static void *_stp_alloc_percpu(size_t size) _stp_mem_debug_percpu(m, ret, size); _stp_allocated_memory += size * num_online_cpus(); } - return ret; -#else - return __alloc_percpu(size); #endif + return ret; } -#endif /* LINUX_VERSION_CODE */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) #define _stp_kmalloc_node(size,node) _stp_kmalloc(size) diff --git a/runtime/autoconf-alloc-percpu-align.c b/runtime/autoconf-alloc-percpu-align.c new file mode 100644 index 00000000..158d579c --- /dev/null +++ b/runtime/autoconf-alloc-percpu-align.c @@ -0,0 +1,6 @@ +#include + +/* kernel commit f2a8205c */ +void foo (void) { + (void) __alloc_percpu(sizeof(int), 8); +} -- cgit From 52aeb26b8d83c26e00adaf70bbf5a3a828689fb2 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 12 Mar 2009 17:12:38 -0700 Subject: PR9947: move runtime cleanup out of the work queue The kernel lockdep checking found a possible deadlock if a forced rmmod tried to destroy _stp_work_queue at the same time that the work queue was unregistering tracepoints. An unlikely scenario, but still possible. Now the work queue will just issue a STP_REQUEST_EXIT down to usermode, and usermode will echo back an STP_EXIT that triggers the actual probe cleanup. This way the unregistrations are happening in exactly the same context as the registrations were. --- runtime/staprun/mainloop.c | 8 ++++++++ runtime/transport/control.c | 7 ++++++- runtime/transport/transport.c | 20 ++++++++++++++++---- runtime/transport/transport_msgs.h | 8 +++++--- 4 files changed, 35 insertions(+), 8 deletions(-) (limited to 'runtime') diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index 29eb4f1f..db6ef6b7 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -477,6 +477,14 @@ int stp_main_loop(void) cleanup_and_exit(0); break; } + case STP_REQUEST_EXIT: + { + /* module asks us to start exiting, so send STP_EXIT */ + dbug(2, "got STP_REQUEST_EXIT\n"); + int32_t rc, btype = STP_EXIT; + rc = write(control_channel, &btype, sizeof(btype)); + break; + } case STP_START: { struct _stp_msg_start *t = (struct _stp_msg_start *)data; diff --git a/runtime/transport/control.c b/runtime/transport/control.c index edde244d..680d7306 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -13,6 +13,8 @@ static _stp_mempool_t *_stp_pool_q; static struct list_head _stp_ctl_ready_q; static DEFINE_SPINLOCK(_stp_ctl_ready_lock); +static void _stp_cleanup_and_exit(int send_exit); + static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { u32 type; @@ -46,7 +48,7 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz } break; case STP_EXIT: - _stp_exit_flag = 1; + _stp_cleanup_and_exit(1); break; case STP_BULK: #ifdef STP_BULKMODE @@ -93,6 +95,9 @@ static void _stp_ctl_write_dbug(int type, void *data, int len) case STP_TRANSPORT: _dbug("sending STP_TRANSPORT\n"); break; + case STP_REQUEST_EXIT: + _dbug("sending STP_REQUEST_EXIT\n"); + break; default: _dbug("ERROR: unknown message type: %d\n", type); break; diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 7fcebd42..762c0a92 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -25,7 +25,6 @@ static struct utt_trace *_stp_utt = NULL; static unsigned int utt_seq = 1; static int _stp_probes_started = 0; static pid_t _stp_target = 0; -static int _stp_exit_called = 0; static int _stp_exit_flag = 0; #include "control.h" #ifdef STP_OLD_TRANSPORT @@ -89,13 +88,14 @@ static void _stp_handle_start(struct _stp_msg_start *st) /* when someone does /sbin/rmmod on a loaded systemtap module. */ static void _stp_cleanup_and_exit(int send_exit) { - if (!_stp_exit_called) { + static int called = 0; + if (!called) { int failures; dbug_trans(1, "cleanup_and_exit (%d)\n", send_exit); _stp_exit_flag = 1; /* we only want to do this stuff once */ - _stp_exit_called = 1; + called = 1; if (_stp_probes_started) { dbug_trans(1, "calling probe_exit\n"); @@ -119,6 +119,18 @@ static void _stp_cleanup_and_exit(int send_exit) } } +static void _stp_request_exit(void) +{ + static int called = 0; + if (!called) { + /* we only want to do this once */ + called = 1; + dbug_trans(1, "ctl_send STP_REQUEST_EXIT\n"); + _stp_ctl_send(STP_REQUEST_EXIT, NULL, 0); + dbug_trans(1, "done with ctl_send STP_REQUEST_EXIT\n"); + } +} + /* * Called when stapio closes the control channel. */ @@ -169,7 +181,7 @@ static void _stp_work_queue(void *data) /* if exit flag is set AND we have finished with probe_start() */ if (unlikely(_stp_exit_flag && _stp_probes_started)) - _stp_cleanup_and_exit(1); + _stp_request_exit(); if (likely(_stp_attached)) queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); } diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index 596f4925..0d9a5983 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -21,19 +21,20 @@ struct _stp_trace { enum { STP_START, - STP_EXIT, + STP_EXIT, STP_OOB_DATA, STP_SYSTEM, STP_TRANSPORT, STP_CONNECT, - STP_DISCONNECT, + STP_DISCONNECT, STP_BULK, STP_READY, - STP_RELOCATION, + STP_RELOCATION, /** deprecated STP_OLD_TRANSPORT **/ STP_BUF_INFO, STP_SUBBUFS_CONSUMED, STP_REALTIME_DATA, + STP_REQUEST_EXIT, STP_MAX_CMD }; @@ -52,6 +53,7 @@ static const char *_stp_command_name[] = { "STP_BUF_INFO", "STP_SUBBUFS_CONSUMED", "STP_REALTIME_DATA", + "STP_REQUEST_EXIT", }; #endif /* DEBUG_TRANS */ -- cgit From 436b47f678c2fc5397ed66a1eddf6b419cc6585b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 13 Mar 2009 16:22:04 -0700 Subject: Move lookup_bad_addr call in STAPCONF_PROBE_KERNEL With most of the implementations, kread/kwrite call deref/store_deref, and so it makes sense to have lookup_bad_addr in the latter as an underlying address check. However, in the STAPCONF_PROBE_KERNEL case that uses probe_kernel_read and probe_kernel_write, the roles are reversed, so lookup_bad_addr needs to be in kread/kwrite. Also note that __deref_bad and __store_deref_bad should only be used in cases that can be determined at compile time. These turn into invalid symbols which prevent the module from loading. (They might be better replaced with compile-time assertions.) --- runtime/loc2c-runtime.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'runtime') diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 0af19edc..92c017d3 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -187,22 +187,22 @@ #define kread(ptr) ({ \ typeof(*(ptr)) _v; \ - if (probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ - DEREF_FAULT(ptr); \ + if (lookup_bad_addr((unsigned long)(ptr)) || \ + probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ + DEREF_FAULT(ptr); \ _v; \ }) #define kwrite(ptr, value) ({ \ typeof(*(ptr)) _v; \ _v = (typeof(*(ptr)))(value); \ - if (probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \ - STORE_DEREF_FAULT(ptr); \ + if (lookup_bad_addr((unsigned long)addr) || \ + probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \ + STORE_DEREF_FAULT(ptr); \ }) #define deref(size, addr) ({ \ intptr_t _i; \ - if (lookup_bad_addr((unsigned long)addr)) \ - __deref_bad(); \ switch (size) { \ case 1: _i = kread((u8 *)(addr)); break; \ case 2: _i = kread((u16 *)(addr)); break; \ @@ -215,8 +215,6 @@ }) #define store_deref(size, addr, value) ({ \ - if (lookup_bad_addr((unsigned long)addr)) \ - __store_deref_bad(); \ switch (size) { \ case 1: kwrite((u8 *)(addr), (value)); break; \ case 2: kwrite((u16 *)(addr), (value)); break; \ -- cgit From bb64f40b58a64a9ae065dba5058463ac604c3896 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Sun, 15 Mar 2009 15:29:01 +0100 Subject: Move vma module tracking from pr6866 branch to master. * tapsets.cxx (utrace_derived_probe_group::emit_module_decls): Always emit vm callback probe for __stp_tf_vm_cb. * runtime/task_finder.c (__stp_tf_vm_cb): Always expose, move _stp_dbug statements under ifdef DEBUG_TASK_FINDER_VMA. Find and record corresponding module when vm_path not NULL. * runtime/task_finder_vma.c (struct __stp_tf_vma_entry): Add _stp_module. (stap_add_vma_map_info): Add _stp_module argument and assign. (__stp_tf_get_vma_entry_addr): New static function to get the __stp_tf_vma_entry given an address. --- runtime/task_finder.c | 22 ++++++++++++++++------ runtime/task_finder_vma.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 7 deletions(-) (limited to 'runtime') diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 9db713c3..ae381a41 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -55,7 +55,6 @@ typedef int (*stap_task_finder_vm_callback)(struct stap_task_finder_target *tgt, unsigned long vm_end, unsigned long vm_pgoff); -#ifdef DEBUG_TASK_FINDER_VMA static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int map_p, char *vm_path, @@ -63,21 +62,32 @@ static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt, unsigned long vm_end, unsigned long vm_pgoff) { + int i; +#ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, "vm_cb: tsk %d:%d path %s, start 0x%08lx, end 0x%08lx, offset 0x%lx\n", tsk->pid, map_p, vm_path, vm_start, vm_end, vm_pgoff); +#endif if (map_p) { - // FIXME: What should we do with vm_path? We can't save - // the vm_path pointer itself, but we don't have any - // storage space allocated to save it in... - stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff); + struct _stp_module *module = NULL; + if (vm_path != NULL) + for (i = 0; i < _stp_num_modules; i++) + if (strcmp(vm_path, _stp_modules[i]->name) == 0) + { +#ifdef DEBUG_TASK_FINDER_VMA + _stp_dbug(__FUNCTION__, __LINE__, + "vm_cb: matched path %s to module\n", vm_path); +#endif + module = _stp_modules[i]; + break; + } + stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff, module); } else { stap_remove_vma_map_info(tsk, vm_start, vm_end, vm_pgoff); } return 0; } -#endif struct stap_task_finder_target { /* private: */ diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c index 4dce4be8..87a32fe5 100644 --- a/runtime/task_finder_vma.c +++ b/runtime/task_finder_vma.c @@ -25,6 +25,9 @@ struct __stp_tf_vma_entry { unsigned long vm_end; unsigned long vm_pgoff; // Is that enough? Should we store a dcookie for vm_file? + + // Module that this vma entry is mapped from, if any. + struct _stp_module *module; }; static struct __stp_tf_vma_entry @@ -211,7 +214,8 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk, // Add the vma info to the vma map hash table. static int stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start, - unsigned long vm_end, unsigned long vm_pgoff) + unsigned long vm_end, unsigned long vm_pgoff, + struct _stp_module *module) { struct hlist_head *head; struct hlist_node *node; @@ -242,6 +246,7 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start, entry->vm_start = vm_start; entry->vm_end = vm_end; entry->vm_pgoff = vm_pgoff; + entry->module = module; head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)]; hlist_add_head(&entry->hlist, head); @@ -305,3 +310,26 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr, mutex_unlock(&__stp_tf_vma_mutex); return rc; } + +// Get vma_entry of the address (vm_start/vm_end) if the vma is +// present in the vma hash table containing. +// Returns NULL if not present. +static struct __stp_tf_vma_entry * +__stp_tf_get_vma_entry_addr(struct task_struct *tsk, unsigned long addr) +{ + struct hlist_head *head; + struct hlist_node *node; + struct __stp_tf_vma_entry *entry; + + mutex_lock(&__stp_tf_vma_mutex); + head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)]; + hlist_for_each_entry(entry, node, head, hlist) { + if (tsk->pid == entry->pid + && addr >= entry->vm_start && addr < entry->vm_end) { + mutex_unlock(&__stp_tf_vma_mutex); + return entry; + } + } + mutex_unlock(&__stp_tf_vma_mutex); + return NULL; +} -- cgit From 924a2ea21d0276229a752e58e5c5c1a9346648be Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 16 Mar 2009 18:36:44 -0700 Subject: PR9951: Prevent GCC warnings in deref() In some configurations, GCC was warning about a possible use of _v in the deref macros. I could not reproduce the error, but the only case where _v is not written is if lookup_bad_addr rejects the address, in which case we will hit DEREF_FAULT and _v won't be used. Now we're priming _v=0 anyway, so GCC has no right to complain... --- runtime/loc2c-runtime.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'runtime') diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 92c017d3..16ddb950 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -186,7 +186,7 @@ */ #define kread(ptr) ({ \ - typeof(*(ptr)) _v; \ + typeof(*(ptr)) _v = 0; \ if (lookup_bad_addr((unsigned long)(ptr)) || \ probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \ DEREF_FAULT(ptr); \ @@ -202,14 +202,13 @@ }) #define deref(size, addr) ({ \ - intptr_t _i; \ + intptr_t _i = 0; \ switch (size) { \ case 1: _i = kread((u8 *)(addr)); break; \ case 2: _i = kread((u16 *)(addr)); break; \ case 4: _i = kread((u32 *)(addr)); break; \ case 8: _i = kread((u64 *)(addr)); break; \ default: __deref_bad(); \ - /* uninitialized _i should also be caught by -Werror */ \ } \ _i; \ }) @@ -235,7 +234,7 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ u8 _b; u16 _w; u32 _l; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ @@ -275,7 +274,7 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ u8 _b; u16 _w; u32 _l; u64 _q; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ @@ -392,7 +391,7 @@ extern void __store_deref_bad(void); #define deref(size, addr) \ ({ \ int _bad = 0; \ - intptr_t _v; \ + intptr_t _v = 0; \ if (lookup_bad_addr((unsigned long)addr)) \ _bad = 1; \ else \ -- cgit From 30cb532a560ed152b86506b80490e99195970271 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Tue, 17 Mar 2009 13:50:33 +0100 Subject: Get the canonical path of the main file for comparison at runtime. When given directly by the user through -d or in case of the kernel name and path might differ. path should be used for matching. * runtime/sym.h (_stp_module): Add path field. * runtime/task_finder.c (__stp_tf_vm_cb): Use module path to compare vm_path. * translate.cxx (dump_unwindsyms): Output canonical path. --- runtime/sym.h | 1 + runtime/task_finder.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime') diff --git a/runtime/sym.h b/runtime/sym.h index e642cab4..586b10ca 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -25,6 +25,7 @@ struct _stp_section { struct _stp_module { const char* name; + const char* path; /* canonical path used for runtime matching. */ struct _stp_section *sections; unsigned num_sections; diff --git a/runtime/task_finder.c b/runtime/task_finder.c index ae381a41..38f9145d 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -72,7 +72,7 @@ static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt, struct _stp_module *module = NULL; if (vm_path != NULL) for (i = 0; i < _stp_num_modules; i++) - if (strcmp(vm_path, _stp_modules[i]->name) == 0) + if (strcmp(vm_path, _stp_modules[i]->path) == 0) { #ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, -- cgit