linux/arch/x86/kernel/dumpstack_32.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 1991, 1992  Linus Torvalds
   3 *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
   4 */
   5#include <linux/kallsyms.h>
   6#include <linux/kprobes.h>
   7#include <linux/uaccess.h>
   8#include <linux/hardirq.h>
   9#include <linux/kdebug.h>
  10#include <linux/module.h>
  11#include <linux/ptrace.h>
  12#include <linux/kexec.h>
  13#include <linux/sysfs.h>
  14#include <linux/bug.h>
  15#include <linux/nmi.h>
  16
  17#include <asm/stacktrace.h>
  18
  19
  20void dump_trace(struct task_struct *task, struct pt_regs *regs,
  21                unsigned long *stack, unsigned long bp,
  22                const struct stacktrace_ops *ops, void *data)
  23{
  24        int graph = 0;
  25
  26        if (!task)
  27                task = current;
  28
  29        if (!stack) {
  30                unsigned long dummy;
  31
  32                stack = &dummy;
  33                if (task && task != current)
  34                        stack = (unsigned long *)task->thread.sp;
  35        }
  36
  37        if (!bp)
  38                bp = stack_frame(task, regs);
  39
  40        for (;;) {
  41                struct thread_info *context;
  42
  43                context = (struct thread_info *)
  44                        ((unsigned long)stack & (~(THREAD_SIZE - 1)));
  45                bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
  46
  47                stack = (unsigned long *)context->previous_esp;
  48                if (!stack)
  49                        break;
  50                if (ops->stack(data, "IRQ") < 0)
  51                        break;
  52                touch_nmi_watchdog();
  53        }
  54}
  55EXPORT_SYMBOL(dump_trace);
  56
  57void
  58show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
  59                   unsigned long *sp, unsigned long bp, char *log_lvl)
  60{
  61        unsigned long *stack;
  62        int i;
  63
  64        if (sp == NULL) {
  65                if (task)
  66                        sp = (unsigned long *)task->thread.sp;
  67                else
  68                        sp = (unsigned long *)&sp;
  69        }
  70
  71        stack = sp;
  72        for (i = 0; i < kstack_depth_to_print; i++) {
  73                if (kstack_end(stack))
  74                        break;
  75                if (i && ((i % STACKSLOTS_PER_LINE) == 0))
  76                        pr_cont("\n");
  77                pr_cont(" %08lx", *stack++);
  78                touch_nmi_watchdog();
  79        }
  80        pr_cont("\n");
  81        show_trace_log_lvl(task, regs, sp, bp, log_lvl);
  82}
  83
  84
  85void show_regs(struct pt_regs *regs)
  86{
  87        int i;
  88
  89        show_regs_print_info(KERN_EMERG);
  90        __show_regs(regs, !user_mode_vm(regs));
  91
  92        /*
  93         * When in-kernel, we also print out the stack and code at the
  94         * time of the fault..
  95         */
  96        if (!user_mode_vm(regs)) {
  97                unsigned int code_prologue = code_bytes * 43 / 64;
  98                unsigned int code_len = code_bytes;
  99                unsigned char c;
 100                u8 *ip;
 101
 102                pr_emerg("Stack:\n");
 103                show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
 104
 105                pr_emerg("Code:");
 106
 107                ip = (u8 *)regs->ip - code_prologue;
 108                if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
 109                        /* try starting at IP */
 110                        ip = (u8 *)regs->ip;
 111                        code_len = code_len - code_prologue + 1;
 112                }
 113                for (i = 0; i < code_len; i++, ip++) {
 114                        if (ip < (u8 *)PAGE_OFFSET ||
 115                                        probe_kernel_address(ip, c)) {
 116                                pr_cont("  Bad EIP value.");
 117                                break;
 118                        }
 119                        if (ip == (u8 *)regs->ip)
 120                                pr_cont(" <%02x>", c);
 121                        else
 122                                pr_cont(" %02x", c);
 123                }
 124        }
 125        pr_cont("\n");
 126}
 127
 128int is_valid_bugaddr(unsigned long ip)
 129{
 130        unsigned short ud2;
 131
 132        if (ip < PAGE_OFFSET)
 133                return 0;
 134        if (probe_kernel_address((unsigned short *)ip, ud2))
 135                return 0;
 136
 137        return ud2 == 0x0b0f;
 138}
 139