diff options
author | Will Deacon <will.deacon@arm.com> | 2010-06-25 07:24:53 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-07-09 09:41:34 -0400 |
commit | e513f8bf240d34bd6e732ba2f74df9ab84686ce6 (patch) | |
tree | 989f646d90b42b583ea1cd51d34ecccf9afd8027 /arch/arm/kernel | |
parent | eb668c6d06dd4f935fc610207c58a5f221384651 (diff) |
ARM: 6199/1: Add kprobe-based event tracer
This patch enables the HAVE_REGS_AND_STACK_ACCESS_API option
for ARM which is required by the kprobe events tracer. Code based
on the PowerPC port.
Cc: Jean Pihet <jpihet@mvista.com>
Tested-by: Jamie Iles <jamie.iles@picochip.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/ptrace.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 3f562a7c0a9..f99d489822d 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
@@ -52,6 +52,102 @@ | |||
52 | #define BREAKINST_THUMB 0xde01 | 52 | #define BREAKINST_THUMB 0xde01 |
53 | #endif | 53 | #endif |
54 | 54 | ||
55 | struct pt_regs_offset { | ||
56 | const char *name; | ||
57 | int offset; | ||
58 | }; | ||
59 | |||
60 | #define REG_OFFSET_NAME(r) \ | ||
61 | {.name = #r, .offset = offsetof(struct pt_regs, ARM_##r)} | ||
62 | #define REG_OFFSET_END {.name = NULL, .offset = 0} | ||
63 | |||
64 | static const struct pt_regs_offset regoffset_table[] = { | ||
65 | REG_OFFSET_NAME(r0), | ||
66 | REG_OFFSET_NAME(r1), | ||
67 | REG_OFFSET_NAME(r2), | ||
68 | REG_OFFSET_NAME(r3), | ||
69 | REG_OFFSET_NAME(r4), | ||
70 | REG_OFFSET_NAME(r5), | ||
71 | REG_OFFSET_NAME(r6), | ||
72 | REG_OFFSET_NAME(r7), | ||
73 | REG_OFFSET_NAME(r8), | ||
74 | REG_OFFSET_NAME(r9), | ||
75 | REG_OFFSET_NAME(r10), | ||
76 | REG_OFFSET_NAME(fp), | ||
77 | REG_OFFSET_NAME(ip), | ||
78 | REG_OFFSET_NAME(sp), | ||
79 | REG_OFFSET_NAME(lr), | ||
80 | REG_OFFSET_NAME(pc), | ||
81 | REG_OFFSET_NAME(cpsr), | ||
82 | REG_OFFSET_NAME(ORIG_r0), | ||
83 | REG_OFFSET_END, | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * regs_query_register_offset() - query register offset from its name | ||
88 | * @name: the name of a register | ||
89 | * | ||
90 | * regs_query_register_offset() returns the offset of a register in struct | ||
91 | * pt_regs from its name. If the name is invalid, this returns -EINVAL; | ||
92 | */ | ||
93 | int regs_query_register_offset(const char *name) | ||
94 | { | ||
95 | const struct pt_regs_offset *roff; | ||
96 | for (roff = regoffset_table; roff->name != NULL; roff++) | ||
97 | if (!strcmp(roff->name, name)) | ||
98 | return roff->offset; | ||
99 | return -EINVAL; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * regs_query_register_name() - query register name from its offset | ||
104 | * @offset: the offset of a register in struct pt_regs. | ||
105 | * | ||
106 | * regs_query_register_name() returns the name of a register from its | ||
107 | * offset in struct pt_regs. If the @offset is invalid, this returns NULL; | ||
108 | */ | ||
109 | const char *regs_query_register_name(unsigned int offset) | ||
110 | { | ||
111 | const struct pt_regs_offset *roff; | ||
112 | for (roff = regoffset_table; roff->name != NULL; roff++) | ||
113 | if (roff->offset == offset) | ||
114 | return roff->name; | ||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * regs_within_kernel_stack() - check the address in the stack | ||
120 | * @regs: pt_regs which contains kernel stack pointer. | ||
121 | * @addr: address which is checked. | ||
122 | * | ||
123 | * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). | ||
124 | * If @addr is within the kernel stack, it returns true. If not, returns false. | ||
125 | */ | ||
126 | bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) | ||
127 | { | ||
128 | return ((addr & ~(THREAD_SIZE - 1)) == | ||
129 | (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * regs_get_kernel_stack_nth() - get Nth entry of the stack | ||
134 | * @regs: pt_regs which contains kernel stack pointer. | ||
135 | * @n: stack entry number. | ||
136 | * | ||
137 | * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which | ||
138 | * is specified by @regs. If the @n th entry is NOT in the kernel stack, | ||
139 | * this returns 0. | ||
140 | */ | ||
141 | unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) | ||
142 | { | ||
143 | unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); | ||
144 | addr += n; | ||
145 | if (regs_within_kernel_stack(regs, (unsigned long)addr)) | ||
146 | return *addr; | ||
147 | else | ||
148 | return 0; | ||
149 | } | ||
150 | |||
55 | /* | 151 | /* |
56 | * this routine will get a word off of the processes privileged stack. | 152 | * this routine will get a word off of the processes privileged stack. |
57 | * the offset is how far from the base addr as stored in the THREAD. | 153 | * the offset is how far from the base addr as stored in the THREAD. |