OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 #include <assert.h> | |
8 #include <elf.h> | |
9 #include <inttypes.h> | |
10 #include <stdio.h> | |
11 #include <stdlib.h> | |
12 #include <string.h> | |
13 #include "decoder.h" | |
14 | |
15 #undef TRUE | |
16 #define TRUE 1 | |
17 | |
18 #undef FALSE | |
19 #define FALSE 0 | |
20 | |
21 static void CheckBounds(unsigned char *data, size_t data_size, | |
22 void *ptr, size_t inside_size) { | |
23 assert(data <= (unsigned char *) ptr); | |
24 assert((unsigned char *) ptr + inside_size <= data + data_size); | |
25 } | |
26 | |
27 void ReadFile(const char *filename, uint8_t **result, size_t *result_size) { | |
28 FILE *fp; | |
29 uint8_t *data; | |
30 size_t file_size; | |
31 size_t got; | |
32 | |
33 fp = fopen(filename, "rb"); | |
34 if (fp == NULL) { | |
35 fprintf(stderr, "Failed to open input file: %s\n", filename); | |
36 exit(1); | |
37 } | |
38 /* Find the file size. */ | |
39 fseek(fp, 0, SEEK_END); | |
40 file_size = ftell(fp); | |
41 data = malloc(file_size); | |
42 if (data == NULL) { | |
43 fprintf(stderr, "Unable to create memory image of input file: %s\n", | |
44 filename); | |
45 exit(1); | |
46 } | |
47 fseek(fp, 0, SEEK_SET); | |
48 got = fread(data, 1, file_size, fp); | |
49 if (got != file_size) { | |
50 fprintf(stderr, "Unable to read data from input file: %s\n", | |
51 filename); | |
52 exit(1); | |
53 } | |
54 fclose(fp); | |
55 | |
56 *result = data; | |
57 *result_size = file_size; | |
58 } | |
59 | |
60 struct DecodeState { | |
61 uint8_t width; | |
62 const uint8_t *fwait; /* Set to true if fwait is detetected. */ | |
63 const uint8_t *offset; | |
64 int ia32_mode; | |
65 }; | |
66 | |
67 void ProcessInstruction(const uint8_t *begin, const uint8_t *end, | |
68 struct instruction *instruction, void *userdata) { | |
69 const char *instruction_name; | |
70 unsigned char operands_count; | |
71 const uint8_t *p; | |
72 char delimeter = ' '; | |
73 int print_rip = FALSE; | |
74 int rex_bits = 0; | |
75 int maybe_rex_bits = 0; | |
76 int show_name_suffix = FALSE; | |
77 #define print_name(x) (printf((x)), shown_name += strlen((x))) | |
78 int shown_name = 0; | |
79 int i, operand_type; | |
80 | |
81 /* "fwait" is nasty: any number of them will be included in other X87 | |
82 instructions ("fclex", "finit", "fstcw", "fstsw", "fsave" have two | |
83 names, other instructions are unchanged) - but if after them we see | |
84 regular instruction then we must print all them. This convoluted | |
85 logic is not needed when we don't print anything so decoder does | |
86 not include it. */ | |
87 if ((end == begin + 1) && (begin[0] == 0x9b)) { | |
88 if (!(((struct DecodeState *)userdata)->fwait)) { | |
89 ((struct DecodeState *)userdata)->fwait = begin; | |
90 } | |
91 return; | |
92 } else if (((struct DecodeState *)userdata)->fwait) { | |
93 if ((begin[0] < 0xd8) || (begin[0] > 0xdf)) { | |
94 while ((((struct DecodeState *)userdata)->fwait) < begin) { | |
95 printf("%*zx:\t \tfwait\n", | |
96 ((struct DecodeState *)userdata)->width, | |
97 ((((struct DecodeState *)userdata)->fwait++) - | |
98 (((struct DecodeState *)userdata)->offset))); | |
99 } | |
100 } else { | |
101 begin = ((struct DecodeState *)userdata)->fwait; | |
102 } | |
103 ((struct DecodeState *)userdata)->fwait = FALSE; | |
104 } | |
105 printf("%*zx:\t", ((struct DecodeState *)userdata)->width, | |
106 (begin - (((struct DecodeState *)userdata)->offset))); | |
107 for (p = begin; p < begin + 7; ++p) { | |
108 if (p >= end) { | |
109 printf(" "); | |
110 } else { | |
111 printf("%02x ", *p); | |
112 } | |
113 } | |
114 printf("\t"); | |
115 instruction_name = instruction->name; | |
116 operands_count = instruction->operands_count; | |
117 /* "cmppd" has two-operand mnemonic names for "imm8" equal to 0x0, ...0x7. */ | |
118 if (!strcmp(instruction_name, "cmppd")) { | |
119 if (instruction->imm[0] < 0x08) { | |
120 switch (instruction->imm[0]) { | |
121 case 0x00: instruction_name = "cmpeqpd"; break; | |
122 case 0x01: instruction_name = "cmpltpd"; break; | |
123 case 0x02: instruction_name = "cmplepd"; break; | |
124 case 0x03: instruction_name = "cmpunordpd"; break; | |
125 case 0x04: instruction_name = "cmpneqpd"; break; | |
126 case 0x05: instruction_name = "cmpnltpd"; break; | |
127 case 0x06: instruction_name = "cmpnlepd"; break; | |
128 case 0x07: instruction_name = "cmpordpd"; break; | |
129 } | |
130 --operands_count; | |
131 } | |
132 } | |
133 /* "vcmppd" has two-operand mnemonic names for "imm8" | |
134 * equal to 0x0, ... 0x1f. */ | |
135 if (!strcmp(instruction_name, "vcmppd")) { | |
136 if (instruction->imm[0] < 0x20) { | |
137 switch (instruction->imm[0]) { | |
138 case 0x00: instruction_name = "vcmpeqpd"; break; | |
139 case 0x01: instruction_name = "vcmpltpd"; break; | |
140 case 0x02: instruction_name = "vcmplepd"; break; | |
141 case 0x03: instruction_name = "vcmpunordpd"; break; | |
142 case 0x04: instruction_name = "vcmpneqpd"; break; | |
143 case 0x05: instruction_name = "vcmpnltpd"; break; | |
144 case 0x06: instruction_name = "vcmpnlepd"; break; | |
145 case 0x07: instruction_name = "vcmpordpd"; break; | |
146 case 0x08: instruction_name = "vcmpeq_uqpd"; break; | |
147 case 0x09: instruction_name = "vcmpngepd"; break; | |
148 case 0x0a: instruction_name = "vcmpngtpd"; break; | |
149 case 0x0b: instruction_name = "vcmpfalsepd"; break; | |
150 case 0x0c: instruction_name = "vcmpneq_oqpd"; break; | |
151 case 0x0d: instruction_name = "vcmpgepd"; break; | |
152 case 0x0e: instruction_name = "vcmpgtpd"; break; | |
153 case 0x0f: instruction_name = "vcmptruepd"; break; | |
154 case 0x10: instruction_name = "vcmpeq_ospd"; break; | |
155 case 0x11: instruction_name = "vcmplt_oqpd"; break; | |
156 case 0x12: instruction_name = "vcmple_oqpd"; break; | |
157 case 0x13: instruction_name = "vcmpunord_spd"; break; | |
158 case 0x14: instruction_name = "vcmpneq_uspd"; break; | |
159 case 0x15: instruction_name = "vcmpnlt_uqpd"; break; | |
160 case 0x16: instruction_name = "vcmpnle_uqpd"; break; | |
161 case 0x17: instruction_name = "vcmpord_spd"; break; | |
162 case 0x18: instruction_name = "vcmpeq_uspd"; break; | |
163 case 0x19: instruction_name = "vcmpnge_uqpd"; break; | |
164 case 0x1a: instruction_name = "vcmpngt_uqpd"; break; | |
165 case 0x1b: instruction_name = "vcmpfalse_ospd"; break; | |
166 case 0x1c: instruction_name = "vcmpneq_ospd"; break; | |
167 case 0x1d: instruction_name = "vcmpge_oqpd"; break; | |
168 case 0x1e: instruction_name = "vcmpgt_oqpd"; break; | |
169 case 0x1f: instruction_name = "vcmptrue_uspd"; break; | |
170 } | |
171 --operands_count; | |
172 } | |
173 } | |
174 /* "cmpps" has two-operand mnemonic names for "imm8" equal to 0x0, ... 0x7. */ | |
175 if (!strcmp(instruction_name, "cmpps")) { | |
176 if (instruction->imm[0] < 0x08) { | |
177 switch (instruction->imm[0]) { | |
178 case 0x00: instruction_name = "cmpeqps"; break; | |
179 case 0x01: instruction_name = "cmpltps"; break; | |
180 case 0x02: instruction_name = "cmpleps"; break; | |
181 case 0x03: instruction_name = "cmpunordps"; break; | |
182 case 0x04: instruction_name = "cmpneqps"; break; | |
183 case 0x05: instruction_name = "cmpnltps"; break; | |
184 case 0x06: instruction_name = "cmpnleps"; break; | |
185 case 0x07: instruction_name = "cmpordps"; break; | |
186 } | |
187 --operands_count; | |
188 } | |
189 } | |
190 /* "vcmpps" has two-operand mnemonic names for "imm8" equal to 0x0, ...0x1f. *
/ | |
191 if (!strcmp(instruction_name, "vcmpps")) { | |
192 if (instruction->imm[0] < 0x20) { | |
193 switch (instruction->imm[0]) { | |
194 case 0x00: instruction_name = "vcmpeqps"; break; | |
195 case 0x01: instruction_name = "vcmpltps"; break; | |
196 case 0x02: instruction_name = "vcmpleps"; break; | |
197 case 0x03: instruction_name = "vcmpunordps"; break; | |
198 case 0x04: instruction_name = "vcmpneqps"; break; | |
199 case 0x05: instruction_name = "vcmpnltps"; break; | |
200 case 0x06: instruction_name = "vcmpnleps"; break; | |
201 case 0x07: instruction_name = "vcmpordps"; break; | |
202 case 0x08: instruction_name = "vcmpeq_uqps"; break; | |
203 case 0x09: instruction_name = "vcmpngeps"; break; | |
204 case 0x0a: instruction_name = "vcmpngtps"; break; | |
205 case 0x0b: instruction_name = "vcmpfalseps"; break; | |
206 case 0x0c: instruction_name = "vcmpneq_oqps"; break; | |
207 case 0x0d: instruction_name = "vcmpgeps"; break; | |
208 case 0x0e: instruction_name = "vcmpgtps"; break; | |
209 case 0x0f: instruction_name = "vcmptrueps"; break; | |
210 case 0x10: instruction_name = "vcmpeq_osps"; break; | |
211 case 0x11: instruction_name = "vcmplt_oqps"; break; | |
212 case 0x12: instruction_name = "vcmple_oqps"; break; | |
213 case 0x13: instruction_name = "vcmpunord_sps"; break; | |
214 case 0x14: instruction_name = "vcmpneq_usps"; break; | |
215 case 0x15: instruction_name = "vcmpnlt_uqps"; break; | |
216 case 0x16: instruction_name = "vcmpnle_uqps"; break; | |
217 case 0x17: instruction_name = "vcmpord_sps"; break; | |
218 case 0x18: instruction_name = "vcmpeq_usps"; break; | |
219 case 0x19: instruction_name = "vcmpnge_uqps"; break; | |
220 case 0x1a: instruction_name = "vcmpngt_uqps"; break; | |
221 case 0x1b: instruction_name = "vcmpfalse_osps"; break; | |
222 case 0x1c: instruction_name = "vcmpneq_osps"; break; | |
223 case 0x1d: instruction_name = "vcmpge_oqps"; break; | |
224 case 0x1e: instruction_name = "vcmpgt_oqps"; break; | |
225 case 0x1f: instruction_name = "vcmptrue_usps"; break; | |
226 } | |
227 --operands_count; | |
228 } | |
229 } | |
230 /* "cmpsd" has two-operand mnemonic names for "imm8" equal to 0x0, ...0x7. */ | |
231 if (!strcmp(instruction_name, "cmpsd")) { | |
232 if (instruction->imm[0] < 0x08) { | |
233 switch (instruction->imm[0]) { | |
234 case 0x00: instruction_name = "cmpeqsd"; break; | |
235 case 0x01: instruction_name = "cmpltsd"; break; | |
236 case 0x02: instruction_name = "cmplesd"; break; | |
237 case 0x03: instruction_name = "cmpunordsd"; break; | |
238 case 0x04: instruction_name = "cmpneqsd"; break; | |
239 case 0x05: instruction_name = "cmpnltsd"; break; | |
240 case 0x06: instruction_name = "cmpnlesd"; break; | |
241 case 0x07: instruction_name = "cmpordsd"; break; | |
242 } | |
243 --operands_count; | |
244 } | |
245 } | |
246 /* "vcmpsd" has two-operand mnemonic names for "imm8" equal to 0x0, ...0x1f. *
/ | |
247 if (!strcmp(instruction_name, "vcmpsd")) { | |
248 if (instruction->imm[0] < 0x20) { | |
249 switch (instruction->imm[0]) { | |
250 case 0x00: instruction_name = "vcmpeqsd"; break; | |
251 case 0x01: instruction_name = "vcmpltsd"; break; | |
252 case 0x02: instruction_name = "vcmplesd"; break; | |
253 case 0x03: instruction_name = "vcmpunordsd"; break; | |
254 case 0x04: instruction_name = "vcmpneqsd"; break; | |
255 case 0x05: instruction_name = "vcmpnltsd"; break; | |
256 case 0x06: instruction_name = "vcmpnlesd"; break; | |
257 case 0x07: instruction_name = "vcmpordsd"; break; | |
258 case 0x08: instruction_name = "vcmpeq_uqsd"; break; | |
259 case 0x09: instruction_name = "vcmpngesd"; break; | |
260 case 0x0a: instruction_name = "vcmpngtsd"; break; | |
261 case 0x0b: instruction_name = "vcmpfalsesd"; break; | |
262 case 0x0c: instruction_name = "vcmpneq_oqsd"; break; | |
263 case 0x0d: instruction_name = "vcmpgesd"; break; | |
264 case 0x0e: instruction_name = "vcmpgtsd"; break; | |
265 case 0x0f: instruction_name = "vcmptruesd"; break; | |
266 case 0x10: instruction_name = "vcmpeq_ossd"; break; | |
267 case 0x11: instruction_name = "vcmplt_oqsd"; break; | |
268 case 0x12: instruction_name = "vcmple_oqsd"; break; | |
269 case 0x13: instruction_name = "vcmpunord_ssd"; break; | |
270 case 0x14: instruction_name = "vcmpneq_ussd"; break; | |
271 case 0x15: instruction_name = "vcmpnlt_uqsd"; break; | |
272 case 0x16: instruction_name = "vcmpnle_uqsd"; break; | |
273 case 0x17: instruction_name = "vcmpord_ssd"; break; | |
274 case 0x18: instruction_name = "vcmpeq_ussd"; break; | |
275 case 0x19: instruction_name = "vcmpnge_uqsd"; break; | |
276 case 0x1a: instruction_name = "vcmpngt_uqsd"; break; | |
277 case 0x1b: instruction_name = "vcmpfalse_ossd"; break; | |
278 case 0x1c: instruction_name = "vcmpneq_ossd"; break; | |
279 case 0x1d: instruction_name = "vcmpge_oqsd"; break; | |
280 case 0x1e: instruction_name = "vcmpgt_oqsd"; break; | |
281 case 0x1f: instruction_name = "vcmptrue_ussd"; break; | |
282 } | |
283 --operands_count; | |
284 } | |
285 } | |
286 /* "cmpss" has two-operand mnemonic names for "imm8" equal to 0x0, ... 0x7. */ | |
287 if (!strcmp(instruction_name, "cmpss")) { | |
288 if (instruction->imm[0] < 0x08) { | |
289 switch (instruction->imm[0]) { | |
290 case 0x00: instruction_name = "cmpeqss"; break; | |
291 case 0x01: instruction_name = "cmpltss"; break; | |
292 case 0x02: instruction_name = "cmpless"; break; | |
293 case 0x03: instruction_name = "cmpunordss"; break; | |
294 case 0x04: instruction_name = "cmpneqss"; break; | |
295 case 0x05: instruction_name = "cmpnltss"; break; | |
296 case 0x06: instruction_name = "cmpnless"; break; | |
297 case 0x07: instruction_name = "cmpordss"; break; | |
298 } | |
299 --operands_count; | |
300 } | |
301 } | |
302 /* "vcmpss" has two-operand mnemonic names for "imm8" equal to 0x0, ...0x1f. *
/ | |
303 if (!strcmp(instruction_name, "vcmpss")) { | |
304 if (instruction->imm[0] < 0x20) { | |
305 switch (instruction->imm[0]) { | |
306 case 0x00: instruction_name = "vcmpeqss"; break; | |
307 case 0x01: instruction_name = "vcmpltss"; break; | |
308 case 0x02: instruction_name = "vcmpless"; break; | |
309 case 0x03: instruction_name = "vcmpunordss"; break; | |
310 case 0x04: instruction_name = "vcmpneqss"; break; | |
311 case 0x05: instruction_name = "vcmpnltss"; break; | |
312 case 0x06: instruction_name = "vcmpnless"; break; | |
313 case 0x07: instruction_name = "vcmpordss"; break; | |
314 case 0x08: instruction_name = "vcmpeq_uqss"; break; | |
315 case 0x09: instruction_name = "vcmpngess"; break; | |
316 case 0x0a: instruction_name = "vcmpngtss"; break; | |
317 case 0x0b: instruction_name = "vcmpfalsess"; break; | |
318 case 0x0c: instruction_name = "vcmpneq_oqss"; break; | |
319 case 0x0d: instruction_name = "vcmpgess"; break; | |
320 case 0x0e: instruction_name = "vcmpgtss"; break; | |
321 case 0x0f: instruction_name = "vcmptruess"; break; | |
322 case 0x10: instruction_name = "vcmpeq_osss"; break; | |
323 case 0x11: instruction_name = "vcmplt_oqss"; break; | |
324 case 0x12: instruction_name = "vcmple_oqss"; break; | |
325 case 0x13: instruction_name = "vcmpunord_sss"; break; | |
326 case 0x14: instruction_name = "vcmpneq_usss"; break; | |
327 case 0x15: instruction_name = "vcmpnlt_uqss"; break; | |
328 case 0x16: instruction_name = "vcmpnle_uqss"; break; | |
329 case 0x17: instruction_name = "vcmpord_sss"; break; | |
330 case 0x18: instruction_name = "vcmpeq_usss"; break; | |
331 case 0x19: instruction_name = "vcmpnge_uqss"; break; | |
332 case 0x1a: instruction_name = "vcmpngt_uqss"; break; | |
333 case 0x1b: instruction_name = "vcmpfalse_osss"; break; | |
334 case 0x1c: instruction_name = "vcmpneq_osss"; break; | |
335 case 0x1d: instruction_name = "vcmpge_oqss"; break; | |
336 case 0x1e: instruction_name = "vcmpgt_oqss"; break; | |
337 case 0x1f: instruction_name = "vcmptrue_usss"; break; | |
338 } | |
339 --operands_count; | |
340 } | |
341 } | |
342 /* "pclmulqdq" has two-operand mnemonic names for "imm8" | |
343 * equal to 0x0, ... 0x3. */ | |
344 if (!strcmp(instruction_name, "pclmulqdq")) { | |
345 if (instruction->imm[0] < 0x04) { | |
346 switch (instruction->imm[0]) { | |
347 case 0x00: instruction_name = "pclmullqlqdq"; break; | |
348 case 0x01: instruction_name = "pclmulhqlqdq"; break; | |
349 case 0x02: instruction_name = "pclmullqhqdq"; break; | |
350 case 0x03: instruction_name = "pclmulhqhqdq"; break; | |
351 } | |
352 --operands_count; | |
353 } | |
354 } | |
355 /* "vpclmulqdq" has two-operand mnemonic names for "imm8" | |
356 * equal to 0x0, ... 0x3. */ | |
357 if (!strcmp(instruction_name, "vpclmulqdq")) { | |
358 if (instruction->imm[0] < 0x04) { | |
359 switch (instruction->imm[0]) { | |
360 case 0x00: instruction_name = "vpclmullqlqdq"; break; | |
361 case 0x01: instruction_name = "vpclmulhqlqdq"; break; | |
362 case 0x02: instruction_name = "vpclmullqhqdq"; break; | |
363 case 0x03: instruction_name = "vpclmulhqhqdq"; break; | |
364 } | |
365 --operands_count; | |
366 } | |
367 } | |
368 if (operands_count > 0) { | |
369 show_name_suffix = TRUE; | |
370 for (i=operands_count-1; i>=0; --i) { | |
371 if (instruction->operands[i].name == JMP_TO) { | |
372 /* Most control flow instructions never use suffixes, but "call" and | |
373 "jmp" do... unless byte offset is used. */ | |
374 if ((!strcmp(instruction_name, "call")) || | |
375 (!strcmp(instruction_name, "jmp"))) { | |
376 switch (instruction->operands[i].type) { | |
377 case OperandSize8bit: show_name_suffix = FALSE; break; | |
378 case OperandSize16bit: show_name_suffix = 'w'; break; | |
379 case OperandSize32bit: | |
380 if (((struct DecodeState *)userdata)->ia32_mode) { | |
381 show_name_suffix = FALSE; | |
382 } else { | |
383 show_name_suffix = 'q'; | |
384 } | |
385 break; | |
386 case OperandSize2bit: | |
387 case OperandSize64bit: | |
388 case OperandSize128bit: | |
389 case OperandSize256bit: | |
390 case OperandFloatSize16bit: | |
391 case OperandFloatSize32bit: | |
392 case OperandFloatSize64bit: | |
393 case OperandFloatSize80bit: | |
394 case OperandX87Size16bit: | |
395 case OperandX87Size32bit: | |
396 case OperandX87Size64bit: | |
397 case OperandX87BCD: | |
398 case OperandX87ENV: | |
399 case OperandX87STATE: | |
400 case OperandX87MMXXMMSTATE: | |
401 case OperandST: | |
402 case OperandSelector: | |
403 case OperandFarPtr: | |
404 case OperandSegmentRegister: | |
405 case OperandControlRegister: | |
406 case OperandDebugRegister: | |
407 case OperandMMX: | |
408 case OperandXMM: | |
409 case OperandYMM: | |
410 assert(FALSE); | |
411 } | |
412 } else { | |
413 show_name_suffix = FALSE; | |
414 } | |
415 } else if ((instruction->operands[i].name == REG_IMM) || | |
416 (instruction->operands[i].name == REG_IMM2) || | |
417 (instruction->operands[i].name == REG_RM) || | |
418 (instruction->operands[i].name == REG_PORT_DX) || | |
419 (instruction->operands[i].name == REG_ES_RDI) || | |
420 (instruction->operands[i].name == REG_DS_RSI)) { | |
421 if (show_name_suffix) { | |
422 switch (instruction->operands[i].type) { | |
423 case OperandSize8bit: show_name_suffix = 'b'; break; | |
424 case OperandSize16bit: show_name_suffix = 'w'; break; | |
425 case OperandSize32bit: show_name_suffix = 'l'; break; | |
426 case OperandSize64bit: show_name_suffix = 'q'; break; | |
427 case OperandFloatSize32bit: show_name_suffix = 's'; break; | |
428 case OperandFloatSize64bit: show_name_suffix = 'l'; break; | |
429 case OperandFloatSize80bit:show_name_suffix = 't'; break; | |
430 case OperandX87Size32bit: show_name_suffix = 'l'; break; | |
431 case OperandX87Size64bit: show_name_suffix = 'L'; break; | |
432 case OperandSize2bit: | |
433 case OperandX87Size16bit: | |
434 case OperandX87BCD: | |
435 case OperandX87ENV: | |
436 case OperandX87STATE: | |
437 case OperandX87MMXXMMSTATE: | |
438 case OperandSize128bit: | |
439 case OperandSize256bit: | |
440 case OperandFarPtr: | |
441 case OperandMMX: | |
442 case OperandXMM: | |
443 case OperandYMM: | |
444 case OperandSelector: show_name_suffix = FALSE; break; | |
445 case OperandFloatSize16bit: | |
446 case OperandST: | |
447 case OperandSegmentRegister: | |
448 case OperandControlRegister: | |
449 case OperandDebugRegister: | |
450 assert(FALSE); | |
451 } | |
452 } | |
453 } else { | |
454 /* First argument of "rcl"/"rcr"/"rol"/"ror"/"sar/""shl"/"shr" | |
455 can not be used to determine size of command. */ | |
456 if (((i != 1) || (strcmp(instruction_name, "rcl") && | |
457 strcmp(instruction_name, "rcr") && | |
458 strcmp(instruction_name, "rol") && | |
459 strcmp(instruction_name, "ror") && | |
460 strcmp(instruction_name, "sal") && | |
461 strcmp(instruction_name, "sar") && | |
462 strcmp(instruction_name, "shl") && | |
463 strcmp(instruction_name, "shr"))) && | |
464 /* Second argument of "crc32" can not be used to determine size of | |
465 command. */ | |
466 ((i != 0) || strcmp(instruction_name, "crc32"))) { | |
467 show_name_suffix = FALSE; | |
468 } | |
469 /* First argument of "crc32" can be used for that but objdump uses | |
470 suffix anyway. */ | |
471 if ((i == 1) && (!strcmp(instruction_name, "crc32"))) { | |
472 switch (instruction->operands[i].type) { | |
473 case OperandSize8bit: show_name_suffix = 'b'; break; | |
474 case OperandSize16bit: show_name_suffix = 'w'; break; | |
475 case OperandSize32bit: show_name_suffix = 'l'; break; | |
476 case OperandSize64bit: show_name_suffix = 'q'; break; | |
477 case OperandSize2bit: | |
478 case OperandSize128bit: | |
479 case OperandSize256bit: | |
480 case OperandFloatSize16bit: | |
481 case OperandFloatSize32bit: | |
482 case OperandFloatSize64bit: | |
483 case OperandFloatSize80bit: | |
484 case OperandX87Size16bit: | |
485 case OperandX87Size32bit: | |
486 case OperandX87Size64bit: | |
487 case OperandX87BCD: | |
488 case OperandX87ENV: | |
489 case OperandX87STATE: | |
490 case OperandX87MMXXMMSTATE: | |
491 case OperandST: | |
492 case OperandSelector: | |
493 case OperandFarPtr: | |
494 case OperandSegmentRegister: | |
495 case OperandControlRegister: | |
496 case OperandDebugRegister: | |
497 case OperandMMX: | |
498 case OperandXMM: | |
499 case OperandYMM: | |
500 assert(FALSE); | |
501 } | |
502 } | |
503 } | |
504 if ((instruction->operands[i].name >= REG_R8) && | |
505 (instruction->operands[i].name <= REG_R15) && | |
506 (instruction->operands[i].type != OperandMMX)) { | |
507 if (!((struct DecodeState *)userdata)->ia32_mode) { | |
508 ++rex_bits; | |
509 /* HACK: objdump mistakenly allows "lock" with "mov %crX,%rXX" only in | |
510 32bit mode. It's perfectly valid in 64bit mode, too, so instead of | |
511 changing the decoder we fix it here. */ | |
512 if (instruction->operands[i].type == OperandControlRegister) { | |
513 if ((*begin == 0xf0) && !(instruction->prefix.lock)) { | |
514 print_name("lock "); | |
515 if (!(instruction->prefix.rex & 0x04)) { | |
516 instruction->operands[i].name -= 8; | |
517 --rex_bits; | |
518 } | |
519 } | |
520 } | |
521 } | |
522 } else if (instruction->operands[i].name == REG_RM) { | |
523 if ((instruction->rm.base >= REG_R8) && | |
524 (instruction->rm.base <= REG_R15)) { | |
525 ++rex_bits; | |
526 } else if ((instruction->rm.base == REG_NONE) || | |
527 (instruction->rm.base == REG_RIP)) { | |
528 ++maybe_rex_bits; | |
529 } | |
530 if ((instruction->rm.index >= REG_R8) && | |
531 (instruction->rm.index <= REG_R15)) { | |
532 ++rex_bits; | |
533 } | |
534 } | |
535 } | |
536 } | |
537 if ((!strcmp(instruction_name, "cvtsi2sd") || | |
538 !strcmp(instruction_name, "cvtsi2ss")) && | |
539 instruction->operands[1].name == REG_RM) { | |
540 if (instruction->operands[1].type == OperandSize32bit) { | |
541 show_name_suffix = 'l'; | |
542 } else { | |
543 show_name_suffix = 'q'; | |
544 } | |
545 } | |
546 if ((!strcmp(instruction_name, "vcvtpd2dq") || | |
547 !strcmp(instruction_name, "vcvtpd2ps") || | |
548 !strcmp(instruction_name, "vcvttpd2dq") || | |
549 !strcmp(instruction_name, "vcvttpd2ps")) && | |
550 instruction->operands[1].name == REG_RM) { | |
551 if (instruction->operands[1].type == OperandXMM) { | |
552 show_name_suffix = 'x'; | |
553 } else { | |
554 show_name_suffix = 'y'; | |
555 } | |
556 } | |
557 if ((!strcmp(instruction_name, "vcvtsi2sd") || | |
558 !strcmp(instruction_name, "vcvtsi2ss")) && | |
559 instruction->operands[2].name == REG_RM) { | |
560 if (instruction->operands[2].type == OperandSize32bit) { | |
561 show_name_suffix = 'l'; | |
562 } else { | |
563 show_name_suffix = 'q'; | |
564 } | |
565 } | |
566 if (instruction->prefix.lock) { | |
567 print_name("lock "); | |
568 } | |
569 if (instruction->prefix.repnz) { | |
570 print_name("repnz "); | |
571 } | |
572 if (instruction->prefix.repz) { | |
573 /* This prefix is "rep" for "ins", "movs", and "outs", "repz" otherwise. */ | |
574 if ((!strcmp(instruction_name, "ins")) || | |
575 (!strcmp(instruction_name, "movs")) || | |
576 (!strcmp(instruction_name, "outs")) || | |
577 (!strcmp(instruction_name, "stos"))) { | |
578 print_name("rep "); | |
579 } else { | |
580 print_name("repz "); | |
581 } | |
582 } | |
583 if (instruction->prefix.rex == 0x40) { | |
584 /* First argument of "crc32"/"rcl"/"rcr"/"rol"/"ror"/"sar"/"shl"/"shr" | |
585 confuses objdump: it does not show it in this case. */ | |
586 if ((show_name_suffix || | |
587 !strcmp(instruction_name, "movsbl") || | |
588 !strcmp(instruction_name, "movsbw") || | |
589 !strcmp(instruction_name, "movzbl") || | |
590 !strcmp(instruction_name, "movzbw") || | |
591 !strcmp(instruction_name, "pextrb") || | |
592 !strcmp(instruction_name, "pinsrb")) && | |
593 ((strcmp(instruction_name, "crc32") && | |
594 strcmp(instruction_name, "movsbl") && | |
595 strcmp(instruction_name, "movsbw") && | |
596 strcmp(instruction_name, "movzbl") && | |
597 strcmp(instruction_name, "movzbw") && | |
598 strcmp(instruction_name, "rcl") && | |
599 strcmp(instruction_name, "rcr") && | |
600 strcmp(instruction_name, "rol") && | |
601 strcmp(instruction_name, "ror") && | |
602 strcmp(instruction_name, "sal") && | |
603 strcmp(instruction_name, "sar") && | |
604 strcmp(instruction_name, "shl") && | |
605 strcmp(instruction_name, "shr")) || | |
606 (instruction->operands[1].name > REG_R15))) { | |
607 print_name("rex "); | |
608 } | |
609 } | |
610 if ((instruction->prefix.rex & 0x08) == 0x08) { | |
611 /* rex.W is ignored by "in"/"out", and "pop"/"push" commands. */ | |
612 if ((!strcmp(instruction_name, "in")) || | |
613 (!strcmp(instruction_name, "ins")) || | |
614 (!strcmp(instruction_name, "out")) || | |
615 (!strcmp(instruction_name, "outs")) || | |
616 (!strcmp(instruction_name, "pop")) || | |
617 (!strcmp(instruction_name, "push"))) { | |
618 rex_bits = -1; | |
619 } | |
620 } | |
621 if (show_name_suffix == 'b') { | |
622 /* "cflush", "int", "invlpg", "prefetch*", and "setcc" never use suffix. */ | |
623 if ((!strcmp(instruction_name, "clflush")) || | |
624 (!strcmp(instruction_name, "int")) || | |
625 (!strcmp(instruction_name, "invlpg")) || | |
626 (!strcmp(instruction_name, "prefetch")) || | |
627 (!strcmp(instruction_name, "prefetchnta")) || | |
628 (!strcmp(instruction_name, "prefetcht0")) || | |
629 (!strcmp(instruction_name, "prefetcht1")) || | |
630 (!strcmp(instruction_name, "prefetcht2")) || | |
631 (!strcmp(instruction_name, "prefetchw")) || | |
632 (!strcmp(instruction_name, "seta")) || | |
633 (!strcmp(instruction_name, "setae")) || | |
634 (!strcmp(instruction_name, "setbe")) || | |
635 (!strcmp(instruction_name, "setb")) || | |
636 (!strcmp(instruction_name, "sete")) || | |
637 (!strcmp(instruction_name, "setg")) || | |
638 (!strcmp(instruction_name, "setge")) || | |
639 (!strcmp(instruction_name, "setle")) || | |
640 (!strcmp(instruction_name, "setl")) || | |
641 (!strcmp(instruction_name, "setne")) || | |
642 (!strcmp(instruction_name, "setno")) || | |
643 (!strcmp(instruction_name, "setnp")) || | |
644 (!strcmp(instruction_name, "setns")) || | |
645 (!strcmp(instruction_name, "seto")) || | |
646 (!strcmp(instruction_name, "setp")) || | |
647 (!strcmp(instruction_name, "sets"))) { | |
648 show_name_suffix = FALSE; | |
649 /* Instruction enter accepts two immediates: word and byte. But | |
650 objdump always uses suffix "q". This is supremely strange, but | |
651 we want to match objdump exactly, so... here goes. */ | |
652 } else if (!strcmp(instruction_name, "enter")) { | |
653 if (((struct DecodeState *)userdata)->ia32_mode) { | |
654 show_name_suffix = FALSE; | |
655 } else { | |
656 show_name_suffix = 'q'; | |
657 } | |
658 } | |
659 } | |
660 if ((show_name_suffix == 'b') || (show_name_suffix == 'l')) { | |
661 /* objdump always shows "6a 01" as "pushq $1", "66 68 01 00" as | |
662 "pushw $1" yet "68 01 00 00 00" as "pushq $1" again. This makes no | |
663 sense whatsoever so we'll just hack around here to make sure we | |
664 produce objdump-compatible output. */ | |
665 if (!strcmp(instruction_name, "push")) { | |
666 if (((struct DecodeState *)userdata)->ia32_mode) { | |
667 if (instruction->operands[0].name != REG_RM) { | |
668 show_name_suffix = FALSE; | |
669 } | |
670 } else { | |
671 show_name_suffix = 'q'; | |
672 } | |
673 } | |
674 } | |
675 if (show_name_suffix == 'w') { | |
676 /* "lldt", "[ls]msw", "lret", "ltr", and "ver[rw]" newer use suffixes at | |
677 all. */ | |
678 if ((!strcmp(instruction_name, "lldt")) || | |
679 (!strcmp(instruction_name, "lmsw")) || | |
680 (!strcmp(instruction_name, "lret")) || | |
681 (!strcmp(instruction_name, "ltr")) || | |
682 (!strcmp(instruction_name, "smsw")) || | |
683 (!strcmp(instruction_name, "verr")) || | |
684 (!strcmp(instruction_name, "verw"))) { | |
685 show_name_suffix = FALSE; | |
686 /* "callw"/"jmpw" already includes suffix in the nanme. */ | |
687 } else if ((!strcmp(instruction_name, "callw")) || | |
688 (!strcmp(instruction_name, "jmpw"))) { | |
689 show_name_suffix = FALSE; | |
690 /* "ret" always uses suffix "q" no matter what. */ | |
691 } else if (!strcmp(instruction_name, "ret")) { | |
692 if (((struct DecodeState *)userdata)->ia32_mode) { | |
693 show_name_suffix = FALSE; | |
694 } else { | |
695 show_name_suffix = 'q'; | |
696 } | |
697 } | |
698 } | |
699 if ((show_name_suffix == 'w') || (show_name_suffix == 'l')) { | |
700 /* "sldt" and "str" newer uses suffixes at all. */ | |
701 if ((!strcmp(instruction_name, "sldt")) || | |
702 (!strcmp(instruction_name, "str"))) { | |
703 show_name_suffix = FALSE; | |
704 } | |
705 } | |
706 if (show_name_suffix == 'l') { | |
707 /* “calll”/“jmpl” do not exist, only “call” do. */ | |
708 if (((struct DecodeState *)userdata)->ia32_mode && | |
709 (!strcmp(instruction_name, "call") || | |
710 !strcmp(instruction_name, "jmp"))) { | |
711 show_name_suffix = FALSE; | |
712 /* “popl” does not exist, only “popq” do. */ | |
713 } else if (!((struct DecodeState *)userdata)->ia32_mode && | |
714 !strcmp(instruction_name, "pop")) { | |
715 show_name_suffix = 'q'; | |
716 } else if (!strcmp(instruction_name, "ldmxcsr") || | |
717 !strcmp(instruction_name, "stmxcsr") || | |
718 !strcmp(instruction_name, "vldmxcsr") || | |
719 !strcmp(instruction_name, "vstmxcsr")) { | |
720 show_name_suffix = FALSE; | |
721 } | |
722 } | |
723 if (show_name_suffix == 'q') { | |
724 /* "callq","cmpxchg8b"/"jmpq" already include suffix in the nanme. */ | |
725 if ((!strcmp(instruction_name, "callq")) || | |
726 (!strcmp(instruction_name, "cmpxchg8b")) || | |
727 (!strcmp(instruction_name, "jmpq"))) { | |
728 show_name_suffix = FALSE; | |
729 } | |
730 } | |
731 i = (instruction->prefix.rex & 0x01) + | |
732 ((instruction->prefix.rex & 0x02) >> 1) + | |
733 ((instruction->prefix.rex & 0x04) >> 2); | |
734 if (instruction->prefix.rex && | |
735 !((i == rex_bits) || | |
736 (maybe_rex_bits && | |
737 (instruction->prefix.rex & 0x01) && (i == rex_bits + 1)))) { | |
738 print_name("rex."); | |
739 if (instruction->prefix.rex & 0x08) { | |
740 print_name("W"); | |
741 } | |
742 if (instruction->prefix.rex & 0x04) { | |
743 print_name("R"); | |
744 } | |
745 if (instruction->prefix.rex & 0x02) { | |
746 print_name("X"); | |
747 } | |
748 if (instruction->prefix.rex & 0x01) { | |
749 print_name("B"); | |
750 } | |
751 print_name(" "); | |
752 } | |
753 printf("%s", instruction_name); | |
754 shown_name += strlen(instruction_name); | |
755 if (show_name_suffix) { | |
756 if (show_name_suffix == 'L') { | |
757 print_name("ll"); | |
758 } else { | |
759 printf("%c", show_name_suffix); | |
760 ++shown_name; | |
761 } | |
762 } | |
763 if (!strcmp(instruction_name, "mov")) { | |
764 if ((instruction->operands[1].name == REG_IMM) && | |
765 (instruction->operands[1].type == OperandSize64bit)) { | |
766 print_name("abs"); | |
767 } | |
768 } | |
769 #undef print_name | |
770 if ((strcmp(instruction_name, "nop") || operands_count != 0) && | |
771 strcmp(instruction_name, "fwait") && | |
772 strcmp(instruction_name, "pop %fs") && | |
773 strcmp(instruction_name, "pop %gs") && | |
774 strcmp(instruction_name, "popq %fs") && | |
775 strcmp(instruction_name, "popq %gs") && | |
776 strcmp(instruction_name, "push %fs") && | |
777 strcmp(instruction_name, "push %gs") && | |
778 strcmp(instruction_name, "pushq %fs") && | |
779 strcmp(instruction_name, "pushq %gs")) { | |
780 while (shown_name < 6) { | |
781 printf(" "); | |
782 ++shown_name; | |
783 } | |
784 if (operands_count == 0) { | |
785 printf(" "); | |
786 } | |
787 } | |
788 for (i=operands_count-1; i>=0; --i) { | |
789 printf("%c", delimeter); | |
790 if ((!strcmp(instruction_name, "call")) || | |
791 (!strcmp(instruction_name, "jmp")) || | |
792 (!strcmp(instruction_name, "lcall")) || | |
793 (!strcmp(instruction_name, "ljmp"))) { | |
794 if (instruction->operands[i].name != JMP_TO) { | |
795 printf("*"); | |
796 } | |
797 } else if ((!strcmp(instruction_name, "callw")) || | |
798 (!strcmp(instruction_name, "callq")) || | |
799 (!strcmp(instruction_name, "jmpw")) || | |
800 (!strcmp(instruction_name, "jmpq")) || | |
801 (!strcmp(instruction_name, "ljmpw")) || | |
802 (!strcmp(instruction_name, "ljmpq")) || | |
803 (!strcmp(instruction_name, "lcallw")) || | |
804 (!strcmp(instruction_name, "lcallq"))) { | |
805 printf("*"); | |
806 } | |
807 /* Dirty hack: both AMD manual and Intel manual agree that mov from general | |
808 purpose register to segment register has signature "mov Ew Sw", but | |
809 objdump insist on 32bit. This is clearly error in objdump so we fix it | |
810 here and not in decoder. */ | |
811 if (((begin[0] == 0x8e) || | |
812 ((begin[0] >= 0x40) && (begin[0] <= 0x4f) && (begin[1] == 0x8e))) && | |
813 (instruction->operands[i].type == OperandSize16bit)) { | |
814 operand_type = OperandSize32bit; | |
815 } else { | |
816 operand_type = instruction->operands[i].type; | |
817 } | |
818 switch (instruction->operands[i].name) { | |
819 case REG_RAX: switch (operand_type) { | |
820 case OperandSize8bit: printf("%%al"); break; | |
821 case OperandSize16bit: printf("%%ax"); break; | |
822 case OperandSize32bit: printf("%%eax"); break; | |
823 case OperandSize64bit: printf("%%rax"); break; | |
824 case OperandST: printf("%%st(0)"); break; | |
825 case OperandMMX: printf("%%mm0"); break; | |
826 case OperandFloatSize32bit: | |
827 case OperandFloatSize64bit: | |
828 case OperandSize128bit: | |
829 case OperandXMM: printf("%%xmm0"); break; | |
830 case OperandSize256bit: | |
831 case OperandYMM: printf("%%ymm0"); break; | |
832 case OperandSegmentRegister: printf("%%es"); break; | |
833 case OperandControlRegister: printf("%%cr0"); break; | |
834 case OperandDebugRegister: printf("%%db0"); break; | |
835 default: assert(FALSE); | |
836 } | |
837 break; | |
838 case REG_RCX: switch (operand_type) { | |
839 case OperandSize8bit: printf("%%cl"); break; | |
840 case OperandSize16bit: printf("%%cx"); break; | |
841 case OperandSize32bit: printf("%%ecx"); break; | |
842 case OperandSize64bit: printf("%%rcx"); break; | |
843 case OperandST: printf("%%st(1)"); break; | |
844 case OperandMMX: printf("%%mm1"); break; | |
845 case OperandFloatSize32bit: | |
846 case OperandFloatSize64bit: | |
847 case OperandSize128bit: | |
848 case OperandXMM: printf("%%xmm1"); break; | |
849 case OperandSize256bit: | |
850 case OperandYMM: printf("%%ymm1"); break; | |
851 case OperandSegmentRegister: printf("%%cs"); break; | |
852 case OperandControlRegister: printf("%%cr1"); break; | |
853 case OperandDebugRegister: printf("%%db1"); break; | |
854 default: assert(FALSE); | |
855 } | |
856 break; | |
857 case REG_RDX: switch (operand_type) { | |
858 case OperandSize8bit: printf("%%dl"); break; | |
859 case OperandSize16bit: printf("%%dx"); break; | |
860 case OperandSize32bit: printf("%%edx"); break; | |
861 case OperandSize64bit: printf("%%rdx"); break; | |
862 case OperandST: printf("%%st(2)"); break; | |
863 case OperandMMX: printf("%%mm2"); break; | |
864 case OperandFloatSize32bit: | |
865 case OperandFloatSize64bit: | |
866 case OperandSize128bit: | |
867 case OperandXMM: printf("%%xmm2"); break; | |
868 case OperandSize256bit: | |
869 case OperandYMM: printf("%%ymm2"); break; | |
870 case OperandSegmentRegister: printf("%%ss"); break; | |
871 case OperandControlRegister: printf("%%cr2"); break; | |
872 case OperandDebugRegister: printf("%%db2"); break; | |
873 default: assert(FALSE); | |
874 } | |
875 break; | |
876 case REG_RBX: switch (operand_type) { | |
877 case OperandSize8bit: printf("%%bl"); break; | |
878 case OperandSize16bit: printf("%%bx"); break; | |
879 case OperandSize32bit: printf("%%ebx"); break; | |
880 case OperandSize64bit: printf("%%rbx"); break; | |
881 case OperandST: printf("%%st(3)"); break; | |
882 case OperandMMX: printf("%%mm3"); break; | |
883 case OperandFloatSize32bit: | |
884 case OperandFloatSize64bit: | |
885 case OperandSize128bit: | |
886 case OperandXMM: printf("%%xmm3"); break; | |
887 case OperandSize256bit: | |
888 case OperandYMM: printf("%%ymm3"); break; | |
889 case OperandSegmentRegister: printf("%%ds"); break; | |
890 case OperandControlRegister: printf("%%cr3"); break; | |
891 case OperandDebugRegister: printf("%%db3"); break; | |
892 default: assert(FALSE); | |
893 } | |
894 break; | |
895 case REG_RSP: switch (operand_type) { | |
896 case OperandSize8bit: if (instruction->prefix.rex) | |
897 printf("%%spl"); | |
898 else | |
899 printf("%%ah"); | |
900 break; | |
901 case OperandSize16bit: printf("%%sp"); break; | |
902 case OperandSize32bit: printf("%%esp"); break; | |
903 case OperandSize64bit: printf("%%rsp"); break; | |
904 case OperandST: printf("%%st(4)"); break; | |
905 case OperandMMX: printf("%%mm4"); break; | |
906 case OperandFloatSize32bit: | |
907 case OperandFloatSize64bit: | |
908 case OperandSize128bit: | |
909 case OperandXMM: printf("%%xmm4"); break; | |
910 case OperandSize256bit: | |
911 case OperandYMM: printf("%%ymm4"); break; | |
912 case OperandSegmentRegister: printf("%%fs"); break; | |
913 case OperandControlRegister: printf("%%cr4"); break; | |
914 case OperandDebugRegister: printf("%%db4"); break; | |
915 default: assert(FALSE); | |
916 } | |
917 break; | |
918 case REG_RBP: switch (operand_type) { | |
919 case OperandSize8bit: if (instruction->prefix.rex) | |
920 printf("%%bpl"); | |
921 else | |
922 printf("%%ch"); | |
923 break; | |
924 case OperandSize16bit: printf("%%bp"); break; | |
925 case OperandSize32bit: printf("%%ebp"); break; | |
926 case OperandSize64bit: printf("%%rbp"); break; | |
927 case OperandST: printf("%%st(5)"); break; | |
928 case OperandMMX: printf("%%mm5"); break; | |
929 case OperandFloatSize32bit: | |
930 case OperandFloatSize64bit: | |
931 case OperandSize128bit: | |
932 case OperandXMM: printf("%%xmm5"); break; | |
933 case OperandSize256bit: | |
934 case OperandYMM: printf("%%ymm5"); break; | |
935 case OperandSegmentRegister: printf("%%gs"); break; | |
936 case OperandControlRegister: printf("%%cr5"); break; | |
937 case OperandDebugRegister: printf("%%db5"); break; | |
938 default: assert(FALSE); | |
939 } | |
940 break; | |
941 case REG_RSI: switch (operand_type) { | |
942 case OperandSize8bit: if (instruction->prefix.rex) | |
943 printf("%%sil"); | |
944 else | |
945 printf("%%dh"); | |
946 break; | |
947 case OperandSize16bit: printf("%%si"); break; | |
948 case OperandSize32bit: printf("%%esi"); break; | |
949 case OperandSize64bit: printf("%%rsi"); break; | |
950 case OperandST: printf("%%st(6)"); break; | |
951 case OperandMMX: printf("%%mm6"); break; | |
952 case OperandFloatSize32bit: | |
953 case OperandFloatSize64bit: | |
954 case OperandSize128bit: | |
955 case OperandXMM: printf("%%xmm6"); break; | |
956 case OperandSize256bit: | |
957 case OperandYMM: printf("%%ymm6"); break; | |
958 case OperandControlRegister: printf("%%cr6"); break; | |
959 case OperandDebugRegister: printf("%%db6"); break; | |
960 default: assert(FALSE); | |
961 } | |
962 break; | |
963 case REG_RDI: switch (operand_type) { | |
964 case OperandSize8bit: if (instruction->prefix.rex) | |
965 printf("%%dil"); | |
966 else | |
967 printf("%%bh"); | |
968 break; | |
969 case OperandSize16bit: printf("%%di"); break; | |
970 case OperandSize32bit: printf("%%edi"); break; | |
971 case OperandSize64bit: printf("%%rdi"); break; | |
972 case OperandST: printf("%%st(7)"); break; | |
973 case OperandMMX: printf("%%mm7"); break; | |
974 case OperandFloatSize32bit: | |
975 case OperandFloatSize64bit: | |
976 case OperandSize128bit: | |
977 case OperandXMM: printf("%%xmm7"); break; | |
978 case OperandSize256bit: | |
979 case OperandYMM: printf("%%ymm7"); break; | |
980 case OperandControlRegister: printf("%%cr7"); break; | |
981 case OperandDebugRegister: printf("%%db7"); break; | |
982 default: assert(FALSE); | |
983 } | |
984 break; | |
985 case REG_R8: switch (operand_type) { | |
986 case OperandSize8bit: printf("%%r8b"); break; | |
987 case OperandSize16bit: printf("%%r8w"); break; | |
988 case OperandSize32bit: printf("%%r8d"); break; | |
989 case OperandSize64bit: printf("%%r8"); break; | |
990 case OperandMMX: printf("%%mm0"); break; | |
991 case OperandFloatSize32bit: | |
992 case OperandFloatSize64bit: | |
993 case OperandSize128bit: | |
994 case OperandXMM: printf("%%xmm8"); break; | |
995 case OperandSize256bit: | |
996 case OperandYMM: printf("%%ymm8"); break; | |
997 case OperandControlRegister: printf("%%cr8"); break; | |
998 default: assert(FALSE); | |
999 } | |
1000 break; | |
1001 case REG_R9: switch (operand_type) { | |
1002 case OperandSize8bit: printf("%%r9b"); break; | |
1003 case OperandSize16bit: printf("%%r9w"); break; | |
1004 case OperandSize32bit: printf("%%r9d"); break; | |
1005 case OperandSize64bit: printf("%%r9"); break; | |
1006 case OperandMMX: printf("%%mm1"); break; | |
1007 case OperandFloatSize32bit: | |
1008 case OperandFloatSize64bit: | |
1009 case OperandSize128bit: | |
1010 case OperandXMM: printf("%%xmm9"); break; | |
1011 case OperandSize256bit: | |
1012 case OperandYMM: printf("%%ymm9"); break; | |
1013 case OperandControlRegister: printf("%%cr9"); break; | |
1014 default: assert(FALSE); | |
1015 } | |
1016 break; | |
1017 case REG_R10: switch (operand_type) { | |
1018 case OperandSize8bit: printf("%%r10b"); break; | |
1019 case OperandSize16bit: printf("%%r10w"); break; | |
1020 case OperandSize32bit: printf("%%r10d"); break; | |
1021 case OperandSize64bit: printf("%%r10"); break; | |
1022 case OperandMMX: printf("%%mm2"); break; | |
1023 case OperandFloatSize32bit: | |
1024 case OperandFloatSize64bit: | |
1025 case OperandSize128bit: | |
1026 case OperandXMM: printf("%%xmm10"); break; | |
1027 case OperandSize256bit: | |
1028 case OperandYMM: printf("%%ymm10"); break; | |
1029 case OperandControlRegister: printf("%%cr10"); break; | |
1030 default: assert(FALSE); | |
1031 } | |
1032 break; | |
1033 case REG_R11: switch (operand_type) { | |
1034 case OperandSize8bit: printf("%%r11b"); break; | |
1035 case OperandSize16bit: printf("%%r11w"); break; | |
1036 case OperandSize32bit: printf("%%r11d"); break; | |
1037 case OperandSize64bit: printf("%%r11"); break; | |
1038 case OperandMMX: printf("%%mm3"); break; | |
1039 case OperandFloatSize32bit: | |
1040 case OperandFloatSize64bit: | |
1041 case OperandSize128bit: | |
1042 case OperandXMM: printf("%%xmm11"); break; | |
1043 case OperandSize256bit: | |
1044 case OperandYMM: printf("%%ymm11"); break; | |
1045 case OperandControlRegister: printf("%%cr11"); break; | |
1046 default: assert(FALSE); | |
1047 } | |
1048 break; | |
1049 case REG_R12: switch (operand_type) { | |
1050 case OperandSize8bit: printf("%%r12b"); break; | |
1051 case OperandSize16bit: printf("%%r12w"); break; | |
1052 case OperandSize32bit: printf("%%r12d"); break; | |
1053 case OperandSize64bit: printf("%%r12"); break; | |
1054 case OperandMMX: printf("%%mm4"); break; | |
1055 case OperandFloatSize32bit: | |
1056 case OperandFloatSize64bit: | |
1057 case OperandSize128bit: | |
1058 case OperandXMM: printf("%%xmm12"); break; | |
1059 case OperandSize256bit: | |
1060 case OperandYMM: printf("%%ymm12"); break; | |
1061 case OperandControlRegister: printf("%%cr12"); break; | |
1062 default: assert(FALSE); | |
1063 } | |
1064 break; | |
1065 case REG_R13: switch (operand_type) { | |
1066 case OperandSize8bit: printf("%%r13b"); break; | |
1067 case OperandSize16bit: printf("%%r13w"); break; | |
1068 case OperandSize32bit: printf("%%r13d"); break; | |
1069 case OperandSize64bit: printf("%%r13"); break; | |
1070 case OperandMMX: printf("%%mm5"); break; | |
1071 case OperandFloatSize32bit: | |
1072 case OperandFloatSize64bit: | |
1073 case OperandSize128bit: | |
1074 case OperandXMM: printf("%%xmm13"); break; | |
1075 case OperandSize256bit: | |
1076 case OperandYMM: printf("%%ymm13"); break; | |
1077 case OperandControlRegister: printf("%%cr13"); break; | |
1078 default: assert(FALSE); | |
1079 } | |
1080 break; | |
1081 case REG_R14: switch (operand_type) { | |
1082 case OperandSize8bit: printf("%%r14b"); break; | |
1083 case OperandSize16bit: printf("%%r14w"); break; | |
1084 case OperandSize32bit: printf("%%r14d"); break; | |
1085 case OperandSize64bit: printf("%%r14"); break; | |
1086 case OperandMMX: printf("%%mm6"); break; | |
1087 case OperandFloatSize32bit: | |
1088 case OperandFloatSize64bit: | |
1089 case OperandSize128bit: | |
1090 case OperandXMM: printf("%%xmm14"); break; | |
1091 case OperandSize256bit: | |
1092 case OperandYMM: printf("%%ymm14"); break; | |
1093 case OperandControlRegister: printf("%%cr14"); break; | |
1094 default: assert(FALSE); | |
1095 } | |
1096 break; | |
1097 case REG_R15: switch (operand_type) { | |
1098 case OperandSize8bit: printf("%%r15b"); break; | |
1099 case OperandSize16bit: printf("%%r15w"); break; | |
1100 case OperandSize32bit: printf("%%r15d"); break; | |
1101 case OperandSize64bit: printf("%%r15"); break; | |
1102 case OperandMMX: printf("%%mm7"); break; | |
1103 case OperandFloatSize32bit: | |
1104 case OperandFloatSize64bit: | |
1105 case OperandSize128bit: | |
1106 case OperandXMM: printf("%%xmm15"); break; | |
1107 case OperandSize256bit: | |
1108 case OperandYMM: printf("%%ymm15"); break; | |
1109 case OperandControlRegister: printf("%%cr15"); break; | |
1110 default: assert(FALSE); | |
1111 } | |
1112 break; | |
1113 case REG_ST: | |
1114 assert(operand_type == OperandST); | |
1115 printf("%%st"); | |
1116 break; | |
1117 case REG_RM: { | |
1118 if (instruction->rm.offset) { | |
1119 printf("0x%"PRIx64, instruction->rm.offset); | |
1120 } | |
1121 if (((struct DecodeState *)userdata)->ia32_mode) { | |
1122 if ((instruction->rm.base != REG_NONE) || | |
1123 (instruction->rm.index != REG_NONE) || | |
1124 (instruction->rm.scale != 0)) { | |
1125 printf("("); | |
1126 } | |
1127 switch (instruction->rm.base) { | |
1128 case REG_RAX: printf("%%eax"); break; | |
1129 case REG_RCX: printf("%%ecx"); break; | |
1130 case REG_RDX: printf("%%edx"); break; | |
1131 case REG_RBX: printf("%%ebx"); break; | |
1132 case REG_RSP: printf("%%esp"); break; | |
1133 case REG_RBP: printf("%%ebp"); break; | |
1134 case REG_RSI: printf("%%esi"); break; | |
1135 case REG_RDI: printf("%%edi"); break; | |
1136 case REG_NONE: break; | |
1137 case REG_R8: | |
1138 case REG_R9: | |
1139 case REG_R10: | |
1140 case REG_R11: | |
1141 case REG_R12: | |
1142 case REG_R13: | |
1143 case REG_R14: | |
1144 case REG_R15: | |
1145 case REG_RIP: | |
1146 case REG_RM: | |
1147 case REG_RIZ: | |
1148 case REG_IMM: | |
1149 case REG_IMM2: | |
1150 case REG_DS_RBX: | |
1151 case REG_ES_RDI: | |
1152 case REG_DS_RSI: | |
1153 case REG_PORT_DX: | |
1154 case REG_ST: | |
1155 case JMP_TO: | |
1156 assert(FALSE); | |
1157 } | |
1158 switch (instruction->rm.index) { | |
1159 case REG_RAX: printf(",%%eax,%d",1<<instruction->rm.scale); break; | |
1160 case REG_RCX: printf(",%%ecx,%d",1<<instruction->rm.scale); break; | |
1161 case REG_RDX: printf(",%%edx,%d",1<<instruction->rm.scale); break; | |
1162 case REG_RBX: printf(",%%ebx,%d",1<<instruction->rm.scale); break; | |
1163 case REG_RSP: printf(",%%esp,%d",1<<instruction->rm.scale); break; | |
1164 case REG_RBP: printf(",%%ebp,%d",1<<instruction->rm.scale); break; | |
1165 case REG_RSI: printf(",%%esi,%d",1<<instruction->rm.scale); break; | |
1166 case REG_RDI: printf(",%%edi,%d",1<<instruction->rm.scale); break; | |
1167 case REG_RIZ: if ((instruction->rm.base != REG_RSP) || | |
1168 (instruction->rm.scale != 0)) | |
1169 printf(",%%eiz,%d",1<<instruction->rm.scale); | |
1170 break; | |
1171 case REG_NONE: break; | |
1172 case REG_R8: | |
1173 case REG_R9: | |
1174 case REG_R10: | |
1175 case REG_R11: | |
1176 case REG_R12: | |
1177 case REG_R13: | |
1178 case REG_R14: | |
1179 case REG_R15: | |
1180 case REG_RM: | |
1181 case REG_RIP: | |
1182 case REG_IMM: | |
1183 case REG_IMM2: | |
1184 case REG_DS_RBX: | |
1185 case REG_ES_RDI: | |
1186 case REG_DS_RSI: | |
1187 case REG_PORT_DX: | |
1188 case REG_ST: | |
1189 case JMP_TO: | |
1190 assert(FALSE); | |
1191 } | |
1192 if ((instruction->rm.base != REG_NONE) || | |
1193 (instruction->rm.index != REG_NONE) || | |
1194 (instruction->rm.scale != 0)) { | |
1195 printf(")"); | |
1196 } | |
1197 } else { | |
1198 if ((instruction->rm.base != REG_NONE) || | |
1199 (instruction->rm.index != REG_RIZ) || | |
1200 (instruction->rm.scale != 0)) { | |
1201 printf("("); | |
1202 } | |
1203 switch (instruction->rm.base) { | |
1204 case REG_RAX: printf("%%rax"); break; | |
1205 case REG_RCX: printf("%%rcx"); break; | |
1206 case REG_RDX: printf("%%rdx"); break; | |
1207 case REG_RBX: printf("%%rbx"); break; | |
1208 case REG_RSP: printf("%%rsp"); break; | |
1209 case REG_RBP: printf("%%rbp"); break; | |
1210 case REG_RSI: printf("%%rsi"); break; | |
1211 case REG_RDI: printf("%%rdi"); break; | |
1212 case REG_R8: printf("%%r8"); break; | |
1213 case REG_R9: printf("%%r9"); break; | |
1214 case REG_R10: printf("%%r10"); break; | |
1215 case REG_R11: printf("%%r11"); break; | |
1216 case REG_R12: printf("%%r12"); break; | |
1217 case REG_R13: printf("%%r13"); break; | |
1218 case REG_R14: printf("%%r14"); break; | |
1219 case REG_R15: printf("%%r15"); break; | |
1220 case REG_RIP: printf("%%rip"); print_rip = TRUE; break; | |
1221 case REG_NONE: break; | |
1222 case REG_RM: | |
1223 case REG_RIZ: | |
1224 case REG_IMM: | |
1225 case REG_IMM2: | |
1226 case REG_DS_RBX: | |
1227 case REG_ES_RDI: | |
1228 case REG_DS_RSI: | |
1229 case REG_PORT_DX: | |
1230 case REG_ST: | |
1231 case JMP_TO: | |
1232 assert(FALSE); | |
1233 } | |
1234 switch (instruction->rm.index) { | |
1235 case REG_RAX: printf(",%%rax,%d",1<<instruction->rm.scale); break; | |
1236 case REG_RCX: printf(",%%rcx,%d",1<<instruction->rm.scale); break; | |
1237 case REG_RDX: printf(",%%rdx,%d",1<<instruction->rm.scale); break; | |
1238 case REG_RBX: printf(",%%rbx,%d",1<<instruction->rm.scale); break; | |
1239 case REG_RSP: printf(",%%rsp,%d",1<<instruction->rm.scale); break; | |
1240 case REG_RBP: printf(",%%rbp,%d",1<<instruction->rm.scale); break; | |
1241 case REG_RSI: printf(",%%rsi,%d",1<<instruction->rm.scale); break; | |
1242 case REG_RDI: printf(",%%rdi,%d",1<<instruction->rm.scale); break; | |
1243 case REG_R8: printf(",%%r8,%d",1<<instruction->rm.scale); break; | |
1244 case REG_R9: printf(",%%r9,%d",1<<instruction->rm.scale); break; | |
1245 case REG_R10: printf(",%%r10,%d",1<<instruction->rm.scale); break; | |
1246 case REG_R11: printf(",%%r11,%d",1<<instruction->rm.scale); break; | |
1247 case REG_R12: printf(",%%r12,%d",1<<instruction->rm.scale); break; | |
1248 case REG_R13: printf(",%%r13,%d",1<<instruction->rm.scale); break; | |
1249 case REG_R14: printf(",%%r14,%d",1<<instruction->rm.scale); break; | |
1250 case REG_R15: printf(",%%r15,%d",1<<instruction->rm.scale); break; | |
1251 case REG_RIZ: if (((instruction->rm.base != REG_NONE) && | |
1252 (instruction->rm.base != REG_RSP) && | |
1253 (instruction->rm.base != REG_R12)) || | |
1254 (instruction->rm.scale != 0)) | |
1255 printf(",%%riz,%d",1<<instruction->rm.scale); | |
1256 break; | |
1257 case REG_NONE: break; | |
1258 case REG_RM: | |
1259 case REG_RIP: | |
1260 case REG_IMM: | |
1261 case REG_IMM2: | |
1262 case REG_DS_RBX: | |
1263 case REG_ES_RDI: | |
1264 case REG_DS_RSI: | |
1265 case REG_PORT_DX: | |
1266 case REG_ST: | |
1267 case JMP_TO: | |
1268 assert(FALSE); | |
1269 } | |
1270 if ((instruction->rm.base != REG_NONE) || | |
1271 (instruction->rm.index != REG_RIZ) || | |
1272 (instruction->rm.scale != 0)) { | |
1273 printf(")"); | |
1274 } | |
1275 } | |
1276 } | |
1277 break; | |
1278 case REG_IMM: { | |
1279 printf("$0x%"PRIx64,instruction->imm[0]); | |
1280 break; | |
1281 } | |
1282 case REG_IMM2: { | |
1283 printf("$0x%"PRIx64,instruction->imm[1]); | |
1284 break; | |
1285 } | |
1286 case REG_PORT_DX: printf("(%%dx)"); break; | |
1287 case REG_DS_RBX: if (((struct DecodeState *)userdata)->ia32_mode) { | |
1288 printf("%%ds:(%%ebx)"); | |
1289 } else { | |
1290 printf("%%ds:(%%rbx)"); | |
1291 } | |
1292 break; | |
1293 case REG_ES_RDI: if (((struct DecodeState *)userdata)->ia32_mode) { | |
1294 printf("%%es:(%%edi)"); | |
1295 } else { | |
1296 printf("%%es:(%%rdi)"); | |
1297 } | |
1298 break; | |
1299 case REG_DS_RSI: if (((struct DecodeState *)userdata)->ia32_mode) { | |
1300 printf("%%ds:(%%esi)"); | |
1301 } else { | |
1302 printf("%%ds:(%%rsi)"); | |
1303 } | |
1304 break; | |
1305 case JMP_TO: if (instruction->operands[0].type == OperandSize16bit) | |
1306 printf("0x%zx", ((end + instruction->rm.offset - | |
1307 (((struct DecodeState *)userdata)->offset)) & 0xffff)); | |
1308 else | |
1309 printf("0x%zx", (end + instruction->rm.offset - | |
1310 (((struct DecodeState *)userdata)->offset))); | |
1311 break; | |
1312 case REG_RIP: | |
1313 case REG_RIZ: | |
1314 case REG_NONE: | |
1315 assert(FALSE); | |
1316 } | |
1317 delimeter = ','; | |
1318 } | |
1319 if (print_rip) { | |
1320 printf(" # 0x%8"PRIx64, | |
1321 (uint64_t) (end + instruction->rm.offset - | |
1322 (((struct DecodeState *)userdata)->offset))); | |
1323 } | |
1324 printf("\n"); | |
1325 begin += 7; | |
1326 while (begin < end) { | |
1327 printf("%*"PRIx64":\t", ((struct DecodeState *)userdata)->width, | |
1328 (uint64_t) (begin - (((struct DecodeState *)userdata)->offset))); | |
1329 for (p = begin; p < begin + 7; ++p) { | |
1330 if (p >= end) { | |
1331 printf("\n"); | |
1332 return; | |
1333 } else { | |
1334 printf("%02x ", *p); | |
1335 } | |
1336 } | |
1337 if (p >= end) { | |
1338 printf("\n"); | |
1339 return; | |
1340 } | |
1341 begin += 7; | |
1342 } | |
1343 } | |
1344 | |
1345 void ProcessError (const uint8_t *ptr, void *userdata) { | |
1346 printf("rejected at %"PRIx64" (byte 0x%02"PRIx32")\n", | |
1347 (uint64_t) (ptr - (((struct DecodeState *)userdata)->offset)), | |
1348 *ptr); | |
1349 } | |
1350 | |
1351 int DecodeFile(const char *filename, int repeat_count) { | |
1352 size_t data_size; | |
1353 uint8_t *data; | |
1354 int count; | |
1355 | |
1356 ReadFile(filename, &data, &data_size); | |
1357 if (data[4] == 1) { | |
1358 for (count = 0; count < repeat_count; ++count) { | |
1359 Elf32_Ehdr *header; | |
1360 int index; | |
1361 | |
1362 header = (Elf32_Ehdr *) data; | |
1363 CheckBounds(data, data_size, header, sizeof(*header)); | |
1364 assert(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); | |
1365 | |
1366 for (index = 0; index < header->e_shnum; ++index) { | |
1367 Elf32_Shdr *section = (Elf32_Shdr *) (data + header->e_shoff + | |
1368 header->e_shentsize * index); | |
1369 CheckBounds(data, data_size, section, sizeof(*section)); | |
1370 | |
1371 if ((section->sh_flags & SHF_EXECINSTR) != 0) { | |
1372 struct DecodeState state; | |
1373 int res; | |
1374 | |
1375 state.ia32_mode = TRUE; | |
1376 state.fwait = FALSE; | |
1377 state.offset = data + section->sh_offset - section->sh_addr; | |
1378 if (section->sh_size <= 0xfff) { | |
1379 state.width = 4; | |
1380 } else if (section->sh_size <= 0xfffffff) { | |
1381 state.width = 8; | |
1382 } else { | |
1383 state.width = 12; | |
1384 } | |
1385 CheckBounds(data, data_size, | |
1386 data + section->sh_offset, section->sh_size); | |
1387 res = DecodeChunkIA32(data + section->sh_offset, section->sh_size, | |
1388 ProcessInstruction, ProcessError, &state); | |
1389 if (res != 0) { | |
1390 return res; | |
1391 } else if (state.fwait) { | |
1392 while (state.fwait < data + section->sh_offset + section->sh_size) { | |
1393 printf("%*zx:\t9b \tfwait\n", | |
1394 state.width, (state.fwait++ - state.offset)); | |
1395 } | |
1396 } | |
1397 } | |
1398 } | |
1399 } | |
1400 } else if (data[4] == 2) { | |
1401 for (count = 0; count < repeat_count; ++count) { | |
1402 Elf64_Ehdr *header; | |
1403 int index; | |
1404 | |
1405 header = (Elf64_Ehdr *) data; | |
1406 CheckBounds(data, data_size, header, sizeof(*header)); | |
1407 assert(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); | |
1408 | |
1409 for (index = 0; index < header->e_shnum; ++index) { | |
1410 Elf64_Shdr *section = (Elf64_Shdr *) (data + header->e_shoff + | |
1411 header->e_shentsize * index); | |
1412 CheckBounds(data, data_size, section, sizeof(*section)); | |
1413 | |
1414 if ((section->sh_flags & SHF_EXECINSTR) != 0) { | |
1415 struct DecodeState state; | |
1416 int res; | |
1417 | |
1418 state.ia32_mode = FALSE; | |
1419 state.fwait = FALSE; | |
1420 state.offset = data + section->sh_offset - section->sh_addr; | |
1421 if (section->sh_size <= 0xfff) { | |
1422 state.width = 4; | |
1423 } else if (section->sh_size <= 0xfffffff) { | |
1424 state.width = 8; | |
1425 } else if (section->sh_size <= 0xfffffffffffLL) { | |
1426 state.width = 12; | |
1427 } else { | |
1428 state.width = 16; | |
1429 } | |
1430 CheckBounds(data, data_size, | |
1431 data + section->sh_offset, section->sh_size); | |
1432 res = DecodeChunkAMD64(data + section->sh_offset, section->sh_size, | |
1433 ProcessInstruction, ProcessError, &state); | |
1434 if (res != 0) { | |
1435 return res; | |
1436 } else if (state.fwait) { | |
1437 while (state.fwait < data + section->sh_offset + section->sh_size) { | |
1438 printf("%*zx:\t9b \tfwait\n", | |
1439 state.width, (state.fwait++ - state.offset)); | |
1440 } | |
1441 } | |
1442 } | |
1443 } | |
1444 } | |
1445 } else { | |
1446 printf("Unknown ELF class: %s\n", filename); | |
1447 exit(1); | |
1448 } | |
1449 return 0; | |
1450 } | |
1451 | |
1452 int main(int argc, char **argv) { | |
1453 int index, initial_index = 1, repeat_count = 1; | |
1454 if (argc == 1) { | |
1455 printf("%s: no input files\n", argv[0]); | |
1456 exit(1); | |
1457 } | |
1458 if (!strcmp(argv[1],"--repeat")) | |
1459 repeat_count = atoi(argv[2]), | |
1460 initial_index += 2; | |
1461 for (index = initial_index; index < argc; ++index) { | |
1462 const char *filename = argv[index]; | |
1463 int rc = DecodeFile(filename, repeat_count); | |
1464 if (rc != 0) { | |
1465 printf("file '%s' can not be fully decoded\n", filename); | |
1466 return 1; | |
1467 } | |
1468 } | |
1469 return 0; | |
1470 } | |
OLD | NEW |