Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dumpstack.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1991, 1992 Linus Torvalds
3  * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
4  * Copyright (C) 2009 Matt Fleming
5  * Copyright (C) 2002 - 2012 Paul Mundt
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License. See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 #include <linux/kallsyms.h>
12 #include <linux/ftrace.h>
13 #include <linux/debug_locks.h>
14 #include <linux/kdebug.h>
15 #include <linux/export.h>
16 #include <linux/uaccess.h>
17 #include <asm/unwinder.h>
18 #include <asm/stacktrace.h>
19 
20 void dump_mem(const char *str, unsigned long bottom, unsigned long top)
21 {
22  unsigned long p;
23  int i;
24 
25  printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
26 
27  for (p = bottom & ~31; p < top; ) {
28  printk("%04lx: ", p & 0xffff);
29 
30  for (i = 0; i < 8; i++, p += 4) {
31  unsigned int val;
32 
33  if (p < bottom || p >= top)
34  printk(" ");
35  else {
36  if (__get_user(val, (unsigned int __user *)p)) {
37  printk("\n");
38  return;
39  }
40  printk("%08x ", val);
41  }
42  }
43  printk("\n");
44  }
45 }
46 
47 void printk_address(unsigned long address, int reliable)
48 {
49  printk(" [<%p>] %s%pS\n", (void *) address,
50  reliable ? "" : "? ", (void *) address);
51 }
52 
53 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
54 static void
55 print_ftrace_graph_addr(unsigned long addr, void *data,
56  const struct stacktrace_ops *ops,
57  struct thread_info *tinfo, int *graph)
58 {
59  struct task_struct *task = tinfo->task;
60  unsigned long ret_addr;
61  int index = task->curr_ret_stack;
62 
63  if (addr != (unsigned long)return_to_handler)
64  return;
65 
66  if (!task->ret_stack || index < *graph)
67  return;
68 
69  index -= *graph;
70  ret_addr = task->ret_stack[index].ret;
71 
72  ops->address(data, ret_addr, 1);
73 
74  (*graph)++;
75 }
76 #else
77 static inline void
78 print_ftrace_graph_addr(unsigned long addr, void *data,
79  const struct stacktrace_ops *ops,
80  struct thread_info *tinfo, int *graph)
81 { }
82 #endif
83 
84 void
85 stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
86  unsigned long *sp, const struct stacktrace_ops *ops,
87  void *data)
88 {
89  struct thread_info *context;
90  int graph = 0;
91 
92  context = (struct thread_info *)
93  ((unsigned long)sp & (~(THREAD_SIZE - 1)));
94 
95  while (!kstack_end(sp)) {
96  unsigned long addr = *sp++;
97 
98  if (__kernel_text_address(addr)) {
99  ops->address(data, addr, 1);
100 
101  print_ftrace_graph_addr(addr, data, ops,
102  context, &graph);
103  }
104  }
105 }
106 
107 static int print_trace_stack(void *data, char *name)
108 {
109  printk("%s <%s> ", (char *)data, name);
110  return 0;
111 }
112 
113 /*
114  * Print one address/symbol entries per line.
115  */
116 static void print_trace_address(void *data, unsigned long addr, int reliable)
117 {
118  printk(data);
119  printk_address(addr, reliable);
120 }
121 
122 static const struct stacktrace_ops print_trace_ops = {
123  .stack = print_trace_stack,
124  .address = print_trace_address,
125 };
126 
127 void show_trace(struct task_struct *tsk, unsigned long *sp,
128  struct pt_regs *regs)
129 {
130  if (regs && user_mode(regs))
131  return;
132 
133  printk("\nCall trace:\n");
134 
135  unwind_stack(tsk, regs, sp, &print_trace_ops, "");
136 
137  printk("\n");
138 
139  if (!tsk)
140  tsk = current;
141 
143 }
144 
145 void show_stack(struct task_struct *tsk, unsigned long *sp)
146 {
147  unsigned long stack;
148 
149  if (!tsk)
150  tsk = current;
151  if (tsk == current)
152  sp = (unsigned long *)current_stack_pointer;
153  else
154  sp = (unsigned long *)tsk->thread.sp;
155 
156  stack = (unsigned long)sp;
157  dump_mem("Stack: ", stack, THREAD_SIZE +
158  (unsigned long)task_stack_page(tsk));
159  show_trace(tsk, sp, NULL);
160 }
161 
162 void dump_stack(void)
163 {
164  show_stack(NULL, NULL);
165 }