diff options
author | Oleg Nesterov <oleg@redhat.com> | 2014-04-22 10:20:55 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2014-04-30 13:10:37 -0400 |
commit | 97aa5cddbe9e01521137f337624469374e3cbde5 (patch) | |
tree | 6a813750457cd69b24e2ef46edf7db198dd99578 /arch | |
parent | 220ef8dc9a7a63fe202aacd3fc61e5104f6dd98c (diff) |
uprobes/x86: Move default_xol_ops's data into arch_uprobe->def
Finally we can move arch_uprobe->fixups/rip_rela_target_address
into the new "def" struct and place this struct in the union, they
are only used by default_xol_ops paths.
The patch also renames rip_rela_target_address to riprel_target just
to make this name shorter.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: Jim Keniston <jkenisto@us.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/uprobes.h | 12 | ||||
-rw-r--r-- | arch/x86/kernel/uprobes.c | 43 |
2 files changed, 28 insertions, 27 deletions
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h index 93bee7b93854..72caff7afbde 100644 --- a/arch/x86/include/asm/uprobes.h +++ b/arch/x86/include/asm/uprobes.h | |||
@@ -41,18 +41,20 @@ struct arch_uprobe { | |||
41 | u8 ixol[MAX_UINSN_BYTES]; | 41 | u8 ixol[MAX_UINSN_BYTES]; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | u16 fixups; | ||
45 | const struct uprobe_xol_ops *ops; | 44 | const struct uprobe_xol_ops *ops; |
46 | 45 | ||
47 | union { | 46 | union { |
48 | #ifdef CONFIG_X86_64 | ||
49 | unsigned long rip_rela_target_address; | ||
50 | #endif | ||
51 | struct { | 47 | struct { |
52 | s32 offs; | 48 | s32 offs; |
53 | u8 ilen; | 49 | u8 ilen; |
54 | u8 opc1; | 50 | u8 opc1; |
55 | } branch; | 51 | } branch; |
52 | struct { | ||
53 | #ifdef CONFIG_X86_64 | ||
54 | long riprel_target; | ||
55 | #endif | ||
56 | u16 fixups; | ||
57 | } def; | ||
56 | }; | 58 | }; |
57 | }; | 59 | }; |
58 | 60 | ||
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index b2bca293fc57..7824ce248f8f 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -251,10 +251,9 @@ static inline bool is_64bit_mm(struct mm_struct *mm) | |||
251 | * If arch_uprobe->insn doesn't use rip-relative addressing, return | 251 | * If arch_uprobe->insn doesn't use rip-relative addressing, return |
252 | * immediately. Otherwise, rewrite the instruction so that it accesses | 252 | * immediately. Otherwise, rewrite the instruction so that it accesses |
253 | * its memory operand indirectly through a scratch register. Set | 253 | * its memory operand indirectly through a scratch register. Set |
254 | * arch_uprobe->fixups and arch_uprobe->rip_rela_target_address | 254 | * def->fixups and def->riprel_target accordingly. (The contents of the |
255 | * accordingly. (The contents of the scratch register will be saved | 255 | * scratch register will be saved before we single-step the modified |
256 | * before we single-step the modified instruction, and restored | 256 | * instruction, and restored afterward). |
257 | * afterward.) | ||
258 | * | 257 | * |
259 | * We do this because a rip-relative instruction can access only a | 258 | * We do this because a rip-relative instruction can access only a |
260 | * relatively small area (+/- 2 GB from the instruction), and the XOL | 259 | * relatively small area (+/- 2 GB from the instruction), and the XOL |
@@ -308,18 +307,18 @@ handle_riprel_insn(struct arch_uprobe *auprobe, struct insn *insn) | |||
308 | * is NOT the register operand, so we use %rcx (register | 307 | * is NOT the register operand, so we use %rcx (register |
309 | * #1) for the scratch register. | 308 | * #1) for the scratch register. |
310 | */ | 309 | */ |
311 | auprobe->fixups = UPROBE_FIX_RIP_CX; | 310 | auprobe->def.fixups = UPROBE_FIX_RIP_CX; |
312 | /* Change modrm from 00 000 101 to 00 000 001. */ | 311 | /* Change modrm from 00 000 101 to 00 000 001. */ |
313 | *cursor = 0x1; | 312 | *cursor = 0x1; |
314 | } else { | 313 | } else { |
315 | /* Use %rax (register #0) for the scratch register. */ | 314 | /* Use %rax (register #0) for the scratch register. */ |
316 | auprobe->fixups = UPROBE_FIX_RIP_AX; | 315 | auprobe->def.fixups = UPROBE_FIX_RIP_AX; |
317 | /* Change modrm from 00 xxx 101 to 00 xxx 000 */ | 316 | /* Change modrm from 00 xxx 101 to 00 xxx 000 */ |
318 | *cursor = (reg << 3); | 317 | *cursor = (reg << 3); |
319 | } | 318 | } |
320 | 319 | ||
321 | /* Target address = address of next instruction + (signed) offset */ | 320 | /* Target address = address of next instruction + (signed) offset */ |
322 | auprobe->rip_rela_target_address = (long)insn->length + insn->displacement.value; | 321 | auprobe->def.riprel_target = (long)insn->length + insn->displacement.value; |
323 | 322 | ||
324 | /* Displacement field is gone; slide immediate field (if any) over. */ | 323 | /* Displacement field is gone; slide immediate field (if any) over. */ |
325 | if (insn->immediate.nbytes) { | 324 | if (insn->immediate.nbytes) { |
@@ -336,25 +335,25 @@ static void | |||
336 | pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, | 335 | pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, |
337 | struct arch_uprobe_task *autask) | 336 | struct arch_uprobe_task *autask) |
338 | { | 337 | { |
339 | if (auprobe->fixups & UPROBE_FIX_RIP_AX) { | 338 | if (auprobe->def.fixups & UPROBE_FIX_RIP_AX) { |
340 | autask->saved_scratch_register = regs->ax; | 339 | autask->saved_scratch_register = regs->ax; |
341 | regs->ax = current->utask->vaddr; | 340 | regs->ax = current->utask->vaddr; |
342 | regs->ax += auprobe->rip_rela_target_address; | 341 | regs->ax += auprobe->def.riprel_target; |
343 | } else if (auprobe->fixups & UPROBE_FIX_RIP_CX) { | 342 | } else if (auprobe->def.fixups & UPROBE_FIX_RIP_CX) { |
344 | autask->saved_scratch_register = regs->cx; | 343 | autask->saved_scratch_register = regs->cx; |
345 | regs->cx = current->utask->vaddr; | 344 | regs->cx = current->utask->vaddr; |
346 | regs->cx += auprobe->rip_rela_target_address; | 345 | regs->cx += auprobe->def.riprel_target; |
347 | } | 346 | } |
348 | } | 347 | } |
349 | 348 | ||
350 | static void | 349 | static void |
351 | handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) | 350 | handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) |
352 | { | 351 | { |
353 | if (auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { | 352 | if (auprobe->def.fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { |
354 | struct arch_uprobe_task *autask; | 353 | struct arch_uprobe_task *autask; |
355 | 354 | ||
356 | autask = ¤t->utask->autask; | 355 | autask = ¤t->utask->autask; |
357 | if (auprobe->fixups & UPROBE_FIX_RIP_AX) | 356 | if (auprobe->def.fixups & UPROBE_FIX_RIP_AX) |
358 | regs->ax = autask->saved_scratch_register; | 357 | regs->ax = autask->saved_scratch_register; |
359 | else | 358 | else |
360 | regs->cx = autask->saved_scratch_register; | 359 | regs->cx = autask->saved_scratch_register; |
@@ -432,17 +431,17 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs | |||
432 | long correction = (long)(utask->vaddr - utask->xol_vaddr); | 431 | long correction = (long)(utask->vaddr - utask->xol_vaddr); |
433 | 432 | ||
434 | handle_riprel_post_xol(auprobe, regs, &correction); | 433 | handle_riprel_post_xol(auprobe, regs, &correction); |
435 | if (auprobe->fixups & UPROBE_FIX_IP) | 434 | if (auprobe->def.fixups & UPROBE_FIX_IP) |
436 | regs->ip += correction; | 435 | regs->ip += correction; |
437 | 436 | ||
438 | if (auprobe->fixups & UPROBE_FIX_CALL) { | 437 | if (auprobe->def.fixups & UPROBE_FIX_CALL) { |
439 | if (adjust_ret_addr(regs->sp, correction)) { | 438 | if (adjust_ret_addr(regs->sp, correction)) { |
440 | regs->sp += sizeof_long(); | 439 | regs->sp += sizeof_long(); |
441 | return -ERESTART; | 440 | return -ERESTART; |
442 | } | 441 | } |
443 | } | 442 | } |
444 | /* popf; tell the caller to not touch TF */ | 443 | /* popf; tell the caller to not touch TF */ |
445 | if (auprobe->fixups & UPROBE_FIX_SETF) | 444 | if (auprobe->def.fixups & UPROBE_FIX_SETF) |
446 | utask->autask.saved_tf = true; | 445 | utask->autask.saved_tf = true; |
447 | 446 | ||
448 | return 0; | 447 | return 0; |
@@ -646,13 +645,13 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
646 | return ret; | 645 | return ret; |
647 | 646 | ||
648 | /* | 647 | /* |
649 | * Figure out which fixups arch_uprobe_post_xol() will need to perform, | 648 | * Figure out which fixups default_post_xol_op() will need to perform, |
650 | * and annotate arch_uprobe->fixups accordingly. To start with, ->fixups | 649 | * and annotate def->fixups accordingly. To start with, ->fixups is |
651 | * is either zero or it reflects rip-related fixups. | 650 | * either zero or it reflects rip-related fixups. |
652 | */ | 651 | */ |
653 | switch (OPCODE1(&insn)) { | 652 | switch (OPCODE1(&insn)) { |
654 | case 0x9d: /* popf */ | 653 | case 0x9d: /* popf */ |
655 | auprobe->fixups |= UPROBE_FIX_SETF; | 654 | auprobe->def.fixups |= UPROBE_FIX_SETF; |
656 | break; | 655 | break; |
657 | case 0xc3: /* ret or lret -- ip is correct */ | 656 | case 0xc3: /* ret or lret -- ip is correct */ |
658 | case 0xcb: | 657 | case 0xcb: |
@@ -680,9 +679,9 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
680 | } | 679 | } |
681 | 680 | ||
682 | if (fix_ip) | 681 | if (fix_ip) |
683 | auprobe->fixups |= UPROBE_FIX_IP; | 682 | auprobe->def.fixups |= UPROBE_FIX_IP; |
684 | if (fix_call) | 683 | if (fix_call) |
685 | auprobe->fixups |= UPROBE_FIX_CALL; | 684 | auprobe->def.fixups |= UPROBE_FIX_CALL; |
686 | 685 | ||
687 | auprobe->ops = &default_xol_ops; | 686 | auprobe->ops = &default_xol_ops; |
688 | return 0; | 687 | return 0; |