summaryrefslogtreecommitdiffstats
path: root/runtime/stack.c
diff options
context:
space:
mode:
authorhunt <hunt>2005-05-26 07:43:25 +0000
committerhunt <hunt>2005-05-26 07:43:25 +0000
commitabedf3db3774b54ee4ed227e3ae69e55fb0ff76c (patch)
tree77bf164eda3f977ba0e964c92493ea8c248fb6f3 /runtime/stack.c
parent3750373a50833fcda902407e5b260cb8c5799ad6 (diff)
downloadsystemtap-steved-abedf3db3774b54ee4ed227e3ae69e55fb0ff76c.tar.gz
systemtap-steved-abedf3db3774b54ee4ed227e3ae69e55fb0ff76c.tar.xz
systemtap-steved-abedf3db3774b54ee4ed227e3ae69e55fb0ff76c.zip
2005-05-26 Martin Hunt <hunt@redhat.com>
* current.c (_stp_sprint_regs): Implement for i386. * sym.c (_stp_symbol_sprint): Check name before trying to print it. (_stp_symbol_print): Change to macro that calls _stp_symbol_sprint().
Diffstat (limited to 'runtime/stack.c')
-rw-r--r--runtime/stack.c284
1 files changed, 102 insertions, 182 deletions
diff --git a/runtime/stack.c b/runtime/stack.c
index f06475dc..1f7073f5 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -7,104 +7,22 @@
*/
/** @addtogroup stack Stack Tracing Functions
+ * Without frames the best that can be done here is to scan the stack and
+ * display everything that fits in the range of a valid IP. Things like function pointers
+ * on the stack will certainly result in bogus addresses in the backtrace.
+ *
+ * With debug info, we could get a proper backtrace, but it would be too slow to do
+ * during a probe. We can eventually make this a postprocessing feature.
+ *
* @{
*/
#include "sym.c"
+#include "regs.h"
static int (*_stp_kta)(unsigned long addr)=(void *)KTA;
-
-struct frame_head {
- struct frame_head * ebp;
- unsigned long ret;
-} __attribute__((packed));
-
-static struct frame_head *
-dump_backtrace(struct frame_head * head)
-{
- _stp_printf ("db: %lx\n", head->ret);
-
- /* frame pointers should strictly progress back up the stack
- * (towards higher addresses) */
- if (head >= head->ebp)
- return NULL;
-
- return head->ebp;
-}
-
-static int pages_present(struct frame_head * head)
-{
- struct mm_struct * mm = current->mm;
-
- /* FIXME: only necessary once per page */
- if (!check_user_page_readable(mm, (unsigned long)head))
- return 0;
-
- return check_user_page_readable(mm, (unsigned long)(head + 1));
-}
-
-static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
-{
- unsigned long headaddr = (unsigned long)head;
- unsigned long stack = (unsigned long)regs;
- unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
- _stp_log ("%lx %lx %lx\n", headaddr, stack, stack_base);
- return headaddr < stack_base;
-}
-
-void
-x86_backtrace(struct pt_regs * const regs, unsigned int depth)
-{
- struct frame_head *head;
-
-#ifdef CONFIG_X86_64
- head = (struct frame_head *)regs->rbp;
-#else
- head = (struct frame_head *)regs->ebp;
-#endif
-
- if (!user_mode(regs)) {
- _stp_log ("kernel mode\n");
- while (depth-- && valid_kernel_stack(head, regs))
- head = dump_backtrace(head);
- _stp_print_flush();
- return;
- }
-
-#ifdef CONFIG_SMP
- if (!spin_trylock(&current->mm->page_table_lock))
- return;
-#endif
-
- while (depth-- && head && pages_present(head))
- head = dump_backtrace(head);
-
-#ifdef CONFIG_SMP
- spin_unlock(&current->mm->page_table_lock);
-#endif
- _stp_print_flush();
-}
-
-
-#ifdef __x86_64__
-static void __stp_stack_print (unsigned long *stack, int verbose, int levels)
-{
- unsigned long addr;
- while (((long) stack & (THREAD_SIZE-1)) != 0) {
- addr = *stack;
- if (_stp_kta(addr)) {
- if (verbose) {
- _stp_symbol_print (addr);
- _stp_print ("\n");
- } else
- _stp_printf ("0x%lx ", addr);
- }
- stack++;
- }
- _stp_print_flush();
-}
-
+#if defined (__x86_64__)
static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels)
{
@@ -113,151 +31,153 @@ static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, i
addr = *stack++;
if (_stp_kta(addr)) {
if (verbose) {
+ _stp_string_cat(str, " ");
_stp_symbol_sprint (str, addr);
- _stp_sprintf (str, "\n");
- } else
- _stp_sprintf (str, "0x%lx\n", addr);
+ _stp_string_cat (str, "\n");
+ } else
+ _stp_sprintf (str, " 0x%lx\n", addr);
}
}
}
-#else /* i386 */
+#elif defined (__i386__)
-static inline int valid_stack_ptr (struct thread_info *tinfo, void *p)
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
{
return p > (void *)tinfo &&
p < (void *)tinfo + THREAD_SIZE - 3;
}
-static inline unsigned long _stp_print_context_stack (
- struct thread_info *tinfo,
- unsigned long *stack,
- unsigned long ebp )
-{
- unsigned long addr;
-
-#ifdef CONFIG_FRAME_POINTER
- while (valid_stack_ptr(tinfo, (void *)ebp)) {
- addr = *(unsigned long *)(ebp + 4);
- _stp_symbol_print (addr);
- _stp_print_cstr("\n");
- ebp = *(unsigned long *)ebp;
- }
-#else
- while (valid_stack_ptr(tinfo, stack)) {
- addr = *stack++;
- if (_stp_kta (addr)) {
- _stp_symbol_print (addr);
- _stp_print_cstr ("\n");
- }
- }
-#endif
- _stp_print_flush();
- return ebp;
-}
-
-static inline unsigned long _stp_sprint_context_stack (
- String str,
- struct thread_info *tinfo,
- unsigned long *stack,
- unsigned long ebp )
+static inline unsigned long print_context_stack(String str, struct thread_info *tinfo,
+ unsigned long *stack, unsigned long ebp)
{
unsigned long addr;
#ifdef CONFIG_FRAME_POINTER
while (valid_stack_ptr(tinfo, (void *)ebp)) {
addr = *(unsigned long *)(ebp + 4);
+ _stp_string_cat(str, " ");
_stp_symbol_sprint (str, addr);
- _stp_string_cat (str, "\n");
+ _stp_string_cat(str, "\n");
ebp = *(unsigned long *)ebp;
}
#else
while (valid_stack_ptr(tinfo, stack)) {
addr = *stack++;
- if (_stp_kta (addr)) {
- _stp_symbol_sprint (str, addr);
- _stp_string_cat (str, "\n");
+ if (_stp_kta(addr)) {
+ _stp_string_cat(str, " ");
+ _stp_symbol_sprint(str, addr);
+ _stp_string_cat(str, "\n");
}
}
#endif
return ebp;
}
-static void __stp_stack_print (unsigned long *stack, int verbose, int levels)
+static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels)
{
unsigned long ebp;
/* Grab ebp right from our regs */
asm ("movl %%ebp, %0" : "=r" (ebp) : );
- while (stack) {
- struct thread_info *context = (struct thread_info *)
+ while (1) {
+ struct thread_info *context;
+ context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1)));
- ebp = _stp_print_context_stack (context, stack, ebp);
+ ebp = print_context_stack(str, context, stack, ebp);
stack = (unsigned long*)context->previous_esp;
+ if (!stack)
+ break;
}
- _stp_print_flush ();
}
-static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels)
-{
- unsigned long ebp;
- /* Grab ebp right from our regs */
- asm ("movl %%ebp, %0" : "=r" (ebp) : );
-
- while (stack) {
- struct thread_info *context = (struct thread_info *)
- ((unsigned long)stack & (~(THREAD_SIZE - 1)));
- ebp = _stp_sprint_context_stack (str, context, stack, ebp);
- stack = (unsigned long*)context->previous_esp;
- }
-}
+#else
+#error "Unsupported architecture"
+#endif
-#endif /* i386 */
-/** Print stack dump.
- * Prints a stack dump to the print buffer.
- * @param verbose Verbosity
- * @param levels Number of levels to trace.
- * @todo Implement verbosity and levels parameters.
- * @bug levels parameter is not functional
+/** Writes stack backtrace to a String
+ *
+ * @param str String
+ * @param regs A pointer to the struct pt_regs.
+ * @returns Same String as was input with trace info appended,
*/
-
-void _stp_stack_jprint (int verbose, int levels)
+String _stp_stack_sprint (String str, struct pt_regs *regs)
{
- unsigned long stack;
- __stp_stack_print (&stack, verbose, levels);
+ _stp_sprintf (str, "trace for %d (%s)\n ", current->pid, current->comm);
+ _stp_symbol_sprint (str, REG_IP(regs));
+ _stp_string_cat(str, "\n");
+ __stp_stack_sprint (str, (unsigned long *)&REG_SP(regs), 1, 0);
+ return str;
}
-void _stp_stack_print (struct pt_regs *regs, int verbose, int levels)
-{
- if (verbose) {
- _stp_printf ("trace for %d (%s)\n", current->pid, current->comm);
- _stp_symbol_print (regs->rip);
- _stp_print ("\n");
- } else
- _stp_printf ("0x%lx ", regs->rip);
+/** Prints the stack backtrace
+ * @param regs A pointer to the struct pt_regs.
+ * @note Calls _stp_print_flush().
+ */
- __stp_stack_print ((unsigned long *)regs->rsp, verbose, levels);
-}
+#define _stp_stack_print(regs) \
+ { \
+ (void)_stp_stack_sprint(_stp_stdout,regs); \
+ _stp_print_flush(); \
+ }
-/** Writes stack dump to a String
- *
+/** Writes stack backtrace to a String.
+ * Use this when calling from a jprobe.
* @param str String
- * @param verbose Verbosity
- * @param levels Number of levels to trace.
- * @returns Same String as was input.
- * @todo Implement verbosity and levels parameters.
- * @bug levels parameter is not functional
+ * @returns Same String as was input with trace info appended,
+ * @sa _stp_stack_sprint()
+ */
+String _stp_stack_sprintj(String str)
+{
+ unsigned long stack;
+ _stp_sprintf (str, "trace for %d (%s)\n", current->pid, current->comm);
+ __stp_stack_sprint (str, &stack, 1, 0);
+ return str;
+}
+
+/** Prints the stack backtrace.
+ * Use this when calling from a jprobe.
+ * @sa _stp_stack_print()
+ * @note Calls _stp_print_flush().
*/
+#define _stp_stack_printj() \
+ { \
+ (void)_stp_stack_sprintj(_stp_stdout); \
+ _stp_print_flush(); \
+ }
-String _stp_stack_sprint (String str, int verbose, int levels)
+/** Writes the user stack backtrace to a String
+ * @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.
+ */
+String _stp_ustack_sprint (String str)
{
- unsigned long stack;
- __stp_stack_sprint (str, &stack, verbose, levels);
- return str;
+ struct pt_regs *nregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) current->thread_info)) - 1;
+#if BITS_PER_LONG == 64
+ _stp_sprintf (str, " 0x%016lx : [user]\n", REG_IP(nregs));
+ if (REG_SP(nregs))
+ _stp_sprintf (str, " 0x%016lx : [user]\n", *(unsigned long *)REG_SP(nregs));
+#else
+ _stp_sprintf (str, " 0x%08lx : [user]\n", REG_IP(nregs));
+ if (REG_SP(nregs))
+ _stp_sprintf (str, " 0x%08lx : [user]\n", *(unsigned long *)REG_SP(nregs));
+#endif
+ return str;
}
+/** Prints the user stack backtrace
+ * @note Currently limited to a depth of two. Works from jprobes and kprobes.
+ * Calls _stp_print_flush().
+ */
+#define _stp_ustack_print() \
+ { \
+ (void)_stp_ustack_sprint(_stp_stdout); \
+ _stp_print_flush(); \
+ }
+
/** @} */
#endif /* _STACK_C_ */