12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- /*
- * AVR32 specific backtracing code for oprofile
- *
- * Copyright 2008 Weinmann GmbH
- *
- * Author: Nikolaus Voss <n.voss@weinmann.de>
- *
- * Based on i386 oprofile backtrace code by John Levon and David Smith
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
- #include <linux/oprofile.h>
- #include <linux/sched.h>
- #include <linux/uaccess.h>
- /* The first two words of each frame on the stack look like this if we have
- * frame pointers */
- struct frame_head {
- unsigned long lr;
- struct frame_head *fp;
- };
- /* copied from arch/avr32/kernel/process.c */
- static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
- {
- return (p > (unsigned long)tinfo)
- && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
- }
- /* copied from arch/x86/oprofile/backtrace.c */
- static struct frame_head *dump_user_backtrace(struct frame_head *head)
- {
- struct frame_head bufhead[2];
- /* Also check accessibility of one struct frame_head beyond */
- if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
- return NULL;
- if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
- return NULL;
- oprofile_add_trace(bufhead[0].lr);
- /* frame pointers should strictly progress back up the stack
- * (towards higher addresses) */
- if (bufhead[0].fp <= head)
- return NULL;
- return bufhead[0].fp;
- }
- void avr32_backtrace(struct pt_regs * const regs, unsigned int depth)
- {
- /* Get first frame pointer */
- struct frame_head *head = (struct frame_head *)(regs->r7);
- if (!user_mode(regs)) {
- #ifdef CONFIG_FRAME_POINTER
- /*
- * Traverse the kernel stack from frame to frame up to
- * "depth" steps.
- */
- while (depth-- && valid_stack_ptr(task_thread_info(current),
- (unsigned long)head)) {
- oprofile_add_trace(head->lr);
- if (head->fp <= head)
- break;
- head = head->fp;
- }
- #endif
- } else {
- /* Assume we have frame pointers in user mode process */
- while (depth-- && head)
- head = dump_user_backtrace(head);
- }
- }
|