diff options
-rw-r--r-- | runtime/stack-i386.c | 7 | ||||
-rw-r--r-- | runtime/stack-x86_64.c | 7 | ||||
-rw-r--r-- | runtime/sym.h | 8 | ||||
-rw-r--r-- | runtime/transport/symbols.c | 8 | ||||
-rw-r--r-- | translate.cxx | 15 |
5 files changed, 34 insertions, 11 deletions
diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c index 69623765..b447e495 100644 --- a/runtime/stack-i386.c +++ b/runtime/stack-i386.c @@ -67,14 +67,15 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels, 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 --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c index 9afdf38a..914242e0 100644 --- a/runtime/stack-x86_64.c +++ b/runtime/stack-x86_64.c @@ -41,14 +41,15 @@ static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels, 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 --git a/runtime/sym.h b/runtime/sym.h index 7e28ebe6..ca69345f 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -61,10 +61,10 @@ struct _stp_module { 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); diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index a329effe..3e6a2fb1 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -30,6 +30,14 @@ static void _stp_do_relocation(const char __user *buf, size_t count) 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 --git a/translate.cxx b/translate.cxx index 9631213e..76530cc4 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4423,6 +4423,7 @@ struct unwindsym_dump_context systemtap_session& session; ostream& output; unsigned stp_module_index; + unsigned long stp_kretprobe_trampoline_addr; set<string> undone_unwindsym_modules; }; @@ -4660,6 +4661,11 @@ dump_unwindsyms (Dwfl_Module *m, 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) { @@ -4709,6 +4715,10 @@ dump_unwindsyms (Dwfl_Module *m, } } + // 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. void *debug_frame = NULL; size_t debug_len = 0; @@ -4893,7 +4903,7 @@ emit_symbol_data (systemtap_session& s) 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. @@ -5011,6 +5021,9 @@ emit_symbol_data_done (unwindsym_dump_context *ctx, systemtap_session& s) 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(); |