summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorDave Brolley <brolley@redhat.com>2009-04-22 11:57:40 -0400
committerDave Brolley <brolley@redhat.com>2009-04-22 11:57:40 -0400
commitbc815e0692536da04956f038f5f79941579f8d74 (patch)
tree98b0f8cfdd90c225f5b5fede18352caee5d9a546 /runtime
parent88e8da383e47adafc9e75c4f10aecd0ce4ad959f (diff)
parent247f1e1fa09953347a4e5313ae0022f151316dae (diff)
downloadsystemtap-steved-bc815e0692536da04956f038f5f79941579f8d74.tar.gz
systemtap-steved-bc815e0692536da04956f038f5f79941579f8d74.tar.xz
systemtap-steved-bc815e0692536da04956f038f5f79941579f8d74.zip
Merge branch 'master' of git://sources.redhat.com/git/systemtap
Diffstat (limited to 'runtime')
-rw-r--r--runtime/stack-arm.c3
-rw-r--r--runtime/stack-i386.c25
-rw-r--r--runtime/stack-ia64.c3
-rw-r--r--runtime/stack-ppc64.c3
-rw-r--r--runtime/stack-s390.c3
-rw-r--r--runtime/stack-x86_64.c23
-rw-r--r--runtime/stack.c34
-rw-r--r--runtime/sym.c31
-rw-r--r--runtime/unwind.c22
-rw-r--r--runtime/uprobes2/uprobes.c3
10 files changed, 92 insertions, 58 deletions
diff --git a/runtime/stack-arm.c b/runtime/stack-arm.c
index 9b0b772d..fcff0a3b 100644
--- a/runtime/stack-arm.c
+++ b/runtime/stack-arm.c
@@ -31,7 +31,8 @@ static int __init find_str_pc_offset(void)
}
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
#ifdef STP_USE_FRAME_POINTER
int pc_offset = find_str_pc_offset();
diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c
index 5a18c9d8..69623765 100644
--- a/runtime/stack-i386.c
+++ b/runtime/stack-i386.c
@@ -23,14 +23,15 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
/* cannot access stack. give up. */
return;
}
- if (_stp_func_print(addr, verbose, 0))
+ if (_stp_func_print(addr, verbose, 0, NULL))
levels--;
stack++;
}
}
#endif
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long context = (unsigned long)&REG_SP(regs) & ~(THREAD_SIZE - 1);
@@ -43,7 +44,7 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
/* cannot access stack. give up. */
return;
}
- _stp_func_print(addr, verbose, 1);
+ _stp_func_print(addr, verbose, 1, NULL);
if (unlikely(_stp_read_address(next_fp, (unsigned long *)fp, KERNEL_DS))) {
/* cannot access stack. give up. */
return;
@@ -60,19 +61,23 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
struct unwind_frame_info info;
arch_unw_init_frame_info(&info, regs);
- while (levels && !arch_unw_user_mode(&info)) {
- int ret = unwind(&info);
+ while (levels && (tsk || !arch_unw_user_mode(&info))) {
+ int ret = unwind(&info, tsk);
dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info));
if (ret == 0) {
- _stp_func_print(UNW_PC(&info), verbose, 1);
+ _stp_func_print(UNW_PC(&info), verbose, 1, tsk);
levels--;
continue;
}
- /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */
- /* FIXME: is there a way to unwind across kretprobe trampolines? */
- if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ /* 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? */
+ if ((ret < 0
+ || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ && ! (tsk || arch_unw_user_mode(&info)))
_stp_stack_print_fallback(UNW_SP(&info), verbose, levels);
- break;
+ return;
}
#else /* ! STP_USE_DWARF_UNWINDER */
_stp_stack_print_fallback((unsigned long)&REG_SP(regs), verbose, levels);
diff --git a/runtime/stack-ia64.c b/runtime/stack-ia64.c
index ca9d25a6..a04355fa 100644
--- a/runtime/stack-ia64.c
+++ b/runtime/stack-ia64.c
@@ -48,7 +48,8 @@ static void __stp_show_stack_addr(struct unw_frame_info *info, void *arg)
} while (unw_unwind(info) >= 0);
}
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long *stack = (unsigned long *)&REG_SP(regs);
struct dump_para para;
diff --git a/runtime/stack-ppc64.c b/runtime/stack-ppc64.c
index 3dc38526..3267194e 100644
--- a/runtime/stack-ppc64.c
+++ b/runtime/stack-ppc64.c
@@ -7,7 +7,8 @@
* later version.
*/
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long ip, newsp, lr = 0;
int count = 0;
diff --git a/runtime/stack-s390.c b/runtime/stack-s390.c
index c9654102..14e9b7d8 100644
--- a/runtime/stack-s390.c
+++ b/runtime/stack-s390.c
@@ -66,7 +66,8 @@ __stp_show_stack (unsigned long sp, unsigned long low,
}
static void __stp_stack_print (struct pt_regs *regs,
- int verbose, int levels)
+ int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long *_sp = (unsigned long *)&REG_SP(regs);
unsigned long sp = (unsigned long)_sp;
diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c
index 03d88ef0..9afdf38a 100644
--- a/runtime/stack-x86_64.c
+++ b/runtime/stack-x86_64.c
@@ -19,7 +19,7 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
/* cannot access stack. give up. */
return;
}
- if (_stp_func_print(addr, verbose, 0))
+ if (_stp_func_print(addr, verbose, 0, NULL))
levels--;
stack++;
}
@@ -27,26 +27,31 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
#endif
-static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
#ifdef STP_USE_DWARF_UNWINDER
// FIXME: large stack allocation
struct unwind_frame_info info;
arch_unw_init_frame_info(&info, regs);
- while (levels && !arch_unw_user_mode(&info)) {
- int ret = unwind(&info);
+ while (levels && (tsk || !arch_unw_user_mode(&info))) {
+ int ret = unwind(&info, tsk);
dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info));
if (ret == 0) {
- _stp_func_print(UNW_PC(&info), verbose, 1);
+ _stp_func_print(UNW_PC(&info), verbose, 1, tsk);
levels--;
continue;
}
- /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */
- /* FIXME: is there a way to unwind across kretprobe trampolines? */
- if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ /* 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? */
+ if ((ret < 0
+ || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ && ! (tsk || arch_unw_user_mode(&info)))
_stp_stack_print_fallback(UNW_SP(&info), verbose, levels);
- break;
+ return;
}
#else /* ! STP_USE_DWARF_UNWINDER */
_stp_stack_print_fallback(REG_SP(regs), verbose, levels);
diff --git a/runtime/stack.c b/runtime/stack.c
index 68fb9b1f..042f44c7 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
* Stack tracing functions
- * Copyright (C) 2005-2008 Red Hat Inc.
+ * Copyright (C) 2005-2009 Red Hat Inc.
* Copyright (C) 2005 Intel Corporation.
*
* This file is part of systemtap, and is free software. You can
@@ -77,7 +77,7 @@ static void print_stack_address(void *data, unsigned long addr, int reliable)
{
struct print_stack_data *sdata = data;
if (sdata->level++ < sdata->max_level)
- _stp_func_print(addr,sdata->verbose, 0);
+ _stp_func_print(addr, sdata->verbose, 0, NULL);
}
static const struct stacktrace_ops print_stack_ops = {
@@ -107,7 +107,7 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
* @param regs A pointer to the struct pt_regs.
*/
-static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
+static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk)
{
if (verbose) {
/* print the current address */
@@ -118,7 +118,10 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
_stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
} else {
_stp_print_char(' ');
- _stp_symbol_print(REG_IP(regs));
+ if (tsk)
+ _stp_usymbol_print(REG_IP(regs), tsk);
+ else
+ _stp_symbol_print(REG_IP(regs));
}
_stp_print_char('\n');
} else if (pi)
@@ -126,7 +129,7 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
else
_stp_printf("%p ", (int64_t) REG_IP(regs));
- __stp_stack_print(regs, verbose, levels);
+ __stp_stack_print(regs, verbose, levels, tsk);
}
/** Writes stack backtrace to a string
@@ -135,37 +138,20 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
* @param regs A pointer to the struct pt_regs.
* @returns void
*/
-static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
+static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk)
{
/* To get a string, we use a simple trick. First flush the print buffer, */
/* then call _stp_stack_print, then copy the result into the output string */
/* and clear the print buffer. */
_stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
_stp_print_flush();
- _stp_stack_print(regs, verbose, pi, levels);
+ _stp_stack_print(regs, verbose, pi, levels, tsk);
strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
pb->len = 0;
}
#endif /* CONFIG_KPROBES */
-/** Prints the user stack backtrace
- * @param str string
- * @returns Same string as was input with trace info appended,
- * @note Currently limited to a depth of two. Works from jprobes and kprobes.
- */
-#if 0
-static void _stp_ustack_print(char *str)
-{
- struct pt_regs *nregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)current->thread_info)) - 1;
- _stp_printf("%p : [user]\n", (int64_t) REG_IP(nregs));
- if (REG_SP(nregs))
- _stp_printf("%p : [user]\n", (int64_t) (*(unsigned long *)REG_SP(nregs)));
-}
-#endif /* 0 */
-
-/** @} */
-
void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
{
#if defined(STAPCONF_KERNEL_STACKTRACE)
diff --git a/runtime/sym.c b/runtime/sym.c
index f6f97ac2..013edd0c 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -329,8 +329,35 @@ static void _stp_symbol_print(unsigned long address)
}
}
+/** Print an user space address from a specific task symbolically.
+ * @param address The address to lookup.
+ * @param task The address to lookup.
+ * @note Symbolic lookups should not normally be done within
+ * a probe because it is too time-consuming. Use at module exit time.
+ */
+
+static void _stp_usymbol_print(unsigned long address, struct task_struct *task)
+{
+ const char *modname;
+ const char *name;
+ unsigned long offset, size;
+
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL,
+ task);
+
+ _stp_printf("%p", (int64_t) address);
+
+ if (name) {
+ if (modname && *modname)
+ _stp_printf(" : %s+%#lx/%#lx [%s]", name, offset, size, modname);
+ else
+ _stp_printf(" : %s+%#lx/%#lx", name, offset, size);
+ }
+}
+
/* Like _stp_symbol_print, except only print if the address is a valid function address */
-static int _stp_func_print(unsigned long address, int verbose, int exact)
+static int _stp_func_print(unsigned long address, int verbose, int exact,
+ struct task_struct *task)
{
const char *modname;
const char *name;
@@ -342,7 +369,7 @@ static int _stp_func_print(unsigned long address, int verbose, int exact)
else
exstr = " (inexact)";
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, NULL);
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, task);
if (name) {
if (verbose) {
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 41af72a7..aacd56f1 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -435,12 +435,18 @@ adjustStartLoc (unsigned long startLoc,
struct _stp_module *m,
struct _stp_section *s)
{
- if (startLoc && (strcmp (m->name, "kernel") != 0))
- {
- startLoc = _stp_module_relocate (m->name, s->name,
- startLoc);
- startLoc -= m->dwarf_module_base;
- }
+ /* XXX - some, or all, of this should really be done by
+ _stp_module_relocate. */
+ if (startLoc == 0
+ || strcmp (m->name, "kernel") == 0
+ || strcmp (s->name, ".absolute") == 0)
+ return startLoc;
+
+ if (strcmp (s->name, ".dynamic") == 0)
+ return startLoc + s->addr;
+
+ startLoc = _stp_module_relocate (m->name, s->name, startLoc);
+ startLoc -= m->dwarf_module_base;
return startLoc;
}
@@ -562,7 +568,7 @@ static char *_stp_eh_enc_name(signed type)
/* Unwind to previous to frame. Returns 0 if successful, negative
* number in case of an error. A positive return means unwinding is finished;
* don't try to fallback to dumping addresses on the stack. */
-static int unwind(struct unwind_frame_info *frame)
+static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
{
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
const u32 *fde, *cie = NULL;
@@ -581,7 +587,7 @@ static int unwind(struct unwind_frame_info *frame)
if (UNW_PC(frame) == 0)
return -EINVAL;
- m = _stp_mod_sec_lookup (pc, current, &s);
+ m = _stp_mod_sec_lookup (pc, tsk, &s);
if (unlikely(m == NULL)) {
dbug_unwind(1, "No module found for pc=%lx", pc);
return -EINVAL;
diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c
index 9ea05349..07ad3984 100644
--- a/runtime/uprobes2/uprobes.c
+++ b/runtime/uprobes2/uprobes.c
@@ -2239,7 +2239,8 @@ static u32 uprobe_report_exit(enum utrace_resume_action action,
}
}
up_read(&uproc->rwsem);
- if (utask->state == UPTASK_TRAMPOLINE_HIT)
+ if (utask->state == UPTASK_TRAMPOLINE_HIT ||
+ utask->state == UPTASK_BP_HIT)
uprobe_decref_process(uproc);
}