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>
This commit is contained in:
Oleg Nesterov 2014-04-22 16:20:55 +02:00
parent 220ef8dc9a
commit 97aa5cddbe
2 changed files with 28 additions and 27 deletions

View File

@ -41,18 +41,20 @@ struct arch_uprobe {
u8 ixol[MAX_UINSN_BYTES];
};
u16 fixups;
const struct uprobe_xol_ops *ops;
union {
#ifdef CONFIG_X86_64
unsigned long rip_rela_target_address;
#endif
struct {
s32 offs;
u8 ilen;
u8 opc1;
} branch;
} branch;
struct {
#ifdef CONFIG_X86_64
long riprel_target;
#endif
u16 fixups;
} def;
};
};

View File

@ -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
* immediately. Otherwise, rewrite the instruction so that it accesses
* its memory operand indirectly through a scratch register. Set
* arch_uprobe->fixups and arch_uprobe->rip_rela_target_address
* accordingly. (The contents of the scratch register will be saved
* before we single-step the modified instruction, and restored
* afterward.)
* def->fixups and def->riprel_target accordingly. (The contents of the
* scratch register will be saved before we single-step the modified
* instruction, and restored afterward).
*
* We do this because a rip-relative instruction can access only a
* 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)
* is NOT the register operand, so we use %rcx (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. */
*cursor = 0x1;
} else {
/* 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 */
*cursor = (reg << 3);
}
/* 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. */
if (insn->immediate.nbytes) {
@ -336,25 +335,25 @@ static void
pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
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;
regs->ax = current->utask->vaddr;
regs->ax += auprobe->rip_rela_target_address;
} else if (auprobe->fixups & UPROBE_FIX_RIP_CX) {
regs->ax += auprobe->def.riprel_target;
} else if (auprobe->def.fixups & UPROBE_FIX_RIP_CX) {
autask->saved_scratch_register = regs->cx;
regs->cx = current->utask->vaddr;
regs->cx += auprobe->rip_rela_target_address;
regs->cx += auprobe->def.riprel_target;
}
}
static void
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;
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;
else
regs->cx = autask->saved_scratch_register;
@ -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);
handle_riprel_post_xol(auprobe, regs, &correction);
if (auprobe->fixups & UPROBE_FIX_IP)
if (auprobe->def.fixups & UPROBE_FIX_IP)
regs->ip += correction;
if (auprobe->fixups & UPROBE_FIX_CALL) {
if (auprobe->def.fixups & UPROBE_FIX_CALL) {
if (adjust_ret_addr(regs->sp, correction)) {
regs->sp += sizeof_long();
return -ERESTART;
}
}
/* 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;
return 0;
@ -646,13 +645,13 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
return ret;
/*
* Figure out which fixups arch_uprobe_post_xol() will need to perform,
* and annotate arch_uprobe->fixups accordingly. To start with, ->fixups
* is either zero or it reflects rip-related fixups.
* Figure out which fixups default_post_xol_op() will need to perform,
* and annotate def->fixups accordingly. To start with, ->fixups is
* either zero or it reflects rip-related fixups.
*/
switch (OPCODE1(&insn)) {
case 0x9d: /* popf */
auprobe->fixups |= UPROBE_FIX_SETF;
auprobe->def.fixups |= UPROBE_FIX_SETF;
break;
case 0xc3: /* ret or lret -- ip is correct */
case 0xcb:
@ -680,9 +679,9 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
}
if (fix_ip)
auprobe->fixups |= UPROBE_FIX_IP;
auprobe->def.fixups |= UPROBE_FIX_IP;
if (fix_call)
auprobe->fixups |= UPROBE_FIX_CALL;
auprobe->def.fixups |= UPROBE_FIX_CALL;
auprobe->ops = &default_xol_ops;
return 0;