Commit | Line | Data |
---|---|---|
00e6c923 JH |
1 | /* |
2 | * Copyright (C) 2010-2013 Imagination Technologies Ltd. | |
3 | * | |
4 | * This file is subject to the terms and conditions of the GNU General Public | |
5 | * License. See the file "COPYING" in the main directory of this archive | |
6 | * for more details. | |
7 | */ | |
8 | ||
9 | #include <linux/oprofile.h> | |
10 | #include <linux/uaccess.h> | |
11 | #include <asm/processor.h> | |
12 | #include <asm/stacktrace.h> | |
13 | ||
14 | #include "backtrace.h" | |
15 | ||
16 | static void user_backtrace_fp(unsigned long __user *fp, unsigned int depth) | |
17 | { | |
18 | while (depth-- && access_ok(VERIFY_READ, fp, 8)) { | |
19 | unsigned long addr; | |
20 | unsigned long __user *fpnew; | |
21 | if (__copy_from_user_inatomic(&addr, fp + 1, sizeof(addr))) | |
22 | break; | |
23 | addr -= 4; | |
24 | ||
25 | oprofile_add_trace(addr); | |
26 | ||
27 | /* stack grows up, so frame pointers must decrease */ | |
28 | if (__copy_from_user_inatomic(&fpnew, fp + 0, sizeof(fpnew))) | |
29 | break; | |
30 | if (fpnew >= fp) | |
31 | break; | |
32 | fp = fpnew; | |
33 | } | |
34 | } | |
35 | ||
36 | static int kernel_backtrace_frame(struct stackframe *frame, void *data) | |
37 | { | |
38 | unsigned int *depth = data; | |
39 | ||
40 | oprofile_add_trace(frame->pc); | |
41 | ||
42 | /* decrement depth and stop if we reach 0 */ | |
43 | if ((*depth)-- == 0) | |
44 | return 1; | |
45 | ||
46 | /* otherwise onto the next frame */ | |
47 | return 0; | |
48 | } | |
49 | ||
50 | void metag_backtrace(struct pt_regs * const regs, unsigned int depth) | |
51 | { | |
52 | if (user_mode(regs)) { | |
53 | unsigned long *fp = (unsigned long *)regs->ctx.AX[1].U0; | |
54 | user_backtrace_fp((unsigned long __user __force *)fp, depth); | |
55 | } else { | |
56 | struct stackframe frame; | |
57 | frame.fp = regs->ctx.AX[1].U0; /* A0FrP */ | |
58 | frame.sp = user_stack_pointer(regs); /* A0StP */ | |
59 | frame.lr = 0; /* from stack */ | |
60 | frame.pc = regs->ctx.CurrPC; /* PC */ | |
61 | walk_stackframe(&frame, &kernel_backtrace_frame, &depth); | |
62 | } | |
63 | } |