diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2009-08-13 16:34:36 -0400 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2009-08-26 18:35:57 -0400 |
commit | 89ae465b0ee470f7d3f8a1c61353445c3acbbe2a (patch) | |
tree | 0a365df6212b47c80ae9456ff42a94dd5a81a1d7 /arch | |
parent | b46b3d70c9c017d7c4ec49f7f3ffd0af5a622277 (diff) |
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/kprobes.c | 128 |
1 files changed, 23 insertions, 105 deletions
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index aa15f3e1f64b..16ae9610f6ff 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c | |||
@@ -108,50 +108,6 @@ static const u32 twobyte_is_boostable[256 / 32] = { | |||
108 | /* ----------------------------------------------- */ | 108 | /* ----------------------------------------------- */ |
109 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | 109 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
110 | }; | 110 | }; |
111 | static const u32 onebyte_has_modrm[256 / 32] = { | ||
112 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | ||
113 | /* ----------------------------------------------- */ | ||
114 | W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 00 */ | ||
115 | W(0x10, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 10 */ | ||
116 | W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 20 */ | ||
117 | W(0x30, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 30 */ | ||
118 | W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */ | ||
119 | W(0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 50 */ | ||
120 | W(0x60, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0) | /* 60 */ | ||
121 | W(0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 70 */ | ||
122 | W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */ | ||
123 | W(0x90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 90 */ | ||
124 | W(0xa0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* a0 */ | ||
125 | W(0xb0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* b0 */ | ||
126 | W(0xc0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* c0 */ | ||
127 | W(0xd0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */ | ||
128 | W(0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* e0 */ | ||
129 | W(0xf0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) /* f0 */ | ||
130 | /* ----------------------------------------------- */ | ||
131 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | ||
132 | }; | ||
133 | static const u32 twobyte_has_modrm[256 / 32] = { | ||
134 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | ||
135 | /* ----------------------------------------------- */ | ||
136 | W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1) | /* 0f */ | ||
137 | W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0) , /* 1f */ | ||
138 | W(0x20, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 2f */ | ||
139 | W(0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 3f */ | ||
140 | W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 4f */ | ||
141 | W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 5f */ | ||
142 | W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 6f */ | ||
143 | W(0x70, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1) , /* 7f */ | ||
144 | W(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 8f */ | ||
145 | W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 9f */ | ||
146 | W(0xa0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1) | /* af */ | ||
147 | W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1) , /* bf */ | ||
148 | W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* cf */ | ||
149 | W(0xd0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* df */ | ||
150 | W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* ef */ | ||
151 | W(0xf0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* ff */ | ||
152 | /* ----------------------------------------------- */ | ||
153 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | ||
154 | }; | ||
155 | #undef W | 111 | #undef W |
156 | 112 | ||
157 | struct kretprobe_blackpoint kretprobe_blacklist[] = { | 113 | struct kretprobe_blackpoint kretprobe_blacklist[] = { |
@@ -348,68 +304,30 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) | |||
348 | static void __kprobes fix_riprel(struct kprobe *p) | 304 | static void __kprobes fix_riprel(struct kprobe *p) |
349 | { | 305 | { |
350 | #ifdef CONFIG_X86_64 | 306 | #ifdef CONFIG_X86_64 |
351 | u8 *insn = p->ainsn.insn; | 307 | struct insn insn; |
352 | s64 disp; | 308 | kernel_insn_init(&insn, p->ainsn.insn); |
353 | int need_modrm; | ||
354 | |||
355 | /* Skip legacy instruction prefixes. */ | ||
356 | while (1) { | ||
357 | switch (*insn) { | ||
358 | case 0x66: | ||
359 | case 0x67: | ||
360 | case 0x2e: | ||
361 | case 0x3e: | ||
362 | case 0x26: | ||
363 | case 0x64: | ||
364 | case 0x65: | ||
365 | case 0x36: | ||
366 | case 0xf0: | ||
367 | case 0xf3: | ||
368 | case 0xf2: | ||
369 | ++insn; | ||
370 | continue; | ||
371 | } | ||
372 | break; | ||
373 | } | ||
374 | 309 | ||
375 | /* Skip REX instruction prefix. */ | 310 | if (insn_rip_relative(&insn)) { |
376 | if (is_REX_prefix(insn)) | 311 | s64 newdisp; |
377 | ++insn; | 312 | u8 *disp; |
378 | 313 | insn_get_displacement(&insn); | |
379 | if (*insn == 0x0f) { | 314 | /* |
380 | /* Two-byte opcode. */ | 315 | * The copied instruction uses the %rip-relative addressing |
381 | ++insn; | 316 | * mode. Adjust the displacement for the difference between |
382 | need_modrm = test_bit(*insn, | 317 | * the original location of this instruction and the location |
383 | (unsigned long *)twobyte_has_modrm); | 318 | * of the copy that will actually be run. The tricky bit here |
384 | } else | 319 | * is making sure that the sign extension happens correctly in |
385 | /* One-byte opcode. */ | 320 | * this calculation, since we need a signed 32-bit result to |
386 | need_modrm = test_bit(*insn, | 321 | * be sign-extended to 64 bits when it's added to the %rip |
387 | (unsigned long *)onebyte_has_modrm); | 322 | * value and yield the same 64-bit result that the sign- |
388 | 323 | * extension of the original signed 32-bit displacement would | |
389 | if (need_modrm) { | 324 | * have given. |
390 | u8 modrm = *++insn; | 325 | */ |
391 | if ((modrm & 0xc7) == 0x05) { | 326 | newdisp = (u8 *) p->addr + (s64) insn.displacement.value - |
392 | /* %rip+disp32 addressing mode */ | 327 | (u8 *) p->ainsn.insn; |
393 | /* Displacement follows ModRM byte. */ | 328 | BUG_ON((s64) (s32) newdisp != newdisp); /* Sanity check. */ |
394 | ++insn; | 329 | disp = (u8 *) p->ainsn.insn + insn_offset_displacement(&insn); |
395 | /* | 330 | *(s32 *) disp = (s32) newdisp; |
396 | * The copied instruction uses the %rip-relative | ||
397 | * addressing mode. Adjust the displacement for the | ||
398 | * difference between the original location of this | ||
399 | * instruction and the location of the copy that will | ||
400 | * actually be run. The tricky bit here is making sure | ||
401 | * that the sign extension happens correctly in this | ||
402 | * calculation, since we need a signed 32-bit result to | ||
403 | * be sign-extended to 64 bits when it's added to the | ||
404 | * %rip value and yield the same 64-bit result that the | ||
405 | * sign-extension of the original signed 32-bit | ||
406 | * displacement would have given. | ||
407 | */ | ||
408 | disp = (u8 *) p->addr + *((s32 *) insn) - | ||
409 | (u8 *) p->ainsn.insn; | ||
410 | BUG_ON((s64) (s32) disp != disp); /* Sanity check. */ | ||
411 | *(s32 *)insn = (s32) disp; | ||
412 | } | ||
413 | } | 331 | } |
414 | #endif | 332 | #endif |
415 | } | 333 | } |