diff options
author | Ingo Molnar <mingo@elte.hu> | 2012-02-17 03:27:41 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2012-02-17 04:18:07 -0500 |
commit | 7b2d81d48a2d8e37efb6ce7b4d5ef58822b30d89 (patch) | |
tree | 23987f194dcd91b0ba6d27f7f6e08c178797488e /arch/x86/kernel/uprobes.c | |
parent | 2b144498350860b6ee9dc57ff27a93ad488de5dc (diff) |
uprobes/core: Clean up, refactor and improve the code
Make the uprobes code readable to me:
- improve the Kconfig text so that a mere mortal gets some idea
what CONFIG_UPROBES=y is really about
- do trivial renames to standardize around the uprobes_*() namespace
- clean up and simplify various code flow details
- separate basic blocks of functionality
- line break artifact and white space related removal
- use standard local varible definition blocks
- use vertical spacing to make things more readable
- remove unnecessary volatile
- restructure comment blocks to make them more uniform and
more readable in general
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Anton Arapov <anton@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Link: http://lkml.kernel.org/n/tip-ewbwhb8o6navvllsauu7k07p@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/uprobes.c')
-rw-r--r-- | arch/x86/kernel/uprobes.c | 129 |
1 files changed, 68 insertions, 61 deletions
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 2a301bb91bdb..cf2a18498425 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Userspace Probes (UProbes) for x86 | 2 | * User-space Probes (UProbes) for x86 |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -20,7 +20,6 @@ | |||
20 | * Srikar Dronamraju | 20 | * Srikar Dronamraju |
21 | * Jim Keniston | 21 | * Jim Keniston |
22 | */ | 22 | */ |
23 | |||
24 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
25 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
26 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
@@ -42,10 +41,10 @@ | |||
42 | #define UPROBES_FIX_RIP_CX 0x4000 | 41 | #define UPROBES_FIX_RIP_CX 0x4000 |
43 | 42 | ||
44 | /* Adaptations for mhiramat x86 decoder v14. */ | 43 | /* Adaptations for mhiramat x86 decoder v14. */ |
45 | #define OPCODE1(insn) ((insn)->opcode.bytes[0]) | 44 | #define OPCODE1(insn) ((insn)->opcode.bytes[0]) |
46 | #define OPCODE2(insn) ((insn)->opcode.bytes[1]) | 45 | #define OPCODE2(insn) ((insn)->opcode.bytes[1]) |
47 | #define OPCODE3(insn) ((insn)->opcode.bytes[2]) | 46 | #define OPCODE3(insn) ((insn)->opcode.bytes[2]) |
48 | #define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value) | 47 | #define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value) |
49 | 48 | ||
50 | #define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\ | 49 | #define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\ |
51 | (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \ | 50 | (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \ |
@@ -55,7 +54,7 @@ | |||
55 | << (row % 32)) | 54 | << (row % 32)) |
56 | 55 | ||
57 | #ifdef CONFIG_X86_64 | 56 | #ifdef CONFIG_X86_64 |
58 | static volatile u32 good_insns_64[256 / 32] = { | 57 | static u32 good_insns_64[256 / 32] = { |
59 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | 58 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
60 | /* ---------------------------------------------- */ | 59 | /* ---------------------------------------------- */ |
61 | W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */ | 60 | W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */ |
@@ -81,7 +80,7 @@ static volatile u32 good_insns_64[256 / 32] = { | |||
81 | 80 | ||
82 | /* Good-instruction tables for 32-bit apps */ | 81 | /* Good-instruction tables for 32-bit apps */ |
83 | 82 | ||
84 | static volatile u32 good_insns_32[256 / 32] = { | 83 | static u32 good_insns_32[256 / 32] = { |
85 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | 84 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
86 | /* ---------------------------------------------- */ | 85 | /* ---------------------------------------------- */ |
87 | W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 00 */ | 86 | W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 00 */ |
@@ -105,7 +104,7 @@ static volatile u32 good_insns_32[256 / 32] = { | |||
105 | }; | 104 | }; |
106 | 105 | ||
107 | /* Using this for both 64-bit and 32-bit apps */ | 106 | /* Using this for both 64-bit and 32-bit apps */ |
108 | static volatile u32 good_2byte_insns[256 / 32] = { | 107 | static u32 good_2byte_insns[256 / 32] = { |
109 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ | 108 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
110 | /* ---------------------------------------------- */ | 109 | /* ---------------------------------------------- */ |
111 | W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */ | 110 | W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */ |
@@ -132,42 +131,47 @@ static volatile u32 good_2byte_insns[256 / 32] = { | |||
132 | 131 | ||
133 | /* | 132 | /* |
134 | * opcodes we'll probably never support: | 133 | * opcodes we'll probably never support: |
135 | * 6c-6d, e4-e5, ec-ed - in | 134 | * |
136 | * 6e-6f, e6-e7, ee-ef - out | 135 | * 6c-6d, e4-e5, ec-ed - in |
137 | * cc, cd - int3, int | 136 | * 6e-6f, e6-e7, ee-ef - out |
138 | * cf - iret | 137 | * cc, cd - int3, int |
139 | * d6 - illegal instruction | 138 | * cf - iret |
140 | * f1 - int1/icebp | 139 | * d6 - illegal instruction |
141 | * f4 - hlt | 140 | * f1 - int1/icebp |
142 | * fa, fb - cli, sti | 141 | * f4 - hlt |
143 | * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2 | 142 | * fa, fb - cli, sti |
143 | * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2 | ||
144 | * | 144 | * |
145 | * invalid opcodes in 64-bit mode: | 145 | * invalid opcodes in 64-bit mode: |
146 | * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5 | ||
147 | * | 146 | * |
148 | * 63 - we support this opcode in x86_64 but not in i386. | 147 | * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5 |
148 | * 63 - we support this opcode in x86_64 but not in i386. | ||
149 | * | 149 | * |
150 | * opcodes we may need to refine support for: | 150 | * opcodes we may need to refine support for: |
151 | * 0f - 2-byte instructions: For many of these instructions, the validity | 151 | * |
152 | * depends on the prefix and/or the reg field. On such instructions, we | 152 | * 0f - 2-byte instructions: For many of these instructions, the validity |
153 | * just consider the opcode combination valid if it corresponds to any | 153 | * depends on the prefix and/or the reg field. On such instructions, we |
154 | * valid instruction. | 154 | * just consider the opcode combination valid if it corresponds to any |
155 | * 8f - Group 1 - only reg = 0 is OK | 155 | * valid instruction. |
156 | * c6-c7 - Group 11 - only reg = 0 is OK | 156 | * |
157 | * d9-df - fpu insns with some illegal encodings | 157 | * 8f - Group 1 - only reg = 0 is OK |
158 | * f2, f3 - repnz, repz prefixes. These are also the first byte for | 158 | * c6-c7 - Group 11 - only reg = 0 is OK |
159 | * certain floating-point instructions, such as addsd. | 159 | * d9-df - fpu insns with some illegal encodings |
160 | * fe - Group 4 - only reg = 0 or 1 is OK | 160 | * f2, f3 - repnz, repz prefixes. These are also the first byte for |
161 | * ff - Group 5 - only reg = 0-6 is OK | 161 | * certain floating-point instructions, such as addsd. |
162 | * | ||
163 | * fe - Group 4 - only reg = 0 or 1 is OK | ||
164 | * ff - Group 5 - only reg = 0-6 is OK | ||
162 | * | 165 | * |
163 | * others -- Do we need to support these? | 166 | * others -- Do we need to support these? |
164 | * 0f - (floating-point?) prefetch instructions | 167 | * |
165 | * 07, 17, 1f - pop es, pop ss, pop ds | 168 | * 0f - (floating-point?) prefetch instructions |
166 | * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- | 169 | * 07, 17, 1f - pop es, pop ss, pop ds |
170 | * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes -- | ||
167 | * but 64 and 65 (fs: and gs:) seem to be used, so we support them | 171 | * but 64 and 65 (fs: and gs:) seem to be used, so we support them |
168 | * 67 - addr16 prefix | 172 | * 67 - addr16 prefix |
169 | * ce - into | 173 | * ce - into |
170 | * f0 - lock prefix | 174 | * f0 - lock prefix |
171 | */ | 175 | */ |
172 | 176 | ||
173 | /* | 177 | /* |
@@ -182,11 +186,11 @@ static bool is_prefix_bad(struct insn *insn) | |||
182 | 186 | ||
183 | for (i = 0; i < insn->prefixes.nbytes; i++) { | 187 | for (i = 0; i < insn->prefixes.nbytes; i++) { |
184 | switch (insn->prefixes.bytes[i]) { | 188 | switch (insn->prefixes.bytes[i]) { |
185 | case 0x26: /*INAT_PFX_ES */ | 189 | case 0x26: /* INAT_PFX_ES */ |
186 | case 0x2E: /*INAT_PFX_CS */ | 190 | case 0x2E: /* INAT_PFX_CS */ |
187 | case 0x36: /*INAT_PFX_DS */ | 191 | case 0x36: /* INAT_PFX_DS */ |
188 | case 0x3E: /*INAT_PFX_SS */ | 192 | case 0x3E: /* INAT_PFX_SS */ |
189 | case 0xF0: /*INAT_PFX_LOCK */ | 193 | case 0xF0: /* INAT_PFX_LOCK */ |
190 | return true; | 194 | return true; |
191 | } | 195 | } |
192 | } | 196 | } |
@@ -201,12 +205,15 @@ static int validate_insn_32bits(struct uprobe *uprobe, struct insn *insn) | |||
201 | insn_get_opcode(insn); | 205 | insn_get_opcode(insn); |
202 | if (is_prefix_bad(insn)) | 206 | if (is_prefix_bad(insn)) |
203 | return -ENOTSUPP; | 207 | return -ENOTSUPP; |
208 | |||
204 | if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_32)) | 209 | if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_32)) |
205 | return 0; | 210 | return 0; |
211 | |||
206 | if (insn->opcode.nbytes == 2) { | 212 | if (insn->opcode.nbytes == 2) { |
207 | if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) | 213 | if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) |
208 | return 0; | 214 | return 0; |
209 | } | 215 | } |
216 | |||
210 | return -ENOTSUPP; | 217 | return -ENOTSUPP; |
211 | } | 218 | } |
212 | 219 | ||
@@ -282,12 +289,12 @@ static void prepare_fixups(struct uprobe *uprobe, struct insn *insn) | |||
282 | * disastrous. | 289 | * disastrous. |
283 | * | 290 | * |
284 | * Some useful facts about rip-relative instructions: | 291 | * Some useful facts about rip-relative instructions: |
285 | * - There's always a modrm byte. | 292 | * |
286 | * - There's never a SIB byte. | 293 | * - There's always a modrm byte. |
287 | * - The displacement is always 4 bytes. | 294 | * - There's never a SIB byte. |
295 | * - The displacement is always 4 bytes. | ||
288 | */ | 296 | */ |
289 | static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, | 297 | static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) |
290 | struct insn *insn) | ||
291 | { | 298 | { |
292 | u8 *cursor; | 299 | u8 *cursor; |
293 | u8 reg; | 300 | u8 reg; |
@@ -342,13 +349,12 @@ static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, | |||
342 | } | 349 | } |
343 | 350 | ||
344 | /* Target address = address of next instruction + (signed) offset */ | 351 | /* Target address = address of next instruction + (signed) offset */ |
345 | uprobe->arch_info.rip_rela_target_address = (long)insn->length | 352 | uprobe->arch_info.rip_rela_target_address = (long)insn->length + insn->displacement.value; |
346 | + insn->displacement.value; | 353 | |
347 | /* Displacement field is gone; slide immediate field (if any) over. */ | 354 | /* Displacement field is gone; slide immediate field (if any) over. */ |
348 | if (insn->immediate.nbytes) { | 355 | if (insn->immediate.nbytes) { |
349 | cursor++; | 356 | cursor++; |
350 | memmove(cursor, cursor + insn->displacement.nbytes, | 357 | memmove(cursor, cursor + insn->displacement.nbytes, insn->immediate.nbytes); |
351 | insn->immediate.nbytes); | ||
352 | } | 358 | } |
353 | return; | 359 | return; |
354 | } | 360 | } |
@@ -361,8 +367,10 @@ static int validate_insn_64bits(struct uprobe *uprobe, struct insn *insn) | |||
361 | insn_get_opcode(insn); | 367 | insn_get_opcode(insn); |
362 | if (is_prefix_bad(insn)) | 368 | if (is_prefix_bad(insn)) |
363 | return -ENOTSUPP; | 369 | return -ENOTSUPP; |
370 | |||
364 | if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_64)) | 371 | if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_64)) |
365 | return 0; | 372 | return 0; |
373 | |||
366 | if (insn->opcode.nbytes == 2) { | 374 | if (insn->opcode.nbytes == 2) { |
367 | if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) | 375 | if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns)) |
368 | return 0; | 376 | return 0; |
@@ -370,34 +378,31 @@ static int validate_insn_64bits(struct uprobe *uprobe, struct insn *insn) | |||
370 | return -ENOTSUPP; | 378 | return -ENOTSUPP; |
371 | } | 379 | } |
372 | 380 | ||
373 | static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, | 381 | static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) |
374 | struct insn *insn) | ||
375 | { | 382 | { |
376 | if (mm->context.ia32_compat) | 383 | if (mm->context.ia32_compat) |
377 | return validate_insn_32bits(uprobe, insn); | 384 | return validate_insn_32bits(uprobe, insn); |
378 | return validate_insn_64bits(uprobe, insn); | 385 | return validate_insn_64bits(uprobe, insn); |
379 | } | 386 | } |
380 | #else | 387 | #else /* 32-bit: */ |
381 | static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, | 388 | static void handle_riprel_insn(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) |
382 | struct insn *insn) | ||
383 | { | 389 | { |
384 | return; | 390 | /* No RIP-relative addressing on 32-bit */ |
385 | } | 391 | } |
386 | 392 | ||
387 | static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, | 393 | static int validate_insn_bits(struct mm_struct *mm, struct uprobe *uprobe, struct insn *insn) |
388 | struct insn *insn) | ||
389 | { | 394 | { |
390 | return validate_insn_32bits(uprobe, insn); | 395 | return validate_insn_32bits(uprobe, insn); |
391 | } | 396 | } |
392 | #endif /* CONFIG_X86_64 */ | 397 | #endif /* CONFIG_X86_64 */ |
393 | 398 | ||
394 | /** | 399 | /** |
395 | * analyze_insn - instruction analysis including validity and fixups. | 400 | * arch_uprobes_analyze_insn - instruction analysis including validity and fixups. |
396 | * @mm: the probed address space. | 401 | * @mm: the probed address space. |
397 | * @uprobe: the probepoint information. | 402 | * @uprobe: the probepoint information. |
398 | * Return 0 on success or a -ve number on error. | 403 | * Return 0 on success or a -ve number on error. |
399 | */ | 404 | */ |
400 | int analyze_insn(struct mm_struct *mm, struct uprobe *uprobe) | 405 | int arch_uprobes_analyze_insn(struct mm_struct *mm, struct uprobe *uprobe) |
401 | { | 406 | { |
402 | int ret; | 407 | int ret; |
403 | struct insn insn; | 408 | struct insn insn; |
@@ -406,7 +411,9 @@ int analyze_insn(struct mm_struct *mm, struct uprobe *uprobe) | |||
406 | ret = validate_insn_bits(mm, uprobe, &insn); | 411 | ret = validate_insn_bits(mm, uprobe, &insn); |
407 | if (ret != 0) | 412 | if (ret != 0) |
408 | return ret; | 413 | return ret; |
414 | |||
409 | handle_riprel_insn(mm, uprobe, &insn); | 415 | handle_riprel_insn(mm, uprobe, &insn); |
410 | prepare_fixups(uprobe, &insn); | 416 | prepare_fixups(uprobe, &insn); |
417 | |||
411 | return 0; | 418 | return 0; |
412 | } | 419 | } |