diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-06-14 02:16:53 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-06-14 02:16:53 -0400 |
commit | eaaaeef392cb245e415c31d480ed2d5a466fd88f (patch) | |
tree | 483761495ceb9cc3a277769f52d0ec8abeed1ac0 | |
parent | 9973e38575070b70c68bad177fb5056548fea349 (diff) |
sh: Add kprobe-based event tracer.
This follows the x86/ppc changes for kprobe-based event tracing on sh.
While kprobes is only supported on 32-bit sh, we provide the API for
HAVE_REGS_AND_STACK_ACCESS_API for both 32 and 64-bit.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/Kconfig | 1 | ||||
-rw-r--r-- | arch/sh/include/asm/kprobes.h | 1 | ||||
-rw-r--r-- | arch/sh/include/asm/processor_32.h | 3 | ||||
-rw-r--r-- | arch/sh/include/asm/processor_64.h | 3 | ||||
-rw-r--r-- | arch/sh/include/asm/ptrace.h | 89 | ||||
-rw-r--r-- | arch/sh/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace.c | 33 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace_32.c | 27 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace_64.c | 79 |
9 files changed, 227 insertions, 11 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 573fca1fbd9b..e6b1f207f7ab 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -23,6 +23,7 @@ config SUPERH | |||
23 | select HAVE_KERNEL_LZMA | 23 | select HAVE_KERNEL_LZMA |
24 | select HAVE_KERNEL_LZO | 24 | select HAVE_KERNEL_LZO |
25 | select HAVE_SYSCALL_TRACEPOINTS | 25 | select HAVE_SYSCALL_TRACEPOINTS |
26 | select HAVE_REGS_AND_STACK_ACCESS_API | ||
26 | select RTC_LIB | 27 | select RTC_LIB |
27 | select GENERIC_ATOMIC64 | 28 | select GENERIC_ATOMIC64 |
28 | help | 29 | help |
diff --git a/arch/sh/include/asm/kprobes.h b/arch/sh/include/asm/kprobes.h index 036c3311233c..134f3980e44a 100644 --- a/arch/sh/include/asm/kprobes.h +++ b/arch/sh/include/asm/kprobes.h | |||
@@ -16,7 +16,6 @@ typedef insn_size_t kprobe_opcode_t; | |||
16 | ? (MAX_STACK_SIZE) \ | 16 | ? (MAX_STACK_SIZE) \ |
17 | : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR))) | 17 | : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR))) |
18 | 18 | ||
19 | #define regs_return_value(_regs) ((_regs)->regs[0]) | ||
20 | #define flush_insn_slot(p) do { } while (0) | 19 | #define flush_insn_slot(p) do { } while (0) |
21 | #define kretprobe_blacklist_size 0 | 20 | #define kretprobe_blacklist_size 0 |
22 | 21 | ||
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 61a445d2d02a..46d5179c9f49 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
14 | #include <asm/page.h> | 14 | #include <asm/page.h> |
15 | #include <asm/types.h> | 15 | #include <asm/types.h> |
16 | #include <asm/ptrace.h> | ||
17 | #include <asm/hw_breakpoint.h> | 16 | #include <asm/hw_breakpoint.h> |
18 | 17 | ||
19 | /* | 18 | /* |
@@ -194,8 +193,6 @@ extern unsigned long get_wchan(struct task_struct *p); | |||
194 | #define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) | 193 | #define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) |
195 | #define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15]) | 194 | #define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15]) |
196 | 195 | ||
197 | #define user_stack_pointer(_regs) ((_regs)->regs[15]) | ||
198 | |||
199 | #if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4) | 196 | #if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4) |
200 | #define PREFETCH_STRIDE L1_CACHE_BYTES | 197 | #define PREFETCH_STRIDE L1_CACHE_BYTES |
201 | #define ARCH_HAS_PREFETCH | 198 | #define ARCH_HAS_PREFETCH |
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h index 621bc4618c6b..2a541ddb5a1b 100644 --- a/arch/sh/include/asm/processor_64.h +++ b/arch/sh/include/asm/processor_64.h | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/compiler.h> | 17 | #include <linux/compiler.h> |
18 | #include <asm/page.h> | 18 | #include <asm/page.h> |
19 | #include <asm/types.h> | 19 | #include <asm/types.h> |
20 | #include <asm/ptrace.h> | ||
21 | #include <cpu/registers.h> | 20 | #include <cpu/registers.h> |
22 | 21 | ||
23 | /* | 22 | /* |
@@ -231,7 +230,5 @@ extern unsigned long get_wchan(struct task_struct *p); | |||
231 | #define KSTK_EIP(tsk) ((tsk)->thread.pc) | 230 | #define KSTK_EIP(tsk) ((tsk)->thread.pc) |
232 | #define KSTK_ESP(tsk) ((tsk)->thread.sp) | 231 | #define KSTK_ESP(tsk) ((tsk)->thread.sp) |
233 | 232 | ||
234 | #define user_stack_pointer(_regs) ((_regs)->regs[15]) | ||
235 | |||
236 | #endif /* __ASSEMBLY__ */ | 233 | #endif /* __ASSEMBLY__ */ |
237 | #endif /* __ASM_SH_PROCESSOR_64_H */ | 234 | #endif /* __ASM_SH_PROCESSOR_64_H */ |
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h index 2168fde25611..33b3f37dcdbb 100644 --- a/arch/sh/include/asm/ptrace.h +++ b/arch/sh/include/asm/ptrace.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef __ASM_SH_PTRACE_H | 1 | #ifndef __ASM_SH_PTRACE_H |
2 | #define __ASM_SH_PTRACE_H | 2 | #define __ASM_SH_PTRACE_H |
3 | 3 | ||
4 | #include <linux/stringify.h> | ||
5 | |||
4 | /* | 6 | /* |
5 | * Copyright (C) 1999, 2000 Niibe Yutaka | 7 | * Copyright (C) 1999, 2000 Niibe Yutaka |
6 | * | 8 | * |
@@ -14,6 +16,13 @@ struct pt_regs { | |||
14 | unsigned long long tregs[8]; | 16 | unsigned long long tregs[8]; |
15 | unsigned long long pad[2]; | 17 | unsigned long long pad[2]; |
16 | }; | 18 | }; |
19 | |||
20 | #define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7]) | ||
21 | #define regs_return_value(regs) ((regs)->regs[3]) | ||
22 | |||
23 | #define TREGS_OFFSET_NAME(num) \ | ||
24 | {.name = __stringify(tr##num), .offset = offsetof(struct pt_regs, tregs[num])} | ||
25 | |||
17 | #else | 26 | #else |
18 | /* | 27 | /* |
19 | * GCC defines register number like this: | 28 | * GCC defines register number like this: |
@@ -66,6 +75,9 @@ struct pt_regs { | |||
66 | long tra; | 75 | long tra; |
67 | }; | 76 | }; |
68 | 77 | ||
78 | #define MAX_REG_OFFSET offsetof(struct pt_regs, tra) | ||
79 | #define regs_return_value(regs) ((regs)->regs[0]) | ||
80 | |||
69 | /* | 81 | /* |
70 | * This struct defines the way the DSP registers are stored on the | 82 | * This struct defines the way the DSP registers are stored on the |
71 | * kernel stack during a system call or other kernel entry. | 83 | * kernel stack during a system call or other kernel entry. |
@@ -113,16 +125,87 @@ struct pt_dspregs { | |||
113 | #include <asm/system.h> | 125 | #include <asm/system.h> |
114 | 126 | ||
115 | #define user_mode(regs) (((regs)->sr & 0x40000000)==0) | 127 | #define user_mode(regs) (((regs)->sr & 0x40000000)==0) |
128 | #define user_stack_pointer(regs) ((unsigned long)(regs)->regs[15]) | ||
129 | #define kernel_stack_pointer(regs) ((unsigned long)(regs)->regs[15]) | ||
116 | #define instruction_pointer(regs) ((unsigned long)(regs)->pc) | 130 | #define instruction_pointer(regs) ((unsigned long)(regs)->pc) |
117 | 131 | ||
118 | extern void show_regs(struct pt_regs *); | 132 | extern void show_regs(struct pt_regs *); |
119 | 133 | ||
134 | #define arch_has_single_step() (1) | ||
135 | |||
120 | /* | 136 | /* |
121 | * These are defined as per linux/ptrace.h. | 137 | * kprobe-based event tracer support |
122 | */ | 138 | */ |
123 | struct task_struct; | 139 | #include <linux/stddef.h> |
140 | #include <linux/thread_info.h> | ||
124 | 141 | ||
125 | #define arch_has_single_step() (1) | 142 | struct pt_regs_offset { |
143 | const char *name; | ||
144 | int offset; | ||
145 | }; | ||
146 | |||
147 | #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} | ||
148 | #define REGS_OFFSET_NAME(num) \ | ||
149 | {.name = __stringify(r##num), .offset = offsetof(struct pt_regs, regs[num])} | ||
150 | #define REG_OFFSET_END {.name = NULL, .offset = 0} | ||
151 | |||
152 | /* Query offset/name of register from its name/offset */ | ||
153 | extern int regs_query_register_offset(const char *name); | ||
154 | extern const char *regs_query_register_name(unsigned int offset); | ||
155 | |||
156 | extern const struct pt_regs_offset regoffset_table[]; | ||
157 | |||
158 | /** | ||
159 | * regs_get_register() - get register value from its offset | ||
160 | * @regs: pt_regs from which register value is gotten. | ||
161 | * @offset: offset number of the register. | ||
162 | * | ||
163 | * regs_get_register returns the value of a register. The @offset is the | ||
164 | * offset of the register in struct pt_regs address which specified by @regs. | ||
165 | * If @offset is bigger than MAX_REG_OFFSET, this returns 0. | ||
166 | */ | ||
167 | static inline unsigned long regs_get_register(struct pt_regs *regs, | ||
168 | unsigned int offset) | ||
169 | { | ||
170 | if (unlikely(offset > MAX_REG_OFFSET)) | ||
171 | return 0; | ||
172 | return *(unsigned long *)((unsigned long)regs + offset); | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * regs_within_kernel_stack() - check the address in the stack | ||
177 | * @regs: pt_regs which contains kernel stack pointer. | ||
178 | * @addr: address which is checked. | ||
179 | * | ||
180 | * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). | ||
181 | * If @addr is within the kernel stack, it returns true. If not, returns false. | ||
182 | */ | ||
183 | static inline int regs_within_kernel_stack(struct pt_regs *regs, | ||
184 | unsigned long addr) | ||
185 | { | ||
186 | return ((addr & ~(THREAD_SIZE - 1)) == | ||
187 | (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); | ||
188 | } | ||
189 | |||
190 | /** | ||
191 | * regs_get_kernel_stack_nth() - get Nth entry of the stack | ||
192 | * @regs: pt_regs which contains kernel stack pointer. | ||
193 | * @n: stack entry number. | ||
194 | * | ||
195 | * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which | ||
196 | * is specified by @regs. If the @n th entry is NOT in the kernel stack, | ||
197 | * this returns 0. | ||
198 | */ | ||
199 | static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, | ||
200 | unsigned int n) | ||
201 | { | ||
202 | unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); | ||
203 | addr += n; | ||
204 | if (regs_within_kernel_stack(regs, (unsigned long)addr)) | ||
205 | return *addr; | ||
206 | else | ||
207 | return 0; | ||
208 | } | ||
126 | 209 | ||
127 | struct perf_event; | 210 | struct perf_event; |
128 | struct perf_sample_data; | 211 | struct perf_sample_data; |
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index e25f3c69525d..1086ba1abdab 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -14,7 +14,7 @@ CFLAGS_REMOVE_return_address.o = -pg | |||
14 | obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \ | 14 | obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \ |
15 | idle.o io.o irq.o \ | 15 | idle.o io.o irq.o \ |
16 | irq_$(BITS).o machvec.o nmi_debug.o process.o \ | 16 | irq_$(BITS).o machvec.o nmi_debug.o process.o \ |
17 | process_$(BITS).o ptrace_$(BITS).o \ | 17 | process_$(BITS).o ptrace.o ptrace_$(BITS).o \ |
18 | reboot.o return_address.o \ | 18 | reboot.o return_address.o \ |
19 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ | 19 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ |
20 | syscalls_$(BITS).o time.o topology.o traps.o \ | 20 | syscalls_$(BITS).o time.o topology.o traps.o \ |
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c new file mode 100644 index 000000000000..0a05983633ca --- /dev/null +++ b/arch/sh/kernel/ptrace.c | |||
@@ -0,0 +1,33 @@ | |||
1 | #include <linux/ptrace.h> | ||
2 | |||
3 | /** | ||
4 | * regs_query_register_offset() - query register offset from its name | ||
5 | * @name: the name of a register | ||
6 | * | ||
7 | * regs_query_register_offset() returns the offset of a register in struct | ||
8 | * pt_regs from its name. If the name is invalid, this returns -EINVAL; | ||
9 | */ | ||
10 | int regs_query_register_offset(const char *name) | ||
11 | { | ||
12 | const struct pt_regs_offset *roff; | ||
13 | for (roff = regoffset_table; roff->name != NULL; roff++) | ||
14 | if (!strcmp(roff->name, name)) | ||
15 | return roff->offset; | ||
16 | return -EINVAL; | ||
17 | } | ||
18 | |||
19 | /** | ||
20 | * regs_query_register_name() - query register name from its offset | ||
21 | * @offset: the offset of a register in struct pt_regs. | ||
22 | * | ||
23 | * regs_query_register_name() returns the name of a register from its | ||
24 | * offset in struct pt_regs. If the @offset is invalid, this returns NULL; | ||
25 | */ | ||
26 | const char *regs_query_register_name(unsigned int offset) | ||
27 | { | ||
28 | const struct pt_regs_offset *roff; | ||
29 | for (roff = regoffset_table; roff->name != NULL; roff++) | ||
30 | if (roff->offset == offset) | ||
31 | return roff->name; | ||
32 | return NULL; | ||
33 | } | ||
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 6c4bbba2a675..2cd42b58cb20 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c | |||
@@ -274,6 +274,33 @@ static int dspregs_active(struct task_struct *target, | |||
274 | } | 274 | } |
275 | #endif | 275 | #endif |
276 | 276 | ||
277 | const struct pt_regs_offset regoffset_table[] = { | ||
278 | REGS_OFFSET_NAME(0), | ||
279 | REGS_OFFSET_NAME(1), | ||
280 | REGS_OFFSET_NAME(2), | ||
281 | REGS_OFFSET_NAME(3), | ||
282 | REGS_OFFSET_NAME(4), | ||
283 | REGS_OFFSET_NAME(5), | ||
284 | REGS_OFFSET_NAME(6), | ||
285 | REGS_OFFSET_NAME(7), | ||
286 | REGS_OFFSET_NAME(8), | ||
287 | REGS_OFFSET_NAME(9), | ||
288 | REGS_OFFSET_NAME(10), | ||
289 | REGS_OFFSET_NAME(11), | ||
290 | REGS_OFFSET_NAME(12), | ||
291 | REGS_OFFSET_NAME(13), | ||
292 | REGS_OFFSET_NAME(14), | ||
293 | REGS_OFFSET_NAME(15), | ||
294 | REG_OFFSET_NAME(pc), | ||
295 | REG_OFFSET_NAME(pr), | ||
296 | REG_OFFSET_NAME(sr), | ||
297 | REG_OFFSET_NAME(gbr), | ||
298 | REG_OFFSET_NAME(mach), | ||
299 | REG_OFFSET_NAME(macl), | ||
300 | REG_OFFSET_NAME(tra), | ||
301 | REG_OFFSET_END, | ||
302 | }; | ||
303 | |||
277 | /* | 304 | /* |
278 | * These are our native regset flavours. | 305 | * These are our native regset flavours. |
279 | */ | 306 | */ |
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index 5fd644da7f02..b97817016b6a 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c | |||
@@ -252,6 +252,85 @@ static int fpregs_active(struct task_struct *target, | |||
252 | } | 252 | } |
253 | #endif | 253 | #endif |
254 | 254 | ||
255 | const struct pt_regs_offset regoffset_table[] = { | ||
256 | REG_OFFSET_NAME(pc), | ||
257 | REG_OFFSET_NAME(sr), | ||
258 | REG_OFFSET_NAME(syscall_nr), | ||
259 | REGS_OFFSET_NAME(0), | ||
260 | REGS_OFFSET_NAME(1), | ||
261 | REGS_OFFSET_NAME(2), | ||
262 | REGS_OFFSET_NAME(3), | ||
263 | REGS_OFFSET_NAME(4), | ||
264 | REGS_OFFSET_NAME(5), | ||
265 | REGS_OFFSET_NAME(6), | ||
266 | REGS_OFFSET_NAME(7), | ||
267 | REGS_OFFSET_NAME(8), | ||
268 | REGS_OFFSET_NAME(9), | ||
269 | REGS_OFFSET_NAME(10), | ||
270 | REGS_OFFSET_NAME(11), | ||
271 | REGS_OFFSET_NAME(12), | ||
272 | REGS_OFFSET_NAME(13), | ||
273 | REGS_OFFSET_NAME(14), | ||
274 | REGS_OFFSET_NAME(15), | ||
275 | REGS_OFFSET_NAME(16), | ||
276 | REGS_OFFSET_NAME(17), | ||
277 | REGS_OFFSET_NAME(18), | ||
278 | REGS_OFFSET_NAME(19), | ||
279 | REGS_OFFSET_NAME(20), | ||
280 | REGS_OFFSET_NAME(21), | ||
281 | REGS_OFFSET_NAME(22), | ||
282 | REGS_OFFSET_NAME(23), | ||
283 | REGS_OFFSET_NAME(24), | ||
284 | REGS_OFFSET_NAME(25), | ||
285 | REGS_OFFSET_NAME(26), | ||
286 | REGS_OFFSET_NAME(27), | ||
287 | REGS_OFFSET_NAME(28), | ||
288 | REGS_OFFSET_NAME(29), | ||
289 | REGS_OFFSET_NAME(30), | ||
290 | REGS_OFFSET_NAME(31), | ||
291 | REGS_OFFSET_NAME(32), | ||
292 | REGS_OFFSET_NAME(33), | ||
293 | REGS_OFFSET_NAME(34), | ||
294 | REGS_OFFSET_NAME(35), | ||
295 | REGS_OFFSET_NAME(36), | ||
296 | REGS_OFFSET_NAME(37), | ||
297 | REGS_OFFSET_NAME(38), | ||
298 | REGS_OFFSET_NAME(39), | ||
299 | REGS_OFFSET_NAME(40), | ||
300 | REGS_OFFSET_NAME(41), | ||
301 | REGS_OFFSET_NAME(42), | ||
302 | REGS_OFFSET_NAME(43), | ||
303 | REGS_OFFSET_NAME(44), | ||
304 | REGS_OFFSET_NAME(45), | ||
305 | REGS_OFFSET_NAME(46), | ||
306 | REGS_OFFSET_NAME(47), | ||
307 | REGS_OFFSET_NAME(48), | ||
308 | REGS_OFFSET_NAME(49), | ||
309 | REGS_OFFSET_NAME(50), | ||
310 | REGS_OFFSET_NAME(51), | ||
311 | REGS_OFFSET_NAME(52), | ||
312 | REGS_OFFSET_NAME(53), | ||
313 | REGS_OFFSET_NAME(54), | ||
314 | REGS_OFFSET_NAME(55), | ||
315 | REGS_OFFSET_NAME(56), | ||
316 | REGS_OFFSET_NAME(57), | ||
317 | REGS_OFFSET_NAME(58), | ||
318 | REGS_OFFSET_NAME(59), | ||
319 | REGS_OFFSET_NAME(60), | ||
320 | REGS_OFFSET_NAME(61), | ||
321 | REGS_OFFSET_NAME(62), | ||
322 | REGS_OFFSET_NAME(63), | ||
323 | TREGS_OFFSET_NAME(0), | ||
324 | TREGS_OFFSET_NAME(1), | ||
325 | TREGS_OFFSET_NAME(2), | ||
326 | TREGS_OFFSET_NAME(3), | ||
327 | TREGS_OFFSET_NAME(4), | ||
328 | TREGS_OFFSET_NAME(5), | ||
329 | TREGS_OFFSET_NAME(6), | ||
330 | TREGS_OFFSET_NAME(7), | ||
331 | REG_OFFSET_END, | ||
332 | }; | ||
333 | |||
255 | /* | 334 | /* |
256 | * These are our native regset flavours. | 335 | * These are our native regset flavours. |
257 | */ | 336 | */ |