Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IA64] kprobe opcode 16 bytes alignment on IA64

On IA64 instruction opcode must be 16 bytes alignment, in kprobe structure
there is one element to save original instruction, currently saved opcode
is not statically allocated in kprobe structure, that can not assure
16 bytes alignment. This patch dynamically allocated kprobe instruction
opcode to assure 16 bytes alignment.

Signed-off-by: bibo mao <bibo.mao@intel.com>
Acked-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>

authored by

bibo mao and committed by
Tony Luck
214ddde2 a4b47ab9

+34 -30
+29 -26
arch/ia64/kernel/kprobes.c
··· 136 136 static int __kprobes unsupported_inst(uint template, uint slot, 137 137 uint major_opcode, 138 138 unsigned long kprobe_inst, 139 - struct kprobe *p) 139 + unsigned long addr) 140 140 { 141 - unsigned long addr = (unsigned long)p->addr; 142 - 143 141 if (bundle_encoding[template][slot] == I) { 144 142 switch (major_opcode) { 145 143 case 0x0: //I_UNIT_MISC_OPCODE: ··· 215 217 struct kprobe *p) 216 218 { 217 219 unsigned long break_inst = BREAK_INST; 218 - bundle_t *bundle = &p->ainsn.insn.bundle; 220 + bundle_t *bundle = &p->opcode.bundle; 219 221 220 222 /* 221 223 * Copy the original kprobe_inst qualifying predicate(qp) ··· 421 423 unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL); 422 424 unsigned long kprobe_inst=0; 423 425 unsigned int slot = addr & 0xf, template, major_opcode = 0; 424 - bundle_t *bundle = &p->ainsn.insn.bundle; 426 + bundle_t *bundle; 425 427 426 - memcpy(&p->opcode.bundle, kprobe_addr, sizeof(bundle_t)); 427 - memcpy(&p->ainsn.insn.bundle, kprobe_addr, sizeof(bundle_t)); 428 - 428 + bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; 429 429 template = bundle->quad0.template; 430 430 431 431 if(valid_kprobe_addr(template, slot, addr)) ··· 436 440 /* Get kprobe_inst and major_opcode from the bundle */ 437 441 get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); 438 442 439 - if (unsupported_inst(template, slot, major_opcode, kprobe_inst, p)) 443 + if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr)) 440 444 return -EINVAL; 445 + 446 + 447 + p->ainsn.insn = get_insn_slot(); 448 + if (!p->ainsn.insn) 449 + return -ENOMEM; 450 + memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t)); 451 + memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t)); 441 452 442 453 prepare_break_inst(template, slot, major_opcode, kprobe_inst, p); 443 454 444 455 return 0; 445 - } 446 - 447 - void __kprobes flush_insn_slot(struct kprobe *p) 448 - { 449 - unsigned long arm_addr; 450 - 451 - arm_addr = ((unsigned long)&p->opcode.bundle) & ~0xFULL; 452 - flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); 453 456 } 454 457 455 458 void __kprobes arch_arm_kprobe(struct kprobe *p) ··· 456 461 unsigned long addr = (unsigned long)p->addr; 457 462 unsigned long arm_addr = addr & ~0xFULL; 458 463 459 - flush_insn_slot(p); 460 - memcpy((char *)arm_addr, &p->ainsn.insn.bundle, sizeof(bundle_t)); 461 - flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); 464 + flush_icache_range((unsigned long)p->ainsn.insn, 465 + (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t)); 466 + memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t)); 467 + flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); 462 468 } 463 469 464 470 void __kprobes arch_disarm_kprobe(struct kprobe *p) ··· 467 471 unsigned long addr = (unsigned long)p->addr; 468 472 unsigned long arm_addr = addr & ~0xFULL; 469 473 470 - /* p->opcode contains the original unaltered bundle */ 471 - memcpy((char *) arm_addr, (char *) &p->opcode.bundle, sizeof(bundle_t)); 472 - flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t)); 474 + /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */ 475 + memcpy((char *) arm_addr, (char *) p->ainsn.insn, 476 + sizeof(kprobe_opcode_t)); 477 + flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t)); 473 478 } 474 479 480 + void __kprobes arch_remove_kprobe(struct kprobe *p) 481 + { 482 + mutex_lock(&kprobe_mutex); 483 + free_insn_slot(p->ainsn.insn); 484 + mutex_unlock(&kprobe_mutex); 485 + } 475 486 /* 476 487 * We are resuming execution after a single step fault, so the pt_regs 477 488 * structure reflects the register state after we executed the instruction ··· 489 486 */ 490 487 static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) 491 488 { 492 - unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL; 489 + unsigned long bundle_addr = (unsigned long) (&p->ainsn.insn->bundle); 493 490 unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; 494 491 unsigned long template; 495 492 int slot = ((unsigned long)p->addr & 0xf); 496 493 497 - template = p->opcode.bundle.quad0.template; 494 + template = p->ainsn.insn->bundle.quad0.template; 498 495 499 496 if (slot == 1 && bundle_encoding[template][1] == L) 500 497 slot = 2; ··· 556 553 557 554 static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs) 558 555 { 559 - unsigned long bundle_addr = (unsigned long) &p->opcode.bundle; 556 + unsigned long bundle_addr = (unsigned long) &p->ainsn.insn->bundle; 560 557 unsigned long slot = (unsigned long)p->addr & 0xf; 561 558 562 559 /* single step inline if break instruction */
+5 -4
include/asm-ia64/kprobes.h
··· 29 29 #include <linux/percpu.h> 30 30 #include <asm/break.h> 31 31 32 - #define MAX_INSN_SIZE 16 32 + #define __ARCH_WANT_KPROBES_INSN_SLOT 33 + #define MAX_INSN_SIZE 1 33 34 #define BREAK_INST (long)(__IA64_BREAK_KPROBE << 6) 34 35 35 36 typedef union cmp_inst { ··· 95 94 #define IP_RELATIVE_PREDICT_OPCODE (7) 96 95 #define LONG_BRANCH_OPCODE (0xC) 97 96 #define LONG_CALL_OPCODE (0xD) 98 - #define arch_remove_kprobe(p) do {} while (0) 97 + #define flush_insn_slot(p) do { } while (0) 99 98 100 99 typedef struct kprobe_opcode { 101 100 bundle_t bundle; ··· 109 108 /* Architecture specific copy of original instruction*/ 110 109 struct arch_specific_insn { 111 110 /* copy of the instruction to be emulated */ 112 - kprobe_opcode_t insn; 111 + kprobe_opcode_t *insn; 113 112 #define INST_FLAG_FIX_RELATIVE_IP_ADDR 1 114 113 #define INST_FLAG_FIX_BRANCH_REG 2 115 114 #define INST_FLAG_BREAK_INST 4 ··· 126 125 } 127 126 extern void invalidate_stacked_regs(void); 128 127 extern void flush_register_stack(void); 129 - extern void flush_insn_slot(struct kprobe *p); 128 + extern void arch_remove_kprobe(struct kprobe *p); 130 129 131 130 #endif /* _ASM_KPROBES_H */