1*970e51feSDaniel Walter /* 2*970e51feSDaniel Walter * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3*970e51feSDaniel Walter * Copyright (C) 2013 Richard Weinberger <richard@nod.at> 4*970e51feSDaniel Walter * Copyright (C) 2014 Google Inc., Author: Daniel Walter <dwalter@google.com> 5*970e51feSDaniel Walter * 6*970e51feSDaniel Walter * This program is free software; you can redistribute it and/or modify 7*970e51feSDaniel Walter * it under the terms of the GNU General Public License version 2 as 8*970e51feSDaniel Walter * published by the Free Software Foundation. 9*970e51feSDaniel Walter */ 10*970e51feSDaniel Walter 11*970e51feSDaniel Walter #include <linux/kallsyms.h> 12*970e51feSDaniel Walter #include <linux/kernel.h> 13*970e51feSDaniel Walter #include <linux/sched.h> 14*970e51feSDaniel Walter #include <linux/stacktrace.h> 15*970e51feSDaniel Walter #include <linux/module.h> 16*970e51feSDaniel Walter #include <linux/uaccess.h> 17*970e51feSDaniel Walter #include <asm/stacktrace.h> 18*970e51feSDaniel Walter 19*970e51feSDaniel Walter void dump_trace(struct task_struct *tsk, 20*970e51feSDaniel Walter const struct stacktrace_ops *ops, 21*970e51feSDaniel Walter void *data) 22*970e51feSDaniel Walter { 23*970e51feSDaniel Walter int reliable = 0; 24*970e51feSDaniel Walter unsigned long *sp, bp, addr; 25*970e51feSDaniel Walter struct pt_regs *segv_regs = tsk->thread.segv_regs; 26*970e51feSDaniel Walter struct stack_frame *frame; 27*970e51feSDaniel Walter 28*970e51feSDaniel Walter bp = get_frame_pointer(tsk, segv_regs); 29*970e51feSDaniel Walter sp = get_stack_pointer(tsk, segv_regs); 30*970e51feSDaniel Walter 31*970e51feSDaniel Walter frame = (struct stack_frame *)bp; 32*970e51feSDaniel Walter while (((long) sp & (THREAD_SIZE-1)) != 0) { 33*970e51feSDaniel Walter addr = *sp; 34*970e51feSDaniel Walter if (__kernel_text_address(addr)) { 35*970e51feSDaniel Walter reliable = 0; 36*970e51feSDaniel Walter if ((unsigned long) sp == bp + sizeof(long)) { 37*970e51feSDaniel Walter frame = frame ? frame->next_frame : NULL; 38*970e51feSDaniel Walter bp = (unsigned long)frame; 39*970e51feSDaniel Walter reliable = 1; 40*970e51feSDaniel Walter } 41*970e51feSDaniel Walter ops->address(data, addr, reliable); 42*970e51feSDaniel Walter } 43*970e51feSDaniel Walter sp++; 44*970e51feSDaniel Walter } 45*970e51feSDaniel Walter } 46*970e51feSDaniel Walter 47*970e51feSDaniel Walter static void save_addr(void *data, unsigned long address, int reliable) 48*970e51feSDaniel Walter { 49*970e51feSDaniel Walter struct stack_trace *trace = data; 50*970e51feSDaniel Walter 51*970e51feSDaniel Walter if (!reliable) 52*970e51feSDaniel Walter return; 53*970e51feSDaniel Walter if (trace->nr_entries >= trace->max_entries) 54*970e51feSDaniel Walter return; 55*970e51feSDaniel Walter 56*970e51feSDaniel Walter trace->entries[trace->nr_entries++] = address; 57*970e51feSDaniel Walter } 58*970e51feSDaniel Walter 59*970e51feSDaniel Walter static const struct stacktrace_ops dump_ops = { 60*970e51feSDaniel Walter .address = save_addr 61*970e51feSDaniel Walter }; 62*970e51feSDaniel Walter 63*970e51feSDaniel Walter static void __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace) 64*970e51feSDaniel Walter { 65*970e51feSDaniel Walter dump_trace(tsk, &dump_ops, trace); 66*970e51feSDaniel Walter if (trace->nr_entries < trace->max_entries) 67*970e51feSDaniel Walter trace->entries[trace->nr_entries++] = ULONG_MAX; 68*970e51feSDaniel Walter } 69*970e51feSDaniel Walter 70*970e51feSDaniel Walter void save_stack_trace(struct stack_trace *trace) 71*970e51feSDaniel Walter { 72*970e51feSDaniel Walter __save_stack_trace(current, trace); 73*970e51feSDaniel Walter } 74*970e51feSDaniel Walter EXPORT_SYMBOL_GPL(save_stack_trace); 75*970e51feSDaniel Walter 76*970e51feSDaniel Walter void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 77*970e51feSDaniel Walter { 78*970e51feSDaniel Walter __save_stack_trace(tsk, trace); 79*970e51feSDaniel Walter } 80*970e51feSDaniel Walter EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 81