diff options
author | Frank Ch. Eigler <fche@elastic.org> | 2008-01-17 21:52:42 -0500 |
---|---|---|
committer | Frank Ch. Eigler <fche@elastic.org> | 2008-01-17 21:52:42 -0500 |
commit | 7ee3e80ec0b7880c33d0ca3018025855d9dd5123 (patch) | |
tree | c39e234447fed3ca04c6467784fae5ddc85ce7d6 | |
parent | 2b7f11a05877405a3dd232ac297e11f9d8253c2d (diff) | |
parent | af3047833424103c4e17728e849670da865d37c3 (diff) | |
download | systemtap-steved-7ee3e80ec0b7880c33d0ca3018025855d9dd5123.tar.gz systemtap-steved-7ee3e80ec0b7880c33d0ca3018025855d9dd5123.tar.xz systemtap-steved-7ee3e80ec0b7880c33d0ca3018025855d9dd5123.zip |
Merge branch 'master' of git://sources.redhat.com/git/systemtap
37 files changed, 1251 insertions, 404 deletions
@@ -1,3 +1,33 @@ +2008-01-17 David Smith <dsmith@redhat.com> + + * tapsets.cxx + (procfs_var_expanding_copy_visitor::visit_target_symbol): Print an + error when trying to use the procfs target variable '$value' as an + array or structure. + (perfmon_var_expanding_copy_visitor::visit_target_symbol): Print an + error when trying to use the perfmon target variable '$counter as + an array or structure. + +2008-01-16 David Smith <dsmith@redhat.com> + + PR 5608. + * tapsets.cxx + (mark_var_expanding_copy_visitor::visit_target_symbol): Print an + error when trying to use a marker argument as an array or + structure. + +2008-01-16 Eugene Teo <eteo@redhat.com> + + * stapfuncs.5.in: Document signal.stp tapset functions. + +2008-01-14 Martin Hunt <hunt@redhat.com> + * translate.cxx (emit_module_init): Call _stp_print_kernel_info() + to print out version information and internal memory usage stats. + +2008-01-14 Martin Hunt <hunt@redhat.com> + * translate.cxx (emit_module_exit): When using timing, delete timing + stats when finished. + 2008-01-12 Frank Ch. Eigler <fche@elastic.org> * configure.ac: Generate a build tree SNAPSHOT file from git-rev-list, diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 8fa11695..7536cc88 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,13 @@ +2008-01-14 Martin Hunt <hunt@redhat.com> + + * print.c (_stp_print_kernel_info): New function. + (all): Call stp memory functions. + + * alloc.c: Rewrite to track allocated memory if + DEBUG_MEM is defined. + * counter.c, map.c, stat.c, time.c: Call stp + memory functions. + 2007-11-14 Zhaolei <zhaolei@cn.fujitsu.com> From Cai Fei <caifei@cn.fujitsu.com> diff --git a/runtime/alloc.c b/runtime/alloc.c index 8f2a7451..f022755a 100644 --- a/runtime/alloc.c +++ b/runtime/alloc.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * Memory allocation functions - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * * 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 @@ -11,55 +11,356 @@ #ifndef _ALLOC_C_ #define _ALLOC_C_ -/* counters of how much memory has been allocated */ -static int _stp_allocated_memory = 0; static int _stp_allocated_net_memory = 0; - #define STP_ALLOC_FLAGS (GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN) +//#define DEBUG_MEM +/* + * If DEBUG_MEM is defined (stap -DDEBUG_MEM ...) then full memory + * tracking is used. Each allocation is recorded and matched with + * a free. Also a fence is set around the allocated memory so overflows + * and underflows can be detected. Errors are written to the system log + * with printk. + * + * NOTE: if youy system is slow or your script makes a very large number + * of allocations, you may get a warning in the system log: + * BUG: soft lockup - CPU#1 stuck for 11s! [staprun:28269] + * This is an expected side-effect of the overhead of tracking, especially + * with a simple linked list of allocations. Optimization + * would be nice, but DEBUG_MEM is only for testing. + */ + +#ifdef DEBUG_MEM + +static spinlock_t _stp_mem_lock = SPIN_LOCK_UNLOCKED; +static int _stp_allocated_memory = 0; + +#define MEM_MAGIC 0xc11cf77f +#define MEM_FENCE_SIZE 32 + +enum _stp_memtype { MEM_KMALLOC, MEM_VMALLOC, MEM_PERCPU }; + +typedef struct { + enum _stp_memtype type; + char *alloc; + char *free; +} _stp_malloc_type; + +static const _stp_malloc_type const _stp_malloc_types[] = { + {MEM_KMALLOC, "kmalloc", "kfree"}, + {MEM_VMALLOC, "vmalloc", "vfree"}, + {MEM_PERCPU, "alloc_percpu", "free_percpu"} +}; + +struct _stp_mem_entry { + struct list_head list; + int32_t magic; + enum _stp_memtype type; + size_t len; + void *addr; +}; + +#define MEM_DEBUG_SIZE (2*MEM_FENCE_SIZE+sizeof(struct _stp_mem_entry)) + +static LIST_HEAD(_stp_mem_list); + +void _stp_check_mem_fence (char *addr, int size) +{ + char *ptr; + int i; + + ptr = addr - MEM_FENCE_SIZE; + while (ptr < addr) { + if (*ptr != 0x55) { + printk("SYSTEMTAP ERROR: Memory fence corrupted before allocated memory\n"); + printk("at addr %p. (Allocation starts at %p)", ptr, addr); + return; + } + ptr++; + } + ptr = addr + size; + while (ptr < addr + size + MEM_FENCE_SIZE) { + if (*ptr != 0x55) { + printk("SYSTEMTAP ERROR: Memory fence corrupted after allocated memory\n"); + printk("at addr %p. (Allocation ends at %p)", ptr, addr + size - 1); + return; + } + ptr++; + } +} + +void *_stp_mem_debug_setup(void *addr, size_t size, enum _stp_memtype type) +{ + struct list_head *p; + struct _stp_mem_entry *m; + memset(addr, 0x55, MEM_FENCE_SIZE); + addr += MEM_FENCE_SIZE; + memset(addr + size, 0x55, MEM_FENCE_SIZE); + p = (struct list_head *)(addr + size + MEM_FENCE_SIZE); + m = (struct _stp_mem_entry *)p; + m->magic = MEM_MAGIC; + m->type = type; + m->len = size; + m->addr = addr; + spin_lock(&_stp_mem_lock); + list_add(p, &_stp_mem_list); + spin_unlock(&_stp_mem_lock); + return addr; +} + +/* Percpu allocations don't have the fence. Implementing it is problematic. */ +void _stp_mem_debug_percpu(struct _stp_mem_entry *m, void *addr, size_t size) +{ + struct list_head *p = (struct list_head *)m; + m->magic = MEM_MAGIC; + m->type = MEM_PERCPU; + m->len = size; + m->addr = addr; + spin_lock(&_stp_mem_lock); + list_add(p, &_stp_mem_list); + spin_unlock(&_stp_mem_lock); +} + +void _stp_mem_debug_free(void *addr, enum _stp_memtype type) +{ + int found = 0; + struct list_head *p, *tmp; + struct _stp_mem_entry *m = NULL; + + spin_lock(&_stp_mem_lock); + list_for_each_safe(p, tmp, &_stp_mem_list) { + m = list_entry(p, struct _stp_mem_entry, list); + if (m->addr == addr) { + list_del(p); + found = 1; + break; + } + } + spin_unlock(&_stp_mem_lock); + if (!found) { + printk("SYSTEMTAP ERROR: Free of unallocated memory %p type=%s\n", + addr, _stp_malloc_types[type].free); + return; + } + if (m->magic != MEM_MAGIC) { + printk("SYSTEMTAP ERROR: Memory at %p corrupted!!\n", addr); + return; + } + if (m->type != type) { + printk("SYSTEMTAP ERROR: Memory allocated with %s and freed with %s\n", + _stp_malloc_types[m->type].alloc, + _stp_malloc_types[type].free); + } + + switch (m->type) { + case MEM_KMALLOC: + _stp_check_mem_fence(addr, m->len); + kfree(addr - MEM_FENCE_SIZE); + break; + case MEM_PERCPU: + free_percpu(addr); + kfree(p); + break; + case MEM_VMALLOC: + _stp_check_mem_fence(addr, m->len); + vfree(addr - MEM_FENCE_SIZE); + break; + default: + printk("SYSTEMTAP ERROR: Attempted to free memory at addr %p len=%d with unknown allocation type.\n", addr, (int)m->len); + } + + return; +} +#endif + static void *_stp_kmalloc(size_t size) { - void *ret = kmalloc(size, STP_ALLOC_FLAGS); - if (ret) +#ifdef DEBUG_MEM + void *ret = kmalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS); + if (likely(ret)) { + ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); _stp_allocated_memory += size; + } return ret; +#else + return kmalloc(size, STP_ALLOC_FLAGS); +#endif } static void *_stp_kzalloc(size_t size) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) { - void *ret = kmalloc(size, STP_ALLOC_FLAGS); - if (ret) { +#ifdef DEBUG_MEM + void *ret = kmalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS); + if (likely(ret)) { + ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); memset (ret, 0, size); _stp_allocated_memory += size; } +#else + void *ret = kmalloc(size, STP_ALLOC_FLAGS); + if (likely(ret)) + memset (ret, 0, size); +#endif /* DEBUG_MEM */ return ret; } -#else +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) */ { - void *ret = kzalloc(size, STP_ALLOC_FLAGS); - if (ret) +#ifdef DEBUG_MEM + void *ret = kzalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS); + if (likely(ret)) { + ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); _stp_allocated_memory += size; + } return ret; -} +#else + return kzalloc(size, STP_ALLOC_FLAGS); #endif +} +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) */ static void *_stp_vmalloc(unsigned long size) { - void *ret = __vmalloc(size, STP_ALLOC_FLAGS, PAGE_KERNEL); - if (ret) +#ifdef DEBUG_MEM + void *ret = __vmalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS, PAGE_KERNEL); + if (likely(ret)) { + ret = _stp_mem_debug_setup(ret, size, MEM_VMALLOC); _stp_allocated_memory += size; + } return ret; +#else + return __vmalloc(size, STP_ALLOC_FLAGS, PAGE_KERNEL); +#endif + } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) -#define _stp_alloc_percpu(size) __alloc_percpu(size, 8) +static void *_stp_alloc_percpu(size_t size) +{ +#ifdef DEBUG_MEM + 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 -#define _stp_alloc_percpu(size) __alloc_percpu(size) + return __alloc_percpu(size, 8); #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)) { + 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); +#endif +} +#endif /* LINUX_VERSION_CODE */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) -#define kmalloc_node(size,flags,node) kmalloc(size,flags) +#define _stp_kmalloc_node(size,node) _stp_kmalloc(size) +#else +static void *_stp_kmalloc_node(size_t size, int node) +{ +#ifdef DEBUG_MEM + void *ret = kmalloc_node(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS, node); + if (likely(ret)) { + ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); + _stp_allocated_memory += size; + } + return ret; +#else + return kmalloc_node(size, STP_ALLOC_FLAGS, node); +#endif +} #endif /* LINUX_VERSION_CODE */ +void _stp_kfree(void *addr) +{ +#ifdef DEBUG_MEM + _stp_mem_debug_free(addr, MEM_KMALLOC); +#else + kfree(addr); +#endif +} + +void _stp_vfree(void *addr) +{ +#ifdef DEBUG_MEM + _stp_mem_debug_free(addr, MEM_VMALLOC); +#else + vfree(addr); +#endif +} + +void _stp_free_percpu(void *addr) +{ +#ifdef DEBUG_MEM + _stp_mem_debug_free(addr, MEM_PERCPU); +#else + free_percpu(addr); +#endif +} + +void _stp_mem_debug_done(void) +{ +#ifdef DEBUG_MEM + struct list_head *p, *tmp; + struct _stp_mem_entry *m; + + spin_lock(&_stp_mem_lock); + list_for_each_safe(p, tmp, &_stp_mem_list) { + m = list_entry(p, struct _stp_mem_entry, list); + list_del(p); + + printk("SYSTEMTAP ERROR: Memory %p len=%d allocation type: %s. Not freed.\n", + m->addr, (int)m->len, _stp_malloc_types[m->type].alloc); + + if (m->magic != MEM_MAGIC) { + printk("SYSTEMTAP ERROR: Memory at %p len=%d corrupted!!\n", m->addr, (int)m->len); + /* Don't free. Too dangerous */ + goto done; + } + + switch (m->type) { + case MEM_KMALLOC: + _stp_check_mem_fence(m->addr, m->len); + kfree(m->addr - MEM_FENCE_SIZE); + break; + case MEM_PERCPU: + free_percpu(m->addr); + kfree(p); + break; + case MEM_VMALLOC: + _stp_check_mem_fence(m->addr, m->len); + vfree(m->addr - MEM_FENCE_SIZE); + break; + default: + printk("SYSTEMTAP ERROR: Attempted to free memory at addr %p len=%d with unknown allocation type.\n", m->addr, (int)m->len); + } + } +done: + spin_unlock(&_stp_mem_lock); + + return; + +#endif +} #endif /* _ALLOC_C_ */ diff --git a/runtime/bench2/bench.rb b/runtime/bench2/bench.rb index a671b582..b3e30204 100644 --- a/runtime/bench2/bench.rb +++ b/runtime/bench2/bench.rb @@ -138,9 +138,8 @@ class Bench end def load - args = "-q" - fork do exec "sudo #{@@staprun} #{args} -o #{@outfile} #{@dir}/bench.ko &> #{@dir}/xxx.out" end - sleep 10 + fork do exec "sudo #{@@staprun} -o #{@outfile} #{@dir}/bench.ko &> #{@dir}/xxx.out" end + sleep 5 end def compile @@ -287,10 +286,8 @@ class Stapbench < Bench protected def load - args = "-vv -DSTP_NO_OVERLOAD" - if @trans == BULK then args = "-bvv -DSTP_NO_OVERLOAD" end - fork do exec "stap #{args} -o #{@outfile} bench.stp &> xxx.out" end - sleep 30 + fork do exec "sudo #{@@staprun} bench.ko &> xxx.out" end + sleep 5 end def compile @@ -316,6 +313,14 @@ class Stapbench < Bench else puts "NO CODE!" end + args = "-p4 -vv -DSTP_NO_OVERLOAD" + if @trans == BULK then args = "-p4 -bvv -DSTP_NO_OVERLOAD" end + `stap #{args} -m bench.ko bench.stp &> xxx.out` + if ($? != 0) + puts "compile failed. status=#{$?}" + system("tail xxx.out") + exit + end end - + end diff --git a/runtime/counter.c b/runtime/counter.c index def734f6..42555dfa 100644 --- a/runtime/counter.c +++ b/runtime/counter.c @@ -54,7 +54,7 @@ typedef struct _counter *Counter; */ Counter _stp_counter_init (void) { - Counter cnt = alloc_percpu (struct _counter); + Counter cnt = _stp_alloc_percpu (struct _counter); #if NEED_COUNTER_LOCKS == 1 { int i; @@ -135,7 +135,7 @@ int64_t _stp_counter_get (Counter cnt, int clear) */ void _stp_counter_free (Counter cnt) { - free_percpu (cnt); + _stp_free_percpu (cnt); } /** @} */ diff --git a/runtime/map.c b/runtime/map.c index 2acf2fe2..70990876 100644 --- a/runtime/map.c +++ b/runtime/map.c @@ -205,18 +205,13 @@ static int _stp_map_init(MAP m, unsigned max_entries, int type, int key_size, in for (i = 0; i < max_entries; i++) { if (cpu < 0) - tmp = kmalloc(size, STP_ALLOC_FLAGS); + tmp = _stp_kmalloc(size); else - tmp = kmalloc_node(size, STP_ALLOC_FLAGS, cpu_to_node(cpu)); + tmp = _stp_kmalloc_node(size, cpu_to_node(cpu)); if (!tmp) return -1; - if (cpu < 0) - _stp_allocated_memory += size; - else - _stp_allocated_memory += size * num_online_cpus(); - // dbug ("allocated %lx\n", (long)tmp); list_add((struct list_head *)tmp, &m->pool); ((struct map_node *)tmp)->map = m; @@ -252,10 +247,9 @@ static PMAP _stp_pmap_new(unsigned max_entries, int type, int key_size, int data if (pmap == NULL) return NULL; - pmap->map = map = (MAP) alloc_percpu (struct map_root); + pmap->map = map = (MAP) _stp_alloc_percpu (sizeof(struct map_root)); if (map == NULL) goto err; - _stp_allocated_memory += sizeof(struct map_root) * num_online_cpus(); /* initialize the memory lists first so if allocations fail */ /* at some point, it is easy to clean up. */ @@ -284,9 +278,9 @@ err1: m = per_cpu_ptr (map, i); __stp_map_del(m); } - free_percpu(map); + _stp_free_percpu(map); err: - kfree(pmap); + _stp_kfree(pmap); return NULL; } @@ -387,13 +381,13 @@ static void __stp_map_del(MAP map) /* free unused pool */ list_for_each_safe(p, tmp, &map->pool) { list_del(p); - kfree(p); + _stp_kfree(p); } /* free used list */ list_for_each_safe(p, tmp, &map->head) { list_del(p); - kfree(p); + _stp_kfree(p); } } @@ -409,7 +403,7 @@ void _stp_map_del(MAP map) __stp_map_del(map); - kfree(map); + _stp_kfree(map); } void _stp_pmap_del(PMAP pmap) @@ -423,12 +417,12 @@ void _stp_pmap_del(PMAP pmap) MAP m = per_cpu_ptr (pmap->map, i); __stp_map_del(m); } - free_percpu(pmap->map); + _stp_free_percpu(pmap->map); /* free agg map elements */ __stp_map_del(&pmap->agg); - kfree(pmap); + _stp_kfree(pmap); } /* sort keynum values */ diff --git a/runtime/print.c b/runtime/print.c index a451f622..0442ba09 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * Print Functions - * Copyright (C) 2007 Red Hat Inc. + * Copyright (C) 2007-2008 Red Hat Inc. * * 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 @@ -50,26 +50,25 @@ void *Stp_lbuf = NULL; /* create percpu print and io buffers */ int _stp_print_init (void) { - Stp_pbuf = alloc_percpu(_stp_pbuf); + Stp_pbuf = _stp_alloc_percpu(sizeof(_stp_pbuf)); if (unlikely(Stp_pbuf == 0)) return -1; /* now initialize IO buffer used in io.c */ - Stp_lbuf = alloc_percpu(_stp_lbuf); + Stp_lbuf = _stp_alloc_percpu(sizeof(_stp_lbuf)); if (unlikely(Stp_lbuf == 0)) { - free_percpu(Stp_pbuf); + _stp_free_percpu(Stp_pbuf); return -1; } - _stp_allocated_memory += (sizeof(_stp_pbuf)+sizeof(_stp_lbuf)) * num_online_cpus(); return 0; } void _stp_print_cleanup (void) { if (Stp_pbuf) - free_percpu(Stp_pbuf); + _stp_free_percpu(Stp_pbuf); if (Stp_lbuf) - free_percpu(Stp_lbuf); + _stp_free_percpu(Stp_lbuf); } #define __DEF_EXPORT_FN(fn, postfix) fn ## _ ## postfix @@ -276,5 +275,31 @@ static char *next_fmt(char *fmt, int *num) return f; } +void _stp_print_kernel_info(char *vstr, int ctx, int num_probes) +{ +#ifdef DEBUG_MEM + printk(KERN_DEBUG "%s: systemtap: %s, base: %p, memory: %lu+%lu+%u+%u+%u data+text+ctx+net+alloc, probes: %d\n", + THIS_MODULE->name, + vstr, + THIS_MODULE->module_core, + (unsigned long) (THIS_MODULE->core_size - THIS_MODULE->core_text_size), + (unsigned long) THIS_MODULE->core_text_size, + ctx, + _stp_allocated_net_memory, + _stp_allocated_memory - _stp_allocated_net_memory, + num_probes); +#else + printk(KERN_DEBUG "%s: systemtap: %s, base: %p, memory: %lu+%lu+%u+%u data+text+ctx+net, probes: %d\n", + THIS_MODULE->name, + vstr, + THIS_MODULE->module_core, + (unsigned long) (THIS_MODULE->core_size - THIS_MODULE->core_text_size), + (unsigned long) THIS_MODULE->core_text_size, + ctx, + _stp_allocated_net_memory, + num_probes); +#endif +} + /** @} */ #endif /* _PRINT_C_ */ diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index a80de048..3675fc97 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * i386 stack tracing functions - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * * 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 @@ -37,7 +37,7 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) #else while (_stp_valid_stack_ptr(context, (unsigned long)stack)) { addr = *stack++; - _stp_func_print(addr, verbose); + _stp_func_print(addr, verbose, 1); } #endif } diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index 16e3bf7c..186b2ad4 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -15,6 +15,6 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) while ((long)stack & (THREAD_SIZE-1)) { addr = *stack++; - _stp_func_print(addr, verbose); + _stp_func_print(addr, verbose, 1); } } diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog index a7b00a9c..3f373863 100644 --- a/runtime/staprun/ChangeLog +++ b/runtime/staprun/ChangeLog @@ -1,3 +1,25 @@ +2008-01-14 Martin Hunt <hunt@redhat.com> + + PR4037 and fixes to better synchronize staprun and stapio. + * symbols.c (send_data): Send header and data seperately, saving + a memcpy and avoiding any alignment issues. + (get_sections): Return -1 on error instead of just exiting + and leaving stapio hanging. Send data in proper format even if kernel + pointers are different size. + (send_module): Return -1 on error instead of just exiting + and leaving stapio hanging. + (do_module): Ditto. + (compar): Removed. + (do_kernel_symbols): Rewrite to be more robust. Return -1 on + error instead of just exiting and leaving stapio hanging. + + * staprun_funcs.c (handle_symbols): Signal stapio if we error out. + Set kernel_ptr_size; + + * staprun.h (kernel_ptr_size): Declare. + + * mainloop.c (stp_main_loop): When ready, send STP_READY. + 2008-01-12 Frank Ch. Eigler <fche@elastic.org> PR 5603 horrible hack. diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c index d8975d18..2e0c3c5c 100644 --- a/runtime/staprun/mainloop.c +++ b/runtime/staprun/mainloop.c @@ -7,7 +7,7 @@ * Public License (GPL); either version 2, or (at your option) any * later version. * - * Copyright (C) 2005-2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. */ #include "staprun.h" @@ -255,6 +255,7 @@ int stp_main_loop(void) setup_main_signals(0); dbug(2, "in main loop\n"); + send_request(STP_READY, NULL, 0); while (1) { /* handle messages from control channel */ nb = read(control_channel, recvbuf, sizeof(recvbuf)); diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h index c22cc4f3..1128fb4c 100644 --- a/runtime/staprun/staprun.h +++ b/runtime/staprun/staprun.h @@ -7,7 +7,7 @@ * Public License (GPL); either version 2, or (at your option) any * later version. * - * Copyright (C) 2005-2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. */ #include <stdio.h> @@ -119,7 +119,7 @@ int stp_main_loop(void); int send_request(int type, void *data, int len); void cleanup_and_exit (int); int do_module(void *); -void do_kernel_symbols(void); +int do_kernel_symbols(void); int init_ctl_channel(int); void close_ctl_channel(void); int init_relayfs(void); @@ -156,6 +156,7 @@ int set_clexec(int fd); extern int control_channel; extern int ncpus; extern int initialized; +extern int kernel_ptr_size; /* flags */ extern int verbose; diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c index 86a72985..ebf05b34 100644 --- a/runtime/staprun/staprun_funcs.c +++ b/runtime/staprun/staprun_funcs.c @@ -7,7 +7,7 @@ * Public License (GPL); either version 2, or (at your option) any * later version. * - * Copyright (C) 2007 Red Hat Inc. + * Copyright (C) 2007-2008 Red Hat Inc. */ #include "staprun.h" @@ -16,6 +16,8 @@ #include <grp.h> #include <pwd.h> +void cleanup(int rc); + void setup_staprun_signals(void) { struct sigaction a; @@ -386,18 +388,20 @@ int check_permissions(void) } pthread_t symbol_thread_id = (pthread_t)0; +int kernel_ptr_size = 0; /* Symbol handling thread */ void *handle_symbols(void __attribute__((unused)) *arg) { ssize_t nb; void *data; - int type; + int32_t type; char recvbuf[8192]; dbug(2, "waiting for symbol requests\n"); - while (1) { /* handle messages from control channel */ + /* handle messages from control channel */ + while (1) { nb = read(control_channel, recvbuf, sizeof(recvbuf)); if (nb <= 0) { if (errno != EINTR) @@ -405,14 +409,15 @@ void *handle_symbols(void __attribute__((unused)) *arg) continue; } - type = *(int *)recvbuf; - data = (void *)(recvbuf + sizeof(int)); - + type = *(int32_t *)recvbuf; + data = (void *)(recvbuf + sizeof(int32_t)); + switch (type) { case STP_MODULE: { dbug(2, "STP_MODULES request received\n"); - do_module(data); + if (do_module(data) < 0) + goto done; break; } case STP_SYMBOLS: @@ -421,14 +426,15 @@ void *handle_symbols(void __attribute__((unused)) *arg) dbug(2, "STP_SYMBOLS request received\n"); if (req->endian != 0x1234) { err("ERROR: staprun is compiled with different endianess than the kernel!\n"); - exit(1); + goto done; } - if (req->ptr_size != sizeof(char *)) { - err("ERROR: staprun is compiled with %d-bit pointers and the kernel uses %d-bit.\n", - 8*(int)sizeof(char *), 8*req->ptr_size); - exit(1); + kernel_ptr_size = req->ptr_size; + if (kernel_ptr_size != 4 && kernel_ptr_size != 8) { + err("ERROR: invalid kernel pointer size %d\n", kernel_ptr_size); + goto done; } - do_kernel_symbols(); + if (do_kernel_symbols() < 0) + goto done; break; } default: @@ -436,6 +442,10 @@ void *handle_symbols(void __attribute__((unused)) *arg) } } +done: + /* signal stapio we're done */ + kill(0, SIGINT); + return NULL; } diff --git a/runtime/staprun/symbols.c b/runtime/staprun/symbols.c index e4d96ee0..5a4855b3 100644 --- a/runtime/staprun/symbols.c +++ b/runtime/staprun/symbols.c @@ -1,7 +1,7 @@ /* -*- linux-c -*- * Symbols and modules functions for staprun. * - * Copyright (C) 2006, 2007 Red Hat Inc. + * Copyright (C) 2006-2008 Red Hat Inc. * * 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 @@ -10,16 +10,19 @@ */ #include "staprun.h" -#include "../sym.h" +/* send symbol data */ static int send_data(void *data, int len) { + int32_t type = STP_SYMBOLS; + if (write(control_channel, &type, 4) <= 0) + return -1; return write(control_channel, data, len); } /* Get the sections for a module. Put them in the supplied buffer */ /* in the following order: */ -/* [struct _stp_module][struct _stp_symbol sections ...][string data] */ +/* [struct _stp_msg_module][struct _stp_symbol sections ...][string data]*/ /* Return the total length of all the data. */ #define SECDIR "/sys/module/%s/sections" @@ -30,33 +33,35 @@ static int get_sections(char *name, char *data_start, int datalen) char buf[32], strdata_start[32768]; char *strdata=strdata_start, *data=data_start; int fd, len, res; - struct _stp_module *mod = (struct _stp_module *)data_start; + struct _stp_msg_module *mod = (struct _stp_msg_module *)data_start; struct dirent *d; DIR *secdir; - struct _stp_symbol *sec; + void *sec; + int struct_symbol_size = kernel_ptr_size == 8 ? sizeof(struct _stp_symbol64) : sizeof(struct _stp_symbol32); + uint64_t sec_addr; - /* start of data is a struct _stp_module */ - data += sizeof(struct _stp_module); + /* start of data is a struct _stp_msg_module */ + data += sizeof(struct _stp_msg_module); res = snprintf(dir, sizeof(dir), SECDIR, name); if (res >= (int)sizeof(dir)) { _err("Couldn't fit module \"%s\" into dir buffer.\n" \ "This should never happen. Please file a bug report.\n", name); - exit(1); + return -1; } if ((secdir = opendir(dir)) == NULL) return 0; /* Initialize mod. */ - memset(mod, 0, sizeof(struct _stp_module)); + memset(mod, 0, sizeof(struct _stp_msg_module)); /* Copy name in and check for overflow. */ strncpy(mod->name, name, STP_MODULE_NAME_LEN); if (mod->name[STP_MODULE_NAME_LEN - 1] != '\0') { _err("Couldn't fit module \"%s\" into mod->name buffer.\n" \ "This should never happen. Please file a bug report.\n", name); - exit(1); + return -1; } while ((d = readdir(secdir))) { @@ -68,7 +73,7 @@ static int get_sections(char *name, char *data_start, int datalen) _err("Couldn't fit secname \"%s\" into filename buffer.\n" \ "This should never happen. Please file a bug report.\n", secname); closedir(secdir); - exit(1); + return -1; } /* filter out some non-useful stuff */ @@ -88,12 +93,19 @@ static int get_sections(char *name, char *data_start, int datalen) if ((fd = open(filename,O_RDONLY)) >= 0) { if (read(fd, buf, 32) > 0) { /* create next section */ - sec = (struct _stp_symbol *)data; - if (data - data_start + (int)sizeof(struct _stp_symbol) > datalen) + sec = data; + if (data - data_start + struct_symbol_size > datalen) goto err1; - data += sizeof(struct _stp_symbol); - sec->addr = strtoul(buf,NULL,16); - sec->symbol = (char *)(strdata - strdata_start); + data += struct_symbol_size; + + sec_addr = (uint64_t)strtoull(buf,NULL,16); + if (kernel_ptr_size == 8) { + ((struct _stp_symbol64 *)sec)->addr = sec_addr; + ((struct _stp_symbol64 *)sec)->symbol = (uint64_t)(strdata - strdata_start); + } else { + ((struct _stp_symbol32 *)sec)->addr = (uint32_t)sec_addr; + ((struct _stp_symbol32 *)sec)->symbol = (uint32_t)(strdata - strdata_start); + } mod->num_sections++; /* now create string data for the @@ -106,13 +118,13 @@ static int get_sections(char *name, char *data_start, int datalen) /* These sections are used a lot so keep the values handy */ if (!strcmp(secname, ".data") || !strncmp(secname, ".rodata", 7)) { - if (mod->data == 0 || sec->addr < mod->data) - mod->data = sec->addr; + if (mod->data == 0 || sec_addr < mod->data) + mod->data = sec_addr; } if (!strcmp(secname, ".text")) - mod->text = sec->addr; + mod->text = sec_addr; if (!strcmp(secname, ".gnu.linkonce.this_module")) - mod->module = sec->addr; + mod->module = sec_addr; } close(fd); } @@ -135,56 +147,55 @@ err1: err0: /* if this happens, something went seriously wrong. */ _err("Unexpected error. Overflowed buffers.\n"); - exit(1); - return 0; /* not reached */ + return -1; } #undef SECDIR /* * For modules, we send the name, section names, and offsets */ -static void send_module (char *mname) +static int send_module (char *mname) { - char data[32768]; - int len = get_sections(mname, data, sizeof(data)); - if (len) { - if (send_request(STP_MODULE, data, len) < 0) { + char data[65536]; + int len; + *(int32_t *)data = STP_MODULE; + len = get_sections(mname, data + sizeof(int32_t), + sizeof(data) - sizeof(int32_t)); + if (len > 0) { + if (write(control_channel, data, len + sizeof(int32_t)) <= 0) { _err("Loading of module %s failed. Exiting...\n", mname); - exit(1); + return -1; } } + return len; } /* * Send either all modules, or a specific one. + * Returns: + * >=0 : OK + * -1 : serious error (exit) */ int do_module (void *data) { - struct _stp_module *mod = (struct _stp_module *)data; + struct _stp_msg_module *mod = (struct _stp_msg_module *)data; if (mod->name[0] == 0) { struct dirent *d; DIR *moddir = opendir("/sys/module"); if (moddir) { while ((d = readdir(moddir))) - send_module(d->d_name); + if (send_module(d->d_name) < 0) { + closedir(moddir); + return -1; + } closedir(moddir); } - send_request(STP_MODULE, data, 0); - return 1; + send_request(STP_MODULE, data, 1); + return 0; } - send_module(mod->name); - return 0; -} - -static int compar(const void *p1, const void *p2) -{ - struct _stp_symbol *s1 = (struct _stp_symbol *)p1; - struct _stp_symbol *s2 = (struct _stp_symbol *)p2; - if (s1->addr == s2->addr) return 0; - if (s1->addr < s2->addr) return -1; - return 1; + return send_module(mod->name); } #define MAX_SYMBOLS 32*1024 @@ -194,29 +205,29 @@ static int compar(const void *p1, const void *p2) * systemtap module. Ignore module symbols; the systemtap module * can access them directly. */ -void do_kernel_symbols(void) +int do_kernel_symbols(void) { FILE *kallsyms=NULL; - char *sym_base=NULL, *data_base=NULL; - char buf[256], *ptr, *name, *data, *dataptr, *datamax, type; - unsigned long addr; - struct _stp_symbol *syms; - int num_syms, i = 0, max_syms= MAX_SYMBOLS; - int data_basesize = MAX_SYMBOLS*32; - - sym_base = malloc(max_syms*sizeof(struct _stp_symbol)+sizeof(long)); + char *name, *mod, *dataptr, *datamax, type, *data_base=NULL; + unsigned long long addr; + void *syms = NULL; + int ret, num_syms, i = 0, struct_symbol_size; + int max_syms= MAX_SYMBOLS, data_basesize = MAX_SYMBOLS*32; + + if (kernel_ptr_size == 8) + struct_symbol_size = sizeof(struct _stp_symbol64); + else + struct_symbol_size = sizeof(struct _stp_symbol32); + + syms = malloc(max_syms * struct_symbol_size); data_base = malloc(data_basesize); - if (data_base == NULL || sym_base == NULL) { + if (data_base == NULL || syms == NULL) { _err("Failed to allocate memory for symbols\n"); goto err; } - *(int *)data_base = STP_SYMBOLS; - dataptr = data = data_base + sizeof(long); + dataptr = data_base; datamax = data_base + data_basesize; - *(int *)sym_base = STP_SYMBOLS; - syms = (struct _stp_symbol *)(sym_base + sizeof(long)); - kallsyms = fopen ("/proc/kallsyms", "r"); if (!kallsyms) { _perr("Fatal error: Unable to open /proc/kallsyms"); @@ -226,35 +237,28 @@ void do_kernel_symbols(void) /* put empty string in data */ *dataptr++ = 0; - while (fgets_unlocked(buf, 256, kallsyms) && dataptr < datamax) { - addr = strtoul(buf, &ptr, 16); - while (isspace(*ptr)) ptr++; - type = *ptr++; + while ((ret = fscanf(kallsyms, "%llx %c %as [%as", &addr, &type, &name, &mod))>0 + && dataptr < datamax) { + if (ret < 3) + continue; + if (ret > 3) { + /* ignore modules */ + free(name); + free(mod); + /* modules are loaded above the kernel, so if we */ + /* are getting modules, then we're done. */ + break; + } + if (type == 't' || type == 'T' || type == 'A') { - while (isspace(*ptr)) ptr++; - name = ptr++; - while (!isspace(*ptr)) ptr++; - *ptr++ = 0; - while (*ptr && *ptr != '[') ptr++; - if (*ptr) - continue; /* it was a module */ - syms[i].addr = addr; - syms[i].symbol = (char *)(dataptr - data); - while (*name) *dataptr++ = *name++; - *dataptr++ = 0; - i++; - if (i >= max_syms) { - char *s; - max_syms *= 2; - s = realloc(sym_base, max_syms*sizeof(struct _stp_symbol)+sizeof(long)); - if (s == NULL) { - _err("Could not allocate enough space for symbols.\n"); - goto err; - } - syms = (struct _stp_symbol *)(s + sizeof(long)); - sym_base = s; - } - if (dataptr > datamax - 1024) { + if (kernel_ptr_size == 8) { + ((struct _stp_symbol64 *)syms)[i].addr = (uint64_t)addr; + ((struct _stp_symbol64 *)syms)[i].symbol = (uint64_t)(dataptr - data_base); + } else { + ((struct _stp_symbol32 *)syms)[i].addr = (uint32_t)addr; + ((struct _stp_symbol32 *)syms)[i].symbol = (uint32_t)(dataptr - data_base); + } + if (dataptr >= datamax - strlen(name)) { char *db; data_basesize *= 2; db = realloc(data_base, data_basesize); @@ -263,43 +267,55 @@ void do_kernel_symbols(void) goto err; } dataptr = db + (dataptr - data_base); - data = db + sizeof(long); datamax = db + data_basesize; data_base = db; } + strcpy(dataptr, name); + dataptr += strlen(name) + 1; + free(name); + i++; + if (i >= max_syms) { + max_syms *= 2; + syms = realloc(syms, max_syms*struct_symbol_size); + if (syms == NULL) { + _err("Could not allocate enough space for symbols.\n"); + goto err; + } + } } } num_syms = i; - qsort(syms, num_syms, sizeof(struct _stp_symbol), compar); + if (num_syms <= 0) + goto err; /* send header */ - *(int *)buf = STP_SYMBOLS; - *(int *)(buf+sizeof(long)) = num_syms; - *(int *)(buf+sizeof(long)+sizeof(int)) = (unsigned)(dataptr - data); - if (send_data(buf, 2*sizeof(int)+sizeof(long)) < 0) + struct _stp_msg_symbol_hdr smsh; + smsh.num_syms = num_syms; + smsh.sym_size = (uint32_t)(dataptr - data_base); + if (send_request(STP_SYMBOLS, &smsh, sizeof(smsh)) <= 0) goto err; /* send syms */ - if (send_data(sym_base, num_syms*sizeof(struct _stp_symbol)+sizeof(long)) < 0) + if (send_data(syms, num_syms*struct_symbol_size) < 0) goto err; /* send data */ - if (send_data(data_base, dataptr-data+sizeof(long)) < 0) + if (send_data(data_base, dataptr-data_base) < 0) goto err; free(data_base); - free(sym_base); + free(syms); fclose(kallsyms); - return; + return 0; err: if (data_base) free(data_base); - if (sym_base) - free(sym_base); + if (syms) + free(syms); if (kallsyms) fclose(kallsyms); _err("Loading of symbols failed. Exiting...\n"); - exit(1); + return -1; } diff --git a/runtime/stat.c b/runtime/stat.c index 3df1d063..298a6653 100644 --- a/runtime/stat.c +++ b/runtime/stat.c @@ -52,7 +52,7 @@ /** Stat struct for stat.c. Maps do not need this */ struct _Stat { struct _Hist hist; - /* per-cpu data. allocated with alloc_percpu() */ + /* per-cpu data. allocated with _stp_alloc_percpu() */ stat *sd; /* aggregated data */ stat *agg; @@ -130,9 +130,9 @@ Stat _stp_stat_init (int type, ...) return st; exit2: - kfree (sd); + _stp_kfree (sd); exit1: - kfree (st); + _stp_kfree (st); return NULL; } @@ -144,9 +144,9 @@ exit1: void _stp_stat_del (Stat st) { if (st) { - free_percpu (st->sd); - kfree (st->agg); - kfree (st); + _stp_free_percpu (st->sd); + _stp_kfree (st->agg); + _stp_kfree (st); } } diff --git a/runtime/sym.c b/runtime/sym.c index c40f48db..56c93064 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -193,7 +193,7 @@ void _stp_symbol_print (unsigned long address) _stp_printf ("%p", (int64_t)address); if (name) { - if (modname) + if (modname && *modname) _stp_printf (" : %s+%#lx/%#lx [%s]", name, offset, size, modname); else _stp_printf (" : %s+%#lx/%#lx", name, offset, size); @@ -202,22 +202,28 @@ void _stp_symbol_print (unsigned long address) /* Like _stp_symbol_print, except only print if the address is a valid function address */ -void _stp_func_print (unsigned long address, int verbose) +void _stp_func_print (unsigned long address, int verbose, int exact) { char *modname; const char *name; unsigned long offset, size; + char *exstr; + + if (exact) + exstr = ""; + else + exstr = " (inexact)"; name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); if (name) { if (verbose) { - if (modname) - _stp_printf (" %p : %s+%#lx/%#lx [%s]\n", - (int64_t)address, name, offset, size, modname); + if (modname && *modname) + _stp_printf (" %p : %s+%#lx/%#lx [%s]%s\n", + (int64_t)address, name, offset, size, modname, exstr); else - _stp_printf (" %p : %s+%#lx/%#lx\n", - (int64_t)address, name, offset, size); + _stp_printf (" %p : %s+%#lx/%#lx%s\n", + (int64_t)address, name, offset, size, exstr); } else _stp_printf ("%p ", (int64_t)address); } diff --git a/runtime/time.c b/runtime/time.c index 688427f4..52a2edbb 100644 --- a/runtime/time.c +++ b/runtime/time.c @@ -219,7 +219,7 @@ _stp_kill_time(void) } #endif - free_percpu(stp_time); + _stp_free_percpu(stp_time); } } @@ -229,10 +229,9 @@ _stp_init_time(void) { int ret = 0; - stp_time = alloc_percpu(stp_time_t); + stp_time = _stp_alloc_percpu(sizeof(stp_time_t)); if (unlikely(stp_time == 0)) return -1; - _stp_allocated_memory += sizeof(stp_time_t) * num_online_cpus(); stp_timer_reregister = 1; ret = on_each_cpu(__stp_init_time, NULL, 0, 1); diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 263a6bf8..e7bbabd8 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,32 @@ +2008-01-15 Martin Hunt <hunt@redhat.com> + + PR4037 and fixes to better synchronize staprun and stapio. + * transport_msgs.h (struct _stp_symbol32): New. + (struct _stp_symbol64): New. + (struct _stp_msg_symbol_hdr): New. + (struct _stp_msg_module): New. + (STP_READY): Declare. + + * transport.c (_stp_handle_start): Don't set _stp_start_finished. + (_stp_work_queue): Don't use _stp_start_finished. + (_stp_transport_init): Don't call _stp_ask_for_symbols(). + + * symbols.c (_stp_do_symbols): Use _stp_msg_symbol_hdr; + + * control.c (_stp_sym_write_cmd): Allow sending of headers + and data in separate messages. + (_stp_ctl_write_cmd): Add STP_READY message. + + * procfs.c (_stp_sym_write_cmd): Allow sending of headers + and data in separate messages. + (_stp_ctl_write_cmd): Add STP_READY message. + +2008-01-15 Martin Hunt <hunt@redhat.com> + + Support for DEBUG_MEM + * transport.c (_stp_transport): Call stp_mem_debug_done(); + * (*.c): Call stp malloc and free functions. + 2007-11-09 Masami Hiramatsu <mhiramat@redhat.com> PR3858 diff --git a/runtime/transport/control.c b/runtime/transport/control.c index 7846572a..3179f507 100644 --- a/runtime/transport/control.c +++ b/runtime/transport/control.c @@ -22,38 +22,44 @@ spinlock_t _stp_sym_ready_lock = SPIN_LOCK_UNLOCKED; static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + static int saved_type = 0; int type; - if (count < sizeof(int)) + if (count < sizeof(int32_t)) return 0; - if (get_user(type, (int __user *)buf)) - return -EFAULT; - - kbug ("count:%d type:%d\n", count, type); - - if (type == STP_SYMBOLS) { - count -= sizeof(long); - buf += sizeof(long); + /* Allow sending of packet type followed by data in the next packet.*/ + if (count == sizeof(int32_t)) { + if (get_user(saved_type, (int __user *)buf)) + return -EFAULT; + return count; + } else if (saved_type) { + type = saved_type; + saved_type = 0; } else { + if (get_user(type, (int __user *)buf)) + return -EFAULT; count -= sizeof(int); buf += sizeof(int); } + + kbug ("count:%d type:%d\n", (int)count, type); switch (type) { - case STP_SYMBOLS: - - if (count) - count = _stp_do_symbols(buf, count); + case STP_SYMBOLS: + count = _stp_do_symbols(buf, count); break; case STP_MODULE: - if (count) + if (count > 1) count = _stp_do_module(buf, count); else { - /* count == 0 indicates end of initial modules list */ + /* count == 1 indicates end of initial modules list */ _stp_ctl_send(STP_TRANSPORT, NULL, 0); } break; + case STP_EXIT: + _stp_exit_flag = 1; + break; default: errk ("invalid symbol command type %d\n", type); return -EINVAL; @@ -73,7 +79,7 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, if (get_user(type, (int __user *)buf)) return -EFAULT; - // kbug ("count:%d type:%d\n", count, type); + kbug ("count:%d type:%d\n", (int)count, type); count -= sizeof(int); buf += sizeof(int); @@ -99,6 +105,11 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, #else return -1; #endif + case STP_READY: + /* request symbolic information */ + _stp_ask_for_symbols(); + break; + default: errk ("invalid command type %d\n", type); return -EINVAL; @@ -422,7 +433,7 @@ static int _stp_register_ctl_channel (void) /* allocate buffers */ for (i = 0; i < STP_DEFAULT_BUFFERS; i++) { - p = (struct list_head *)kmalloc(sizeof(struct _stp_buffer),STP_ALLOC_FLAGS); + p = (struct list_head *)_stp_kmalloc(sizeof(struct _stp_buffer)); // printk("allocated buffer at %lx\n", (long)p); if (!p) goto err0; @@ -448,7 +459,7 @@ err0: list_for_each_safe(p, tmp, &_stp_pool_q) { list_del(p); - kfree(p); + _stp_kfree(p); } errk ("Error creating systemtap debugfs entries.\n"); return -1; @@ -464,15 +475,15 @@ static void _stp_unregister_ctl_channel (void) /* free memory pools */ list_for_each_safe(p, tmp, &_stp_pool_q) { list_del(p); - kfree(p); + _stp_kfree(p); } list_for_each_safe(p, tmp, &_stp_sym_ready_q) { list_del(p); - kfree(p); + _stp_kfree(p); } list_for_each_safe(p, tmp, &_stp_ctl_ready_q) { list_del(p); - kfree(p); + _stp_kfree(p); } } diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c index 069e379e..85e97d15 100644 --- a/runtime/transport/procfs.c +++ b/runtime/transport/procfs.c @@ -1,7 +1,7 @@ /* -*- linux-c -*- * * /proc transport and control - * Copyright (C) 2005-2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * * 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 @@ -68,35 +68,38 @@ static struct file_operations _stp_proc_fops = { static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + static int saved_type = 0; int type; - if (count < sizeof(int)) + if (count < sizeof(int32_t)) return 0; - if (get_user(type, (int __user *)buf)) - return -EFAULT; - - kbug ("count:%d type:%d\n", (int)count, type); - - if (type == STP_SYMBOLS) { - count -= sizeof(long); - buf += sizeof(long); + /* Allow sending of packet type followed by data in the next packet.*/ + if (count == sizeof(int32_t)) { + if (get_user(saved_type, (int __user *)buf)) + return -EFAULT; + return count; + } else if (saved_type) { + type = saved_type; + saved_type = 0; } else { + if (get_user(type, (int __user *)buf)) + return -EFAULT; count -= sizeof(int); buf += sizeof(int); } + + // kbug ("count:%d type:%d\n", (int)count, type); switch (type) { - case STP_SYMBOLS: - - if (count) - count = _stp_do_symbols(buf, count); + case STP_SYMBOLS: + count = _stp_do_symbols(buf, count); break; case STP_MODULE: - if (count) + if (count > 1) count = _stp_do_module(buf, count); else { - /* count == 0 indicates end of initial modules list */ + /* count == 1 indicates end of initial modules list */ _stp_ctl_send(STP_TRANSPORT, NULL, 0); } break; @@ -106,6 +109,7 @@ static ssize_t _stp_sym_write_cmd (struct file *file, const char __user *buf, } return count; + } static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, size_t count, loff_t *ppos) @@ -139,6 +143,10 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf, case STP_EXIT: _stp_exit_flag = 1; break; + case STP_READY: + /* request symbolic information */ + _stp_ask_for_symbols(); + break; default: errk ("invalid command type %d\n", type); return -EINVAL; @@ -485,7 +493,7 @@ static int _stp_set_buffers(int num) if (num > _stp_current_buffers) { for (i = 0; i < num - _stp_current_buffers; i++) { - p = (struct list_head *)kmalloc(sizeof(struct _stp_buffer),STP_ALLOC_FLAGS); + p = (struct list_head *)_stp_kmalloc(sizeof(struct _stp_buffer)); if (!p) { _stp_current_buffers += i; goto err; @@ -501,7 +509,7 @@ static int _stp_set_buffers(int num) p = _stp_pool_q.next; list_del(p); spin_unlock_irqrestore(&_stp_pool_lock, flags); - kfree(p); + _stp_kfree(p); } } _stp_current_buffers = num; @@ -542,7 +550,7 @@ static int _stp_register_ctl_channel (void) /* allocate buffers */ for (i = 0; i < STP_DEFAULT_BUFFERS; i++) { - p = (struct list_head *)kmalloc(sizeof(struct _stp_buffer),STP_ALLOC_FLAGS); + p = (struct list_head *)_stp_kmalloc(sizeof(struct _stp_buffer)); // printk("allocated buffer at %lx\n", (long)p); if (!p) goto err0; @@ -593,7 +601,7 @@ err2: err1: #ifdef STP_BULKMODE for (de = _stp_proc_root->subdir; de; de = de->next) - kfree (de->data); + _stp_kfree (de->data); for_each_cpu(j) { if (j == i) break; @@ -607,7 +615,7 @@ err1: err0: list_for_each_safe(p, tmp, &_stp_pool_q) { list_del(p); - kfree(p); + _stp_kfree(p); } errk ("Error creating systemtap /proc entries.\n"); @@ -624,7 +632,7 @@ static void _stp_unregister_ctl_channel (void) struct proc_dir_entry *de; kbug("unregistering procfs\n"); for (de = _stp_proc_root->subdir; de; de = de->next) - kfree (de->data); + _stp_kfree (de->data); for_each_cpu(i) { sprintf(buf, "%d", i); @@ -640,15 +648,15 @@ static void _stp_unregister_ctl_channel (void) /* free memory pools */ list_for_each_safe(p, tmp, &_stp_pool_q) { list_del(p); - kfree(p); + _stp_kfree(p); } list_for_each_safe(p, tmp, &_stp_sym_ready_q) { list_del(p); - kfree(p); + _stp_kfree(p); } list_for_each_safe(p, tmp, &_stp_ctl_ready_q) { list_del(p); - kfree(p); + _stp_kfree(p); } } diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c index 2c7ca754..375c8e59 100644 --- a/runtime/transport/relayfs.c +++ b/runtime/transport/relayfs.c @@ -118,7 +118,7 @@ err: _stp_remove_relay_dir(utt->dir); if (utt->utt_tree_root) _stp_remove_relay_root(utt->utt_tree_root); - kfree(utt); + _stp_kfree(utt); return NULL; } @@ -173,7 +173,7 @@ int utt_trace_remove(struct utt_trace *utt) _stp_remove_relay_dir(utt->dir); if (utt->utt_tree_root) _stp_remove_relay_root(utt->utt_tree_root); - kfree(utt); + _stp_kfree(utt); } return 0; } diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 1d930183..dde0f967 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -1,7 +1,7 @@ /* -*- linux-c -*- * symbols.c - stp symbol and module functions * - * Copyright (C) Red Hat Inc, 2006, 2007 + * Copyright (C) Red Hat Inc, 2006-2008 * * 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 @@ -84,16 +84,20 @@ static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize) goto bad; mod->allocated |= 2; } + mod->num_symbols = num; return mod; bad: if (mod) { - if (mod->allocated && mod->symbols) - vfree(mod->symbols); - else - kfree(mod->symbols); - kfree(mod); + if (mod->symbols) { + if (mod->allocated & 1) + _stp_vfree(mod->symbols); + else + _stp_kfree(mod->symbols); + mod->symbols = NULL; + } + _stp_kfree(mod); } return NULL; } @@ -107,21 +111,27 @@ static struct _stp_module * _stp_alloc_module_from_module (struct module *m) static void _stp_free_module(struct _stp_module *mod) { /* free symbol memory */ - if (mod->num_symbols) { + if (mod->symbols) { if (mod->allocated & 1) - vfree(mod->symbols); + _stp_vfree(mod->symbols); else - kfree(mod->symbols); + _stp_kfree(mod->symbols); + mod->symbols = NULL; + } + if (mod->symbol_data) { if (mod->allocated & 2) - vfree(mod->symbol_data); + _stp_vfree(mod->symbol_data); else - kfree(mod->symbol_data); - } - if (mod->sections) - kfree(mod->sections); + _stp_kfree(mod->symbol_data); + mod->symbol_data = NULL; + } + if (mod->sections) { + _stp_kfree(mod->sections); + mod->sections = NULL; + } /* free module memory */ - kfree(mod); + _stp_kfree(mod); } /* Delete a module and free its memory. */ @@ -174,20 +184,21 @@ static unsigned long _stp_kallsyms_lookup_name(const char *name); /* process the KERNEL symbols */ static int _stp_do_symbols(const char __user *buf, int count) { - unsigned i, datasize, num; struct _stp_symbol *s; + unsigned datasize, num; + int i; switch (_stp_symbol_state) { case 0: - if (count != 8) { - errk(" _stp_do_symbols: count=%d\n", count); + if (count != sizeof(struct _stp_msg_symbol_hdr)) { + errk("count=%d\n", count); return -EFAULT; } if (get_user(num, (unsigned __user *)buf)) return -EFAULT; if (get_user(datasize, (unsigned __user *)(buf+4))) return -EFAULT; - // kbug("num=%d datasize=%d\n", num, datasize); + //kbug("num=%d datasize=%d\n", num, datasize); _stp_modules[0] = _stp_alloc_module(num, datasize); if (_stp_modules[0] == NULL) { @@ -197,26 +208,27 @@ static int _stp_do_symbols(const char __user *buf, int count) _stp_symbol_state = 1; break; case 1: + //kbug("got stap_symbols, count=%d\n", count); if (copy_from_user ((char *)_stp_modules[0]->symbols, buf, count)) return -EFAULT; - // kbug("got stap_symbols, count=%d\n", count); _stp_symbol_state = 2; break; case 2: + //kbug("got symbol data, count=%d buf=%p\n", count, buf); if (copy_from_user (_stp_modules[0]->symbol_data, buf, count)) return -EFAULT; - // kbug("got symbol data, count=%d\n", count); _stp_num_modules = 1; - s = _stp_modules[0]->symbols; for (i = 0; i < _stp_modules[0]->num_symbols; i++) s[i].symbol += (long)_stp_modules[0]->symbol_data; + _stp_symbol_state = 3; /* NB: this mapping is used by kernel/_stext pseudo-relocations. */ _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext"); _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext"); _stp_modules_by_addr[0] = _stp_modules[0]; + //kbug("done with symbol data\n"); break; default: errk("unexpected symbol data of size %d.\n", count); @@ -433,8 +445,9 @@ done: /* Called from procfs.c when a STP_MODULE msg is received */ static int _stp_do_module(const char __user *buf, int count) { - struct _stp_module tmpmod, *mod; - unsigned i; + struct _stp_msg_module tmpmod; + struct _stp_module mod, *m; + unsigned i, section_len; if (count < (int)sizeof(tmpmod)) { errk("expected %d and got %d\n", (int)sizeof(tmpmod), count); @@ -443,41 +456,53 @@ static int _stp_do_module(const char __user *buf, int count) if (copy_from_user ((char *)&tmpmod, buf, sizeof(tmpmod))) return -EFAULT; - // kbug("Got module %s, count=%d(0x%x)\n", tmpmod.name, count,count); - - if (_stp_module_exists(&tmpmod)) + section_len = count - sizeof(tmpmod); + if (section_len <= 0) { + errk("section_len = %d\n", section_len); + return -EFAULT; + } + kbug("Got module %s, count=%d section_len=%d\n", + tmpmod.name, count, section_len); + + strcpy(mod.name, tmpmod.name); + mod.module = tmpmod.module; + mod.text = tmpmod.text; + mod.data = tmpmod.data; + mod.num_sections = tmpmod.num_sections; + + if (_stp_module_exists(&mod)) return count; /* copy in section data */ - tmpmod.sections = _stp_kmalloc(count - sizeof(tmpmod)); - if (tmpmod.sections == NULL) { + mod.sections = _stp_kmalloc(section_len); + if (mod.sections == NULL) { errk("unable to allocate memory.\n"); return -EFAULT; } - if (copy_from_user ((char *)tmpmod.sections, buf+sizeof(tmpmod), count-sizeof(tmpmod))) { - kfree(tmpmod.sections); + if (copy_from_user ((char *)mod.sections, buf+sizeof(tmpmod), section_len)) { + _stp_kfree(mod.sections); return -EFAULT; } - for (i = 0; i < tmpmod.num_sections; i++) { - tmpmod.sections[i].symbol = - (char *)((long)tmpmod.sections[i].symbol - + (long)((long)tmpmod.sections + tmpmod.num_sections * sizeof(struct _stp_symbol))); + for (i = 0; i < mod.num_sections; i++) { + mod.sections[i].symbol = + (char *)((long)mod.sections[i].symbol + + (long)((long)mod.sections + mod.num_sections * sizeof(struct _stp_symbol))); } #ifdef DEBUG_SYMBOLS - for (i = 0; i < tmpmod.num_sections; i++) - printk("section %d (stored at %p): %s %lx\n", i, &tmpmod.sections[i], tmpmod.sections[i].symbol, tmpmod.sections[i].addr); + for (i = 0; i < mod.num_sections; i++) + printk("section %d (stored at %p): %s %lx\n", i, &mod.sections[i], mod.sections[i].symbol, mod.sections[i].addr); #endif /* load symbols from tmpmod.module to mod */ - mod = _stp_load_module_symbols(&tmpmod); - if (mod == NULL) { - kfree(tmpmod.sections); + m = _stp_load_module_symbols(&mod); + if (m == NULL) { + _stp_kfree(mod.sections); return 0; } - if (_stp_ins_module(mod) < 0) { - _stp_free_module(mod); + if (_stp_ins_module(m) < 0) { + _stp_free_module(m); return -ENOMEM; } diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c index 2904cf2f..6b90ee64 100644 --- a/runtime/transport/transport.c +++ b/runtime/transport/transport.c @@ -2,7 +2,7 @@ * transport.c - stp transport functions * * Copyright (C) IBM Corporation, 2005 - * Copyright (C) Red Hat Inc, 2005-2007 + * Copyright (C) Red Hat Inc, 2005-2008 * Copyright (C) Intel Corporation, 2006 * * This file is part of systemtap, and is free software. You can @@ -31,7 +31,6 @@ static struct utt_trace *_stp_utt = NULL; static unsigned int utt_seq = 1; -static int _stp_start_finished = 0; static int _stp_probes_started = 0; /* module parameters */ @@ -61,6 +60,7 @@ static DECLARE_WORK(_stp_work, _stp_work_queue, NULL); #endif static struct workqueue_struct *_stp_wq; +static void _stp_ask_for_symbols(void); #ifdef STP_OLD_TRANSPORT #include "procfs.c" @@ -72,16 +72,20 @@ static void _stp_ask_for_symbols(void) { struct _stp_msg_symbol req; struct _stp_module mod; - - /* ask for symbols and modules */ - kbug("AFS\n"); - - req.endian = 0x1234; - req.ptr_size = sizeof(char *); - _stp_ctl_send(STP_SYMBOLS, &req, sizeof(req)); - - strcpy(mod.name, ""); - _stp_ctl_send(STP_MODULE, &mod, sizeof(mod)); + static int sent_symbols = 0; + + if (sent_symbols == 0) { + /* ask for symbols and modules */ + kbug("AFS\n"); + + req.endian = 0x1234; + req.ptr_size = sizeof(char *); + _stp_ctl_send(STP_SYMBOLS, &req, sizeof(req)); + + strcpy(mod.name, ""); + _stp_ctl_send(STP_MODULE, &mod, sizeof(mod)); + sent_symbols = 1; + } } /* @@ -97,7 +101,6 @@ void _stp_handle_start (struct _stp_msg_start *st) _stp_target = st->target; st->res = probe_start(); - _stp_start_finished = 1; if (st->res >= 0) _stp_probes_started = 1; @@ -193,7 +196,7 @@ static void _stp_work_queue (void *data) wake_up_interruptible(&_stp_ctl_wq); /* if exit flag is set AND we have finished with probe_start() */ - if (unlikely(_stp_exit_flag && _stp_start_finished)) + if (unlikely(_stp_exit_flag)) _stp_cleanup_and_exit(0); else if (likely(_stp_attached)) queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER); @@ -215,6 +218,7 @@ void _stp_transport_close() _stp_free_modules(); _stp_kill_time(); _stp_print_cleanup(); /* free print buffers */ + _stp_mem_debug_done(); kbug("---- CLOSED ----\n"); } @@ -287,9 +291,6 @@ int _stp_transport_init(void) _stp_wq = create_workqueue("systemtap"); if (!_stp_wq) goto err3; - - /* request symbolic information */ - _stp_ask_for_symbols(); return 0; err3: diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h index c6090969..b2187cd5 100644 --- a/runtime/transport/transport_msgs.h +++ b/runtime/transport/transport_msgs.h @@ -1,7 +1,7 @@ /* -*- linux-c -*- * transport_msgs.h - messages exchanged between module and userspace * - * Copyright (C) Red Hat Inc, 2006-2007 + * Copyright (C) Red Hat Inc, 2006-2008 * * 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 @@ -9,6 +9,8 @@ * later version. */ +#define STP_MODULE_NAME_LEN 64 + struct _stp_trace { uint32_t sequence; /* event number */ uint32_t pdu_len; /* length of data after this trace */ @@ -27,6 +29,7 @@ enum STP_CONNECT, STP_DISCONNECT, STP_BULK, + STP_READY, #ifdef STP_OLD_TRANSPORT /** deprecated **/ STP_BUF_INFO, @@ -58,6 +61,43 @@ struct _stp_msg_start int32_t res; // for reply: result of probe_start() }; +struct _stp_symbol32 +{ + uint32_t addr; + uint32_t symbol; +}; + +struct _stp_symbol64 +{ + uint64_t addr; + uint64_t symbol; +}; + +struct _stp_msg_symbol_hdr +{ + uint32_t num_syms; + uint32_t sym_size; + uint32_t unwind_size; +}; + +struct _stp_msg_module { + /* the module name, or "" for kernel */ + char name[STP_MODULE_NAME_LEN]; + + /* A pointer to the struct module */ + uint64_t module; + + /* the start of the module's text and data sections */ + uint64_t text; + uint64_t data; + + /* how many sections this module has */ + uint32_t num_sections; + + /* length of unwind data */ + uint32_t unwind_len; +}; + #ifdef STP_OLD_TRANSPORT /**** for compatibility with old relayfs ****/ struct _stp_buf_info diff --git a/runtime/transport/utt.c b/runtime/transport/utt.c index ac2e1513..182c1178 100644 --- a/runtime/transport/utt.c +++ b/runtime/transport/utt.c @@ -88,7 +88,7 @@ void utt_trace_cleanup(struct utt_trace *utt) if (utt->dropped_file) debugfs_remove(utt->dropped_file); utt_remove_tree(utt); - kfree(utt); + _stp_kfree(utt); } int utt_trace_remove(struct utt_trace *utt) @@ -207,7 +207,7 @@ struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts) goto err; ret = -ENOMEM; - utt = kzalloc(sizeof(*utt), GFP_KERNEL); + utt = _stp_kzalloc(sizeof(*utt)); if (!utt) goto err; @@ -251,7 +251,7 @@ err: debugfs_remove(utt->dropped_file); if (utt->rchan) relay_close(utt->rchan); - kfree(utt); + _stp_kfree(utt); } if (dir) utt_remove_tree(utt); diff --git a/stapfuncs.5.in b/stapfuncs.5.in index 3802117a..85a00b37 100644 --- a/stapfuncs.5.in +++ b/stapfuncs.5.in @@ -444,6 +444,29 @@ Convert from host to network byte order, 32-bit. htons:long (x:long) Convert from host to network byte order, 16-bit. +.SS SIGNAL +.TP +get_sa_flags:long (act:long) +Returns the numeric value of sa_flags. +.TP +get_sa_handler:long (act:long) +Returns the numeric value of sa_handler. +.TP +sigset_mask_str:string (mask:long) +Returns the string representation of the sigset sa_mask. +.TP +is_sig_blocked:long (task:long, sig:long) +Returns 1 if the signal is currently blocked, or 0 if it is not. +.TP +sa_flags_str:string (sa_flags:long) +Returns the string representation of sa_flags. +.TP +sa_handler_str(handler) +Returns the string representation of sa_handler. If it is not SIG_DFL, SIG_IGN +or SIG_ERR, it will return the address of the handler. +.TP +signal_str(num) +Returns the string representation of the given signal number. .SH FILES .nh diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 5519ef58..a7f8fdf8 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,16 @@ +2008-01-16 Eugene Teo <eteo@redhat.com> + + * signal.stp (get_sa_flags, get_sa_handler): New functions to + return addresses of sa_flags and sa_handler of struct k_sigaction. + (sigset_mask_str): New function. Returns a string containing the + set of signals to be blocked when executing the signal handler. + (is_sig_blocked): New function. Checks task_struct->blocked signal + mask for signals that are currently blocked. + (signal_str): New function. Translates a signal number. + (sa_flags_str): New function. Translates the sa_flags. + (sa_handler_str): New function. Returns the signal action or handler + associated to the signal. + 2008-1-4 Masami Hiramatsu <mhiramat@redhat.com> * aux_syscalls.stp (_stp_fork_list): Check kernel version for new diff --git a/tapset/signal.stp b/tapset/signal.stp index f472f370..ec947eb7 100644 --- a/tapset/signal.stp +++ b/tapset/signal.stp @@ -1,6 +1,7 @@ // Signal tapset // Copyright (C) 2006 IBM Corp. // Copyright (C) 2006 Intel Corporation. +// Copyright (C) 2008 Red Hat, Inc. // // 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 @@ -505,3 +506,165 @@ probe signal.flush = kernel.function("flush_signals") sig_pid = $t->pid pid_name = kernel_string($t->comm) } + +function get_sa_flags:long (act:long) %{ /* pure */ + struct k_sigaction *act = (struct k_sigaction *)((long)THIS->act); + THIS->__retvalue = kread(&act->sa.sa_flags); + CATCH_DEREF_FAULT(); +%} + +function get_sa_handler:long (act:long) %{ /* pure */ + struct k_sigaction *act = (struct k_sigaction *)((long)THIS->act); + THIS->__retvalue = (long)kread(&act->sa.sa_handler); + CATCH_DEREF_FAULT(); +%} + +/* + * sa_mask contains the set of signals to be blocked when executing the + * signal handler. This function returns a string, delimited by ",". + * + * struct task_struct { + * [...] + * struct signal_struct *signal; + * struct sighand_struct *sighand; + * [...] + * struct sighand_struct { + * atomic_t count; + * struct k_sigaction action[_NSIG]; + * [...] + * struct k_sigaction { + * struct sigaction sa; + * }; + * + * struct sigaction { + * [...] + * sigset_t sa_mask; + * }; + */ +function sigset_mask_str:string (mask:long) %{ /* pure */ + int i, len; + char *str = THIS->__retvalue, tmp[5]; + for (i = 1; i < _NSIG; ++i, THIS->mask >>=1) + if (THIS->mask & 1) { + sprintf(tmp, "%u,", i); + strlcat(str, tmp, MAXSTRINGLEN); + } + len = strlen(str); + if (len) str[len - 1] = '\0'; +%} + +/* + * task_struct->blocked signal mask contains the set of signals that are + * currently blocked. + * + * struct task_struct { + * [...] + * sigset_t blocked, real_blocked; + */ +function is_sig_blocked:long (task:long, sig:long) %{ /* pure */ + int i; + sigset_t blocked; + struct task_struct *p = (struct task_struct *)((long)THIS->task); + for (i = 0; i < _NSIG_WORDS; ++i) + blocked.sig[i] = kread(&p->blocked.sig[i]); + THIS->__retvalue = sigismember(&blocked, THIS->sig); + CATCH_DEREF_FAULT(); +%} + +function sa_flags_str:string (sa_flags:long) %{ /* pure */ + int len; + char *str = THIS->__retvalue; + if (THIS->sa_flags & 0x00000001u) strlcat(str, "NOCLDSTOP|", MAXSTRINGLEN); + if (THIS->sa_flags & 0x00000002u) strlcat(str, "NOCLDWAIT|", MAXSTRINGLEN); + if (THIS->sa_flags & 0x00000004u) strlcat(str, "SIGINFO|", MAXSTRINGLEN); + if (THIS->sa_flags & 0x08000000u) strlcat(str, "ONSTACK|", MAXSTRINGLEN); + if (THIS->sa_flags & 0x10000000u) strlcat(str, "RESTART|", MAXSTRINGLEN); + if (THIS->sa_flags & 0x40000000u) strlcat(str, "NODEFER|", MAXSTRINGLEN); + if (THIS->sa_flags & 0x80000000u) strlcat(str, "RESETHAND|", MAXSTRINGLEN); + if (THIS->sa_flags & 0x04000000) strlcat(str, "RESTORER|", MAXSTRINGLEN); + len = strlen(str); + if (len) str[len - 1] = '\0'; +%} + +function sa_handler_str(handler) { + if (handler == 0) return "default"; /* SIG_DFL */ + if (handler == 1) return "ignored"; /* SIG_IGN */ + if (handler == -1) return "error"; /* SIG_ERR */ + return sprintf("%p", handler); /* userspace address */ +} + +/* + * Signals start from 1 not 0. + */ +function signal_str(num) { + return __sig[num] +} + +global __sig[64] + +probe begin(-1) { + __sig[1] = "HUP" + __sig[2] = "INT" + __sig[3] = "QUIT" + __sig[4] = "ILL" + __sig[5] = "TRAP" + __sig[6] = "ABRT" /* or IOT */ + __sig[7] = "BUS" + __sig[8] = "FPE" + __sig[9] = "KILL" + __sig[10] = "USR1" + __sig[11] = "SEGV" + __sig[12] = "USR2" + __sig[13] = "PIPE" + __sig[14] = "ALRM" + __sig[15] = "TERM" + __sig[16] = "STKFLT" + __sig[17] = "CHLD" /* or CLD */ + __sig[18] = "CONT" + __sig[19] = "STOP" + __sig[20] = "TSTP" + __sig[21] = "TTIN" + __sig[22] = "TTOU" + __sig[23] = "URG" + __sig[24] = "XCPU" + __sig[25] = "XFSZ" + __sig[26] = "VTALRM" + __sig[27] = "PROF" + __sig[28] = "WINCH" + __sig[29] = "IO/POLL" + __sig[30] = "PWR" + __sig[31] = "SYS" /* or UNUSED */ + __sig[32] = "RTMIN" + __sig[33] = "RTMIN+1" + __sig[34] = "RTMIN+2" + __sig[35] = "RTMIN+3" + __sig[36] = "RTMIN+4" + __sig[37] = "RTMIN+5" + __sig[38] = "RTMIN+6" + __sig[39] = "RTMIN+7" + __sig[40] = "RTMIN+8" + __sig[41] = "RTMIN+9" + __sig[42] = "RTMIN+10" + __sig[43] = "RTMIN+11" + __sig[44] = "RTMIN+12" + __sig[45] = "RTMIN+13" + __sig[46] = "RTMIN+14" + __sig[47] = "RTMIN+15" + __sig[48] = "RTMIN+16" + __sig[49] = "RTMIN+17" + __sig[50] = "RTMIN+18" + __sig[51] = "RTMIN+19" + __sig[52] = "RTMIN+20" + __sig[53] = "RTMIN+21" + __sig[54] = "RTMIN+22" + __sig[55] = "RTMIN+23" + __sig[56] = "RTMIN+24" + __sig[57] = "RTMIN+25" + __sig[58] = "RTMIN+26" + __sig[59] = "RTMIN+27" + __sig[60] = "RTMIN+28" + __sig[61] = "RTMIN+29" + __sig[62] = "RTMIN+30" + __sig[63] = "RTMIN+31" + __sig[64] = "RTMIN+32" +} diff --git a/tapsets.cxx b/tapsets.cxx index ebc07ba3..84187960 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1343,14 +1343,15 @@ struct dwflpp dwfl_assert ("dwfl_addrmodule", mod == NULL); int n = dwfl_module_relocations (mod); dwfl_assert ("dwfl_module_relocations", n < 0); - if (n > 0) - { - int i = dwfl_module_relocate_address (mod, &address); - dwfl_assert ("dwfl_module_relocate_address", i < 0); - const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, - NULL, NULL, NULL, NULL); - dwfl_assert ("dwfl_module_info", modname == NULL); - const char *secname = dwfl_module_relocation_info (mod, i, NULL); + int i = dwfl_module_relocate_address (mod, &address); + dwfl_assert ("dwfl_module_relocate_address", i < 0); + const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, + NULL, NULL, NULL, NULL); + dwfl_assert ("dwfl_module_info", modname == NULL); + const char *secname = dwfl_module_relocation_info (mod, i, NULL); + + if (n > 0 && !(n == 1 && secname == NULL)) + { dwfl_assert ("dwfl_module_relocation_info", secname == NULL); if (n > 1 || secname[0] != '\0') { @@ -2137,6 +2138,7 @@ struct dwarf_query : public base_query int line, Dwarf_Die *scope_die, Dwarf_Addr addr); + string get_blacklist_section(Dwarf_Addr addr); set<string> blacklisted_probes; set<string> blacklisted_return_probes; @@ -2551,6 +2553,34 @@ dwarf_query::blacklisted_p(const string& funcname, return false; } +string dwarf_query::get_blacklist_section(Dwarf_Addr addr) +{ + Dwarf_Addr baseaddr; + string blacklist_section; + Elf* elf = dwfl_module_getelf (dw.module, & baseaddr); + Dwarf_Addr offset = addr - baseaddr; + if (elf) + { + Elf_Scn* scn = 0; + size_t shstrndx; + dw.dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (! shdr) continue; // XXX error? + + GElf_Addr start = shdr->sh_addr; + GElf_Addr end = start + shdr->sh_size; + if (! (offset >= start && offset < end)) + continue; + + blacklist_section = elf_strptr (elf, shstrndx, shdr->sh_name); + break; + } + } + return blacklist_section; +} void @@ -2577,43 +2607,13 @@ dwarf_query::add_probe_point(const string& funcname, if (r_s) reloc_section = r_s; blacklist_section = reloc_section; + + if(reloc_section == "" && dwfl_module_relocations (dw.module) == 1) + blacklist_section = this->get_blacklist_section(addr); } else { - // This is not a relocatable module, so addr is all set. To - // find the section name, must do this the long way - scan - // through elf section headers. - Dwarf_Addr baseaddr; - Elf* elf = dwfl_module_getelf (dw.module, & baseaddr); - Dwarf_Addr offset = addr - baseaddr; - // NB: this offset does not end up as reloc_addr, since the latter is - // only computed differently if load-time relocation is needed. For - // non-relocatable modules, this is not the case. - if (elf) - { - // Iterate through section headers to find which one - // contains the given offset. - Elf_Scn* scn = 0; - size_t shstrndx; - dw.dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (! shdr) continue; // XXX error? - - // check for address inclusion - GElf_Addr start = shdr->sh_addr; - GElf_Addr end = start + shdr->sh_size; - if (! (offset >= start && offset < end)) - continue; - - // check for section name - blacklist_section = elf_strptr (elf, shstrndx, shdr->sh_name); - break; - } - } - + blacklist_section = this->get_blacklist_section(addr); reloc_section = ""; } @@ -4800,6 +4800,25 @@ procfs_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) throw semantic_error ("invalid target symbol for procfs probe, $value expected", e->tok); + if (e->components.size() > 0) + { + switch (e->components[0].first) + { + case target_symbol::comp_literal_array_index: + throw semantic_error("procfs target variable '$value' may not be used as array", + e->tok); + break; + case target_symbol::comp_struct_member: + throw semantic_error("procfs target variable '$value' may not be used as a structure", + e->tok); + break; + default: + throw semantic_error ("invalid use of procfs target variable '$value'", + e->tok); + break; + } + } + bool lvalue = is_active_lvalue(e); if (write_probe && lvalue) throw semantic_error("procfs $value variable is read-only in a procfs write probe", e->tok); @@ -5044,6 +5063,24 @@ mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) if (is_active_lvalue (e)) throw semantic_error("write to marker parameter not permitted", e->tok); + if (e->components.size() > 0) + { + switch (e->components[0].first) + { + case target_symbol::comp_literal_array_index: + throw semantic_error("marker argument may not be used as array", + e->tok); + break; + case target_symbol::comp_struct_member: + throw semantic_error("marker argument may not be used as a structure", + e->tok); + break; + default: + throw semantic_error ("invalid marker argument use", e->tok); + break; + } + } + // Remember that we've seen a target variable. target_symbol_seen = true; @@ -5100,7 +5137,7 @@ mark_derived_probe::mark_derived_probe (systemtap_session &s, this->locations.push_back (pp); if (cond) - add_condition (cond); + add_condition (cond); insert_condition_statement (); // expand the signature string @@ -5845,6 +5882,25 @@ perfmon_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) if (e->base_name != "$counter") throw semantic_error ("target variables not available to perfmon probes"); + if (e->components.size() > 0) + { + switch (e->components[0].first) + { + case target_symbol::comp_literal_array_index: + throw semantic_error("perfmon probe '$counter' variable may not be used as array", + e->tok); + break; + case target_symbol::comp_struct_member: + throw semantic_error("perfmon probe '$counter' variable may not be used as a structure", + e->tok); + break; + default: + throw semantic_error ("invalid use of perfmon probe '$counter' variable", + e->tok); + break; + } + } + ec->code = "THIS->__retvalue = _pfm_pmd_x[" + lex_cast<string>(counter_number) + "].reg_num;"; ec->code += "/* pure */"; diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index d8439450..6dd0d8de 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,25 @@ +2008-01-17 David Smith <dsmith@redhat.com> + + * semko/procfs11.stp: Added test for invalid use of procfs probe + '$value' target variable. + * semko/procfs12.stp: Ditto. + +2008-01-16 David Smith <dsmith@redhat.com> + + PR 5608. + * systemtap.base/marker.exp: Added 2 tests for treating marker + arguments incorrectly. + +2008-01-16 Eugene Teo <eteo@redhat.com> + + * buildok/signal-embedded.stp: Add all new embedded C functions + in signal. + +2008-01-14 Frank Ch. Eigler <fche@elastic.org> + + PR 4935. + * systemtap.base/onoffprobe.*: Toughen test. + 2008-01-12 Frank Ch. Eigler <fche@elastic.org> * lib/systemtap.exp (get_system_info): Look for $builddir/SNAPSHOT too. diff --git a/testsuite/buildok/signal-embedded.stp b/testsuite/buildok/signal-embedded.stp index 5a0d9d8b..24e218e9 100755 --- a/testsuite/buildok/signal-embedded.stp +++ b/testsuite/buildok/signal-embedded.stp @@ -2,5 +2,10 @@ probe begin { print (get_sigset(0)) + print (get_sa_flags(0)) + print (get_sa_handler(0)) + print (sigset_mask_str(0)) + print (is_sig_blocked(0, 0)) + print (sa_flags_str(0)) } diff --git a/testsuite/semko/procfs11.stp b/testsuite/semko/procfs11.stp new file mode 100755 index 00000000..719346fb --- /dev/null +++ b/testsuite/semko/procfs11.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# use $value as a structure pointer in a procfs probe +probe procfs.write { print($value->foo) } diff --git a/testsuite/semko/procfs12.stp b/testsuite/semko/procfs12.stp new file mode 100755 index 00000000..c8af619b --- /dev/null +++ b/testsuite/semko/procfs12.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# use $value as an array in a procfs probe +probe procfs.write { print($value[0]) } diff --git a/testsuite/systemtap.base/marker.exp b/testsuite/systemtap.base/marker.exp index 01d1ed54..bfa3b02d 100644 --- a/testsuite/systemtap.base/marker.exp +++ b/testsuite/systemtap.base/marker.exp @@ -11,7 +11,7 @@ proc stap_compile { TEST_NAME compile script args } { set cmd [concat {stap -v -p4 -e} $script $args] - #puts "running $cmd" + puts "running $cmd" eval spawn $cmd set compile_errors 0 expect { @@ -47,9 +47,13 @@ proc stap_compile { TEST_NAME compile script args } { set kernel_markers_found 0 set kernel_marker_names {} +set num_marker_found 0 +set num_marker_name "" + set kernel_script {"probe kernel.mark(\"%s\") { }"} set kernel_script_arg {"probe kernel.mark(\"%s\") { print(%s) }"} set kernel_script_arg2 {"probe kernel.mark(\"%s\") { %s = 0 }"} +set kernel_script_arg3 {"probe kernel.mark(\"%s\") { print(\$arg1%s) }"} # Try to read in the marker list from the Module.markers file. set uname [exec /bin/uname -r] @@ -59,9 +63,17 @@ if {! [catch {open $path RDONLY} fl]} { while {[gets $fl s] >= 0} { # This regexp only picks up markers that contain arguments. # This helps ensure that K_MARKER04 passes correctly. - if [regexp {^([^ \t]+)\t[^ \t]+.*%.+$} $s match name] { + if [regexp {^([^ \t]+)\t[^ \t]+.*(%.+)$} $s match name fmt] { set kernel_markers_found 1 lappend kernel_marker_names $name + + # Look for a marker whose first argument is numeric + # (either '%d', '%u', or '%p'). If we find such a marker, + # we can run K_MARKER09 and K_MARKER10. + if {$num_marker_found == 0 && [regexp {^%[dup]} $fmt]} { + set num_marker_found 1 + set num_marker_name $name + } } } catch {close $fl} @@ -156,3 +168,27 @@ if {$kernel_markers_found == 0} { [lindex $kernel_marker_names 0] {\$arg1}] stap_compile $TEST_NAME 0 $script } + +set TEST_NAME "K_MARKER09" +if {$kernel_markers_found == 0} { + untested "$TEST_NAME : no kernel markers present" +} elseif {$num_marker_found == 0} { + untested "$TEST_NAME : no kernel marker found with a numeric first argument" +} else { + # Try compiling a script that treats its first marker argument + # as a structure (which isn't allowed). + set script [format $kernel_script_arg3 $num_marker_name "->foo"] + stap_compile $TEST_NAME 0 $script +} + +set TEST_NAME "K_MARKER10" +if {$kernel_markers_found == 0} { + untested "$TEST_NAME : no kernel markers present" +} elseif {$num_marker_found == 0} { + untested "$TEST_NAME : no kernel marker found with a numeric first argument" +} else { + # Try compiling a script that treats its first marker argument + # like an array (which isn't allowed). + set script [format $kernel_script_arg3 $num_marker_name {\[0\]}] + stap_compile $TEST_NAME 0 $script +} diff --git a/testsuite/systemtap.base/onoffprobe.exp b/testsuite/systemtap.base/onoffprobe.exp index 41e107d7..b86de4ea 100644 --- a/testsuite/systemtap.base/onoffprobe.exp +++ b/testsuite/systemtap.base/onoffprobe.exp @@ -4,54 +4,37 @@ if {![installtest_p]} { untested $test; return } spawn stap $srcdir/$subdir/$test.stp -m $test set pid $spawn_id set ok 0 + +proc advance {} { + global test + global expect_out + global ok + pass "$test $expect_out(1,string)" + incr ok + exec echo $ok > /proc/systemtap/$test/switch + exec echo dummy > /dev/null + exp_continue +} + expect { -timeout 240 - "begin probed\r\n" { - if {$ok == 0} { - incr ok - pass "conditional begin probe" - exec echo 1 > /proc/systemtap/$test/switch - exec echo "dummy" > /dev/null - exp_continue; - } - } - "function return probed\r\n" { - if {$ok == 1} { - incr ok - pass "conditional dwarf probe (return)" - exec echo 2 > /proc/systemtap/$test/switch - exec echo "dummy" > /dev/null - exp_continue; - } - } - "function entry probed\r\n" { - if {$ok == 2} { - incr ok - pass "conditional dwarf probe (entry)" - exec echo 3 > /proc/systemtap/$test/switch - exp_continue; - } - } - "timer probed\r\n" { - if {$ok == 3} { - incr ok - pass "conditional timer probe" - exec echo 4 > /proc/systemtap/$test/switch - exp_continue; - } - } - "profile probed\r\n" { - if {$ok == 4} { - incr ok - pass "conditional profile probe" - } + -re "(begin1 probed)\r\n" { advance } + -re "^(function return probed)\r\n" { advance } + -re "^(function entry probed)\r\n" { advance } + -re "^(timer probed)\r\n" { advance } + -re "^(profile probed)\r\n" { advance } + -re "^(alias\.one\.a and alias\.one and alias\.\* probed)\r\n" { advance } + -re "^(alias\.one\.b and alias\.one and alias\.\* probed)\r\n" { advance } + -re "^(alias\.two and alias\.\* probed)\r\n" { + pass "$test $expect_out(1,string)" + incr ok } - timeout { fail "$test (timeout)" } - eof { } + timeout { fail "$test (timeout)" } + eof { } } send "\003" #FIXME does not handle case of hanging pfaults.stp correctly wait exec rm -f $test.ko -if {$ok != 5} {fail "conditional probes ($ok)"} +if {$ok != 8} {fail "conditional probes ($ok)"} diff --git a/testsuite/systemtap.base/onoffprobe.stp b/testsuite/systemtap.base/onoffprobe.stp index 11968540..f7169039 100644 --- a/testsuite/systemtap.base/onoffprobe.stp +++ b/testsuite/systemtap.base/onoffprobe.stp @@ -1,34 +1,45 @@ -global switch=0 +global switch=-1 #begin probe +probe begin if (switch==-1) { + log("begin1 probed"); +} + probe begin if (switch==0) { - log("begin probed\n"); + log("begin2 probed"); } #dwarf probe (return) probe kernel.function("sys_write").return if (switch == 1) { - log("function return probed\n") + log("function return probed") switch = 0 } #dwarf probe (entry) probe kernel.function("sys_write") if (switch == 2) { - log("function entry probed\n") + log("function entry probed") switch = 0 } #timer probe probe timer.s(1) if (switch == 3) { - log("timer probed\n") + log("timer probed") switch = 0 } #profile probe probe timer.profile if (switch == 4) { - log("profile probed\n") + log("profile probed") switch = 0 } +# aliasess +probe alias.one.a = timer.s(2) if (switch == 5) { print("alias.one.a and") } +probe alias.one.b = timer.s(3) if (switch == 6) { print("alias.one.b and") } +probe alias.one = alias.one.* if (switch >= 5 && switch < 7) { print(" alias.one and") } +probe alias.two = timer.s(4) if (switch == 7) { print("alias.two and") } +probe alias.* if (switch) { log(" alias.* probed") } + probe procfs("switch").write { switch = strtol($value, 10) } diff --git a/translate.cxx b/translate.cxx index 27b28d5f..7f42ceec 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1,5 +1,5 @@ // translation pass -// Copyright (C) 2005-2007 Red Hat Inc. +// Copyright (C) 2005-2008 Red Hat Inc. // Copyright (C) 2005-2007 Intel Corporation. // // This file is part of systemtap, and is free software. You can @@ -1148,21 +1148,13 @@ c_unparser::emit_module_init () // Print a message to the kernel log about this module. This is // intended to help debug problems with systemtap modules. - o->newline() << "printk (KERN_DEBUG \"%s: " - << "systemtap: " << VERSION << "/" << dwfl_version (NULL) - << ", base: %p" - << ", memory: %lu+%lu+%lu+%lu+%lu data+text+ctx+io+glob" - << ", probes: " << session->probes.size() - << "\\n\"" - // printk arguments - << ", THIS_MODULE->name" - << ", THIS_MODULE->module_core" - << ", (unsigned long) (THIS_MODULE->core_size - THIS_MODULE->core_text_size)" - << ", (unsigned long) THIS_MODULE->core_text_size" - << ", (unsigned long) (num_online_cpus() * sizeof(struct context))" - << ", (unsigned long) _stp_allocated_net_memory" - << ", (unsigned long) _stp_allocated_memory" - << ");"; + + o->newline() << "_stp_print_kernel_info(" + << "\"" << VERSION + << "/" << dwfl_version (NULL) << "\"" + << ", (num_online_cpus() * sizeof(struct context))" + << ", " << session->probes.size() + << ");"; // Run all probe registrations. This actually runs begin probes. @@ -1298,6 +1290,7 @@ c_unparser::emit_module_exit () o->newline() << "_stp_printf (\"probe %s (%s), hits: %lld, cycles: %lldmin/%lldavg/%lldmax\\n\","; o->newline() << "probe_point, decl_location, (long long) stats->count, (long long) stats->min, (long long) avg, (long long) stats->max);"; o->newline(-1) << "}"; + o->newline() << "_stp_stat_del (time_" << p->name << ");"; o->newline(-1) << "}"; } } |