]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/x86/kernel/dumpstack.c
Merge branch 'core-debugobjects-for-linus' of git://git.kernel.org/pub/scm/linux...
[karo-tx-linux.git] / arch / x86 / kernel / dumpstack.c
index 92e8f0a7159cadbafba6763081c2b33293be420a..0cfd01d2754cc9e074c5f44cb79b212e3afa7e68 100644 (file)
 #include <linux/sysfs.h>
 
 #include <asm/stacktrace.h>
-
+#include <asm/unwind.h>
 
 int panic_on_unrecovered_nmi;
 int panic_on_io_nmi;
 unsigned int code_bytes = 64;
-int kstack_depth_to_print = 3 * STACKSLOTS_PER_LINE;
 static int die_counter;
 
-static void printk_stack_address(unsigned long address, int reliable,
-               void *data)
+bool in_task_stack(unsigned long *stack, struct task_struct *task,
+                  struct stack_info *info)
 {
-       printk("%s [<%p>] %s%pB\n",
-               (char *)data, (void *)address, reliable ? "" : "? ",
-               (void *)address);
-}
+       unsigned long *begin = task_stack_page(task);
+       unsigned long *end   = task_stack_page(task) + THREAD_SIZE;
 
-void printk_address(unsigned long address)
-{
-       pr_cont(" [<%p>] %pS\n", (void *)address, (void *)address);
-}
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-static void
-print_ftrace_graph_addr(unsigned long addr, void *data,
-                       const struct stacktrace_ops *ops,
-                       struct task_struct *task, int *graph)
-{
-       unsigned long ret_addr;
-       int index;
-
-       if (addr != (unsigned long)return_to_handler)
-               return;
+       if (stack < begin || stack >= end)
+               return false;
 
-       index = task->curr_ret_stack;
+       info->type      = STACK_TYPE_TASK;
+       info->begin     = begin;
+       info->end       = end;
+       info->next_sp   = NULL;
 
-       if (!task->ret_stack || index < *graph)
-               return;
-
-       index -= *graph;
-       ret_addr = task->ret_stack[index].ret;
-
-       ops->address(data, ret_addr, 1);
-
-       (*graph)++;
+       return true;
 }
-#else
-static inline void
-print_ftrace_graph_addr(unsigned long addr, void *data,
-                       const struct stacktrace_ops *ops,
-                       struct task_struct *task, int *graph)
-{ }
-#endif
-
-/*
- * x86-64 can have up to three kernel stacks:
- * process stack
- * interrupt stack
- * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
- */
 
-static inline int valid_stack_ptr(struct task_struct *task,
-                       void *p, unsigned int size, void *end)
+static void printk_stack_address(unsigned long address, int reliable,
+                                char *log_lvl)
 {
-       void *t = task_stack_page(task);
-       if (end) {
-               if (p < end && p >= (end-THREAD_SIZE))
-                       return 1;
-               else
-                       return 0;
-       }
-       return p >= t && p < t + THREAD_SIZE - size;
+       touch_nmi_watchdog();
+       printk("%s %s%pB\n", log_lvl, reliable ? "" : "? ", (void *)address);
 }
 
-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)
+void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+                       unsigned long *stack, char *log_lvl)
 {
-       struct stack_frame *frame = (struct stack_frame *)bp;
+       struct unwind_state state;
+       struct stack_info stack_info = {0};
+       unsigned long visit_mask = 0;
+       int graph_idx = 0;
 
-       /*
-        * If we overflowed the stack into a guard page, jump back to the
-        * bottom of the usable stack.
-        */
-       if ((unsigned long)task_stack_page(task) - (unsigned long)stack <
-           PAGE_SIZE)
-               stack = (unsigned long *)task_stack_page(task);
-
-       while (valid_stack_ptr(task, stack, sizeof(*stack), end)) {
-               unsigned long addr;
-
-               addr = *stack;
-               if (__kernel_text_address(addr)) {
-                       if ((unsigned long) stack == bp + sizeof(long)) {
-                               ops->address(data, addr, 1);
-                               frame = frame->next_frame;
-                               bp = (unsigned long) frame;
-                       } else {
-                               ops->address(data, addr, 0);
-                       }
-                       print_ftrace_graph_addr(addr, data, ops, task, graph);
-               }
-               stack++;
-       }
-       return bp;
-}
-EXPORT_SYMBOL_GPL(print_context_stack);
+       printk("%sCall Trace:\n", log_lvl);
 
-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_frame *frame = (struct stack_frame *)bp;
-       unsigned long *ret_addr = &frame->return_address;
+       unwind_start(&state, task, regs, stack);
+       stack = stack ? : get_stack_pointer(task, regs);
 
-       while (valid_stack_ptr(task, ret_addr, sizeof(*ret_addr), end)) {
-               unsigned long addr = *ret_addr;
+       /*
+        * Iterate through the stacks, starting with the current stack pointer.
+        * Each stack has a pointer to the next one.
+        *
+        * x86-64 can have several stacks:
+        * - task stack
+        * - interrupt stack
+        * - HW exception stacks (double fault, nmi, debug, mce)
+        *
+        * x86-32 can have up to three stacks:
+        * - task stack
+        * - softirq stack
+        * - hardirq stack
+        */
+       for (regs = NULL; stack; stack = stack_info.next_sp) {
+               const char *stack_name;
 
-               if (!__kernel_text_address(addr))
-                       break;
+               /*
+                * If we overflowed the task stack into a guard page, jump back
+                * to the bottom of the usable stack.
+                */
+               if (task_stack_page(task) - (void *)stack < PAGE_SIZE)
+                       stack = task_stack_page(task);
 
-               if (ops->address(data, addr, 1))
+               if (get_stack_info(stack, task, &stack_info, &visit_mask))
                        break;
-               frame = frame->next_frame;
-               ret_addr = &frame->return_address;
-               print_ftrace_graph_addr(addr, data, ops, task, graph);
-       }
 
-       return (unsigned long)frame;
-}
-EXPORT_SYMBOL_GPL(print_context_stack_bp);
-
-static int print_trace_stack(void *data, char *name)
-{
-       printk("%s <%s> ", (char *)data, name);
-       return 0;
-}
-
-/*
- * Print one address/symbol entries per line.
- */
-static int print_trace_address(void *data, unsigned long addr, int reliable)
-{
-       touch_nmi_watchdog();
-       printk_stack_address(addr, reliable, data);
-       return 0;
-}
-
-static const struct stacktrace_ops print_trace_ops = {
-       .stack                  = print_trace_stack,
-       .address                = print_trace_address,
-       .walk_stack             = print_context_stack,
-};
+               stack_name = stack_type_name(stack_info.type);
+               if (stack_name)
+                       printk("%s <%s>\n", log_lvl, stack_name);
+
+               /*
+                * Scan the stack, printing any text addresses we find.  At the
+                * same time, follow proper stack frames with the unwinder.
+                *
+                * Addresses found during the scan which are not reported by
+                * the unwinder are considered to be additional clues which are
+                * sometimes useful for debugging and are prefixed with '?'.
+                * This also serves as a failsafe option in case the unwinder
+                * goes off in the weeds.
+                */
+               for (; stack < stack_info.end; stack++) {
+                       unsigned long real_addr;
+                       int reliable = 0;
+                       unsigned long addr = READ_ONCE_NOCHECK(*stack);
+                       unsigned long *ret_addr_p =
+                               unwind_get_return_address_ptr(&state);
+
+                       if (!__kernel_text_address(addr))
+                               continue;
+
+                       /*
+                        * Don't print regs->ip again if it was already printed
+                        * by __show_regs() below.
+                        */
+                       if (regs && stack == &regs->ip) {
+                               unwind_next_frame(&state);
+                               continue;
+                       }
 
-void
-show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp, char *log_lvl)
-{
-       printk("%sCall Trace:\n", log_lvl);
-       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
-}
+                       if (stack == ret_addr_p)
+                               reliable = 1;
+
+                       /*
+                        * When function graph tracing is enabled for a
+                        * function, its return address on the stack is
+                        * replaced with the address of an ftrace handler
+                        * (return_to_handler).  In that case, before printing
+                        * the "real" address, we want to print the handler
+                        * address as an "unreliable" hint that function graph
+                        * tracing was involved.
+                        */
+                       real_addr = ftrace_graph_ret_addr(task, &graph_idx,
+                                                         addr, stack);
+                       if (real_addr != addr)
+                               printk_stack_address(addr, 0, log_lvl);
+                       printk_stack_address(real_addr, reliable, log_lvl);
+
+                       if (!reliable)
+                               continue;
+
+                       /*
+                        * Get the next frame from the unwinder.  No need to
+                        * check for an error: if anything goes wrong, the rest
+                        * of the addresses will just be printed as unreliable.
+                        */
+                       unwind_next_frame(&state);
+
+                       /* if the frame has entry regs, print them */
+                       regs = unwind_get_entry_regs(&state);
+                       if (regs)
+                               __show_regs(regs, 0);
+               }
 
-void show_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack, unsigned long bp)
-{
-       show_trace_log_lvl(task, regs, stack, bp, "");
+               if (stack_name)
+                       printk("%s </%s>\n", log_lvl, stack_name);
+       }
 }
 
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
-       unsigned long bp = 0;
-       unsigned long stack;
+       task = task ? : current;
 
        /*
         * Stack frames below this one aren't interesting.  Don't show them
         * if we're printing for %current.
         */
-       if (!sp && (!task || task == current)) {
-               sp = &stack;
-               bp = stack_frame(current, NULL);
-       }
+       if (!sp && task == current)
+               sp = get_stack_pointer(current, NULL);
 
-       show_stack_log_lvl(task, NULL, sp, bp, "");
+       show_trace_log_lvl(task, NULL, sp, KERN_DEFAULT);
 }
 
 void show_stack_regs(struct pt_regs *regs)
 {
-       show_stack_log_lvl(current, regs, (unsigned long *)regs->sp, regs->bp, "");
+       show_trace_log_lvl(current, regs, NULL, KERN_DEFAULT);
 }
 
 static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
@@ -299,14 +268,11 @@ int __die(const char *str, struct pt_regs *regs, long err)
                sp = kernel_stack_pointer(regs);
                savesegment(ss, ss);
        }
-       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
-       print_symbol("%s", regs->ip);
-       printk(" SS:ESP %04x:%08lx\n", ss, sp);
+       printk(KERN_EMERG "EIP: %pS SS:ESP: %04x:%08lx\n",
+              (void *)regs->ip, ss, sp);
 #else
        /* Executive summary in case the oops scrolled away */
-       printk(KERN_ALERT "RIP ");
-       printk_address(regs->ip);
-       printk(" RSP <%016lx>\n", regs->sp);
+       printk(KERN_ALERT "RIP: %pS RSP: %016lx\n", (void *)regs->ip, regs->sp);
 #endif
        return 0;
 }
@@ -329,22 +295,6 @@ void die(const char *str, struct pt_regs *regs, long err)
        oops_end(flags, regs, sig);
 }
 
-static int __init kstack_setup(char *s)
-{
-       ssize_t ret;
-       unsigned long val;
-
-       if (!s)
-               return -EINVAL;
-
-       ret = kstrtoul(s, 0, &val);
-       if (ret)
-               return ret;
-       kstack_depth_to_print = val;
-       return 0;
-}
-early_param("kstack", kstack_setup);
-
 static int __init code_bytes_setup(char *s)
 {
        ssize_t ret;