x86/dumpstack: Remove NULL task pointer convention
[cascardo/linux.git] / arch / x86 / include / asm / stacktrace.h
index 0944218..ed2be1b 100644 (file)
@@ -8,6 +8,40 @@
 
 #include <linux/uaccess.h>
 #include <linux/ptrace.h>
+#include <asm/switch_to.h>
+
+enum stack_type {
+       STACK_TYPE_UNKNOWN,
+       STACK_TYPE_TASK,
+       STACK_TYPE_IRQ,
+       STACK_TYPE_SOFTIRQ,
+       STACK_TYPE_EXCEPTION,
+       STACK_TYPE_EXCEPTION_LAST = STACK_TYPE_EXCEPTION + N_EXCEPTION_STACKS-1,
+};
+
+struct stack_info {
+       enum stack_type type;
+       unsigned long *begin, *end, *next_sp;
+};
+
+bool in_task_stack(unsigned long *stack, struct task_struct *task,
+                  struct stack_info *info);
+
+int get_stack_info(unsigned long *stack, struct task_struct *task,
+                  struct stack_info *info, unsigned long *visit_mask);
+
+void stack_type_str(enum stack_type type, const char **begin,
+                   const char **end);
+
+static inline bool on_stack(struct stack_info *info, void *addr, size_t len)
+{
+       void *begin = info->begin;
+       void *end   = info->end;
+
+       return (info->type != STACK_TYPE_UNKNOWN &&
+               addr >= begin && addr < end &&
+               addr + len > begin && addr + len <= end);
+}
 
 extern int kstack_depth_to_print;
 
@@ -19,27 +53,27 @@ typedef unsigned long (*walk_stack_t)(struct task_struct *task,
                                      unsigned long bp,
                                      const struct stacktrace_ops *ops,
                                      void *data,
-                                     unsigned long *end,
+                                     struct stack_info *info,
                                      int *graph);
 
 extern unsigned long
 print_context_stack(struct task_struct *task,
                    unsigned long *stack, unsigned long bp,
                    const struct stacktrace_ops *ops, void *data,
-                   unsigned long *end, int *graph);
+                   struct stack_info *info, int *graph);
 
 extern unsigned long
 print_context_stack_bp(struct task_struct *task,
                       unsigned long *stack, unsigned long bp,
                       const struct stacktrace_ops *ops, void *data,
-                      unsigned long *end, int *graph);
+                      struct stack_info *info, int *graph);
 
 /* Generic stack tracer with callbacks */
 
 struct stacktrace_ops {
        int (*address)(void *data, unsigned long address, int reliable);
        /* On negative return stop dumping */
-       int (*stack)(void *data, char *name);
+       int (*stack)(void *data, const char *name);
        walk_stack_t    walk_stack;
 };
 
@@ -49,37 +83,41 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
 
 #ifdef CONFIG_X86_32
 #define STACKSLOTS_PER_LINE 8
-#define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
 #else
 #define STACKSLOTS_PER_LINE 4
-#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
 #endif
 
 #ifdef CONFIG_FRAME_POINTER
-static inline unsigned long
-stack_frame(struct task_struct *task, struct pt_regs *regs)
+static inline unsigned long *
+get_frame_pointer(struct task_struct *task, struct pt_regs *regs)
 {
-       unsigned long bp;
-
        if (regs)
-               return regs->bp;
+               return (unsigned long *)regs->bp;
 
-       if (task == current) {
-               /* Grab bp right from our regs */
-               get_bp(bp);
-               return bp;
-       }
+       if (task == current)
+               return __builtin_frame_address(0);
 
-       /* bp is the last reg pushed by switch_to */
-       return *(unsigned long *)task->thread.sp;
+       return (unsigned long *)((struct inactive_task_frame *)task->thread.sp)->bp;
 }
 #else
-static inline unsigned long
-stack_frame(struct task_struct *task, struct pt_regs *regs)
+static inline unsigned long *
+get_frame_pointer(struct task_struct *task, struct pt_regs *regs)
 {
-       return 0;
+       return NULL;
+}
+#endif /* CONFIG_FRAME_POINTER */
+
+static inline unsigned long *
+get_stack_pointer(struct task_struct *task, struct pt_regs *regs)
+{
+       if (regs)
+               return (unsigned long *)kernel_stack_pointer(regs);
+
+       if (task == current)
+               return __builtin_frame_address(0);
+
+       return (unsigned long *)task->thread.sp;
 }
-#endif
 
 extern void
 show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
@@ -106,7 +144,7 @@ static inline unsigned long caller_frame_pointer(void)
 {
        struct stack_frame *frame;
 
-       get_bp(frame);
+       frame = __builtin_frame_address(0);
 
 #ifdef CONFIG_FRAME_POINTER
        frame = frame->next_frame;