kprobes: Cleanup fix_riprel() using insn decoder on x86
Cleanup fix_riprel() in arch/x86/kernel/kprobes.c by using the new x86 instruction decoder instead of using comparisons with raw ad hoc numeric opcodes. Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Avi Kivity <avi@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Frank Ch. Eigler <fche@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Jason Baron <jbaron@redhat.com> Cc: Jim Keniston <jkenisto@us.ibm.com> Cc: K.Prasad <prasad@linux.vnet.ibm.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Przemysław Pawełczyk <przemyslaw@pawelczyk.it> Cc: Roland McGrath <roland@redhat.com> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Vegard Nossum <vegard.nossum@gmail.com> LKML-Reference: <20090813203436.31965.34374.stgit@localhost.localdomain> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
This commit is contained in:
committed by
Frederic Weisbecker
parent
b46b3d70c9
commit
89ae465b0e
@@ -108,50 +108,6 @@ static const u32 twobyte_is_boostable[256 / 32] = {
|
|||||||
/* ----------------------------------------------- */
|
/* ----------------------------------------------- */
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||||
};
|
};
|
||||||
static const u32 onebyte_has_modrm[256 / 32] = {
|
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
||||||
/* ----------------------------------------------- */
|
|
||||||
W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 00 */
|
|
||||||
W(0x10, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 10 */
|
|
||||||
W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 20 */
|
|
||||||
W(0x30, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 30 */
|
|
||||||
W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */
|
|
||||||
W(0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 50 */
|
|
||||||
W(0x60, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0) | /* 60 */
|
|
||||||
W(0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 70 */
|
|
||||||
W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
|
|
||||||
W(0x90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 90 */
|
|
||||||
W(0xa0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* a0 */
|
|
||||||
W(0xb0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* b0 */
|
|
||||||
W(0xc0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* c0 */
|
|
||||||
W(0xd0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
|
|
||||||
W(0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* e0 */
|
|
||||||
W(0xf0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) /* f0 */
|
|
||||||
/* ----------------------------------------------- */
|
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
||||||
};
|
|
||||||
static const u32 twobyte_has_modrm[256 / 32] = {
|
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
||||||
/* ----------------------------------------------- */
|
|
||||||
W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1) | /* 0f */
|
|
||||||
W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0) , /* 1f */
|
|
||||||
W(0x20, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 2f */
|
|
||||||
W(0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 3f */
|
|
||||||
W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 4f */
|
|
||||||
W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 5f */
|
|
||||||
W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 6f */
|
|
||||||
W(0x70, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1) , /* 7f */
|
|
||||||
W(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 8f */
|
|
||||||
W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 9f */
|
|
||||||
W(0xa0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1) | /* af */
|
|
||||||
W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1) , /* bf */
|
|
||||||
W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* cf */
|
|
||||||
W(0xd0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* df */
|
|
||||||
W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* ef */
|
|
||||||
W(0xf0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* ff */
|
|
||||||
/* ----------------------------------------------- */
|
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
||||||
};
|
|
||||||
#undef W
|
#undef W
|
||||||
|
|
||||||
struct kretprobe_blackpoint kretprobe_blacklist[] = {
|
struct kretprobe_blackpoint kretprobe_blacklist[] = {
|
||||||
@@ -348,68 +304,30 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
|
|||||||
static void __kprobes fix_riprel(struct kprobe *p)
|
static void __kprobes fix_riprel(struct kprobe *p)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
u8 *insn = p->ainsn.insn;
|
struct insn insn;
|
||||||
s64 disp;
|
kernel_insn_init(&insn, p->ainsn.insn);
|
||||||
int need_modrm;
|
|
||||||
|
|
||||||
/* Skip legacy instruction prefixes. */
|
if (insn_rip_relative(&insn)) {
|
||||||
while (1) {
|
s64 newdisp;
|
||||||
switch (*insn) {
|
u8 *disp;
|
||||||
case 0x66:
|
insn_get_displacement(&insn);
|
||||||
case 0x67:
|
|
||||||
case 0x2e:
|
|
||||||
case 0x3e:
|
|
||||||
case 0x26:
|
|
||||||
case 0x64:
|
|
||||||
case 0x65:
|
|
||||||
case 0x36:
|
|
||||||
case 0xf0:
|
|
||||||
case 0xf3:
|
|
||||||
case 0xf2:
|
|
||||||
++insn;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip REX instruction prefix. */
|
|
||||||
if (is_REX_prefix(insn))
|
|
||||||
++insn;
|
|
||||||
|
|
||||||
if (*insn == 0x0f) {
|
|
||||||
/* Two-byte opcode. */
|
|
||||||
++insn;
|
|
||||||
need_modrm = test_bit(*insn,
|
|
||||||
(unsigned long *)twobyte_has_modrm);
|
|
||||||
} else
|
|
||||||
/* One-byte opcode. */
|
|
||||||
need_modrm = test_bit(*insn,
|
|
||||||
(unsigned long *)onebyte_has_modrm);
|
|
||||||
|
|
||||||
if (need_modrm) {
|
|
||||||
u8 modrm = *++insn;
|
|
||||||
if ((modrm & 0xc7) == 0x05) {
|
|
||||||
/* %rip+disp32 addressing mode */
|
|
||||||
/* Displacement follows ModRM byte. */
|
|
||||||
++insn;
|
|
||||||
/*
|
/*
|
||||||
* The copied instruction uses the %rip-relative
|
* The copied instruction uses the %rip-relative addressing
|
||||||
* addressing mode. Adjust the displacement for the
|
* mode. Adjust the displacement for the difference between
|
||||||
* difference between the original location of this
|
* the original location of this instruction and the location
|
||||||
* instruction and the location of the copy that will
|
* of the copy that will actually be run. The tricky bit here
|
||||||
* actually be run. The tricky bit here is making sure
|
* is making sure that the sign extension happens correctly in
|
||||||
* that the sign extension happens correctly in this
|
* this calculation, since we need a signed 32-bit result to
|
||||||
* calculation, since we need a signed 32-bit result to
|
* be sign-extended to 64 bits when it's added to the %rip
|
||||||
* be sign-extended to 64 bits when it's added to the
|
* value and yield the same 64-bit result that the sign-
|
||||||
* %rip value and yield the same 64-bit result that the
|
* extension of the original signed 32-bit displacement would
|
||||||
* sign-extension of the original signed 32-bit
|
* have given.
|
||||||
* displacement would have given.
|
|
||||||
*/
|
*/
|
||||||
disp = (u8 *) p->addr + *((s32 *) insn) -
|
newdisp = (u8 *) p->addr + (s64) insn.displacement.value -
|
||||||
(u8 *) p->ainsn.insn;
|
(u8 *) p->ainsn.insn;
|
||||||
BUG_ON((s64) (s32) disp != disp); /* Sanity check. */
|
BUG_ON((s64) (s32) newdisp != newdisp); /* Sanity check. */
|
||||||
*(s32 *)insn = (s32) disp;
|
disp = (u8 *) p->ainsn.insn + insn_offset_displacement(&insn);
|
||||||
}
|
*(s32 *) disp = (s32) newdisp;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user