aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/tools
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/tools')
-rw-r--r--arch/x86/tools/Makefile31
-rw-r--r--arch/x86/tools/chkobjdump.awk33
-rw-r--r--arch/x86/tools/distill.awk47
-rw-r--r--arch/x86/tools/gen-insn-attr-x86.awk378
-rw-r--r--arch/x86/tools/test_get_len.c173
5 files changed, 662 insertions, 0 deletions
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
new file mode 100644
index 000000000000..f82082677337
--- /dev/null
+++ b/arch/x86/tools/Makefile
@@ -0,0 +1,31 @@
1PHONY += posttest
2
3ifeq ($(KBUILD_VERBOSE),1)
4 posttest_verbose = -v
5else
6 posttest_verbose =
7endif
8
9ifeq ($(CONFIG_64BIT),y)
10 posttest_64bit = -y
11else
12 posttest_64bit = -n
13endif
14
15distill_awk = $(srctree)/arch/x86/tools/distill.awk
16chkobjdump = $(srctree)/arch/x86/tools/chkobjdump.awk
17
18quiet_cmd_posttest = TEST $@
19 cmd_posttest = ($(OBJDUMP) -v | $(AWK) -f $(chkobjdump)) || $(OBJDUMP) -d -j .text $(objtree)/vmlinux | $(AWK) -f $(distill_awk) | $(obj)/test_get_len $(posttest_64bit) $(posttest_verbose)
20
21posttest: $(obj)/test_get_len vmlinux
22 $(call cmd,posttest)
23
24hostprogs-y := test_get_len
25
26# -I needed for generated C source and C source which in the kernel tree.
27HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/
28
29# Dependencies are also needed.
30$(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
31
diff --git a/arch/x86/tools/chkobjdump.awk b/arch/x86/tools/chkobjdump.awk
new file mode 100644
index 000000000000..fd1ab80be0de
--- /dev/null
+++ b/arch/x86/tools/chkobjdump.awk
@@ -0,0 +1,33 @@
1# GNU objdump version checker
2#
3# Usage:
4# objdump -v | awk -f chkobjdump.awk
5BEGIN {
6 # objdump version 2.19 or later is OK for the test.
7 od_ver = 2;
8 od_sver = 19;
9}
10
11/^GNU objdump/ {
12 verstr = ""
13 for (i = 3; i <= NF; i++)
14 if (match($(i), "^[0-9]")) {
15 verstr = $(i);
16 break;
17 }
18 if (verstr == "") {
19 printf("Warning: Failed to find objdump version number.\n");
20 exit 0;
21 }
22 split(verstr, ver, ".");
23 if (ver[1] > od_ver ||
24 (ver[1] == od_ver && ver[2] >= od_sver)) {
25 exit 1;
26 } else {
27 printf("Warning: objdump version %s is older than %d.%d\n",
28 verstr, od_ver, od_sver);
29 print("Warning: Skipping posttest.");
30 # Logic is inverted, because we just skip test without error.
31 exit 0;
32 }
33}
diff --git a/arch/x86/tools/distill.awk b/arch/x86/tools/distill.awk
new file mode 100644
index 000000000000..c13c0ee48ab4
--- /dev/null
+++ b/arch/x86/tools/distill.awk
@@ -0,0 +1,47 @@
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
9BEGIN {
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 # Symbol entry
20 printf("%s%s\n", $2, $1)
21}
22
23/^ *[0-9a-f]+:/ {
24 if (split($0, field, "\t") < 3) {
25 # This is a continuation of the same insn.
26 prev_hex = prev_hex field[2]
27 } else {
28 # Skip bad instructions
29 if (match(prev_mnemonic, bad_expr))
30 prev_addr = ""
31 # Split fwait from other f* instructions
32 if (match(prev_hex, fwait_expr) && prev_mnemonic != "fwait") {
33 printf "%s\t%s\n", prev_addr, fwait_str
34 sub(fwait_expr, "", prev_hex)
35 }
36 if (prev_addr != "")
37 printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic
38 prev_addr = field[1]
39 prev_hex = field[2]
40 prev_mnemonic = field[3]
41 }
42}
43
44END {
45 if (prev_addr != "")
46 printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic
47}
diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk
new file mode 100644
index 000000000000..eaf11f52fc0b
--- /dev/null
+++ b/arch/x86/tools/gen-insn-attr-x86.awk
@@ -0,0 +1,378 @@
1#!/bin/awk -f
2# gen-insn-attr-x86.awk: Instruction attribute table generator
3# Written by Masami Hiramatsu <mhiramat@redhat.com>
4#
5# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
6
7# Awk implementation sanity check
8function check_awk_implement() {
9 if (sprintf("%x", 0) != "0")
10 return "Your awk has a printf-format problem."
11 return ""
12}
13
14# Clear working vars
15function clear_vars() {
16 delete table
17 delete lptable2
18 delete lptable1
19 delete lptable3
20 eid = -1 # escape id
21 gid = -1 # group id
22 aid = -1 # AVX id
23 tname = ""
24}
25
26BEGIN {
27 # Implementation error checking
28 awkchecked = check_awk_implement()
29 if (awkchecked != "") {
30 print "Error: " awkchecked > "/dev/stderr"
31 print "Please try to use gawk." > "/dev/stderr"
32 exit 1
33 }
34
35 # Setup generating tables
36 print "/* x86 opcode map generated from x86-opcode-map.txt */"
37 print "/* Do not change this code. */\n"
38 ggid = 1
39 geid = 1
40 gaid = 0
41 delete etable
42 delete gtable
43 delete atable
44
45 opnd_expr = "^[A-Za-z/]"
46 ext_expr = "^\\("
47 sep_expr = "^\\|$"
48 group_expr = "^Grp[0-9A-Za-z]+"
49
50 imm_expr = "^[IJAO][a-z]"
51 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
52 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
53 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
54 imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
55 imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
56 imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
57 imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
58 imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
59 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
60 imm_flag["Ob"] = "INAT_MOFFSET"
61 imm_flag["Ov"] = "INAT_MOFFSET"
62
63 modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
64 force64_expr = "\\([df]64\\)"
65 rex_expr = "^REX(\\.[XRWB]+)*"
66 fpu_expr = "^ESC" # TODO
67
68 lprefix1_expr = "\\(66\\)"
69 lprefix2_expr = "\\(F3\\)"
70 lprefix3_expr = "\\(F2\\)"
71 max_lprefix = 4
72
73 vexok_expr = "\\(VEX\\)"
74 vexonly_expr = "\\(oVEX\\)"
75
76 prefix_expr = "\\(Prefix\\)"
77 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
78 prefix_num["REPNE"] = "INAT_PFX_REPNE"
79 prefix_num["REP/REPE"] = "INAT_PFX_REPE"
80 prefix_num["LOCK"] = "INAT_PFX_LOCK"
81 prefix_num["SEG=CS"] = "INAT_PFX_CS"
82 prefix_num["SEG=DS"] = "INAT_PFX_DS"
83 prefix_num["SEG=ES"] = "INAT_PFX_ES"
84 prefix_num["SEG=FS"] = "INAT_PFX_FS"
85 prefix_num["SEG=GS"] = "INAT_PFX_GS"
86 prefix_num["SEG=SS"] = "INAT_PFX_SS"
87 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
88 prefix_num["2bytes-VEX"] = "INAT_PFX_VEX2"
89 prefix_num["3bytes-VEX"] = "INAT_PFX_VEX3"
90
91 clear_vars()
92}
93
94function semantic_error(msg) {
95 print "Semantic error at " NR ": " msg > "/dev/stderr"
96 exit 1
97}
98
99function debug(msg) {
100 print "DEBUG: " msg
101}
102
103function array_size(arr, i,c) {
104 c = 0
105 for (i in arr)
106 c++
107 return c
108}
109
110/^Table:/ {
111 print "/* " $0 " */"
112 if (tname != "")
113 semantic_error("Hit Table: before EndTable:.");
114}
115
116/^Referrer:/ {
117 if (NF != 1) {
118 # escape opcode table
119 ref = ""
120 for (i = 2; i <= NF; i++)
121 ref = ref $i
122 eid = escape[ref]
123 tname = sprintf("inat_escape_table_%d", eid)
124 }
125}
126
127/^AVXcode:/ {
128 if (NF != 1) {
129 # AVX/escape opcode table
130 aid = $2
131 if (gaid <= aid)
132 gaid = aid + 1
133 if (tname == "") # AVX only opcode table
134 tname = sprintf("inat_avx_table_%d", $2)
135 }
136 if (aid == -1 && eid == -1) # primary opcode table
137 tname = "inat_primary_table"
138}
139
140/^GrpTable:/ {
141 print "/* " $0 " */"
142 if (!($2 in group))
143 semantic_error("No group: " $2 )
144 gid = group[$2]
145 tname = "inat_group_table_" gid
146}
147
148function print_table(tbl,name,fmt,n)
149{
150 print "const insn_attr_t " name " = {"
151 for (i = 0; i < n; i++) {
152 id = sprintf(fmt, i)
153 if (tbl[id])
154 print " [" id "] = " tbl[id] ","
155 }
156 print "};"
157}
158
159/^EndTable/ {
160 if (gid != -1) {
161 # print group tables
162 if (array_size(table) != 0) {
163 print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
164 "0x%x", 8)
165 gtable[gid,0] = tname
166 }
167 if (array_size(lptable1) != 0) {
168 print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
169 "0x%x", 8)
170 gtable[gid,1] = tname "_1"
171 }
172 if (array_size(lptable2) != 0) {
173 print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
174 "0x%x", 8)
175 gtable[gid,2] = tname "_2"
176 }
177 if (array_size(lptable3) != 0) {
178 print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
179 "0x%x", 8)
180 gtable[gid,3] = tname "_3"
181 }
182 } else {
183 # print primary/escaped tables
184 if (array_size(table) != 0) {
185 print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
186 "0x%02x", 256)
187 etable[eid,0] = tname
188 if (aid >= 0)
189 atable[aid,0] = tname
190 }
191 if (array_size(lptable1) != 0) {
192 print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
193 "0x%02x", 256)
194 etable[eid,1] = tname "_1"
195 if (aid >= 0)
196 atable[aid,1] = tname "_1"
197 }
198 if (array_size(lptable2) != 0) {
199 print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
200 "0x%02x", 256)
201 etable[eid,2] = tname "_2"
202 if (aid >= 0)
203 atable[aid,2] = tname "_2"
204 }
205 if (array_size(lptable3) != 0) {
206 print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
207 "0x%02x", 256)
208 etable[eid,3] = tname "_3"
209 if (aid >= 0)
210 atable[aid,3] = tname "_3"
211 }
212 }
213 print ""
214 clear_vars()
215}
216
217function add_flags(old,new) {
218 if (old && new)
219 return old " | " new
220 else if (old)
221 return old
222 else
223 return new
224}
225
226# convert operands to flags.
227function convert_operands(count,opnd, i,j,imm,mod)
228{
229 imm = null
230 mod = null
231 for (j = 1; j <= count; j++) {
232 i = opnd[j]
233 if (match(i, imm_expr) == 1) {
234 if (!imm_flag[i])
235 semantic_error("Unknown imm opnd: " i)
236 if (imm) {
237 if (i != "Ib")
238 semantic_error("Second IMM error")
239 imm = add_flags(imm, "INAT_SCNDIMM")
240 } else
241 imm = imm_flag[i]
242 } else if (match(i, modrm_expr))
243 mod = "INAT_MODRM"
244 }
245 return add_flags(imm, mod)
246}
247
248/^[0-9a-f]+\:/ {
249 if (NR == 1)
250 next
251 # get index
252 idx = "0x" substr($1, 1, index($1,":") - 1)
253 if (idx in table)
254 semantic_error("Redefine " idx " in " tname)
255
256 # check if escaped opcode
257 if ("escape" == $2) {
258 if ($3 != "#")
259 semantic_error("No escaped name")
260 ref = ""
261 for (i = 4; i <= NF; i++)
262 ref = ref $i
263 if (ref in escape)
264 semantic_error("Redefine escape (" ref ")")
265 escape[ref] = geid
266 geid++
267 table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
268 next
269 }
270
271 variant = null
272 # converts
273 i = 2
274 while (i <= NF) {
275 opcode = $(i++)
276 delete opnds
277 ext = null
278 flags = null
279 opnd = null
280 # parse one opcode
281 if (match($i, opnd_expr)) {
282 opnd = $i
283 count = split($(i++), opnds, ",")
284 flags = convert_operands(count, opnds)
285 }
286 if (match($i, ext_expr))
287 ext = $(i++)
288 if (match($i, sep_expr))
289 i++
290 else if (i < NF)
291 semantic_error($i " is not a separator")
292
293 # check if group opcode
294 if (match(opcode, group_expr)) {
295 if (!(opcode in group)) {
296 group[opcode] = ggid
297 ggid++
298 }
299 flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
300 }
301 # check force(or default) 64bit
302 if (match(ext, force64_expr))
303 flags = add_flags(flags, "INAT_FORCE64")
304
305 # check REX prefix
306 if (match(opcode, rex_expr))
307 flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
308
309 # check coprocessor escape : TODO
310 if (match(opcode, fpu_expr))
311 flags = add_flags(flags, "INAT_MODRM")
312
313 # check VEX only code
314 if (match(ext, vexonly_expr))
315 flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
316
317 # check VEX only code
318 if (match(ext, vexok_expr))
319 flags = add_flags(flags, "INAT_VEXOK")
320
321 # check prefixes
322 if (match(ext, prefix_expr)) {
323 if (!prefix_num[opcode])
324 semantic_error("Unknown prefix: " opcode)
325 flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
326 }
327 if (length(flags) == 0)
328 continue
329 # check if last prefix
330 if (match(ext, lprefix1_expr)) {
331 lptable1[idx] = add_flags(lptable1[idx],flags)
332 variant = "INAT_VARIANT"
333 } else if (match(ext, lprefix2_expr)) {
334 lptable2[idx] = add_flags(lptable2[idx],flags)
335 variant = "INAT_VARIANT"
336 } else if (match(ext, lprefix3_expr)) {
337 lptable3[idx] = add_flags(lptable3[idx],flags)
338 variant = "INAT_VARIANT"
339 } else {
340 table[idx] = add_flags(table[idx],flags)
341 }
342 }
343 if (variant)
344 table[idx] = add_flags(table[idx],variant)
345}
346
347END {
348 if (awkchecked != "")
349 exit 1
350 # print escape opcode map's array
351 print "/* Escape opcode map array */"
352 print "const insn_attr_t const *inat_escape_tables[INAT_ESC_MAX + 1]" \
353 "[INAT_LSTPFX_MAX + 1] = {"
354 for (i = 0; i < geid; i++)
355 for (j = 0; j < max_lprefix; j++)
356 if (etable[i,j])
357 print " ["i"]["j"] = "etable[i,j]","
358 print "};\n"
359 # print group opcode map's array
360 print "/* Group opcode map array */"
361 print "const insn_attr_t const *inat_group_tables[INAT_GRP_MAX + 1]"\
362 "[INAT_LSTPFX_MAX + 1] = {"
363 for (i = 0; i < ggid; i++)
364 for (j = 0; j < max_lprefix; j++)
365 if (gtable[i,j])
366 print " ["i"]["j"] = "gtable[i,j]","
367 print "};\n"
368 # print AVX opcode map's array
369 print "/* AVX opcode map array */"
370 print "const insn_attr_t const *inat_avx_tables[X86_VEX_M_MAX + 1]"\
371 "[INAT_LSTPFX_MAX + 1] = {"
372 for (i = 0; i < gaid; i++)
373 for (j = 0; j < max_lprefix; j++)
374 if (atable[i,j])
375 print " ["i"]["j"] = "atable[i,j]","
376 print "};"
377}
378
diff --git a/arch/x86/tools/test_get_len.c b/arch/x86/tools/test_get_len.c
new file mode 100644
index 000000000000..bee8d6ac2691
--- /dev/null
+++ b/arch/x86/tools/test_get_len.c
@@ -0,0 +1,173 @@
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#include <unistd.h>
24
25#define unlikely(cond) (cond)
26
27#include <asm/insn.h>
28#include <inat.c>
29#include <insn.c>
30
31/*
32 * Test of instruction analysis in general and insn_get_length() in
33 * particular. See if insn_get_length() and the disassembler agree
34 * on the length of each instruction in an elf disassembly.
35 *
36 * Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len
37 */
38
39const char *prog;
40static int verbose;
41static int x86_64;
42
43static void usage(void)
44{
45 fprintf(stderr, "Usage: objdump -d a.out | awk -f distill.awk |"
46 " %s [-y|-n] [-v] \n", prog);
47 fprintf(stderr, "\t-y 64bit mode\n");
48 fprintf(stderr, "\t-n 32bit mode\n");
49 fprintf(stderr, "\t-v verbose mode\n");
50 exit(1);
51}
52
53static void malformed_line(const char *line, int line_nr)
54{
55 fprintf(stderr, "%s: malformed line %d:\n%s", prog, line_nr, line);
56 exit(3);
57}
58
59static void dump_field(FILE *fp, const char *name, const char *indent,
60 struct insn_field *field)
61{
62 fprintf(fp, "%s.%s = {\n", indent, name);
63 fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n",
64 indent, field->value, field->bytes[0], field->bytes[1],
65 field->bytes[2], field->bytes[3]);
66 fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent,
67 field->got, field->nbytes);
68}
69
70static void dump_insn(FILE *fp, struct insn *insn)
71{
72 fprintf(fp, "Instruction = { \n");
73 dump_field(fp, "prefixes", "\t", &insn->prefixes);
74 dump_field(fp, "rex_prefix", "\t", &insn->rex_prefix);
75 dump_field(fp, "vex_prefix", "\t", &insn->vex_prefix);
76 dump_field(fp, "opcode", "\t", &insn->opcode);
77 dump_field(fp, "modrm", "\t", &insn->modrm);
78 dump_field(fp, "sib", "\t", &insn->sib);
79 dump_field(fp, "displacement", "\t", &insn->displacement);
80 dump_field(fp, "immediate1", "\t", &insn->immediate1);
81 dump_field(fp, "immediate2", "\t", &insn->immediate2);
82 fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n",
83 insn->attr, insn->opnd_bytes, insn->addr_bytes);
84 fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n",
85 insn->length, insn->x86_64, insn->kaddr);
86}
87
88static void parse_args(int argc, char **argv)
89{
90 int c;
91 prog = argv[0];
92 while ((c = getopt(argc, argv, "ynv")) != -1) {
93 switch (c) {
94 case 'y':
95 x86_64 = 1;
96 break;
97 case 'n':
98 x86_64 = 0;
99 break;
100 case 'v':
101 verbose = 1;
102 break;
103 default:
104 usage();
105 }
106 }
107}
108
109#define BUFSIZE 256
110
111int main(int argc, char **argv)
112{
113 char line[BUFSIZE], sym[BUFSIZE] = "<unknown>";
114 unsigned char insn_buf[16];
115 struct insn insn;
116 int insns = 0;
117 int warnings = 0;
118
119 parse_args(argc, argv);
120
121 while (fgets(line, BUFSIZE, stdin)) {
122 char copy[BUFSIZE], *s, *tab1, *tab2;
123 int nb = 0;
124 unsigned int b;
125
126 if (line[0] == '<') {
127 /* Symbol line */
128 strcpy(sym, line);
129 continue;
130 }
131
132 insns++;
133 memset(insn_buf, 0, 16);
134 strcpy(copy, line);
135 tab1 = strchr(copy, '\t');
136 if (!tab1)
137 malformed_line(line, insns);
138 s = tab1 + 1;
139 s += strspn(s, " ");
140 tab2 = strchr(s, '\t');
141 if (!tab2)
142 malformed_line(line, insns);
143 *tab2 = '\0'; /* Characters beyond tab2 aren't examined */
144 while (s < tab2) {
145 if (sscanf(s, "%x", &b) == 1) {
146 insn_buf[nb++] = (unsigned char) b;
147 s += 3;
148 } else
149 break;
150 }
151 /* Decode an instruction */
152 insn_init(&insn, insn_buf, x86_64);
153 insn_get_length(&insn);
154 if (insn.length != nb) {
155 warnings++;
156 fprintf(stderr, "Warning: %s found difference at %s\n",
157 prog, sym);
158 fprintf(stderr, "Warning: %s", line);
159 fprintf(stderr, "Warning: objdump says %d bytes, but "
160 "insn_get_length() says %d\n", nb,
161 insn.length);
162 if (verbose)
163 dump_insn(stderr, &insn);
164 }
165 }
166 if (warnings)
167 fprintf(stderr, "Warning: decoded and checked %d"
168 " instructions with %d warnings\n", insns, warnings);
169 else
170 fprintf(stderr, "Succeed: decoded and checked %d"
171 " instructions\n", insns);
172 return 0;
173}