diff options
| -rw-r--r-- | arch/ppc64/kernel/kprobes.c | 99 | ||||
| -rw-r--r-- | arch/ppc64/kernel/process.c | 4 | ||||
| -rw-r--r-- | include/asm-ppc64/kprobes.h | 3 | 
3 files changed, 106 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c index 86cc5496db9f..1d2ff6d6b0b3 100644 --- a/arch/ppc64/kernel/kprobes.c +++ b/arch/ppc64/kernel/kprobes.c  | |||
| @@ -122,6 +122,23 @@ static inline void restore_previous_kprobe(void) | |||
| 122 | kprobe_saved_msr = kprobe_saved_msr_prev; | 122 | kprobe_saved_msr = kprobe_saved_msr_prev; | 
| 123 | } | 123 | } | 
| 124 | 124 | ||
| 125 | void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) | ||
| 126 | { | ||
| 127 | struct kretprobe_instance *ri; | ||
| 128 | |||
| 129 | if ((ri = get_free_rp_inst(rp)) != NULL) { | ||
| 130 | ri->rp = rp; | ||
| 131 | ri->task = current; | ||
| 132 | ri->ret_addr = (kprobe_opcode_t *)regs->link; | ||
| 133 | |||
| 134 | /* Replace the return addr with trampoline addr */ | ||
| 135 | regs->link = (unsigned long)kretprobe_trampoline; | ||
| 136 | add_rp_inst(ri); | ||
| 137 | } else { | ||
| 138 | rp->nmissed++; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 125 | static inline int kprobe_handler(struct pt_regs *regs) | 142 | static inline int kprobe_handler(struct pt_regs *regs) | 
| 126 | { | 143 | { | 
| 127 | struct kprobe *p; | 144 | struct kprobe *p; | 
| @@ -212,6 +229,78 @@ no_kprobe: | |||
| 212 | } | 229 | } | 
| 213 | 230 | ||
| 214 | /* | 231 | /* | 
| 232 | * Function return probe trampoline: | ||
| 233 | * - init_kprobes() establishes a probepoint here | ||
| 234 | * - When the probed function returns, this probe | ||
| 235 | * causes the handlers to fire | ||
| 236 | */ | ||
| 237 | void kretprobe_trampoline_holder(void) | ||
| 238 | { | ||
| 239 | asm volatile(".global kretprobe_trampoline\n" | ||
| 240 | "kretprobe_trampoline:\n" | ||
| 241 | "nop\n"); | ||
| 242 | } | ||
| 243 | |||
| 244 | /* | ||
| 245 | * Called when the probe at kretprobe trampoline is hit | ||
| 246 | */ | ||
| 247 | int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | ||
| 248 | { | ||
| 249 | struct kretprobe_instance *ri = NULL; | ||
| 250 | struct hlist_head *head; | ||
| 251 | struct hlist_node *node, *tmp; | ||
| 252 | unsigned long orig_ret_address = 0; | ||
| 253 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; | ||
| 254 | |||
| 255 | head = kretprobe_inst_table_head(current); | ||
| 256 | |||
| 257 | /* | ||
| 258 | * It is possible to have multiple instances associated with a given | ||
| 259 | * task either because an multiple functions in the call path | ||
| 260 | * have a return probe installed on them, and/or more then one return | ||
| 261 | * return probe was registered for a target function. | ||
| 262 | * | ||
| 263 | * We can handle this because: | ||
| 264 | * - instances are always inserted at the head of the list | ||
| 265 | * - when multiple return probes are registered for the same | ||
| 266 | * function, the first instance's ret_addr will point to the | ||
| 267 | * real return address, and all the rest will point to | ||
| 268 | * kretprobe_trampoline | ||
| 269 | */ | ||
| 270 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | ||
| 271 | if (ri->task != current) | ||
| 272 | /* another task is sharing our hash bucket */ | ||
| 273 | continue; | ||
| 274 | |||
| 275 | if (ri->rp && ri->rp->handler) | ||
| 276 | ri->rp->handler(ri, regs); | ||
| 277 | |||
| 278 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
| 279 | recycle_rp_inst(ri); | ||
| 280 | |||
| 281 | if (orig_ret_address != trampoline_address) | ||
| 282 | /* | ||
| 283 | * This is the real return address. Any other | ||
| 284 | * instances associated with this task are for | ||
| 285 | * other calls deeper on the call stack | ||
| 286 | */ | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | |||
| 290 | BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); | ||
| 291 | regs->nip = orig_ret_address; | ||
| 292 | |||
| 293 | unlock_kprobes(); | ||
| 294 | |||
| 295 | /* | ||
| 296 | * By returning a non-zero value, we are telling | ||
| 297 | * kprobe_handler() that we have handled unlocking | ||
| 298 | * and re-enabling preemption. | ||
| 299 | */ | ||
| 300 | return 1; | ||
| 301 | } | ||
| 302 | |||
| 303 | /* | ||
| 215 | * Called after single-stepping. p->addr is the address of the | 304 | * Called after single-stepping. p->addr is the address of the | 
| 216 | * instruction whose first byte has been replaced by the "breakpoint" | 305 | * instruction whose first byte has been replaced by the "breakpoint" | 
| 217 | * instruction. To avoid the SMP problems that can occur when we | 306 | * instruction. To avoid the SMP problems that can occur when we | 
| @@ -349,3 +438,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 349 | memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); | 438 | memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); | 
| 350 | return 1; | 439 | return 1; | 
| 351 | } | 440 | } | 
| 441 | |||
| 442 | static struct kprobe trampoline_p = { | ||
| 443 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, | ||
| 444 | .pre_handler = trampoline_probe_handler | ||
| 445 | }; | ||
| 446 | |||
| 447 | int __init arch_init(void) | ||
| 448 | { | ||
| 449 | return register_kprobe(&trampoline_p); | ||
| 450 | } | ||
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index aba89554d89d..f7cae05e40fb 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c  | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/kallsyms.h> | 36 | #include <linux/kallsyms.h> | 
| 37 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> | 
| 38 | #include <linux/utsname.h> | 38 | #include <linux/utsname.h> | 
| 39 | #include <linux/kprobes.h> | ||
| 39 | 40 | ||
| 40 | #include <asm/pgtable.h> | 41 | #include <asm/pgtable.h> | 
| 41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> | 
| @@ -307,6 +308,8 @@ void show_regs(struct pt_regs * regs) | |||
| 307 | 308 | ||
| 308 | void exit_thread(void) | 309 | void exit_thread(void) | 
| 309 | { | 310 | { | 
| 311 | kprobe_flush_task(current); | ||
| 312 | |||
| 310 | #ifndef CONFIG_SMP | 313 | #ifndef CONFIG_SMP | 
| 311 | if (last_task_used_math == current) | 314 | if (last_task_used_math == current) | 
| 312 | last_task_used_math = NULL; | 315 | last_task_used_math = NULL; | 
| @@ -321,6 +324,7 @@ void flush_thread(void) | |||
| 321 | { | 324 | { | 
| 322 | struct thread_info *t = current_thread_info(); | 325 | struct thread_info *t = current_thread_info(); | 
| 323 | 326 | ||
| 327 | kprobe_flush_task(current); | ||
| 324 | if (t->flags & _TIF_ABI_PENDING) | 328 | if (t->flags & _TIF_ABI_PENDING) | 
| 325 | t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); | 329 | t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); | 
| 326 | 330 | ||
diff --git a/include/asm-ppc64/kprobes.h b/include/asm-ppc64/kprobes.h index 790cf7c52774..0802919c3235 100644 --- a/include/asm-ppc64/kprobes.h +++ b/include/asm-ppc64/kprobes.h  | |||
| @@ -42,6 +42,9 @@ typedef unsigned int kprobe_opcode_t; | |||
| 42 | 42 | ||
| 43 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) | 43 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) | 
| 44 | 44 | ||
| 45 | #define ARCH_SUPPORTS_KRETPROBES | ||
| 46 | void kretprobe_trampoline(void); | ||
| 47 | |||
| 45 | /* Architecture specific copy of original instruction */ | 48 | /* Architecture specific copy of original instruction */ | 
| 46 | struct arch_specific_insn { | 49 | struct arch_specific_insn { | 
| 47 | /* copy of original instruction */ | 50 | /* copy of original instruction */ | 
