summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
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/staprun/common.c112
-rw-r--r--runtime/sym.c31
-rw-r--r--runtime/syscall.h13
-rw-r--r--runtime/unwind.c22
-rw-r--r--runtime/uprobes2/uprobes.c3
12 files changed, 109 insertions, 166 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/staprun/common.c b/runtime/staprun/common.c
index 26b166c2..c67ce340 100644
--- a/runtime/staprun/common.c
+++ b/runtime/staprun/common.c
@@ -55,112 +55,15 @@ static char *get_abspath(char *path)
int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t)
{
- char *c = buf;
- const char *c2 = fmt, *end = buf + max;
- int ret, num;
struct tm tm;
+ size_t ret;
if (buf == NULL || fmt == NULL || max <= 1)
return -EINVAL;
localtime_r(&t, &tm);
-
- while (*c2 != '\0'){
- if (c + 1 >= end)
- return -EINVAL;
- if (*c2 != '%') {
- *c++ = *c2++;
- continue;
- }
- c2++;
- switch (*c2++) {
- case '%':
- *c++ = '%';
- break;
- case 'Y':
- num = tm.tm_year + 1900;
- goto numbering;
- case 'y':
- num = tm.tm_year % 100;
- goto numbering02;
- case 'C':
- num = ((tm.tm_year + 1900) / 100);
- goto numbering;
- case 'm':
- num = tm.tm_mon + 1;
- goto numbering02;
- case 'd':
- num = tm.tm_mday;
- goto numbering02;
- case 'e':
- num = tm.tm_mday;
- goto numbering;
- case 'F':
- ret = snprintf(c, end - c, "%d-%02d-%02d",
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
- if (ret < 0) return ret;
- c += ret;
- break;
- case 'H':
- num = tm.tm_hour;
- goto numbering02;
- case 'I':
- num = tm.tm_hour % 12;
- if (num == 0) num = 12;
- goto numbering02;
- case 'j':
- ret = snprintf(c, end - c, "%03d", tm.tm_yday + 1);
- if (ret < 0) return ret;
- c += ret;
- break;
- case 'k':
- num = tm.tm_hour;
- goto numbering;
- case 'l':
- num = tm.tm_hour % 12;
- if (num == 0) num = 12;
- ret = snprintf(c, end - c, "%2d", num);
- if (ret < 0) return ret;
- c += ret;
- break;
- case 'M':
- num = tm.tm_min;
- goto numbering02;
- case 'S':
- num = tm.tm_sec;
- goto numbering02;
- case 'R':
- ret = snprintf(c, end - c, "%02d:%02d",
- tm.tm_hour, tm.tm_min);
- if (ret < 0) return ret;
- c += ret;
- break;
- case 'T':
- ret = snprintf(c, end - c, "%02d:%02d:%02d",
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- if (ret < 0) return ret;
- c += ret;
- break;
- case 'u':
- num = tm.tm_wday == 0 ? 7 : tm.tm_wday;
- goto numbering;
- case 'w':
- num = tm.tm_wday;
- goto numbering;
- default:
- return -EINVAL;
- }
- continue;
-numbering:
- ret = snprintf(c, end - c, "%d", num);
- if (ret < 0) return ret;
- c += ret;
- continue;
-numbering02:
- ret = snprintf(c, end - c, "%02d", num);
- if (ret < 0) return ret;
- c += ret;
- }
- *c = '\0';
- return c - buf;
+ ret = strftime(buf, max, fmt, &tm);
+ if (ret == 0)
+ return -EINVAL;
+ return (int)ret;
}
void parse_args(int argc, char **argv)
@@ -309,9 +212,8 @@ void usage(char *prog)
err(" exit when it does. The '_stp_target' variable\n");
err(" will contain the pid for the command.\n");
err("-x pid Sets the '_stp_target' variable to pid.\n");
- err("-o FILE Send output to FILE. This supports a subset of\n");
- err(" strftime(3) (%%%%,%%C,%%Y,%%y,%%m,%%d,%%e,%%F,%%H,%%I\n");
- err(" %%j,%%k,%%l,%%M,%%S,%%R,%%T,%%u,%%w) for FILE.\n");
+ err("-o FILE Send output to FILE. This supports strftime(3)\n");
+ err(" formats for FILE.\n");
err("-b buffer size The systemtap module specifies a buffer size.\n");
err(" Setting one here will override that value. The\n");
err(" value should be an integer between 1 and 4095 \n");
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/syscall.h b/runtime/syscall.h
index ffc21efc..38b523e1 100644
--- a/runtime/syscall.h
+++ b/runtime/syscall.h
@@ -345,6 +345,10 @@ struct syscall_get_set_args {
int rw;
};
+#define CFM_SOF(cfm) ((cfm) & 0x7f) /* Size of frame */
+#define CFM_SOL(cfm) (((cfm) >> 7) & 0x7f) /* Size of locals */
+#define CFM_OUT(cfm) (CFM_SOF(cfm) - CFM_SOL(cfm)) /* Size of outputs */
+
static void syscall_get_set_args_cb(struct unw_frame_info *info, void *data)
{
struct syscall_get_set_args *args = data;
@@ -361,15 +365,18 @@ static void syscall_get_set_args_cb(struct unw_frame_info *info, void *data)
count = 0;
if (in_syscall(pt))
- count = min_t(int, args->n, cfm & 0x7f);
+ /* args->i + args->n must be less equal than nr outputs */
+ count = min_t(int, args->n, CFM_OUT(cfm) - args->i);
for (i = 0; i < count; i++) {
+ /* Skips dirties and locals */
if (args->rw)
- *ia64_rse_skip_regs(krbs, ndirty + i + args->i) =
+ *ia64_rse_skip_regs(krbs,
+ ndirty + CFM_SOL(cfm) + args->i + i) =
args->args[i];
else
args->args[i] = *ia64_rse_skip_regs(krbs,
- ndirty + i + args->i);
+ ndirty + CFM_SOL(cfm) + args->i + i);
}
if (!args->rw) {
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);
}