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 573fca1fbd9..e6b1f207f7a 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 036c3311233..134f3980e44 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 61a445d2d02..46d5179c9f4 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 621bc4618c6..2a541ddb5a1 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 2168fde2561..33b3f37dcdb 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 | ||
