1 /* 2 * AVR32 specific backtracing code for oprofile 3 * 4 * Copyright 2008 Weinmann GmbH 5 * 6 * Author: Nikolaus Voss <n.voss@weinmann.de> 7 * 8 * Based on i386 oprofile backtrace code by John Levon and David Smith 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 */ 15 16 #include <linux/oprofile.h> 17 #include <linux/sched.h> 18 #include <linux/uaccess.h> 19 20 /* The first two words of each frame on the stack look like this if we have 21 * frame pointers */ 22 struct frame_head { 23 unsigned long lr; 24 struct frame_head *fp; 25 }; 26 27 /* copied from arch/avr32/kernel/process.c */ valid_stack_ptr(struct thread_info * tinfo,unsigned long p)28static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p) 29 { 30 return (p > (unsigned long)tinfo) 31 && (p < (unsigned long)tinfo + THREAD_SIZE - 3); 32 } 33 34 /* copied from arch/x86/oprofile/backtrace.c */ dump_user_backtrace(struct frame_head * head)35static struct frame_head *dump_user_backtrace(struct frame_head *head) 36 { 37 struct frame_head bufhead[2]; 38 39 /* Also check accessibility of one struct frame_head beyond */ 40 if (!access_ok(VERIFY_READ, head, sizeof(bufhead))) 41 return NULL; 42 if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead))) 43 return NULL; 44 45 oprofile_add_trace(bufhead[0].lr); 46 47 /* frame pointers should strictly progress back up the stack 48 * (towards higher addresses) */ 49 if (bufhead[0].fp <= head) 50 return NULL; 51 52 return bufhead[0].fp; 53 } 54 avr32_backtrace(struct pt_regs * const regs,unsigned int depth)55void avr32_backtrace(struct pt_regs * const regs, unsigned int depth) 56 { 57 /* Get first frame pointer */ 58 struct frame_head *head = (struct frame_head *)(regs->r7); 59 60 if (!user_mode(regs)) { 61 #ifdef CONFIG_FRAME_POINTER 62 /* 63 * Traverse the kernel stack from frame to frame up to 64 * "depth" steps. 65 */ 66 while (depth-- && valid_stack_ptr(task_thread_info(current), 67 (unsigned long)head)) { 68 oprofile_add_trace(head->lr); 69 if (head->fp <= head) 70 break; 71 head = head->fp; 72 } 73 #endif 74 } else { 75 /* Assume we have frame pointers in user mode process */ 76 while (depth-- && head) 77 head = dump_user_backtrace(head); 78 } 79 } 80 81 82