diff options
Diffstat (limited to 'arch/x86/tools')
-rw-r--r-- | arch/x86/tools/Makefile | 15 | ||||
-rw-r--r-- | arch/x86/tools/distill.awk | 42 | ||||
-rw-r--r-- | arch/x86/tools/test_get_len.c | 113 |
3 files changed, 170 insertions, 0 deletions
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile new file mode 100644 index 000000000000..3dd626b99dc8 --- /dev/null +++ b/arch/x86/tools/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | PHONY += posttest | ||
2 | quiet_cmd_posttest = TEST $@ | ||
3 | cmd_posttest = $(OBJDUMP) -d $(objtree)/vmlinux | awk -f $(srctree)/arch/x86/tools/distill.awk | $(obj)/test_get_len | ||
4 | |||
5 | posttest: $(obj)/test_get_len vmlinux | ||
6 | $(call cmd,posttest) | ||
7 | |||
8 | hostprogs-y := test_get_len | ||
9 | |||
10 | # -I needed for generated C source and C source which in the kernel tree. | ||
11 | HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ | ||
12 | |||
13 | # Dependancies are also needed. | ||
14 | $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c | ||
15 | |||
diff --git a/arch/x86/tools/distill.awk b/arch/x86/tools/distill.awk new file mode 100644 index 000000000000..d433619bb866 --- /dev/null +++ b/arch/x86/tools/distill.awk | |||
@@ -0,0 +1,42 @@ | |||
1 | #!/bin/awk -f | ||
2 | # Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len | ||
3 | # Distills the disassembly as follows: | ||
4 | # - Removes all lines except the disassembled instructions. | ||
5 | # - For instructions that exceed 1 line (7 bytes), crams all the hex bytes | ||
6 | # into a single line. | ||
7 | # - Remove bad(or prefix only) instructions | ||
8 | |||
9 | BEGIN { | ||
10 | prev_addr = "" | ||
11 | prev_hex = "" | ||
12 | prev_mnemonic = "" | ||
13 | bad_expr = "(\\(bad\\)|^rex|^.byte|^rep(z|nz)$|^lock$|^es$|^cs$|^ss$|^ds$|^fs$|^gs$|^data(16|32)$|^addr(16|32|64))" | ||
14 | fwait_expr = "^9b " | ||
15 | fwait_str="9b\tfwait" | ||
16 | } | ||
17 | |||
18 | /^ *[0-9a-f]+:/ { | ||
19 | if (split($0, field, "\t") < 3) { | ||
20 | # This is a continuation of the same insn. | ||
21 | prev_hex = prev_hex field[2] | ||
22 | } else { | ||
23 | # Skip bad instructions | ||
24 | if (match(prev_mnemonic, bad_expr)) | ||
25 | prev_addr = "" | ||
26 | # Split fwait from other f* instructions | ||
27 | if (match(prev_hex, fwait_expr) && prev_mnemonic != "fwait") { | ||
28 | printf "%s\t%s\n", prev_addr, fwait_str | ||
29 | sub(fwait_expr, "", prev_hex) | ||
30 | } | ||
31 | if (prev_addr != "") | ||
32 | printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic | ||
33 | prev_addr = field[1] | ||
34 | prev_hex = field[2] | ||
35 | prev_mnemonic = field[3] | ||
36 | } | ||
37 | } | ||
38 | |||
39 | END { | ||
40 | if (prev_addr != "") | ||
41 | printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic | ||
42 | } | ||
diff --git a/arch/x86/tools/test_get_len.c b/arch/x86/tools/test_get_len.c new file mode 100644 index 000000000000..1e81adb2d8a9 --- /dev/null +++ b/arch/x86/tools/test_get_len.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | * | ||
16 | * Copyright (C) IBM Corporation, 2009 | ||
17 | */ | ||
18 | |||
19 | #include <stdlib.h> | ||
20 | #include <stdio.h> | ||
21 | #include <string.h> | ||
22 | #include <assert.h> | ||
23 | |||
24 | #ifdef __x86_64__ | ||
25 | #define CONFIG_X86_64 | ||
26 | #else | ||
27 | #define CONFIG_X86_32 | ||
28 | #endif | ||
29 | #define unlikely(cond) (cond) | ||
30 | |||
31 | #include <asm/insn.h> | ||
32 | #include <inat.c> | ||
33 | #include <insn.c> | ||
34 | |||
35 | /* | ||
36 | * Test of instruction analysis in general and insn_get_length() in | ||
37 | * particular. See if insn_get_length() and the disassembler agree | ||
38 | * on the length of each instruction in an elf disassembly. | ||
39 | * | ||
40 | * Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len | ||
41 | */ | ||
42 | |||
43 | const char *prog; | ||
44 | |||
45 | static void usage(void) | ||
46 | { | ||
47 | fprintf(stderr, "Usage: objdump -d a.out | awk -f distill.awk |" | ||
48 | " ./test_get_len\n"); | ||
49 | exit(1); | ||
50 | } | ||
51 | |||
52 | static void malformed_line(const char *line, int line_nr) | ||
53 | { | ||
54 | fprintf(stderr, "%s: malformed line %d:\n%s", prog, line_nr, line); | ||
55 | exit(3); | ||
56 | } | ||
57 | |||
58 | #define BUFSIZE 256 | ||
59 | |||
60 | int main(int argc, char **argv) | ||
61 | { | ||
62 | char line[BUFSIZE]; | ||
63 | unsigned char insn_buf[16]; | ||
64 | struct insn insn; | ||
65 | int insns = 0; | ||
66 | |||
67 | prog = argv[0]; | ||
68 | if (argc > 1) | ||
69 | usage(); | ||
70 | |||
71 | while (fgets(line, BUFSIZE, stdin)) { | ||
72 | char copy[BUFSIZE], *s, *tab1, *tab2; | ||
73 | int nb = 0; | ||
74 | unsigned int b; | ||
75 | |||
76 | insns++; | ||
77 | memset(insn_buf, 0, 16); | ||
78 | strcpy(copy, line); | ||
79 | tab1 = strchr(copy, '\t'); | ||
80 | if (!tab1) | ||
81 | malformed_line(line, insns); | ||
82 | s = tab1 + 1; | ||
83 | s += strspn(s, " "); | ||
84 | tab2 = strchr(s, '\t'); | ||
85 | if (!tab2) | ||
86 | malformed_line(line, insns); | ||
87 | *tab2 = '\0'; /* Characters beyond tab2 aren't examined */ | ||
88 | while (s < tab2) { | ||
89 | if (sscanf(s, "%x", &b) == 1) { | ||
90 | insn_buf[nb++] = (unsigned char) b; | ||
91 | s += 3; | ||
92 | } else | ||
93 | break; | ||
94 | } | ||
95 | /* Decode an instruction */ | ||
96 | #ifdef __x86_64__ | ||
97 | insn_init(&insn, insn_buf, 1); | ||
98 | #else | ||
99 | insn_init(&insn, insn_buf, 0); | ||
100 | #endif | ||
101 | insn_get_length(&insn); | ||
102 | if (insn.length != nb) { | ||
103 | fprintf(stderr, "Error: %s", line); | ||
104 | fprintf(stderr, "Error: objdump says %d bytes, but " | ||
105 | "insn_get_length() says %d (attr:%x)\n", nb, | ||
106 | insn.length, insn.attr); | ||
107 | exit(2); | ||
108 | } | ||
109 | } | ||
110 | fprintf(stderr, "Succeed: decoded and checked %d instructions\n", | ||
111 | insns); | ||
112 | return 0; | ||
113 | } | ||