aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/kprobes.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2009-08-13 16:34:36 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-08-26 18:35:57 -0400
commit89ae465b0ee470f7d3f8a1c61353445c3acbbe2a (patch)
tree0a365df6212b47c80ae9456ff42a94dd5a81a1d7 /arch/x86/kernel/kprobes.c
parentb46b3d70c9c017d7c4ec49f7f3ffd0af5a622277 (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/x86/kernel/kprobes.c')
-rw-r--r--arch/x86/kernel/kprobes.c128
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};
111static 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};
133static 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
157struct kretprobe_blackpoint kretprobe_blacklist[] = { 113struct kretprobe_blackpoint kretprobe_blacklist[] = {
@@ -348,68 +304,30 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
348static void __kprobes fix_riprel(struct kprobe *p) 304static 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}