diff options
-rw-r--r-- | buildrun.cxx | 2 | ||||
-rwxr-xr-x | dtrace | 2 | ||||
-rw-r--r-- | runtime/autoconf-asm-syscall.c | 2 | ||||
-rw-r--r-- | runtime/loc2c-runtime.h | 11 | ||||
-rw-r--r-- | runtime/stack.c | 8 | ||||
-rw-r--r-- | runtime/sym.c | 3 | ||||
-rw-r--r-- | runtime/syscall.h | 298 | ||||
-rw-r--r-- | runtime/task_finder.c | 65 | ||||
-rw-r--r-- | tapset/utrace.stp | 8 | ||||
-rw-r--r-- | tapsets.cxx | 79 | ||||
-rw-r--r-- | testsuite/lib/systemtap.exp | 4 | ||||
-rw-r--r-- | testsuite/systemtap.base/bitfield.exp | 3 | ||||
-rw-r--r-- | testsuite/systemtap.base/bitfield.stp | 46 | ||||
-rw-r--r-- | testsuite/systemtap.base/labels.exp | 41 | ||||
-rw-r--r-- | testsuite/systemtap.base/stmt_rel.exp | 4 | ||||
-rw-r--r-- | testsuite/systemtap.base/uprobes_exe.c | 8 | ||||
-rw-r--r-- | testsuite/systemtap.base/uprobes_lib.c | 3 | ||||
-rw-r--r-- | testsuite/systemtap.base/uprobes_lib.exp | 13 | ||||
-rw-r--r-- | testsuite/systemtap.base/uprobes_lib.stp | 10 | ||||
-rw-r--r-- | testsuite/systemtap.base/uprobes_uname.exp | 46 | ||||
-rw-r--r-- | testsuite/systemtap.base/uprobes_uname.stp | 7 | ||||
-rwxr-xr-x | testsuite/systemtap.examples/network/nettop.stp | 8 | ||||
-rw-r--r-- | translate.cxx | 45 |
23 files changed, 482 insertions, 234 deletions
diff --git a/buildrun.cxx b/buildrun.cxx index 1eecb3f7..3c0d8f4b 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -168,6 +168,8 @@ compile_pass (systemtap_session& s) #endif output_autoconf(s, o, "autoconf-save-stack-trace.c", "STAPCONF_KERNEL_STACKTRACE", NULL); + output_autoconf(s, o, "autoconf-asm-syscall.c", + "STAPCONF_ASM_SYSCALL_H", NULL); o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl; @@ -94,7 +94,7 @@ class provider: ######################################################################## def usage (): - print "Usage " + sys.argv[0] + "[-h | -G] -s File.d -o File {Files}" + print "Usage " + sys.argv[0] + " [-h | -G] -s File.d -o File {Files}" sys.exit(1) def open_file (arg): diff --git a/runtime/autoconf-asm-syscall.c b/runtime/autoconf-asm-syscall.c new file mode 100644 index 00000000..bf7a273f --- /dev/null +++ b/runtime/autoconf-asm-syscall.c @@ -0,0 +1,2 @@ +#include <asm/syscall.h> + diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index eaf47cad..620e1615 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -29,11 +29,12 @@ & (((__typeof (base)) 1 << (nbits)) - 1)) #define store_bitfield(target, base, higherbits, nbits) \ - target = (target \ - &~ ((((__typeof (base)) 1 << (nbits)) - 1) \ - << (sizeof (base) * 8 - (higherbits) - (nbits))) \ - | ((__typeof (base)) (base) \ - << (sizeof (base) * 8 - (higherbits) - (nbits)))) + target = ((target \ + &~ ((((__typeof (target)) 1 << (nbits)) - 1) \ + << (sizeof (target) * 8 - (higherbits) - (nbits)))) \ + | ((((__typeof (target)) (base)) \ + & (((__typeof (target)) 1 << (nbits)) - 1)) \ + << (sizeof (target) * 8 - (higherbits) - (nbits)))) /* Given a DWARF register number, fetch its intptr_t (long) value from the diff --git a/runtime/stack.c b/runtime/stack.c index f6b1cd08..68fb9b1f 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -97,6 +97,12 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve &print_data); } #endif + +// Without KPROBES very little works atm. +// But this file is unconditionally imported, while these two functions are only +// used through context-unwind.stp. +#if defined (CONFIG_KPROBES) + /** Prints the stack backtrace * @param regs A pointer to the struct pt_regs. */ @@ -141,6 +147,8 @@ static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int ve pb->len = 0; } +#endif /* CONFIG_KPROBES */ + /** Prints the user stack backtrace * @param str string * @returns Same string as was input with trace info appended, diff --git a/runtime/sym.c b/runtime/sym.c index 835e1b46..a2cdd0ff 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -47,7 +47,7 @@ static int _stp_tf_mmap_cb(struct stap_task_finder_target *tgt, #ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, "mmap_cb: tsk %d:%d path %s, addr 0x%08lx, length 0x%08lx, offset 0x%lx, flags 0x%lx\n", - tsk->pid, tsk->tgid, path, addr, length, offset, flags); + tsk->pid, tsk->tgid, path, addr, length, offset, vm_flags); #endif if (path != NULL) { for (i = 0; i < _stp_num_modules; i++) { @@ -128,7 +128,6 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio return 0; } - /* Return module owner and, if sec != NULL, fills in closest section of the address if found, return NULL otherwise. XXX: needs to be address-space-specific. */ diff --git a/runtime/syscall.h b/runtime/syscall.h index ae451070..6d22ba83 100644 --- a/runtime/syscall.h +++ b/runtime/syscall.h @@ -1,5 +1,6 @@ -/* syscall defines and inlines - * Copyright (C) 2008 Red Hat Inc. +/* + * syscall defines and inlines + * Copyright (C) 2008-2009 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 @@ -89,9 +90,17 @@ #error "Unimplemented architecture" #endif +#ifdef STAPCONF_ASM_SYSCALL_H + +/* If the system has asm/syscall.h, use defines from it. */ +#include <asm/syscall.h> + +#else /* !STAPCONF_ASM_SYSCALL_H */ + +/* If the system doesn't have asm/syscall.h, use our defines. */ #if defined(__i386__) || defined(__x86_64__) -static inline unsigned long -__stp_user_syscall_nr(struct pt_regs *regs) +static inline long +syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { #if defined(STAPCONF_X86_UNIREGS) return regs->orig_ax; @@ -104,37 +113,37 @@ __stp_user_syscall_nr(struct pt_regs *regs) #endif #if defined(__powerpc__) -static inline unsigned long -__stp_user_syscall_nr(struct pt_regs *regs) +static inline long +syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { return regs->gpr[0]; } #endif #if defined(__ia64__) -static inline unsigned long -__stp_user_syscall_nr(struct pt_regs *regs) +static inline long +syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { return regs->r15; } #endif #if defined(__s390__) || defined(__s390x__) -static inline unsigned long -__stp_user_syscall_nr(struct pt_regs *regs) +static inline long +syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { - // might need to be 'orig_gpr2' + // might need to be 'orig_gpr2' return regs->gprs[2]; } #endif #if defined(__i386__) || defined(__x86_64__) -static inline long * -__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) +static inline long +syscall_get_return_value(struct task_struct *task, struct pt_regs *regs) { #ifdef CONFIG_IA32_EMULATION // This code works, but isn't what we need. Since -// __stp_user_syscall_arg() doesn't sign-extend, a value passed in as +// syscall_get_syscall_arg() doesn't sign-extend, a value passed in as // an argument and then returned won't compare correctly anymore. So, // for now, disable this code. # if 0 @@ -145,158 +154,233 @@ __stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) # endif #endif #if defined(STAPCONF_X86_UNIREGS) - return ®s->ax; + return regs->ax; #elif defined(__x86_64__) - return ®s->rax; + return regs->rax; #elif defined (__i386__) - return ®s->eax; + return regs->eax; #endif } #endif #if defined(__powerpc__) -static inline long * -__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) +static inline long +syscall_get_return_value(struct task_struct *task, struct pt_regs *regs) { - return ®s->gpr[3]; + return regs->gpr[3]; } #endif #if defined(__ia64__) -static inline long * -__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) +static inline long +syscall_get_return_value(struct task_struct *task, struct pt_regs *regs) { - return ®s->r8; + return regs->r8; } #endif #if defined(__s390__) || defined(__s390x__) -static inline long * -__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) +static inline long +syscall_get_return_value(struct task_struct *task, struct pt_regs *regs) { - return ®s->gprs[2]; + return regs->gprs[2]; } #endif #if defined(__i386__) || defined(__x86_64__) -static inline long * -__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, - unsigned int n) +static inline void +syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, unsigned long *args) { -#if defined(__i386__) - if (n > 5) { - _stp_error("syscall arg > 5"); - return NULL; + if (i + n > 6) { + _stp_error("invalid syscall arg request"); + return; } +#if defined(__i386__) #if defined(STAPCONF_X86_UNIREGS) - return ®s->bx + n; + memcpy(args, ®s->bx + i, n * sizeof(args[0])); #else - return ®s->ebx + n; + memcpy(args, ®s->ebx + i, n * sizeof(args[0])); #endif #elif defined(__x86_64__) #ifdef CONFIG_IA32_EMULATION - if (test_tsk_thread_flag(task, TIF_IA32)) - switch (n) { + if (test_tsk_thread_flag(task, TIF_IA32)) { + switch (i) { #if defined(STAPCONF_X86_UNIREGS) - case 0: return ®s->bx; - case 1: return ®s->cx; - case 2: return ®s->dx; - case 3: return ®s->si; - case 4: return ®s->di; - case 5: return ®s->bp; + case 0: + if (!n--) break; + *args++ = regs->bx; + case 1: + if (!n--) break; + *args++ = regs->cx; + case 2: + if (!n--) break; + *args++ = regs->dx; + case 3: + if (!n--) break; + *args++ = regs->si; + case 4: + if (!n--) break; + *args++ = regs->di; + case 5: + if (!n--) break; + *args++ = regs->bp; #else - case 0: return ®s->rbx; - case 1: return ®s->rcx; - case 2: return ®s->rdx; - case 3: return ®s->rsi; - case 4: return ®s->rdi; - case 5: return ®s->rbp; + case 0: + if (!n--) break; + *args++ = regs->rbx; + case 1: + if (!n--) break; + *args++ = regs->rcx; + case 2: + if (!n--) break; + *args++ = regs->rdx; + case 3: + if (!n--) break; + *args++ = regs->rsi; + case 4: + if (!n--) break; + *args++ = regs->rdi; + case 5: + if (!n--) break; + *args++ = regs->rbp; #endif - default: - _stp_error("syscall arg > 5"); - return NULL; } + return; + } #endif /* CONFIG_IA32_EMULATION */ - switch (n) { + switch (i) { #if defined(STAPCONF_X86_UNIREGS) - case 0: return ®s->di; - case 1: return ®s->si; - case 2: return ®s->dx; - case 3: return ®s->r10; - case 4: return ®s->r8; - case 5: return ®s->r9; + case 0: + if (!n--) break; + *args++ = regs->di; + case 1: + if (!n--) break; + *args++ = regs->si; + case 2: + if (!n--) break; + *args++ = regs->dx; + case 3: + if (!n--) break; + *args++ = regs->r10; + case 4: + if (!n--) break; + *args++ = regs->r8; + case 5: + if (!n--) break; + *args++ = regs->r9; #else - case 0: return ®s->rdi; - case 1: return ®s->rsi; - case 2: return ®s->rdx; - case 3: return ®s->r10; - case 4: return ®s->r8; - case 5: return ®s->r9; + case 0: + if (!n--) break; + *args++ = regs->rdi; + case 1: + if (!n--) break; + *args++ = regs->rsi; + case 2: + if (!n--) break; + *args++ = regs->rdx; + case 3: + if (!n--) break; + *args++ = regs->r10; + case 4: + if (!n--) break; + *args++ = regs->r8; + case 5: + if (!n--) break; + *args++ = regs->r9; #endif - default: - _stp_error("syscall arg > 5"); - return NULL; } #endif /* CONFIG_X86_32 */ + return; } #endif #if defined(__powerpc__) -static inline long * -__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, - unsigned int n) +static inline void +syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, unsigned long *args) { - switch (n) { - case 0: return ®s->gpr[3]; - case 1: return ®s->gpr[4]; - case 2: return ®s->gpr[5]; - case 3: return ®s->gpr[6]; - case 4: return ®s->gpr[7]; - case 5: return ®s->gpr[8]; - default: - _stp_error("syscall arg > 5"); - return NULL; + if (i + n > 6) { + _stp_error("invalid syscall arg request"); + return; } + memcpy(args, ®s->gpr[3 + i], n * sizeof(args[0])); } #endif #if defined(__ia64__) -#define __stp_user_syscall_arg(task, regs, n) \ - ____stp_user_syscall_arg(task, regs, n, &c->unwaddr) +#define syscall_get_arguments(task, regs, i, n, args) \ + __ia64_syscall_get_arguments(task, regs, i, n, args, &c->unwaddr) -static inline long * -____stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, - unsigned int n, unsigned long **cache) +static inline void +__ia64_syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args, unsigned long **cache) { - if (n > 5) { - _stp_error("syscall arg > 5"); - return NULL; + if (i + n > 6) { + _stp_error("invalid syscall arg request"); + return; + } + switch (i) { + case 0: + if (!n--) break; + *args++ = *__ia64_fetch_register(i + 32, regs, cache); + case 1: + if (!n--) break; + *args++ = *__ia64_fetch_register(i + 33, regs, cache); + case 2: + if (!n--) break; + *args++ = *__ia64_fetch_register(i + 34, regs, cache); + case 3: + if (!n--) break; + *args++ = *__ia64_fetch_register(i + 35, regs, cache); + case 4: + if (!n--) break; + *args++ = *__ia64_fetch_register(i + 36, regs, cache); + case 5: + if (!n--) break; + *args++ = *__ia64_fetch_register(i + 37, regs, cache); } - return __ia64_fetch_register(n + 32, regs, cache); } #endif #if defined(__s390__) || defined(__s390x__) -static inline long * -__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, - unsigned int n) +static inline void +syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, unsigned long *args) { - /* If we were returning a value, we could check for TIF_31BIT - * here and cast the value with '(u32)' to make sure it got - * down to 32bits. But, since we're returning an address, - * there isn't much we can do. */ - switch (n) { - case 0: return ®s->orig_gpr2; - case 1: return ®s->gprs[3]; - case 2: return ®s->gprs[4]; - case 3: return ®s->gprs[5]; - case 4: return ®s->gprs[6]; - case 5: return ®s->args[0]; - default: - _stp_error("syscall arg > 5"); - return NULL; + unsigned long mask = -1UL; + + if (i + n > 6) { + _stp_error("invalid syscall arg request"); + return; + } +#ifdef CONFIG_COMPAT + if (test_tsk_thread_flag(task, TIF_31BIT)) + mask = 0xffffffff; +#endif + switch (i) { + case 0: + if (!n--) break; + *args++ = regs->orig_gpr2 & mask; + case 1: + if (!n--) break; + *args++ = regs->gprs[3] & mask; + case 2: + if (!n--) break; + *args++ = regs->gprs[4] & mask; + case 3: + if (!n--) break; + *args++ = regs->gprs[5] & mask; + case 4: + if (!n--) break; + *args++ = regs->gprs[6] & mask; + case 5: + if (!n--) break; + *args++ = regs->args[0] & mask; } } #endif +#endif /* !STAPCONF_ASM_SYSCALL_H */ #endif /* _SYSCALL_H_ */ diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 69b6246b..fa6c296e 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -2,8 +2,9 @@ #define TASK_FINDER_C #if ! defined(CONFIG_UTRACE) -#error "Need CONFIG_UTRACE!" -#endif +/* Dummy definitions for use in sym.c */ +struct stap_task_finder_target { }; +#else #include <linux/utrace.h> @@ -178,7 +179,7 @@ stap_register_task_finder_target(struct stap_task_finder_target *new_tgt) && strcmp(tgt->pathname, new_tgt->pathname) == 0) /* pid-based target (a specific pid or all * pids) */ - || (new_tgt->pathlen == 0 + || (new_tgt->pathlen == 0 && tgt->pathlen == 0 && tgt->pid == new_tgt->pid))) { found_node = 1; break; @@ -1064,11 +1065,9 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, #endif { struct stap_task_finder_target *tgt = engine->data; - unsigned long syscall_no; - unsigned long *rv_addr, rv; - unsigned long *arg_addr, arg0; - unsigned long arg1 = 0; - unsigned long arg2 = 0; + long syscall_no; + unsigned long rv; + unsigned long args[3]; int rc; struct mm_struct *mm; struct vm_area_struct *vma; @@ -1087,7 +1086,7 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, // See if syscall is one we're interested in. // // FIXME: do we need to handle mremap()? - syscall_no = __stp_user_syscall_nr(regs); + syscall_no = syscall_get_nr(tsk, regs); if (syscall_no != MMAP_SYSCALL_NO(tsk) && syscall_no != MMAP2_SYSCALL_NO(tsk) && syscall_no != MPROTECT_SYSCALL_NO(tsk) @@ -1105,21 +1104,11 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, return UTRACE_RESUME; // Get return value - rv_addr = __stp_user_syscall_return_value(tsk, regs); - if ((rc = __stp_get_user(rv, rv_addr)) != 0) { - _stp_error("couldn't read syscall return value for pid %d: %d", - tsk->pid, rc); - return UTRACE_RESUME; - } + rv = syscall_get_return_value(tsk, regs); // We need the first syscall argument to see what address we // were operating on. - arg_addr = __stp_user_syscall_arg(tsk, regs, 0); - if ((rc = __stp_get_user(arg0, arg_addr)) != 0) { - _stp_error("couldn't read syscall arg 0 for pid %d: %d", - tsk->pid, rc); - return UTRACE_RESUME; - } + syscall_get_arguments(tsk, regs, 0, 1, args); #ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, @@ -1130,20 +1119,15 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, : ((syscall_no == MPROTECT_SYSCALL_NO(tsk)) ? "mprotect" : ((syscall_no == MUNMAP_SYSCALL_NO(tsk)) ? "munmap" : "UNKNOWN")))), - arg0, rv); + args[0], rv); #endif __stp_tf_handler_start(); if (syscall_no == MUNMAP_SYSCALL_NO(tsk)) { // We need the 2nd syscall argument for the length. - arg_addr = __stp_user_syscall_arg(tsk, regs, 1); - if ((rc = __stp_get_user(arg1, arg_addr)) != 0) { - _stp_error("couldn't read syscall arg 1 for pid %d: %d", - tsk->pid, rc); - goto syscall_exit_done; - } + syscall_get_arguments(tsk, regs, 1, 1, &args[1]); // Call the callbacks - __stp_call_munmap_callbacks(tgt, tsk, arg0, arg1); + __stp_call_munmap_callbacks(tgt, tsk, args[0], args[1]); } else if (syscall_no == MMAP_SYSCALL_NO(tsk) || syscall_no == MMAP2_SYSCALL_NO(tsk)) { @@ -1164,24 +1148,13 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, } } else { - // We need the 2nd syscall argument for the length. - arg_addr = __stp_user_syscall_arg(tsk, regs, 1); - if ((rc = __stp_get_user(arg1, arg_addr)) != 0) { - _stp_error("couldn't read syscall arg 1 for pid %d: %d", - tsk->pid, rc); - goto syscall_exit_done; - } - - // We need the 3nd syscall argument for the protection. - arg_addr = __stp_user_syscall_arg(tsk, regs, 2); - if ((rc = __stp_get_user(arg2, arg_addr)) != 0) { - _stp_error("couldn't read syscall arg 2 for pid %d: %d", - tsk->pid, rc); - goto syscall_exit_done; - } + // We need the 2nd syscall argument for the length and + // the 3rd argument for the protection. + syscall_get_arguments(tsk, regs, 1, 2, &args[1]); // Call the callbacks - __stp_call_mprotect_callbacks(tgt, tsk, arg0, arg1, arg2); + __stp_call_mprotect_callbacks(tgt, tsk, args[0], args[1], + args[2]); } syscall_exit_done: @@ -1324,5 +1297,5 @@ stap_stop_task_finder(void) debug_task_finder_report(); } - +#endif /* defined(CONFIG_UTRACE) */ #endif /* TASK_FINDER_C */ diff --git a/tapset/utrace.stp b/tapset/utrace.stp index 34cb32c5..00f427e6 100644 --- a/tapset/utrace.stp +++ b/tapset/utrace.stp @@ -6,13 +6,15 @@ %} function _utrace_syscall_nr:long () %{ - THIS->__retvalue = __stp_user_syscall_nr(CONTEXT->regs); /* pure */ + THIS->__retvalue = syscall_get_nr(current, CONTEXT->regs); /* pure */ %} function _utrace_syscall_arg:long (n:long) %{ - THIS->__retvalue = *__stp_user_syscall_arg(current, CONTEXT->regs, (int)THIS->n); /* pure */ + unsigned long arg = 0; /* pure */ + syscall_get_arguments(current, CONTEXT->regs, (int)THIS->n, 1, &arg); + THIS->__retvalue = arg; %} function _utrace_syscall_return:long () %{ - THIS->__retvalue = *__stp_user_syscall_return_value(current, CONTEXT->regs); /* pure */ + THIS->__retvalue = syscall_get_return_value(current, CONTEXT->regs); /* pure */ %} diff --git a/tapsets.cxx b/tapsets.cxx index 04402a27..c63151e1 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1339,7 +1339,12 @@ struct dwflpp } void - iterate_over_cu_labels (string label_val, Dwarf_Die *cu, void *data, + iterate_over_cu_labels (string label_val, + string function, + Dwarf_Die *cu, + vector<derived_probe *> & results, + probe_point *base_loc, + void *data, void (* callback)(const string &, const char *, int, @@ -1364,14 +1369,30 @@ struct dwflpp Dwarf_Attribute *attr = dwarf_attr (&die, DW_AT_name, &attr_mem); int tag = dwarf_tag(&die); const char *name = dwarf_formstring (attr); - if (tag == DW_TAG_subprogram && name != 0) + if (name == 0) + continue; + switch (tag) { + case DW_TAG_label: + break; + case DW_TAG_subprogram: function_name = name; + default: + if (dwarf_haschildren (&die)) + iterate_over_cu_labels (label_val, function, &die, results, base_loc, q, callback); + continue; + } + + if (strcmp(function_name.c_str(), function.c_str()) == 0 + || (name_has_wildcard(function) + && function_name_matches_pattern (function_name, function))) + { } - else if (tag == DW_TAG_label && name != 0 - && ((strncmp(name, sym, strlen(sym)) == 0) - || (name_has_wildcard (sym) - && function_name_matches_pattern (name, sym)))) + else + continue; + if (strcmp(name, sym) == 0 + || (name_has_wildcard(sym) + && function_name_matches_pattern (name, sym))) { const char *file = dwarf_decl_file (&die); // Get the line number for this label @@ -1403,19 +1424,18 @@ struct dwflpp int nscopes = 0; nscopes = dwarf_getscopes_die (&die, &scopes); if (nscopes > 1) - callback(function_name.c_str(), file, - (int)dline, &scopes[1], stmt_addr, q); - } - if (dwarf_haschildren (&die) && tag != DW_TAG_structure_type - && tag != DW_TAG_union_type) - { - iterate_over_cu_labels (label_val, &die, q, callback); + { + callback(function_name.c_str(), file, + (int)dline, &scopes[1], stmt_addr, q); + if (sess.listing_mode) + results.back()->locations[0]->components.push_back + (new probe_point::component(TOK_LABEL, new literal_string (name))); + } } } while (dwarf_siblingof (&die, &die) == 0); } - void collect_srcfiles_matching (string const & pattern, set<char const *> & filtered_srcfiles) { @@ -1986,7 +2006,7 @@ struct dwflpp Dwarf_Die *die_mem, Dwarf_Attribute *attr_mem) { - Dwarf_Die *die = die_mem; + Dwarf_Die *die = NULL; Dwarf_Die struct_die; Dwarf_Attribute temp_attr; @@ -1995,6 +2015,9 @@ struct dwflpp if (vardie) *die_mem = *vardie; + if (e->components.empty()) + return die_mem; + static unsigned int func_call_level ; static unsigned int dwarf_error_flag ; // indicates current error is dwarf error static unsigned int dwarf_error_count ; // keeps track of no of dwarf errors @@ -2011,6 +2034,7 @@ struct dwflpp obstack_printf (pool, "c->last_stmt = %s;", lex_cast_qstring(piece).c_str()); #endif + die = die ? dwarf_formref_die (attr_mem, die_mem) : die_mem; const int typetag = dwarf_tag (die); switch (typetag) { @@ -2168,7 +2192,6 @@ struct dwflpp /* Now iterate on the type in DIE's attribute. */ if (dwarf_attr_integrate (die, DW_AT_type, attr_mem) == NULL) throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1)), e->tok); - die = dwarf_formref_die (attr_mem, die_mem); } return die; } @@ -2414,13 +2437,12 @@ struct dwflpp /* Translate the ->bar->baz[NN] parts. */ - Dwarf_Die die_mem, *die = NULL; - die = dwarf_formref_die (&attr_mem, &die_mem); + Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); die = translate_components (&pool, &tail, pc, e, die, &die_mem, &attr_mem); if(!die) { - die = dwarf_formref_die (&attr_mem, &vardie); + die = dwarf_formref_die (&attr_mem, &die_mem); stringstream alternatives; if (die != NULL) print_members(die,alternatives); @@ -2496,17 +2518,19 @@ struct dwflpp /* Translate the ->bar->baz[NN] parts. */ Dwarf_Attribute attr_mem; - Dwarf_Attribute *attr = dwarf_attr (scope_die, DW_AT_type, &attr_mem); - - Dwarf_Die vardie_mem; - Dwarf_Die *vardie = dwarf_formref_die (attr, &vardie_mem); + if (dwarf_attr_integrate (scope_die, DW_AT_type, &attr_mem) == NULL) + throw semantic_error("failed to retrieve return value type attribute for " + + string(dwarf_diename(scope_die) ?: "<unknown>") + + "(" + string(dwarf_diename(cu) ?: "<unknown>") + + ")", + e->tok); - Dwarf_Die die_mem, *die = NULL; + Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); die = translate_components (&pool, &tail, pc, e, - vardie, &die_mem, &attr_mem); + die, &die_mem, &attr_mem); if(!die) { - die = dwarf_formref_die (&attr_mem, vardie); + die = dwarf_formref_die (&attr_mem, &die_mem); stringstream alternatives; if (die != NULL) print_members(die,alternatives); @@ -4110,7 +4134,7 @@ query_cu (Dwarf_Die * cudie, void * arg) { // If we have a pattern string with target *label*, we // have to look at labels in all the matched srcfiles. - q->dw.iterate_over_cu_labels (q->label_val, q->dw.cu, q, query_statement); + q->dw.iterate_over_cu_labels (q->label_val, q->function, q->dw.cu, q->results, q->base_loc, q, query_statement); } else { @@ -6474,6 +6498,7 @@ itrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(); s.op->newline() << "/* ---- itrace probes ---- */"; + s.op->newline() << "struct stap_itrace_probe {"; s.op->indent(1); s.op->newline() << "struct stap_task_finder_target tgt;"; diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index 43116a85..019b1bf8 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -85,7 +85,7 @@ proc setup_server {} { # Make sure that the necessary resources are available to run the client/server. if {[installtest_p]} then { - if {[exec /usr/bin/which stap-client-connect] == ""} then { + if {[catch {exec /usr/bin/which stap-client-connect} dummy]} then { print "Unable to start a server: stap-client-connect is not found in PATH" return 0 } @@ -93,7 +93,7 @@ proc setup_server {} { print "Unable to start a server: [exec pwd]/../stap-client-connect is not found" return 0 } - if {[exec /usr/bin/which avahi-publish-service] == ""} then { + if {[catch {exec /usr/bin/which avahi-publish-service} dummy]} then { print "Unable to start a server: avahi-publish-service is not found in PATH" return 0 } diff --git a/testsuite/systemtap.base/bitfield.exp b/testsuite/systemtap.base/bitfield.exp new file mode 100644 index 00000000..16451369 --- /dev/null +++ b/testsuite/systemtap.base/bitfield.exp @@ -0,0 +1,3 @@ +# test that bitfield r/w works correctly +set test "bitfield" +stap_run $srcdir/$subdir/$test.stp no_load $all_pass_string -g diff --git a/testsuite/systemtap.base/bitfield.stp b/testsuite/systemtap.base/bitfield.stp new file mode 100644 index 00000000..c2ff4929 --- /dev/null +++ b/testsuite/systemtap.base/bitfield.stp @@ -0,0 +1,46 @@ +%{ +#include <linux/tcp.h> +static struct tcphdr foo = {0}; +%} + +function get_ptr:long() %{ THIS->__retvalue = (long)&foo; /* pure */ %} +function get_ack:long() %{ THIS->__retvalue = foo.ack; /* pure */ %} +function get_urg:long() %{ THIS->__retvalue = foo.urg; /* pure */ %} + +function check:long(ack:long, urg:long) { + ptr = get_ptr() + + /* set the bits with cast */ + @cast(ptr, "tcphdr")->ack = ack + @cast(ptr, "tcphdr")->urg = urg + + /* check that reading with embedded-C is ok */ + real_ack = get_ack() + real_urg = get_urg() + errors = (ack != real_ack) + (urg != real_urg) + + /* check that reading with a cast is ok */ + cast_ack = @cast(ptr, "tcphdr")->ack + cast_urg = @cast(ptr, "tcphdr")->urg + errors += (ack != cast_ack) + (urg != cast_urg) + + if (errors) + printf("bitfield had %d errors; expect(%d%d), real(%d%d), cast(%d%d)\n", + errors, ack, urg, real_ack, real_urg, cast_ack, cast_urg) + + return errors +} + +probe begin { + println("systemtap starting probe") + + errors = check(0, 0) + errors += check(0, 1) + errors += check(1, 0) + errors += check(1, 1) + + println("systemtap ending probe") + if (errors == 0) + println("systemtap test success") + exit() +} diff --git a/testsuite/systemtap.base/labels.exp b/testsuite/systemtap.base/labels.exp index 2f79a502..88ed4619 100644 --- a/testsuite/systemtap.base/labels.exp +++ b/testsuite/systemtap.base/labels.exp @@ -10,15 +10,22 @@ set label_flags "additional_flags=-g" set fp [open $label_srcpath "w"] puts $fp " int +foo () +{ +init_an_int: + return 1; +} +int main () { sleep(5); + foo(); int a = 0; int b = 0; char *c; init_an_int: a = 2; -init_another_int: +init_an_int_again: b = 3; c = \"abc\"; ptr_inited: @@ -30,8 +37,9 @@ close $fp set label_stppath "[pwd]/labels.stp" set fp [open $label_stppath "w"] puts $fp " -probe process(\"labels.x\").function(\"main*@labels.c\").label(\"init_*\") {printf (\"VARS %s\\n\",\$\$vars)} -probe process(\"labels.x\").function(\"main*@labels.c\").label(\"ptr_inited\") {printf (\"VARS %s\\n\",\$\$vars)} +probe process(\"labels.x\").function(\"main@labels.c\").label(\"init_*\") {printf (\"VARS %s\\n\",\$\$vars)} +probe process(\"labels.x\").function(\"main@labels.c\").label(\"ptr_inited\") {printf (\"VARS %s\\n\",\$\$vars)} +probe process(\"labels.x\").function(\"main@labels.c\").label(\"init_an_int\") {printf (\"init_an_int\\n\")} " close $fp @@ -47,20 +55,35 @@ if { $res != "" } { pass "compiling labels.c -g" } +# list of labels + +spawn stap -l "process(\"$label_exepath\").function(\"*\").label(\"*\")" + +wait +expect { + -timeout 180 + -re {process.*function.*labels.c:5...label..init_an_int.*process.*function.*labels.c:16...label..init_an_int.*process.*function.*labels.c:18...label..init_an_int_again} { incr ok; exp_continue } + timeout { fail "$test (timeout)" } + eof { } +} + +if {$ok == 1} { pass "$test -l .label" } { fail "$test -l .label $ok" } + # label in an executable +set ok 0 verbose -log "spawn stap -c $label_exepath $label_stppath" spawn stap -c $label_exepath $label_stppath wait expect { -timeout 180 - -re {VARS a=0x0 b=0x0.*VARS a=0x2 b=0x0.*VARS a=0x2 b=0x3 c=0x[a-f01-9]} { incr ok; exp_continue } + -re {VARS a=0x0 b=0x0.*init_an_int.*VARS a=0x2 b=0x0.*VARS a=0x2 b=0x3 c=0x[a-f01-9]} { incr ok; exp_continue } timeout { fail "$test (timeout)" } eof { } } -if {$ok == 1} { pass "$test exe .label" } { fail "$test exe .label" } +if {$ok == 1} { pass "$test exe .label" } { fail "$test exe .label $ok" } # address of label in an executable @@ -68,7 +91,7 @@ set label_shpath "[pwd]/label.sh" set fp [open $label_shpath "w"] puts $fp " readelf --debug-dump $label_exepath | awk \" -/init_another_int/ {have_label=1} +/init_an_int_again/ {have_label=1} /DW_AT_low_pc/ {if (have_label) {print \$3;exit;}} \" " @@ -103,7 +126,7 @@ if { $res != "" } { # label in a shared object -spawn stap -p2 -l "process\(\"$label_sopath\"\).function\(\"\*\"\).label\(\"init_another_int\"\)" +spawn stap -p2 -l "process\(\"$label_sopath\"\).function\(\"\*\"\).label\(\"init_an_int_again\"\)" expect { -timeout 180 -re {process.*function} { incr ok; exp_continue } @@ -111,7 +134,7 @@ expect { eof { } } -if {$ok == 1} { pass "$test so .label" } { fail "$test so .label" } +if {$ok == 1} { pass "$test so .label" } { fail "$test so .label $ok" } # address of label in a shared object @@ -119,7 +142,7 @@ set label_shpath "[pwd]/label.sh" set fp [open $label_shpath "w"] puts $fp " readelf --debug-dump $label_sopath | awk \" -/init_another_int/ {have_label=1} +/init_an_int_again/ {have_label=1} /DW_AT_low_pc/ {if (have_label) {print \$3;exit;}} \" " diff --git a/testsuite/systemtap.base/stmt_rel.exp b/testsuite/systemtap.base/stmt_rel.exp index ec12e484..619c91a5 100644 --- a/testsuite/systemtap.base/stmt_rel.exp +++ b/testsuite/systemtap.base/stmt_rel.exp @@ -33,7 +33,9 @@ expect { eof { } } -if { $ok == 3 } { +# bio_init drifts a bit in different kernels. +# maybe 3, 4 or 15 lines in it. +if { $ok >= 3 } { pass "$test wildcard" } else { fail "$test wildcard ($ok)" diff --git a/testsuite/systemtap.base/uprobes_exe.c b/testsuite/systemtap.base/uprobes_exe.c index 447434c6..b4811335 100644 --- a/testsuite/systemtap.base/uprobes_exe.c +++ b/testsuite/systemtap.base/uprobes_exe.c @@ -15,13 +15,15 @@ int lib_main (void); void main_func (int foo) { - ; // nothing here... + if (foo > 1) + main_func (foo - 1); + else + lib_main(); } int main (int argc, char *argv[], char *envp[]) { - main_func(1); - lib_main(); + main_func (3); return 0; } diff --git a/testsuite/systemtap.base/uprobes_lib.c b/testsuite/systemtap.base/uprobes_lib.c index c9d70625..25297b6b 100644 --- a/testsuite/systemtap.base/uprobes_lib.c +++ b/testsuite/systemtap.base/uprobes_lib.c @@ -10,7 +10,8 @@ void lib_func (int bar) { - ; // nothing here... + if (bar > 1) + lib_func (bar - 1); } void diff --git a/testsuite/systemtap.base/uprobes_lib.exp b/testsuite/systemtap.base/uprobes_lib.exp index 63ef957a..313c01b6 100644 --- a/testsuite/systemtap.base/uprobes_lib.exp +++ b/testsuite/systemtap.base/uprobes_lib.exp @@ -29,11 +29,14 @@ if { $res != "" } { pass "$test compile $testsrc" } -# XXX main_func needs another/extra test. Disabled for now. -# Enable (and in uprobes_lib.stp) after PR9940 is fixed. -# set ::result_string {main_func -# lib_func} -set ::result_string {lib_func} +set ::result_string {main +main_func +main_func +main_func +lib_main +lib_func +lib_func +lib_func} # Only run on make installcheck if {! [installtest_p]} { untested "$test"; return } diff --git a/testsuite/systemtap.base/uprobes_lib.stp b/testsuite/systemtap.base/uprobes_lib.stp index bc6cc249..459351a4 100644 --- a/testsuite/systemtap.base/uprobes_lib.stp +++ b/testsuite/systemtap.base/uprobes_lib.stp @@ -1,8 +1,14 @@ -/* - Not activated probe... Seems always skipped? +probe process("uprobes_exe").function("main") { + printf("main\n"); +} + probe process("uprobes_exe").function("main_func") { printf("main_func\n"); } -*/ + +probe process("libuprobes_lib.so").function("lib_main") { + printf("lib_main\n"); +} probe process("libuprobes_lib.so").function("lib_func") { printf("lib_func\n"); diff --git a/testsuite/systemtap.base/uprobes_uname.exp b/testsuite/systemtap.base/uprobes_uname.exp new file mode 100644 index 00000000..65e1ff70 --- /dev/null +++ b/testsuite/systemtap.base/uprobes_uname.exp @@ -0,0 +1,46 @@ +set test "uprobes_uname" +set testpath "$srcdir/$subdir" +set testsrc "$testpath/uprobes_exe.c" +set testsrclib "$testpath/uprobes_lib.c" +set testexe "./uprobes_exe" +set testlibname "uprobes_lib" +set testlibdir "." +set testso "$testlibdir/lib${testlibname}.so" +set testflags "additional_flags=-g additional_flags=-O" +set testlibflags "$testflags additional_flags=-fPIC additional_flags=-shared" +set maintestflags "$testflags additional_flags=-L$testlibdir additional_flags=-l$testlibname additional_flags=-Wl,-rpath,$testlibdir" + +# Compile our test program and library. +set res [target_compile $testsrclib $testso executable $testlibflags] +if { $res != "" } { + verbose "target_compile for $testso failed: $res" 2 + fail "$test compile $testsrclib" + return +} else { + pass "$test compile $testsrclib" +} + +set res [target_compile $testsrc $testexe executable $maintestflags] +if { $res != "" } { + verbose "target_compile failed: $res" 2 + fail "$test compile $testsrc" + return +} else { + pass "$test compile $testsrc" +} + +set ::result_string {exe: main=main +exe: main_func=main_func +exe: main_func=main_func +exe: main_func=main_func +lib: lib_main=lib_main +lib: lib_func=lib_func +lib: lib_func=lib_func +lib: lib_func=lib_func} + +# Only run on make installcheck +if {! [installtest_p]} { untested "$test"; return } +if {! [utrace_p]} { untested $test; return } +stap_run2 $srcdir/$subdir/$test.stp -c $testexe + +#exec rm -f $testexe $testso diff --git a/testsuite/systemtap.base/uprobes_uname.stp b/testsuite/systemtap.base/uprobes_uname.stp new file mode 100644 index 00000000..a44d78d3 --- /dev/null +++ b/testsuite/systemtap.base/uprobes_uname.stp @@ -0,0 +1,7 @@ +probe process("uprobes_exe").function("*") { + printf("exe: %s=%s\n",probefunc(), usymname(uaddr())); +} + +probe process("libuprobes_lib.so").function("*") { + printf("lib: %s=%s\n",probefunc(), usymname(uaddr())); +} diff --git a/testsuite/systemtap.examples/network/nettop.stp b/testsuite/systemtap.examples/network/nettop.stp index b84e4882..e96548f1 100755 --- a/testsuite/systemtap.examples/network/nettop.stp +++ b/testsuite/systemtap.examples/network/nettop.stp @@ -19,11 +19,11 @@ function print_activity() "PID", "UID", "DEV", "XMIT_PK", "RECV_PK", "XMIT_KB", "RECV_KB", "COMMAND") - foreach ([pid, dev, exec, uid] in ifrecv-) { - ifmerged[pid, dev, exec, uid] = 1; + foreach ([pid, dev, exec, uid] in ifrecv) { + ifmerged[pid, dev, exec, uid] += @count(ifrecv[pid,dev,exec,uid]); } - foreach ([pid, dev, exec, uid] in ifxmit-) { - ifmerged[pid, dev, exec, uid] = 1; + foreach ([pid, dev, exec, uid] in ifxmit) { + ifmerged[pid, dev, exec, uid] += @count(ifxmit[pid,dev,exec,uid]); } foreach ([pid, dev, exec, uid] in ifmerged-) { n_xmit = @count(ifxmit[pid, dev, exec, uid]) diff --git a/translate.cxx b/translate.cxx index 95986924..971c1498 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4516,7 +4516,7 @@ dump_unwindsyms (Dwfl_Module *m, // In the future, we'll also care about data symbols. int syments = dwfl_module_getsymtab(m); - assert(syments); + dwfl_assert ("Getting symbol table for " + modname, syments >= 0); //extract build-id from debuginfo file int build_id_len = 0; @@ -4562,6 +4562,10 @@ dump_unwindsyms (Dwfl_Module *m, } } + // Use end as sanity check when resolving symbol addresses. + Dwarf_Addr end; + dwfl_module_info (m, NULL, NULL, &end, NULL, NULL, NULL, NULL); + // Look up the relocation basis for symbols int n = dwfl_module_relocations (m); @@ -4576,10 +4580,11 @@ dump_unwindsyms (Dwfl_Module *m, Dwarf_Addr extra_offset = 0; - for (int i = 1 /* XXX: why not 0? */ ; i < syments; ++i) + for (int i = 0; i < syments; ++i) { GElf_Sym sym; - const char *name = dwfl_module_getsym(m, i, &sym, NULL); + GElf_Word shndxp; + const char *name = dwfl_module_getsym(m, i, &sym, &shndxp); if (name) { // NB: Yey, we found the kernel's _stext value. @@ -4602,17 +4607,15 @@ dump_unwindsyms (Dwfl_Module *m, clog << "Found kernel _stext extra offset 0x" << hex << extra_offset << dec << endl; } - // We only need the function symbols to identify kernel-mode - // PC's, so we omit undefined or "fake" absolute addresses. - // These fake absolute addresses occur in some older i386 - // kernels to indicate they are vDSO symbols, not real - // functions in the kernel. We also omit symbols that have - // suspicious addresses (before base). + // We are only interested in "real" symbols. + // We omit symbols that have suspicious addresses (before base, + // or after end). if ((GELF_ST_TYPE (sym.st_info) == STT_FUNC || GELF_ST_TYPE (sym.st_info) == STT_OBJECT) // PR10000: also need .data - && !(sym.st_shndx == SHN_UNDEF - || sym.st_shndx == SHN_ABS - || sym.st_value < base)) + && !(sym.st_shndx == SHN_UNDEF // Value undefined, + || shndxp == (GElf_Word) -1 // in a non-allocated section, + || sym.st_value >= end // beyond current module, + || sym.st_value < base)) // before first section. { Dwarf_Addr sym_addr = sym.st_value; const char *secname = NULL; @@ -4637,6 +4640,16 @@ dump_unwindsyms (Dwfl_Module *m, { // This is a symbol within a (possibly relocatable) // kernel image. + + // We only need the function symbols to identify kernel-mode + // PC's, so we omit undefined or "fake" absolute addresses. + // These fake absolute addresses occur in some older i386 + // kernels to indicate they are vDSO symbols, not real + // functions in the kernel. We also omit symbols that have + if (GELF_ST_TYPE (sym.st_info) == STT_FUNC + && sym.st_shndx == SHN_ABS) + continue; + secname = "_stext"; // NB: don't subtract session.sym_stext, which could be inconveniently NULL. // Instead, sym_addr will get compensated later via extra_offset. @@ -4696,10 +4709,10 @@ dump_unwindsyms (Dwfl_Module *m, // There would be only a small benefit to warning. A user // likely can't do anything about this; backtraces for the // affected module would just get all icky heuristicy. -#if 0 - c->session.print_warning ("No unwind data for " + modname - + ", " + dwfl_errmsg (-1)); -#endif + // So only report in verbose mode. + if (c->session.verbose > 2) + c->session.print_warning ("No unwind data for " + modname + + ", " + dwfl_errmsg (-1)); } for (unsigned secidx = 0; secidx < seclist.size(); secidx++) |