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 */ 6#include <linux/kallsyms.h> 7#include <linux/ftrace.h> 8#include <linux/debug_locks.h> 9#include <asm/unwinder.h> 10#include <asm/stacktrace.h> 11 12void printk_address(unsigned long address, int reliable) 13{ 14 printk(" [<%p>] %s%pS\n", (void *) address, 15 reliable ? "" : "? ", (void *) address); 16} 17 18#ifdef CONFIG_FUNCTION_GRAPH_TRACER 19static void 20print_ftrace_graph_addr(unsigned long addr, void *data, 21 const struct stacktrace_ops *ops, 22 struct thread_info *tinfo, int *graph) 23{ 24 struct task_struct *task = tinfo->task; 25 unsigned long ret_addr; 26 int index = task->curr_ret_stack; 27 28 if (addr != (unsigned long)return_to_handler) 29 return; 30 31 if (!task->ret_stack || index < *graph) 32 return; 33 34 index -= *graph; 35 ret_addr = task->ret_stack[index].ret; 36 37 ops->address(data, ret_addr, 1); 38 39 (*graph)++; 40} 41#else 42static inline void 43print_ftrace_graph_addr(unsigned long addr, void *data, 44 const struct stacktrace_ops *ops, 45 struct thread_info *tinfo, int *graph) 46{ } 47#endif 48 49void 50stack_reader_dump(struct task_struct *task, struct pt_regs *regs, 51 unsigned long *sp, const struct stacktrace_ops *ops, 52 void *data) 53{ 54 struct thread_info *context; 55 int graph = 0; 56 57 context = (struct thread_info *) 58 ((unsigned long)sp & (~(THREAD_SIZE - 1))); 59 60 while (!kstack_end(sp)) { 61 unsigned long addr = *sp++; 62 63 if (__kernel_text_address(addr)) { 64 ops->address(data, addr, 1); 65 66 print_ftrace_graph_addr(addr, data, ops, 67 context, &graph); 68 } 69 } 70} 71 72static void 73print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) 74{ 75 printk(data); 76 print_symbol(msg, symbol); 77 printk("\n"); 78} 79 80static void print_trace_warning(void *data, char *msg) 81{ 82 printk("%s%s\n", (char *)data, msg); 83} 84 85static int print_trace_stack(void *data, char *name) 86{ 87 printk("%s <%s> ", (char *)data, name); 88 return 0; 89} 90 91/* 92 * Print one address/symbol entries per line. 93 */ 94static void print_trace_address(void *data, unsigned long addr, int reliable) 95{ 96 printk(data); 97 printk_address(addr, reliable); 98} 99 100static const struct stacktrace_ops print_trace_ops = { 101 .warning = print_trace_warning, 102 .warning_symbol = print_trace_warning_symbol, 103 .stack = print_trace_stack, 104 .address = print_trace_address, 105}; 106 107void show_trace(struct task_struct *tsk, unsigned long *sp, 108 struct pt_regs *regs) 109{ 110 if (regs && user_mode(regs)) 111 return; 112 113 printk("\nCall trace:\n"); 114 115 unwind_stack(tsk, regs, sp, &print_trace_ops, ""); 116 117 printk("\n"); 118 119 if (!tsk) 120 tsk = current; 121 122 debug_show_held_locks(tsk); 123} 124