Blame view
arch/arm/oprofile/common.c
2.67 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 |
/** * @file common.c * * @remark Copyright 2004 Oprofile Authors |
8c1fc96f6 ARM: 6072/1: opro... |
5 |
* @remark Copyright 2010 ARM Ltd. |
1da177e4c Linux-2.6.12-rc2 |
6 7 8 |
* @remark Read the file COPYING * * @author Zwane Mwaikambo |
8c1fc96f6 ARM: 6072/1: opro... |
9 |
* @author Will Deacon [move to perf] |
1da177e4c Linux-2.6.12-rc2 |
10 |
*/ |
8c1fc96f6 ARM: 6072/1: opro... |
11 |
#include <linux/cpumask.h> |
1da177e4c Linux-2.6.12-rc2 |
12 |
#include <linux/init.h> |
8c1fc96f6 ARM: 6072/1: opro... |
13 |
#include <linux/mutex.h> |
1da177e4c Linux-2.6.12-rc2 |
14 |
#include <linux/oprofile.h> |
8c1fc96f6 ARM: 6072/1: opro... |
15 |
#include <linux/perf_event.h> |
d1e86d64b ARM: 6074/1: opro... |
16 |
#include <linux/platform_device.h> |
ae92dc9f7 [ARM] Oprofile: d... |
17 |
#include <linux/slab.h> |
8c1fc96f6 ARM: 6072/1: opro... |
18 19 20 21 22 |
#include <asm/stacktrace.h> #include <linux/uaccess.h> #include <asm/perf_event.h> #include <asm/ptrace.h> |
1da177e4c Linux-2.6.12-rc2 |
23 |
|
8c1fc96f6 ARM: 6072/1: opro... |
24 |
#ifdef CONFIG_HW_PERF_EVENTS |
56946331b oprofile: Make op... |
25 |
char *op_name_from_perf_id(void) |
8c1fc96f6 ARM: 6072/1: opro... |
26 |
{ |
56946331b oprofile: Make op... |
27 |
enum arm_perf_pmu_ids id = armpmu_get_pmu_id(); |
8c1fc96f6 ARM: 6072/1: opro... |
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
switch (id) { case ARM_PERF_PMU_ID_XSCALE1: return "arm/xscale1"; case ARM_PERF_PMU_ID_XSCALE2: return "arm/xscale2"; case ARM_PERF_PMU_ID_V6: return "arm/armv6"; case ARM_PERF_PMU_ID_V6MP: return "arm/mpcore"; case ARM_PERF_PMU_ID_CA8: return "arm/armv7"; case ARM_PERF_PMU_ID_CA9: return "arm/armv7-ca9"; default: return NULL; } } |
d14dd7e20 ARM: oprofile: Fi... |
45 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
46 |
|
8c1fc96f6 ARM: 6072/1: opro... |
47 |
static int report_trace(struct stackframe *frame, void *d) |
1da177e4c Linux-2.6.12-rc2 |
48 |
{ |
8c1fc96f6 ARM: 6072/1: opro... |
49 |
unsigned int *depth = d; |
c6b9dafce [ARM] 4/4 Combine... |
50 |
|
8c1fc96f6 ARM: 6072/1: opro... |
51 52 53 54 |
if (*depth) { oprofile_add_trace(frame->pc); (*depth)--; } |
1b7b56982 [ARM] 4237/2: opr... |
55 |
|
8c1fc96f6 ARM: 6072/1: opro... |
56 57 |
return *depth == 0; } |
c6b9dafce [ARM] 4/4 Combine... |
58 |
|
8c1fc96f6 ARM: 6072/1: opro... |
59 60 61 62 63 64 65 66 67 68 69 |
/* * The registers we're interested in are at the end of the variable * length saved register structure. The fp points at the end of this * structure so the address of this struct is: * (struct frame_tail *)(xxx->fp)-1 */ struct frame_tail { struct frame_tail *fp; unsigned long sp; unsigned long lr; } __attribute__((packed)); |
2d9e1ae06 [ARM] oprofile: a... |
70 |
|
8c1fc96f6 ARM: 6072/1: opro... |
71 72 73 |
static struct frame_tail* user_backtrace(struct frame_tail *tail) { struct frame_tail buftail[2]; |
10c03f696 [ARM] oprofile: a... |
74 |
|
8c1fc96f6 ARM: 6072/1: opro... |
75 76 77 78 79 |
/* Also check accessibility of one struct frame_tail beyond */ if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) return NULL; if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) return NULL; |
d7ac4e28c [ARM] 5195/1: ARM... |
80 |
|
8c1fc96f6 ARM: 6072/1: opro... |
81 |
oprofile_add_trace(buftail[0].lr); |
c6b9dafce [ARM] 4/4 Combine... |
82 |
|
8c1fc96f6 ARM: 6072/1: opro... |
83 84 |
/* frame pointers should strictly progress back up the stack * (towards higher addresses) */ |
cb06199b1 ARM: 6654/1: perf... |
85 |
if (tail + 1 >= buftail[0].fp) |
8c1fc96f6 ARM: 6072/1: opro... |
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
return NULL; return buftail[0].fp-1; } static void arm_backtrace(struct pt_regs * const regs, unsigned int depth) { struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1; if (!user_mode(regs)) { struct stackframe frame; frame.fp = regs->ARM_fp; frame.sp = regs->ARM_sp; frame.lr = regs->ARM_lr; frame.pc = regs->ARM_pc; walk_stackframe(&frame, report_trace, &depth); return; } while (depth-- && tail && !((unsigned long) tail & 3)) tail = user_backtrace(tail); } |
58850e210 ARM: oprofile: Mo... |
108 109 |
int __init oprofile_arch_init(struct oprofile_operations *ops) { |
d14dd7e20 ARM: oprofile: Fi... |
110 |
/* provide backtrace support also in timer mode: */ |
58850e210 ARM: oprofile: Mo... |
111 112 113 114 |
ops->backtrace = arm_backtrace; return oprofile_perf_init(ops); } |
55205c916 oprofile, arm/sh:... |
115 |
void oprofile_arch_exit(void) |
58850e210 ARM: oprofile: Mo... |
116 117 118 |
{ oprofile_perf_exit(); } |