diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2013-07-18 07:47:50 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-07-19 03:57:04 -0400 |
commit | a7b0133ea94e4421a81702d5c0e6dcdbbbab8f6b (patch) | |
tree | cdffdd36bd256d81c65a083d50a9a2e9be050a6f | |
parent | c7e85c42be68fca743df58a306edd29aa295e155 (diff) |
kprobes/x86: Use text_poke_bp() instead of text_poke_smp*()
Use text_poke_bp() for optimizing kprobes instead of
text_poke_smp*(). Since the number of kprobes is usually not so
large (<100) and text_poke_bp() is much lighter than
text_poke_smp() [which uses stop_machine()], this just stops
using batch processing.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Cc: H. Peter Anvin <hpa@linux.intel.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Jason Baron <jbaron@akamai.com>
Cc: yrl.pp-manager.tt@hitachi.com
Cc: Borislav Petkov <bpetkov@suse.de>
Link: http://lkml.kernel.org/r/20130718114750.26675.9174.stgit@mhiramat-M0-7522
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/kernel/kprobes/common.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/kprobes/core.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/kprobes/opt.c | 100 |
3 files changed, 23 insertions, 84 deletions
diff --git a/arch/x86/kernel/kprobes/common.h b/arch/x86/kernel/kprobes/common.h index 2e9d4b5af036..c6ee63f927ab 100644 --- a/arch/x86/kernel/kprobes/common.h +++ b/arch/x86/kernel/kprobes/common.h | |||
@@ -82,14 +82,9 @@ extern void synthesize_reljump(void *from, void *to); | |||
82 | extern void synthesize_relcall(void *from, void *to); | 82 | extern void synthesize_relcall(void *from, void *to); |
83 | 83 | ||
84 | #ifdef CONFIG_OPTPROBES | 84 | #ifdef CONFIG_OPTPROBES |
85 | extern int arch_init_optprobes(void); | ||
86 | extern int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter); | 85 | extern int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter); |
87 | extern unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr); | 86 | extern unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr); |
88 | #else /* !CONFIG_OPTPROBES */ | 87 | #else /* !CONFIG_OPTPROBES */ |
89 | static inline int arch_init_optprobes(void) | ||
90 | { | ||
91 | return 0; | ||
92 | } | ||
93 | static inline int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter) | 88 | static inline int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter) |
94 | { | 89 | { |
95 | return 0; | 90 | return 0; |
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 211bce445522..cd49b2c96d32 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c | |||
@@ -1068,7 +1068,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
1068 | 1068 | ||
1069 | int __init arch_init_kprobes(void) | 1069 | int __init arch_init_kprobes(void) |
1070 | { | 1070 | { |
1071 | return arch_init_optprobes(); | 1071 | return 0; |
1072 | } | 1072 | } |
1073 | 1073 | ||
1074 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) | 1074 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) |
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index d7d8a8c10635..d71e99439376 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c | |||
@@ -371,31 +371,6 @@ int __kprobes arch_prepare_optimized_kprobe(struct optimized_kprobe *op) | |||
371 | return 0; | 371 | return 0; |
372 | } | 372 | } |
373 | 373 | ||
374 | #define MAX_OPTIMIZE_PROBES 256 | ||
375 | static struct text_poke_param *jump_poke_params; | ||
376 | static struct jump_poke_buffer { | ||
377 | u8 buf[RELATIVEJUMP_SIZE]; | ||
378 | } *jump_poke_bufs; | ||
379 | |||
380 | static void __kprobes setup_optimize_kprobe(struct text_poke_param *tprm, | ||
381 | u8 *insn_buf, | ||
382 | struct optimized_kprobe *op) | ||
383 | { | ||
384 | s32 rel = (s32)((long)op->optinsn.insn - | ||
385 | ((long)op->kp.addr + RELATIVEJUMP_SIZE)); | ||
386 | |||
387 | /* Backup instructions which will be replaced by jump address */ | ||
388 | memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE, | ||
389 | RELATIVE_ADDR_SIZE); | ||
390 | |||
391 | insn_buf[0] = RELATIVEJUMP_OPCODE; | ||
392 | *(s32 *)(&insn_buf[1]) = rel; | ||
393 | |||
394 | tprm->addr = op->kp.addr; | ||
395 | tprm->opcode = insn_buf; | ||
396 | tprm->len = RELATIVEJUMP_SIZE; | ||
397 | } | ||
398 | |||
399 | /* | 374 | /* |
400 | * Replace breakpoints (int3) with relative jumps. | 375 | * Replace breakpoints (int3) with relative jumps. |
401 | * Caller must call with locking kprobe_mutex and text_mutex. | 376 | * Caller must call with locking kprobe_mutex and text_mutex. |
@@ -403,32 +378,38 @@ static void __kprobes setup_optimize_kprobe(struct text_poke_param *tprm, | |||
403 | void __kprobes arch_optimize_kprobes(struct list_head *oplist) | 378 | void __kprobes arch_optimize_kprobes(struct list_head *oplist) |
404 | { | 379 | { |
405 | struct optimized_kprobe *op, *tmp; | 380 | struct optimized_kprobe *op, *tmp; |
406 | int c = 0; | 381 | u8 insn_buf[RELATIVEJUMP_SIZE]; |
407 | 382 | ||
408 | list_for_each_entry_safe(op, tmp, oplist, list) { | 383 | list_for_each_entry_safe(op, tmp, oplist, list) { |
384 | s32 rel = (s32)((long)op->optinsn.insn - | ||
385 | ((long)op->kp.addr + RELATIVEJUMP_SIZE)); | ||
386 | |||
409 | WARN_ON(kprobe_disabled(&op->kp)); | 387 | WARN_ON(kprobe_disabled(&op->kp)); |
410 | /* Setup param */ | 388 | |
411 | setup_optimize_kprobe(&jump_poke_params[c], | 389 | /* Backup instructions which will be replaced by jump address */ |
412 | jump_poke_bufs[c].buf, op); | 390 | memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE, |
391 | RELATIVE_ADDR_SIZE); | ||
392 | |||
393 | insn_buf[0] = RELATIVEJUMP_OPCODE; | ||
394 | *(s32 *)(&insn_buf[1]) = rel; | ||
395 | |||
396 | text_poke_bp(op->kp.addr, insn_buf, RELATIVEJUMP_SIZE, | ||
397 | op->optinsn.insn); | ||
398 | |||
413 | list_del_init(&op->list); | 399 | list_del_init(&op->list); |
414 | if (++c >= MAX_OPTIMIZE_PROBES) | ||
415 | break; | ||
416 | } | 400 | } |
417 | |||
418 | text_poke_smp_batch(jump_poke_params, c); | ||
419 | } | 401 | } |
420 | 402 | ||
421 | static void __kprobes setup_unoptimize_kprobe(struct text_poke_param *tprm, | 403 | /* Replace a relative jump with a breakpoint (int3). */ |
422 | u8 *insn_buf, | 404 | void __kprobes arch_unoptimize_kprobe(struct optimized_kprobe *op) |
423 | struct optimized_kprobe *op) | ||
424 | { | 405 | { |
406 | u8 insn_buf[RELATIVEJUMP_SIZE]; | ||
407 | |||
425 | /* Set int3 to first byte for kprobes */ | 408 | /* Set int3 to first byte for kprobes */ |
426 | insn_buf[0] = BREAKPOINT_INSTRUCTION; | 409 | insn_buf[0] = BREAKPOINT_INSTRUCTION; |
427 | memcpy(insn_buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE); | 410 | memcpy(insn_buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE); |
428 | 411 | text_poke_bp(op->kp.addr, insn_buf, RELATIVEJUMP_SIZE, | |
429 | tprm->addr = op->kp.addr; | 412 | op->optinsn.insn); |
430 | tprm->opcode = insn_buf; | ||
431 | tprm->len = RELATIVEJUMP_SIZE; | ||
432 | } | 413 | } |
433 | 414 | ||
434 | /* | 415 | /* |
@@ -439,29 +420,11 @@ extern void arch_unoptimize_kprobes(struct list_head *oplist, | |||
439 | struct list_head *done_list) | 420 | struct list_head *done_list) |
440 | { | 421 | { |
441 | struct optimized_kprobe *op, *tmp; | 422 | struct optimized_kprobe *op, *tmp; |
442 | int c = 0; | ||
443 | 423 | ||
444 | list_for_each_entry_safe(op, tmp, oplist, list) { | 424 | list_for_each_entry_safe(op, tmp, oplist, list) { |
445 | /* Setup param */ | 425 | arch_unoptimize_kprobe(op); |
446 | setup_unoptimize_kprobe(&jump_poke_params[c], | ||
447 | jump_poke_bufs[c].buf, op); | ||
448 | list_move(&op->list, done_list); | 426 | list_move(&op->list, done_list); |
449 | if (++c >= MAX_OPTIMIZE_PROBES) | ||
450 | break; | ||
451 | } | 427 | } |
452 | |||
453 | text_poke_smp_batch(jump_poke_params, c); | ||
454 | } | ||
455 | |||
456 | /* Replace a relative jump with a breakpoint (int3). */ | ||
457 | void __kprobes arch_unoptimize_kprobe(struct optimized_kprobe *op) | ||
458 | { | ||
459 | u8 buf[RELATIVEJUMP_SIZE]; | ||
460 | |||
461 | /* Set int3 to first byte for kprobes */ | ||
462 | buf[0] = BREAKPOINT_INSTRUCTION; | ||
463 | memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE); | ||
464 | text_poke_smp(op->kp.addr, buf, RELATIVEJUMP_SIZE); | ||
465 | } | 428 | } |
466 | 429 | ||
467 | int __kprobes | 430 | int __kprobes |
@@ -481,22 +444,3 @@ setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter) | |||
481 | } | 444 | } |
482 | return 0; | 445 | return 0; |
483 | } | 446 | } |
484 | |||
485 | int __kprobes arch_init_optprobes(void) | ||
486 | { | ||
487 | /* Allocate code buffer and parameter array */ | ||
488 | jump_poke_bufs = kmalloc(sizeof(struct jump_poke_buffer) * | ||
489 | MAX_OPTIMIZE_PROBES, GFP_KERNEL); | ||
490 | if (!jump_poke_bufs) | ||
491 | return -ENOMEM; | ||
492 | |||
493 | jump_poke_params = kmalloc(sizeof(struct text_poke_param) * | ||
494 | MAX_OPTIMIZE_PROBES, GFP_KERNEL); | ||
495 | if (!jump_poke_params) { | ||
496 | kfree(jump_poke_bufs); | ||
497 | jump_poke_bufs = NULL; | ||
498 | return -ENOMEM; | ||
499 | } | ||
500 | |||
501 | return 0; | ||
502 | } | ||