diff options
author | hunt <hunt> | 2006-10-12 18:19:18 +0000 |
---|---|---|
committer | hunt <hunt> | 2006-10-12 18:19:18 +0000 |
commit | fabf5ed4db3cce35725023ebc424ffe28a7dd74a (patch) | |
tree | ba5eb2e481c668c502df62fa078ebecae5e3a596 | |
parent | 40cfa2bce2cf09160da6b767603e11a2cfac3a3e (diff) | |
download | systemtap-steved-fabf5ed4db3cce35725023ebc424ffe28a7dd74a.tar.gz systemtap-steved-fabf5ed4db3cce35725023ebc424ffe28a7dd74a.tar.xz systemtap-steved-fabf5ed4db3cce35725023ebc424ffe28a7dd74a.zip |
2006-10-12 Martin Hunt <hunt@redhat.com>
* stack.c: Reorganize and split arch-specific functions to
separate files.
(_stp_kta): Better checking.
(_stp_stack_sprint): Better handling of return probes.
* stack-i386.c: New file. Uses 2.6.18 DWARF unwinder if available.
* stack-x86_64.c: New file. Uses 2.6.18 DWARF unwinder if available.
* stack-ppc64.c: New file.
* stack-ia64.c: New file.
* sym.c (_stp_kallsyms_lookup_name): New function. Like
kallsyms_lookup_name() except use our internal lookup table.
-rw-r--r-- | runtime/ChangeLog | 15 | ||||
-rw-r--r-- | runtime/stack-i386.c | 102 | ||||
-rw-r--r-- | runtime/stack-ia64.c | 65 | ||||
-rw-r--r-- | runtime/stack-ppc64.c | 62 | ||||
-rw-r--r-- | runtime/stack-x86_64.c | 72 | ||||
-rw-r--r-- | runtime/stack.c | 236 | ||||
-rw-r--r-- | runtime/sym.c | 25 |
7 files changed, 378 insertions, 199 deletions
diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 6871025f..66519fa8 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,18 @@ +2006-10-12 Martin Hunt <hunt@redhat.com> + + * stack.c: Reorganize and split arch-specific functions to + separate files. + (_stp_kta): Better checking. + (_stp_stack_sprint): Better handling of return probes. + + * stack-i386.c: New file. Uses 2.6.18 DWARF unwinder if available. + * stack-x86_64.c: New file. Uses 2.6.18 DWARF unwinder if available. + * stack-ppc64.c: New file. + * stack-ia64.c: New file. + + * sym.c (_stp_kallsyms_lookup_name): New function. Like + kallsyms_lookup_name() except use our internal lookup table. + 2006-10-10 Frank Ch. Eigler <fche@elastic.org> * runtime/lket/b2a/lket_b2a.c: Add several missing #ifdef HAS_MYSQL. diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c new file mode 100644 index 00000000..d36f30d2 --- /dev/null +++ b/runtime/stack-i386.c @@ -0,0 +1,102 @@ +/* -*- linux-c -*- + * i386 stack tracing functions + * Copyright (C) 2005, 2006 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 + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ +#ifdef CONFIG_STACK_UNWIND +#include <linux/unwind.h> + +static inline int _stp_valid_stack_ptr_info(struct unwind_frame_info *info) +{ + unsigned long context = (unsigned long)UNW_SP(info) & ~(THREAD_SIZE - 1); + unsigned long p = UNW_PC(info); + return p > context && p < context + THREAD_SIZE - 3; +} + +static int +_stp_show_trace_unwind(String str, struct unwind_frame_info *info, int verbose) +{ + int n = 0; + + while (unwind(info) == 0 && UNW_PC(info)) { + if (_stp_valid_stack_ptr_info(info)) + break; + n++; + if (verbose) { + _stp_string_cat(str, " "); + _stp_symbol_sprint (str, UNW_PC(info)); + _stp_string_cat(str, "\n"); + } else + _stp_sprintf (str, "%p ", UNW_PC(info)); + if (arch_unw_user_mode(info)) + break; + } + return n; +} +#endif /* CONFIG_STACK_UNWIND */ + +static inline int _stp_valid_stack_ptr(unsigned long context, unsigned long p) +{ + return p > context && p < context + THREAD_SIZE - 3; +} + +static void __stp_stack_sprint (String str, struct pt_regs *regs, int verbose, int levels) +{ + unsigned long *stack = (unsigned long *)®_SP(regs); + unsigned long context = (unsigned long)stack & ~(THREAD_SIZE - 1); + unsigned long addr; + int uw_ret = 0; + +#ifdef CONFIG_STACK_UNWIND + struct unwind_frame_info info; + if (unwind_init_frame_info(&info, current, regs) == 0) + uw_ret = _stp_show_trace_unwind(str, &info, verbose); + stack = (void *)UNW_SP(&info); +#endif + + if (uw_ret == 0) + _stp_string_cat(str, "Inexact backtrace:\n"); + +#ifdef CONFIG_FRAME_POINTER + { + unsigned long ebp; + /* Grab ebp right from our regs.*/ + asm ("movl %%ebp, %0" : "=r" (ebp) : ); + + while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) { + addr = *(unsigned long *)(ebp + 4); + if (verbose) { + if (uw_ret) { + uw_ret = 0; + _stp_string_cat(str, "Leftover inexact backtrace:\n"); + } + _stp_string_cat(str, " "); + _stp_symbol_sprint (str, addr); + _stp_string_cat(str, "\n"); + } else + _stp_sprintf (str, "%p ", (void *)addr); + ebp = *(unsigned long *)ebp; + } + } +#else + while (_stp_valid_stack_ptr(context, (unsigned long)stack)) { + addr = *stack++; + if (_stp_kta(addr)) { + if (verbose) { + if (uw_ret) { + uw_ret = 0; + _stp_string_cat(str, "Leftover inexact backtrace:\n"); + } + _stp_string_cat(str, " "); + _stp_symbol_sprint(str, addr); + _stp_string_cat(str, "\n"); + } else + _stp_sprintf (str, "%p ", (void *)addr); + } + } +#endif +} diff --git a/runtime/stack-ia64.c b/runtime/stack-ia64.c new file mode 100644 index 00000000..f941869e --- /dev/null +++ b/runtime/stack-ia64.c @@ -0,0 +1,65 @@ +/* -*- linux-c -*- + * ia64 stack tracing functions + * Copyright (C) 2005 Intel Corporation. + * + * This file is part of systemtap, and is free software. You can + * redistribute it and/or modify it under the terms of the GNU General + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ + +struct dump_para{ + unsigned long *sp; + String str; +}; + +static void __stp_show_stack_sym(struct unw_frame_info *info, void *arg) +{ + unsigned long ip, skip=1; + String str = ((struct dump_para*)arg)->str; + struct pt_regs *regs = container_of(((struct dump_para*)arg)->sp, struct pt_regs, r12); + + do { + unw_get_ip(info, &ip); + if (ip == 0) break; + if (skip){ + if (ip == REG_IP(regs)) + skip = 0; + else continue; + } + _stp_string_cat(str, " "); + _stp_symbol_sprint(str, ip); + _stp_string_cat (str, "\n"); + } while (unw_unwind(info) >= 0); +} + +static void __stp_show_stack_addr(struct unw_frame_info *info, void *arg) +{ + unsigned long ip, skip=1; + String str = ((struct dump_para*)arg)->str; + struct pt_regs *regs = container_of(((struct dump_para*)arg)->sp, struct pt_regs, r12); + + do { + unw_get_ip(info, &ip); + if (ip == 0) break; + if (skip){ + if (ip == REG_IP(regs)) + skip = 0; + continue; + } + _stp_sprintf (str, "%lx ", ip); + } while (unw_unwind(info) >= 0); +} + +static void __stp_stack_sprint (String str, struct pt_regs *regs, int verbose, int levels) +{ + unsigned long *stack = (unsigned long *)®_SP(regs); + struct dump_para para; + + para.str = str; + para.sp = stack; + if (verbose) + unw_init_running(__stp_show_stack_sym, ¶); + else + unw_init_running(__stp_show_stack_addr, ¶); +} diff --git a/runtime/stack-ppc64.c b/runtime/stack-ppc64.c new file mode 100644 index 00000000..0a30bc84 --- /dev/null +++ b/runtime/stack-ppc64.c @@ -0,0 +1,62 @@ +/* -*- linux-c -*- + * ppc64 stack tracing functions + * + * This file is part of systemtap, and is free software. You can + * redistribute it and/or modify it under the terms of the GNU General + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ + +static void __stp_stack_sprint (String str, struct pt_regs *regs, int verbose, int levels) +{ + unsigned long ip, newsp, lr = 0; + int count = 0; + unsigned long sp = (unsigned long)_sp; + int firstframe = 1; + unsigned long *_sp = (unsigned long *)®_SP(regs); + lr = 0; + do { + if (sp < KERNELBASE) + return; + _sp = (unsigned long *) sp; + newsp = _sp[0]; + ip = _sp[2]; + if (!firstframe || ip != lr) { + if (verbose) { + _stp_sprintf(str, "[%016lx] [%016lx] ", sp, ip); + _stp_symbol_sprint(str, ip); + if (firstframe) + _stp_string_cat(str, " (unreliable)"); + _stp_string_cat(str, "\n"); + } + else + _stp_sprintf(str,"%lx ", ip); + } + firstframe = 0; + /* + * See if this is an exception frame. + * We look for the "regshere" marker in the current frame. + */ + if ( _sp[12] == 0x7265677368657265ul) { + struct pt_regs *regs = (struct pt_regs *) + (sp + STACK_FRAME_OVERHEAD); + if (verbose) { + _stp_sprintf(str, "--- Exception: %lx at ", + regs->trap); + _stp_symbol_sprint(str, regs->nip); + _stp_string_cat(str, "\n"); + lr = regs->link; + _stp_string_cat(str, " LR ="); + _stp_symbol_sprint(str, lr); + _stp_string_cat(str, "\n"); + firstframe = 1; + } + else { + _stp_sprintf(str, "%lx ",regs->nip); + _stp_sprintf(str, "%lx ",regs->link); + } + } + + sp = newsp; + } while (str->len < STP_STRING_SIZE); +} diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c new file mode 100644 index 00000000..3a188c2c --- /dev/null +++ b/runtime/stack-x86_64.c @@ -0,0 +1,72 @@ +/* -*- linux-c -*- + * x86_64 stack tracing functions + * Copyright (C) 2005, 2006 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 + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ +#ifdef CONFIG_STACK_UNWIND +#include <linux/unwind.h> + +static inline int _stp_valid_stack_ptr(struct unwind_frame_info *info) +{ + unsigned long context = (unsigned long)UNW_SP(info) & ~(THREAD_SIZE - 1); + unsigned long p = UNW_PC(info); + return p > context && p < context + THREAD_SIZE - 3; +} + +static int _stp_show_trace_unwind(String str, struct unwind_frame_info *info, int verbose) +{ + int n = 0; + + while (unwind(info) == 0 && UNW_PC(info)) { + if (_stp_valid_stack_ptr(info)) + break; + n++; + if (verbose) { + _stp_string_cat(str, " "); + _stp_symbol_sprint (str, UNW_PC(info)); + _stp_string_cat(str, "\n"); + } else + _stp_sprintf (str, "%p ", UNW_PC(info)); + if (arch_unw_user_mode(info)) + break; + } + return n; +} +#endif /* CONFIG_STACK_UNWIND */ + +static void __stp_stack_sprint (String str, struct pt_regs *regs, int verbose, int levels) +{ + unsigned long *stack = (unsigned long *)®_SP(regs); + unsigned long addr; + int uw_ret = 0; + +#ifdef CONFIG_STACK_UNWIND + struct unwind_frame_info info; + if (unwind_init_frame_info(&info, current, regs) == 0) + uw_ret = _stp_show_trace_unwind(str, &info, verbose); + stack = (void *)UNW_SP(&info); +#endif + + if (uw_ret == 0) + _stp_string_cat(str, "Inexact backtrace:\n"); + + while ((long)stack & (THREAD_SIZE-1)) { + addr = *stack++; + if (_stp_kta(addr)) { + if (verbose) { + if (uw_ret) { + uw_ret = 0; + _stp_string_cat(str, "Leftover inexact backtrace:\n"); + } + _stp_string_cat(str, " "); + _stp_symbol_sprint(str, addr); + _stp_string_cat(str, "\n"); + } else + _stp_sprintf (str, "%p ", (void *)addr); + } + } +} diff --git a/runtime/stack.c b/runtime/stack.c index 7037fa8f..dbbac9ac 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -1,5 +1,6 @@ -/* Stack tracing functions - * Copyright (C) 2005 Red Hat Inc. +/* -*- linux-c -*- + * Stack tracing functions + * Copyright (C) 2005, 2006 Red Hat Inc. * Copyright (C) 2005 Intel Corporation. * * This file is part of systemtap, and is free software. You can @@ -8,7 +9,7 @@ * later version. */ -#ifndef _STACK_C_ /* -*- linux-c -*- */ +#ifndef _STACK_C_ #define _STACK_C_ @@ -29,222 +30,65 @@ #include "sym.c" #include "regs.h" - -static int _stp_kta(unsigned long addr) -{ - if (addr >= stap_symbols[0].addr && - addr <= stap_symbols[stap_num_symbols-1].addr) - return 1; - return 0; -} +static int _stp_kta(unsigned long addr); #if defined (__x86_64__) - -static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels) -{ - unsigned long addr; - while (((long) stack & (THREAD_SIZE-1)) != 0) { - addr = *stack++; - if (_stp_kta(addr)) { - if (verbose) { - _stp_string_cat(str, " "); - _stp_symbol_sprint (str, addr); - _stp_string_cat (str, "\n"); - } else - _stp_sprintf (str, "%lx ", addr); - } - } -} - +#include "stack-x86_64.c" #elif defined (__ia64__) -struct dump_para{ - unsigned long *sp; - String str; -}; - -static void __stp_show_stack_sym(struct unw_frame_info *info, void *arg) -{ - unsigned long ip, skip=1; - String str = ((struct dump_para*)arg)->str; - struct pt_regs *regs = container_of(((struct dump_para*)arg)->sp, struct pt_regs, r12); - - do { - unw_get_ip(info, &ip); - if (ip == 0) break; - if (skip){ - if (ip == REG_IP(regs)) - skip = 0; - else continue; - } - _stp_string_cat(str, " "); - _stp_symbol_sprint(str, ip); - _stp_string_cat (str, "\n"); - } while (unw_unwind(info) >= 0); -} - -static void __stp_show_stack_addr(struct unw_frame_info *info, void *arg) -{ - unsigned long ip, skip=1; - String str = ((struct dump_para*)arg)->str; - struct pt_regs *regs = container_of(((struct dump_para*)arg)->sp, struct pt_regs, r12); - - do { - unw_get_ip(info, &ip); - if (ip == 0) break; - if (skip){ - if (ip == REG_IP(regs)) - skip = 0; - continue; - } - _stp_sprintf (str, "%lx ", ip); - } while (unw_unwind(info) >= 0); -} - -static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels) -{ - struct dump_para para; - - para.str = str; - para.sp = stack; - if (verbose) - unw_init_running(__stp_show_stack_sym, ¶); - else - unw_init_running(__stp_show_stack_addr, ¶); -} - +#include "stack-ia64.c" #elif defined (__i386__) - -static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) -{ - return p > (void *)tinfo && - p < (void *)tinfo + THREAD_SIZE - 3; -} - -static inline unsigned long print_context_stack(String str, struct thread_info *tinfo, - unsigned long *stack, unsigned long ebp, int verbose) -{ - unsigned long addr; - -#ifdef CONFIG_FRAME_POINTER - while (valid_stack_ptr(tinfo, (void *)ebp)) { - addr = *(unsigned long *)(ebp + 4); - if (verbose) { - _stp_string_cat(str, " "); - _stp_symbol_sprint (str, addr); - _stp_string_cat(str, "\n"); - } else - _stp_sprintf (str, "%lx ", addr); - ebp = *(unsigned long *)ebp; - } +#include "stack-i386.c" +#elif defined (__powerpc64__) +#include "stack-ppc64.c" #else - while (valid_stack_ptr(tinfo, stack)) { - addr = *stack++; - if (_stp_kta(addr)) { - if (verbose) { - _stp_string_cat(str, " "); - _stp_symbol_sprint(str, addr); - _stp_string_cat(str, "\n"); - } else - _stp_sprintf (str, "%lx ", addr); - } - } +#error "Unsupported architecture" #endif - return ebp; -} -static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels) -{ - unsigned long ebp; - - /* Grab ebp right from our regs */ - asm ("movl %%ebp, %0" : "=r" (ebp) : ); - while (1) { - struct thread_info *context; - context = (struct thread_info *) - ((unsigned long)stack & (~(THREAD_SIZE - 1))); - ebp = print_context_stack(str, context, stack, ebp, verbose); - stack = (unsigned long*)context->previous_esp; - if (!stack) - break; +/* our copy of kernel_text_address() */ +static int _stp_kta(unsigned long addr) +{ + static unsigned long stext, etext, sinittext, einittext; + static int init = 0; + + if (init == 0) { + init = 1; + etext = _stp_kallsyms_lookup_name("_etext"); + stext = _stp_kallsyms_lookup_name("_stext"); + sinittext = _stp_kallsyms_lookup_name("_sinittext"); + einittext = _stp_kallsyms_lookup_name("_einittext"); } -} -#elif defined (__powerpc64__) -static void __stp_stack_sprint (String str, unsigned long *_sp, - int verbose, int levels) -{ - unsigned long ip, newsp, lr = 0; - int count = 0; - unsigned long sp = (unsigned long)_sp; - int firstframe = 1; + if (addr >= stext && addr <= etext) + return 1; - lr = 0; - do { - if (sp < KERNELBASE) - return; - _sp = (unsigned long *) sp; - newsp = _sp[0]; - ip = _sp[2]; - if (!firstframe || ip != lr) { - if (verbose) { - _stp_sprintf(str, "[%016lx] [%016lx] ", sp, ip); - _stp_symbol_sprint(str, ip); - if (firstframe) - _stp_string_cat(str, " (unreliable)"); - } - else - _stp_sprintf(str,"%lx ", ip); - } - firstframe = 0; - /* - * See if this is an exception frame. - * We look for the "regshere" marker in the current frame. - */ - if ( _sp[12] == 0x7265677368657265ul) { - struct pt_regs *regs = (struct pt_regs *) - (sp + STACK_FRAME_OVERHEAD); - if (verbose) { - _stp_sprintf(str, "--- Exception: %lx at ", - regs->trap); - _stp_symbol_sprint(str, regs->nip); - _stp_string_cat(str, "\n"); - lr = regs->link; - _stp_string_cat(str, " LR ="); - _stp_symbol_sprint(str, lr); - _stp_string_cat(str, "\n"); - firstframe = 1; - } - else { - _stp_sprintf(str, "%lx ",regs->nip); - _stp_sprintf(str, "%lx ",regs->link); - } - } + if (addr >= sinittext && addr <= einittext) + return 1; - sp = newsp; - } while (str->len < STP_STRING_SIZE); + return 0; } -#else -#error "Unsupported architecture" -#endif - - /** Writes stack backtrace to a String * * @param str String * @param regs A pointer to the struct pt_regs. * @returns Same String as was input with trace info appended, */ -String _stp_stack_sprint (String str, struct pt_regs *regs, int verbose) +String _stp_stack_sprint (String str, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi) { if (verbose) { - _stp_sprintf (str, "trace for %d (%s)\n ", current->pid, current->comm); - _stp_symbol_sprint (str, REG_IP(regs)); + /* print the current address */ + if (pi) { + _stp_string_cat(str, "Returning from: "); + _stp_symbol_sprint(str, (unsigned long)_stp_probe_addr_r(pi)); + _stp_string_cat(str, "\nReturning to: "); + _stp_symbol_sprint(str, (unsigned long)_stp_ret_addr_r(pi)); + } else + _stp_symbol_sprint (str, REG_IP(regs)); _stp_string_cat(str, "\n"); } else _stp_sprintf (str, "%lx ", REG_IP(regs)); - __stp_stack_sprint (str, (unsigned long *)®_SP(regs), verbose, 0); + __stp_stack_sprint (str, regs, verbose, 0); return str; } @@ -252,7 +96,7 @@ String _stp_stack_sprint (String str, struct pt_regs *regs, int verbose) * @param regs A pointer to the struct pt_regs. */ -#define _stp_stack_print(regs) (void)_stp_stack_sprint(_stp_stdout,regs,1) +#define _stp_stack_print(regs,pi) (void)_stp_stack_sprint(_stp_stdout,regs,1,pi) /** Writes stack backtrace to a String. * Use this when calling from a jprobe. @@ -264,7 +108,7 @@ String _stp_stack_sprintj(String str) { unsigned long stack; _stp_sprintf (str, "trace for %d (%s)\n", current->pid, current->comm); - __stp_stack_sprint (str, &stack, 1, 0); +/* __stp_stack_sprint (str, &stack, 1, 0); */ return str; } diff --git a/runtime/sym.c b/runtime/sym.c index 3843a3a5..c10e89fd 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -20,6 +20,25 @@ * @{ */ +/* Lookup the kernel address for this symbol. Returns 0 if not found. */ +static unsigned long _stp_kallsyms_lookup_name(const char *name) +{ + struct stap_symbol *s = &stap_symbols[0]; + unsigned num = stap_num_symbols; + + /* Warning: Linear search. If this function ends up being used in */ + /* time-critical places, maybe we need to create a new symbol table */ + /* sorted by name. */ + + while (num--) { + if ((strcmp(name, s->symbol) == 0) && (strcmp(s->modname,"") == 0)) + return s->addr; + s++; + } + + return 0; +} + static const char * _stp_kallsyms_lookup ( unsigned long addr, unsigned long *symbolsize, @@ -80,7 +99,7 @@ String _stp_symbol_sprint (String str, unsigned long address) name = _stp_kallsyms_lookup(address, &size, &offset, &modname, namebuf); - _stp_sprintf (str, "0x%lx", address); + _stp_sprintf (str, "%p", (void *)address); if (name) { if (modname) @@ -119,13 +138,13 @@ const char *_stp_symbol_sprint_basic (char *str, size_t len, unsigned long addre if (len > KSYM_NAME_LEN) { name = _stp_kallsyms_lookup(address, &size, &offset, &modname, str); if (!name) - snprintf(str, len, "0x%lx", address); + snprintf(str, len, "%p", (void *)address); } else { name = _stp_kallsyms_lookup(address, &size, &offset, &modname, namebuf); if (name) strlcpy(str, namebuf, len); else - snprintf(str, len, "0x%lx", address); + snprintf(str, len, "%p", (void *)address); } return str; |