aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-06-14 02:16:53 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-06-14 02:16:53 -0400
commiteaaaeef392cb245e415c31d480ed2d5a466fd88f (patch)
tree483761495ceb9cc3a277769f52d0ec8abeed1ac0
parent9973e38575070b70c68bad177fb5056548fea349 (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/Kconfig1
-rw-r--r--arch/sh/include/asm/kprobes.h1
-rw-r--r--arch/sh/include/asm/processor_32.h3
-rw-r--r--arch/sh/include/asm/processor_64.h3
-rw-r--r--arch/sh/include/asm/ptrace.h89
-rw-r--r--arch/sh/kernel/Makefile2
-rw-r--r--arch/sh/kernel/ptrace.c33
-rw-r--r--arch/sh/kernel/ptrace_32.c27
-rw-r--r--arch/sh/kernel/ptrace_64.c79
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
118extern void show_regs(struct pt_regs *); 132extern 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 */
123struct task_struct; 139#include <linux/stddef.h>
140#include <linux/thread_info.h>
124 141
125#define arch_has_single_step() (1) 142struct 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 */
153extern int regs_query_register_offset(const char *name);
154extern const char *regs_query_register_name(unsigned int offset);
155
156extern 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 */
167static 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 */
183static 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 */
199static 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
127struct perf_event; 210struct perf_event;
128struct perf_sample_data; 211struct 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
14obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \ 14obj-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 */
10int 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 */
26const 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
277const 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
255const 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 */