Commit 97aa5cdd authored by Oleg Nesterov's avatar Oleg Nesterov

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: default avatarOleg Nesterov <oleg@redhat.com>
Reviewed-by: default avatarJim Keniston <jkenisto@us.ibm.com>
parent 220ef8dc
...@@ -41,18 +41,20 @@ struct arch_uprobe { ...@@ -41,18 +41,20 @@ struct arch_uprobe {
u8 ixol[MAX_UINSN_BYTES]; u8 ixol[MAX_UINSN_BYTES];
}; };
u16 fixups;
const struct uprobe_xol_ops *ops; const struct uprobe_xol_ops *ops;
union { union {
#ifdef CONFIG_X86_64
unsigned long rip_rela_target_address;
#endif
struct { struct {
s32 offs; s32 offs;
u8 ilen; u8 ilen;
u8 opc1; u8 opc1;
} branch; } branch;
struct {
#ifdef CONFIG_X86_64
long riprel_target;
#endif
u16 fixups;
} def;
}; };
}; };
......
...@@ -251,10 +251,9 @@ static inline bool is_64bit_mm(struct mm_struct *mm) ...@@ -251,10 +251,9 @@ static inline bool is_64bit_mm(struct mm_struct *mm)
* If arch_uprobe->insn doesn't use rip-relative addressing, return * If arch_uprobe->insn doesn't use rip-relative addressing, return
* immediately. Otherwise, rewrite the instruction so that it accesses * immediately. Otherwise, rewrite the instruction so that it accesses
* its memory operand indirectly through a scratch register. Set * its memory operand indirectly through a scratch register. Set
* arch_uprobe->fixups and arch_uprobe->rip_rela_target_address * def->fixups and def->riprel_target accordingly. (The contents of the
* accordingly. (The contents of the scratch register will be saved * scratch register will be saved before we single-step the modified
* before we single-step the modified instruction, and restored * instruction, and restored afterward).
* afterward.)
* *
* We do this because a rip-relative instruction can access only a * We do this because a rip-relative instruction can access only a
* relatively small area (+/- 2 GB from the instruction), and the XOL * 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,18 +307,18 @@ handle_riprel_insn(struct arch_uprobe *auprobe, struct insn *insn)
* is NOT the register operand, so we use %rcx (register * is NOT the register operand, so we use %rcx (register
* #1) for the scratch register. * #1) for the scratch register.
*/ */
auprobe->fixups = UPROBE_FIX_RIP_CX; auprobe->def.fixups = UPROBE_FIX_RIP_CX;
/* Change modrm from 00 000 101 to 00 000 001. */ /* Change modrm from 00 000 101 to 00 000 001. */
*cursor = 0x1; *cursor = 0x1;
} else { } else {
/* Use %rax (register #0) for the scratch register. */ /* Use %rax (register #0) for the scratch register. */
auprobe->fixups = UPROBE_FIX_RIP_AX; auprobe->def.fixups = UPROBE_FIX_RIP_AX;
/* Change modrm from 00 xxx 101 to 00 xxx 000 */ /* Change modrm from 00 xxx 101 to 00 xxx 000 */
*cursor = (reg << 3); *cursor = (reg << 3);
} }
/* Target address = address of next instruction + (signed) offset */ /* Target address = address of next instruction + (signed) offset */
auprobe->rip_rela_target_address = (long)insn->length + insn->displacement.value; auprobe->def.riprel_target = (long)insn->length + insn->displacement.value;
/* Displacement field is gone; slide immediate field (if any) over. */ /* Displacement field is gone; slide immediate field (if any) over. */
if (insn->immediate.nbytes) { if (insn->immediate.nbytes) {
...@@ -336,25 +335,25 @@ static void ...@@ -336,25 +335,25 @@ static void
pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
struct arch_uprobe_task *autask) struct arch_uprobe_task *autask)
{ {
if (auprobe->fixups & UPROBE_FIX_RIP_AX) { if (auprobe->def.fixups & UPROBE_FIX_RIP_AX) {
autask->saved_scratch_register = regs->ax; autask->saved_scratch_register = regs->ax;
regs->ax = current->utask->vaddr; regs->ax = current->utask->vaddr;
regs->ax += auprobe->rip_rela_target_address; regs->ax += auprobe->def.riprel_target;
} else if (auprobe->fixups & UPROBE_FIX_RIP_CX) { } else if (auprobe->def.fixups & UPROBE_FIX_RIP_CX) {
autask->saved_scratch_register = regs->cx; autask->saved_scratch_register = regs->cx;
regs->cx = current->utask->vaddr; regs->cx = current->utask->vaddr;
regs->cx += auprobe->rip_rela_target_address; regs->cx += auprobe->def.riprel_target;
} }
} }
static void static void
handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction)
{ {
if (auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) { if (auprobe->def.fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) {
struct arch_uprobe_task *autask; struct arch_uprobe_task *autask;
autask = &current->utask->autask; autask = &current->utask->autask;
if (auprobe->fixups & UPROBE_FIX_RIP_AX) if (auprobe->def.fixups & UPROBE_FIX_RIP_AX)
regs->ax = autask->saved_scratch_register; regs->ax = autask->saved_scratch_register;
else else
regs->cx = autask->saved_scratch_register; 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,17 +431,17 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs
long correction = (long)(utask->vaddr - utask->xol_vaddr); long correction = (long)(utask->vaddr - utask->xol_vaddr);
handle_riprel_post_xol(auprobe, regs, &correction); handle_riprel_post_xol(auprobe, regs, &correction);
if (auprobe->fixups & UPROBE_FIX_IP) if (auprobe->def.fixups & UPROBE_FIX_IP)
regs->ip += correction; regs->ip += correction;
if (auprobe->fixups & UPROBE_FIX_CALL) { if (auprobe->def.fixups & UPROBE_FIX_CALL) {
if (adjust_ret_addr(regs->sp, correction)) { if (adjust_ret_addr(regs->sp, correction)) {
regs->sp += sizeof_long(); regs->sp += sizeof_long();
return -ERESTART; return -ERESTART;
} }
} }
/* popf; tell the caller to not touch TF */ /* popf; tell the caller to not touch TF */
if (auprobe->fixups & UPROBE_FIX_SETF) if (auprobe->def.fixups & UPROBE_FIX_SETF)
utask->autask.saved_tf = true; utask->autask.saved_tf = true;
return 0; return 0;
...@@ -646,13 +645,13 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, ...@@ -646,13 +645,13 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
return ret; return ret;
/* /*
* Figure out which fixups arch_uprobe_post_xol() will need to perform, * Figure out which fixups default_post_xol_op() will need to perform,
* and annotate arch_uprobe->fixups accordingly. To start with, ->fixups * and annotate def->fixups accordingly. To start with, ->fixups is
* is either zero or it reflects rip-related fixups. * either zero or it reflects rip-related fixups.
*/ */
switch (OPCODE1(&insn)) { switch (OPCODE1(&insn)) {
case 0x9d: /* popf */ case 0x9d: /* popf */
auprobe->fixups |= UPROBE_FIX_SETF; auprobe->def.fixups |= UPROBE_FIX_SETF;
break; break;
case 0xc3: /* ret or lret -- ip is correct */ case 0xc3: /* ret or lret -- ip is correct */
case 0xcb: case 0xcb:
...@@ -680,9 +679,9 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, ...@@ -680,9 +679,9 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
} }
if (fix_ip) if (fix_ip)
auprobe->fixups |= UPROBE_FIX_IP; auprobe->def.fixups |= UPROBE_FIX_IP;
if (fix_call) if (fix_call)
auprobe->fixups |= UPROBE_FIX_CALL; auprobe->def.fixups |= UPROBE_FIX_CALL;
auprobe->ops = &default_xol_ops; auprobe->ops = &default_xol_ops;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment