summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/stack-i386.c7
-rw-r--r--runtime/stack-x86_64.c7
-rw-r--r--runtime/sym.h8
-rw-r--r--runtime/transport/symbols.c8
-rw-r--r--translate.cxx15
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();