From: Mark Wielaard <mjw@redhat.com> Date: Wed, 3 Jun 2009 13:36:03 +0000 (+0200) Subject: Detect kretprobe trampoline and use fallback unwinder. X-Git-Url: http://sourceware.org/git/?p=systemtap.git;a=commitdiff_plain;h=129de 9ef18cd142e31ed509a7704d4faf0879f4c Detect kretprobe trampoline and use fallback unwinder. * runtime/sym.h (_stp_kretprobe_trampoline): Document. * translate.cxx (unwindsym_dump_context): Add stp_kretprobe_trampoline_addr. (dump_unwindsyms): Detect kretprobe_trampoline_holder symbol address. (emit_symbol_data): Initialize and emit _stp_kretprobe_trampoline. * runtime/transport/symbols.c (_stp_do_relocation): Detect kernel load address and adjust _stp_kretprobe_trampoline. * runtime/stack-i386.c (__stp_stack_print): Always use fallback unwinder when hitting kretprobe_trampoline_holder. * runtime/stack-x86_64.c (__stp_stack_print): Likewise. --- diff -ur systemtap-0.9.7.orig/runtime/stack-i386.c systemtap-0.9.7/runtime/stack-i386.c --- systemtap-0.9.7.orig/runtime/stack-i386.c 2009-04-24 00:11:37.000000000 +0200 +++ systemtap-0.9.7/runtime/stack-i386.c 2009-06-03 17:52:13.000000000 +0200 @@ -67,14 +67,15 @@ if (ret == 0) { _stp_func_print(UNW_PC(&info), verbose, 1, tsk); levels--; - continue; + if (UNW_PC(&info) != _stp_kretprobe_trampoline) + continue; } /* If an error happened or we hit a kretprobe trampoline, * use fallback backtrace, unless user task backtrace. * FIXME: is there a way to unwind across kretprobe - * trampolines? */ + * trampolines? PR9999. */ if ((ret < 0 - || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline)) + || UNW_PC(&info) == _stp_kretprobe_trampoline) && ! (tsk || arch_unw_user_mode(&info))) _stp_stack_print_fallback(UNW_SP(&info), verbose, levels); return; diff -ur systemtap-0.9.7.orig/runtime/stack-x86_64.c systemtap-0.9.7/runtime/stack-x86_64.c --- systemtap-0.9.7.orig/runtime/stack-x86_64.c 2009-04-24 00:11:37.000000000 +0200 +++ systemtap-0.9.7/runtime/stack-x86_64.c 2009-06-03 17:52:13.000000000 +0200 @@ -41,14 +41,15 @@ if (ret == 0) { _stp_func_print(UNW_PC(&info), verbose, 1, tsk); levels--; - continue; + if (UNW_PC(&info) != _stp_kretprobe_trampoline) + continue; } /* If an error happened or we hit a kretprobe trampoline, * use fallback backtrace, unless user task backtrace. * FIXME: is there a way to unwind across kretprobe - * trampolines? */ + * trampolines? PR9999. */ if ((ret < 0 - || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline)) + || UNW_PC(&info) == _stp_kretprobe_trampoline) && ! (tsk || arch_unw_user_mode(&info))) _stp_stack_print_fallback(UNW_SP(&info), verbose, levels); return; diff -ur systemtap-0.9.7.orig/runtime/sym.h systemtap-0.9.7/runtime/sym.h --- systemtap-0.9.7.orig/runtime/sym.h 2009-04-24 00:11:37.000000000 +0200 +++ systemtap-0.9.7/runtime/sym.h 2009-06-03 17:52:13.000000000 +0200 @@ -59,10 +59,10 @@ static struct _stp_module *_stp_modules []; static unsigned _stp_num_modules; - -/* the number of modules in the arrays */ - -static unsigned long _stp_kretprobe_trampoline = 0; +/* Used in the unwinder to special case unwinding through kretprobes. */ +/* Initialized through translator (stap-symbols.h) relative to kernel */ +/* load address, fixup by transport symbols _stp_do_relocation */ +static unsigned long _stp_kretprobe_trampoline; static unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset); static struct _stp_module *_stp_get_unwind_info (unsigned long addr); Only in systemtap-0.9.7/runtime: sym.h.orig diff -ur systemtap-0.9.7.orig/runtime/transport/symbols.c systemtap-0.9.7/runtime/transport/symbols.c --- systemtap-0.9.7.orig/runtime/transport/symbols.c 2009-04-24 00:11:37.000000000 +0200 +++ systemtap-0.9.7/runtime/transport/symbols.c 2009-06-03 17:52:13.000000000 +0200 @@ -30,6 +30,14 @@ dbug_sym(2, "relocate (%s %s 0x%lx)\n", msg.module, msg.reloc, (unsigned long) msg.address); + /* Detect actual kernel load address. */ + if (!strcmp ("kernel", msg.module) + && !strcmp ("_stext", msg.reloc)) { + dbug_sym(2, "found kernel _stext load address: 0x%lx\n", + (unsigned long) msg.address); + if (_stp_kretprobe_trampoline != (unsigned long) -1) + _stp_kretprobe_trampoline += (unsigned long) msg.address; + } /* Save the relocation value. XXX: While keeping the data here is fine for the kernel address space ("kernel" and "*.ko" modules), diff -ur systemtap-0.9.7.orig/translate.cxx systemtap-0.9.7/translate.cxx --- systemtap-0.9.7.orig/translate.cxx 2009-04-24 00:11:37.000000000 +0200 +++ systemtap-0.9.7/translate.cxx 2009-06-03 17:52:13.000000000 +0200 @@ -4409,6 +4409,7 @@ systemtap_session& session; ostream& output; unsigned stp_module_index; + unsigned long stp_kretprobe_trampoline_addr; set<string> undone_unwindsym_modules; }; @@ -4630,6 +4631,11 @@ secname = "_stext"; // NB: don't subtract session.sym_stext, which could be inconveniently NULL. // Instead, sym_addr will get compensated later via extra_offset. + + // We need to note this for the unwinder. + if (c->stp_kretprobe_trampoline_addr == (unsigned long) -1 + && ! strcmp (name, "kretprobe_trampoline_holder")) + c->stp_kretprobe_trampoline_addr = sym_addr; } else if (n > 0) { @@ -4679,6 +4685,10 @@ } } + // Must be relative to actual kernel load address. + if (c->stp_kretprobe_trampoline_addr != (unsigned long) -1) + c->stp_kretprobe_trampoline_addr -= extra_offset; + // Add unwind data to be included if it exists for this module. size_t len = 0; void *unwind = get_unwind_data (m, &len); @@ -4826,7 +4836,7 @@ ofstream kallsyms_out ((s.tmpdir + "/" + symfile).c_str()); - unwindsym_dump_context ctx = { s, kallsyms_out, 0, s.unwindsym_modules }; + unwindsym_dump_context ctx = { s, kallsyms_out, 0, -1, s.unwindsym_modules }; // Micro optimization, mainly to speed up tiny regression tests // using just begin probe. @@ -4944,6 +4954,9 @@ ctx->output << "};\n"; ctx->output << "static unsigned _stp_num_modules = " << ctx->stp_module_index << ";\n"; + ctx->output << "static unsigned long _stp_kretprobe_trampoline = 0x" + << hex << ctx->stp_kretprobe_trampoline_addr << dec << ";\n"; + // Some nonexistent modules may have been identified with "-d". Note them. for (set<string>::iterator it = ctx->undone_unwindsym_modules.begin(); it != ctx->undone_unwindsym_modules.end();