Merge branch 'linus' into x86/mce3
[safe/jmp/linux-2.6] / arch / x86 / kernel / stacktrace.c
index b151530..4aaf7e4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Stack trace management functions
  *
- *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *  Copyright (C) 2006-2009 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  */
 #include <linux/sched.h>
 #include <linux/stacktrace.h>
@@ -20,7 +20,7 @@ save_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
 
 static int save_stack_stack(void *data, char *name)
 {
-       return -1;
+       return 0;
 }
 
 static void save_stack_address(void *data, unsigned long addr, int reliable)
@@ -89,7 +89,7 @@ EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
 
 struct stack_frame {
        const void __user       *next_fp;
-       unsigned long           return_address;
+       unsigned long           ret_addr;
 };
 
 static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
@@ -108,33 +108,40 @@ static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
        return ret;
 }
 
+static inline void __save_stack_trace_user(struct stack_trace *trace)
+{
+       const struct pt_regs *regs = task_pt_regs(current);
+       const void __user *fp = (const void __user *)regs->bp;
+
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = regs->ip;
+
+       while (trace->nr_entries < trace->max_entries) {
+               struct stack_frame frame;
+
+               frame.next_fp = NULL;
+               frame.ret_addr = 0;
+               if (!copy_stack_frame(fp, &frame))
+                       break;
+               if ((unsigned long)fp < regs->sp)
+                       break;
+               if (frame.ret_addr) {
+                       trace->entries[trace->nr_entries++] =
+                               frame.ret_addr;
+               }
+               if (fp == frame.next_fp)
+                       break;
+               fp = frame.next_fp;
+       }
+}
+
 void save_stack_trace_user(struct stack_trace *trace)
 {
        /*
         * Trace user stack if we are not a kernel thread
         */
        if (current->mm) {
-               const struct pt_regs *regs = task_pt_regs(current);
-               const void __user *fp = (const void __user *)regs->bp;
-
-               if (trace->nr_entries < trace->max_entries)
-                       trace->entries[trace->nr_entries++] = regs->ip;
-
-               while (trace->nr_entries < trace->max_entries) {
-                       struct stack_frame frame;
-                       frame.next_fp = NULL;
-                       frame.return_address = 0;
-                       if (!copy_stack_frame(fp, &frame))
-                               break;
-                       if ((unsigned long)fp < regs->sp)
-                               break;
-                       if (frame.return_address)
-                               trace->entries[trace->nr_entries++] =
-                                       frame.return_address;
-                       if (fp == frame.next_fp)
-                               break;
-                       fp = frame.next_fp;
-               }
+               __save_stack_trace_user(trace);
        }
        if (trace->nr_entries < trace->max_entries)
                trace->entries[trace->nr_entries++] = ULONG_MAX;