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 /* | |
8 * New table driven generator for a decoder of x86 code. | |
9 * | |
10 * Note: Most of the organization of this document is based on the | |
11 * NaClOpcode Map appendix of one of the following documents: | |
12 | |
13 * (1) "Intel 64 and IA-32 Architectures | |
14 * Software Developer's Manual (volumes 1, 2a, and 2b; documents | |
15 * 253665.pdf, 253666.pdf, and 253667.pdf)". | |
16 * | |
17 * (2) "Intel 80386 Reference Programmer's Manual" (document | |
18 * http://pdos.csail.mit.edu/6.828/2004/readings/i386/toc.htm). | |
19 */ | |
20 | |
21 #ifndef NACL_TRUSTED_BUT_NOT_TCB | |
22 #error("This file is not meant for use in the TCB") | |
23 #endif | |
24 | |
25 #include <stdio.h> | |
26 #include <stdlib.h> | |
27 #include <assert.h> | |
28 #include <string.h> | |
29 | |
30 #include "native_client/src/trusted/validator/x86/decoder/generator/ncdecode_tab
legen.h" | |
31 | |
32 | |
33 #include "native_client/src/include/portability.h" | |
34 #include "native_client/src/include/portability_io.h" | |
35 #include "native_client/src/shared/utils/flags.h" | |
36 #include "native_client/src/shared/platform/nacl_log.h" | |
37 #include "native_client/src/trusted/validator/x86/x86_insts.h" | |
38 #include "native_client/src/trusted/validator/x86/decoder/generator/gen/nacl_dis
allows.h" | |
39 #include "native_client/src/trusted/validator/x86/decoder/generator/nacl_regsgen
.h" | |
40 #include "native_client/src/trusted/validator/x86/decoder/generator/ncdecode_for
ms.h" | |
41 #include "native_client/src/trusted/validator/x86/decoder/generator/ncdecode_st.
h" | |
42 #include "native_client/src/trusted/validator/x86/decoder/generator/ncval_simpli
fy.h" | |
43 #include "native_client/src/trusted/validator/x86/decoder/generator/nc_compress.
h" | |
44 | |
45 /* To turn on debugging of instruction decoding, change value of | |
46 * DEBUGGING to 1. | |
47 */ | |
48 #define DEBUGGING 0 | |
49 | |
50 #include "native_client/src/shared/utils/debugging.h" | |
51 | |
52 /* Define the default buffer size to use. */ | |
53 #define BUFFER_SIZE 256 | |
54 | |
55 /* Model an NaClInst, sorted by OpcodeInModRm values. */ | |
56 typedef struct NaClMrmInst { | |
57 NaClModeledInst inst; | |
58 struct NaClMrmInst* next; | |
59 } NaClMrmInst; | |
60 | |
61 /* Note: in general all errors in this module will be fatal. | |
62 * To debug: use gdb or your favorite debugger. | |
63 */ | |
64 void NaClFatal(const char* s) { | |
65 NaClLog(LOG_FATAL, "Error: %s\n", s); | |
66 NaClLog(LOG_FATAL, "Fatal: cannot recover\n"); | |
67 exit(-1); | |
68 } | |
69 | |
70 /* Returns the print name of the given run mode. */ | |
71 static const char* NaClRunModeName(NaClRunMode mode) { | |
72 switch (mode) { | |
73 case X86_32: return "x86-32 bit mode"; | |
74 case X86_64: return "x86-64 bit mode"; | |
75 default: assert(0); | |
76 } | |
77 | |
78 /* NOTREACHED */ | |
79 return NULL; | |
80 } | |
81 | |
82 /* Defines if we should simplify the instructions to | |
83 * what is needed by the validator. | |
84 */ | |
85 static Bool NACL_FLAGS_validator_decoder = FALSE; | |
86 | |
87 /* Defines the run mode files that should be generated. */ | |
88 NaClRunMode NACL_FLAGS_run_mode = NaClRunModeSize; | |
89 | |
90 /* Defines whether the output of the instruction set should | |
91 * be as a header file, or human readable (for documentation). | |
92 */ | |
93 static Bool NACL_FLAGS_human_readable = FALSE; | |
94 | |
95 /* Defines whether the output should be instruction modeling tables, | |
96 * or hardware registers. | |
97 */ | |
98 static Bool NACL_FLAGS_nacl_subregs = FALSE; | |
99 | |
100 /* Holds the current instruction prefix. */ | |
101 static NaClInstPrefix current_opcode_prefix = NoPrefix; | |
102 | |
103 /* Holds the default instruction prefix. */ | |
104 static NaClInstPrefix default_opcode_prefix = NoPrefix; | |
105 | |
106 /* Holds the current instruction being built. */ | |
107 static NaClModeledInst* current_inst = NULL; | |
108 | |
109 /* Holds the current opcode sequence to be associated with the next | |
110 * defined opcode. | |
111 */ | |
112 static NaClModeledInstNode* current_inst_node = NULL; | |
113 | |
114 /* Holds the candidate for the current_inst_node, when | |
115 * NaClDefInst is called. | |
116 */ | |
117 static NaClModeledInstNode* current_cand_inst_node = NULL; | |
118 | |
119 /* Holds the current instruction with mrm extention being built. */ | |
120 static NaClMrmInst* current_inst_mrm = NULL; | |
121 | |
122 /* Holds tables used to generate/compress the modeled instructions. */ | |
123 NaClInstTables tables; | |
124 | |
125 /* True if we are to apply sanity checks as we define operantions. */ | |
126 static Bool apply_sanity_checks = TRUE; | |
127 | |
128 #define NACL_DEFAULT_CHOICE_COUNT (-1) | |
129 | |
130 #define NACL_NO_MODRM_OPCODE 8 | |
131 | |
132 #define NACL_MODRM_OPCODE_SIZE (NACL_NO_MODRM_OPCODE + 1) | |
133 | |
134 /* Holds the expected number of entries in the defined instructions. | |
135 * Note: the last index corresponds to the modrm opcode, or | |
136 * NACL_NO_MODRM_OPCODE if no modrm opcode. | |
137 */ | |
138 static int NaClInstCount[NCDTABLESIZE] | |
139 [NaClInstPrefixEnumSize][NACL_MODRM_OPCODE_SIZE]; | |
140 | |
141 static NaClMrmInst* NaClInstMrmTable[NCDTABLESIZE] | |
142 [NaClInstPrefixEnumSize][NACL_MODRM_OPCODE_SIZE]; | |
143 | |
144 /* Holds encodings of prefix bytes. */ | |
145 static const char* NaClPrefixTable[NCDTABLESIZE]; | |
146 | |
147 | |
148 /* Prints out the opcode prefix being defined, the opcode pattern | |
149 * being defined, and the given error message. Then aborts the | |
150 * execution of the program. | |
151 */ | |
152 static void NaClFatalInst(const char* message) { | |
153 NaClLog(LOG_INFO, "Prefix: %s\n", NaClInstPrefixName(current_opcode_prefix)); | |
154 NaClModeledInstPrint(NaClLogGetGio(), current_inst); | |
155 NaClFatal(message); | |
156 } | |
157 | |
158 /* Prints out what operand is currently being defined, followed by the given | |
159 * error message. Then aborts the execution of the program. | |
160 */ | |
161 static void NaClFatalOp(int index, const char* message) { | |
162 if (0 <= index && index <= current_inst->num_operands) { | |
163 NaClLog(LOG_ERROR, "On operand %d: %s\n", index, | |
164 NaClOpKindName(current_inst->operands[index].kind)); | |
165 } else { | |
166 NaClLog(LOG_ERROR, "On operand %d:\n", index); | |
167 } | |
168 NaClFatalInst(message); | |
169 } | |
170 | |
171 /* Advance the buffer/buffer_size values by count characters. */ | |
172 static void CharAdvance(char** buffer, size_t* buffer_size, size_t count) { | |
173 *buffer += count; | |
174 *buffer_size += count; | |
175 } | |
176 | |
177 /* Generates a (malloc allocated) string describing the form for the | |
178 * operands. | |
179 * Note: This code used to be part of the validator (runtime) library. | |
180 * By moving it here, we remove this code, and runtime cost, from | |
181 * the validator runtime. | |
182 */ | |
183 static void NaClFillOperandDescs(NaClModeledInst* inst) { | |
184 char buffer[BUFFER_SIZE]; | |
185 int i; | |
186 | |
187 /* Make sure inst is defined before trying to fix. */ | |
188 if (NULL == inst) return; | |
189 | |
190 for (i = 0; i < inst->num_operands; ++i) { | |
191 char* buf = buffer; | |
192 size_t buf_size = BUFFER_SIZE; | |
193 Bool is_implicit = (NACL_EMPTY_OPFLAGS != (inst->operands[i].flags & | |
194 NACL_OPFLAG(OpImplicit))); | |
195 NaClOpKind kind = inst->operands[i].kind; | |
196 | |
197 if (NULL != inst->operands[i].format_string) continue; | |
198 | |
199 buffer[0] = '\0'; /* just in case there isn't any operands. */ | |
200 if (is_implicit) { | |
201 CharAdvance(&buf, &buf_size, | |
202 SNPRINTF(buf, buf_size, "{")); | |
203 } | |
204 switch (kind) { | |
205 case A_Operand: | |
206 CharAdvance(&buf, &buf_size, | |
207 SNPRINTF(buf, buf_size, "$A")); | |
208 break; | |
209 case E_Operand: | |
210 case Eb_Operand: | |
211 case Ew_Operand: | |
212 case Ev_Operand: | |
213 case Eo_Operand: | |
214 case Edq_Operand: | |
215 CharAdvance(&buf, &buf_size, | |
216 SNPRINTF(buf, buf_size, "$E")); | |
217 break; | |
218 case G_Operand: | |
219 case Gb_Operand: | |
220 case Gw_Operand: | |
221 case Gv_Operand: | |
222 case Go_Operand: | |
223 case Gdq_Operand: | |
224 CharAdvance(&buf, &buf_size, | |
225 SNPRINTF(buf, buf_size, "$G")); | |
226 break; | |
227 case Seg_G_Operand: | |
228 CharAdvance(&buf, &buf_size, | |
229 SNPRINTF(buf, buf_size, "$SegG")); | |
230 break; | |
231 case G_OpcodeBase: | |
232 CharAdvance(&buf, &buf_size, | |
233 SNPRINTF(buf, buf_size, "$/r")); | |
234 break; | |
235 case I_Operand: | |
236 case Ib_Operand: | |
237 case Iw_Operand: | |
238 case Iv_Operand: | |
239 case Io_Operand: | |
240 case I2_Operand: | |
241 case J_Operand: | |
242 case Jb_Operand: | |
243 case Jw_Operand: | |
244 case Jv_Operand: | |
245 CharAdvance(&buf, &buf_size, | |
246 SNPRINTF(buf, buf_size, "$I")); | |
247 break; | |
248 case M_Operand: | |
249 case Mb_Operand: | |
250 case Mw_Operand: | |
251 case Mv_Operand: | |
252 case Mo_Operand: | |
253 case Mdq_Operand: | |
254 /* Special case $Ma, which adds two operands. */ | |
255 if ((i > 0) && (NULL != inst->operands[i-1].format_string) && | |
256 (0 == strcmp(inst->operands[i-1].format_string, "$Ma"))) { | |
257 /* Don't add a format string in this case. */ | |
258 continue; | |
259 } else { | |
260 CharAdvance(&buf, &buf_size, | |
261 SNPRINTF(buf, buf_size, "$M")); | |
262 } | |
263 break; | |
264 case Mpw_Operand: | |
265 CharAdvance(&buf, &buf_size, | |
266 SNPRINTF(buf, buf_size, "m16:16")); | |
267 break; | |
268 case Mpv_Operand: | |
269 CharAdvance(&buf, &buf_size, | |
270 SNPRINTF(buf, buf_size, "m16:32")); | |
271 break; | |
272 case Mpo_Operand: | |
273 CharAdvance(&buf, &buf_size, | |
274 SNPRINTF(buf, buf_size, "m16:64")); | |
275 break; | |
276 case Mmx_E_Operand: | |
277 case Mmx_N_Operand: | |
278 CharAdvance(&buf, &buf_size, | |
279 SNPRINTF(buf, buf_size, "$E(mmx)")); | |
280 break; | |
281 case Mmx_G_Operand: | |
282 case Mmx_Gd_Operand: | |
283 CharAdvance(&buf, &buf_size, | |
284 SNPRINTF(buf, buf_size, "$G(mmx)")); | |
285 break; | |
286 case Xmm_E_Operand: | |
287 case Xmm_Eo_Operand: | |
288 CharAdvance(&buf, &buf_size, | |
289 SNPRINTF(buf, buf_size, "$E(xmm)")); | |
290 break; | |
291 case Xmm_G_Operand: | |
292 case Xmm_Go_Operand: | |
293 CharAdvance(&buf, &buf_size, | |
294 SNPRINTF(buf, buf_size, "$G(xmm)")); | |
295 break; | |
296 case O_Operand: | |
297 case Ob_Operand: | |
298 case Ow_Operand: | |
299 case Ov_Operand: | |
300 case Oo_Operand: | |
301 CharAdvance(&buf, &buf_size, | |
302 SNPRINTF(buf, buf_size, "$O")); | |
303 break; | |
304 case S_Operand: | |
305 CharAdvance(&buf, &buf_size, | |
306 SNPRINTF(buf, buf_size, "%%Sreg")); | |
307 break; | |
308 case C_Operand: | |
309 CharAdvance(&buf, &buf_size, | |
310 SNPRINTF(buf, buf_size, "%%Creg")); | |
311 break; | |
312 case D_Operand: | |
313 CharAdvance(&buf, &buf_size, | |
314 SNPRINTF(buf, buf_size, "%%Dreg")); | |
315 break; | |
316 case St_Operand: | |
317 CharAdvance(&buf, &buf_size, | |
318 SNPRINTF(buf, buf_size, "%%st")); | |
319 break; | |
320 case RegAL: | |
321 case RegBL: | |
322 case RegCL: | |
323 case RegDL: | |
324 case RegAH: | |
325 case RegBH: | |
326 case RegCH: | |
327 case RegDH: | |
328 case RegDIL: | |
329 case RegSIL: | |
330 case RegBPL: | |
331 case RegSPL: | |
332 case RegR8B: | |
333 case RegR9B: | |
334 case RegR10B: | |
335 case RegR11B: | |
336 case RegR12B: | |
337 case RegR13B: | |
338 case RegR14B: | |
339 case RegR15B: | |
340 case RegAX: | |
341 case RegBX: | |
342 case RegCX: | |
343 case RegDX: | |
344 case RegSI: | |
345 case RegDI: | |
346 case RegBP: | |
347 case RegSP: | |
348 case RegR8W: | |
349 case RegR9W: | |
350 case RegR10W: | |
351 case RegR11W: | |
352 case RegR12W: | |
353 case RegR13W: | |
354 case RegR14W: | |
355 case RegR15W: | |
356 case RegEAX: | |
357 case RegEBX: | |
358 case RegECX: | |
359 case RegEDX: | |
360 case RegESI: | |
361 case RegEDI: | |
362 case RegEBP: | |
363 case RegESP: | |
364 case RegR8D: | |
365 case RegR9D: | |
366 case RegR10D: | |
367 case RegR11D: | |
368 case RegR12D: | |
369 case RegR13D: | |
370 case RegR14D: | |
371 case RegR15D: | |
372 case RegCS: | |
373 case RegDS: | |
374 case RegSS: | |
375 case RegES: | |
376 case RegFS: | |
377 case RegGS: | |
378 case RegEFLAGS: | |
379 case RegRFLAGS: | |
380 case RegEIP: | |
381 case RegRIP: | |
382 case RegRAX: | |
383 case RegRBX: | |
384 case RegRCX: | |
385 case RegRDX: | |
386 case RegRSI: | |
387 case RegRDI: | |
388 case RegRBP: | |
389 case RegRSP: | |
390 case RegR8: | |
391 case RegR9: | |
392 case RegR10: | |
393 case RegR11: | |
394 case RegR12: | |
395 case RegR13: | |
396 case RegR14: | |
397 case RegR15: | |
398 case RegREIP: | |
399 case RegREAX: | |
400 case RegREBX: | |
401 case RegRECX: | |
402 case RegREDX: | |
403 case RegRESP: | |
404 case RegREBP: | |
405 case RegRESI: | |
406 case RegREDI: | |
407 case RegDS_EDI: | |
408 case RegDS_EBX: | |
409 case RegES_EDI: | |
410 case RegST0: | |
411 case RegST1: | |
412 case RegST2: | |
413 case RegST3: | |
414 case RegST4: | |
415 case RegST5: | |
416 case RegST6: | |
417 case RegST7: | |
418 case RegMMX0: | |
419 case RegMMX1: | |
420 case RegMMX2: | |
421 case RegMMX3: | |
422 case RegMMX4: | |
423 case RegMMX5: | |
424 case RegMMX6: | |
425 case RegMMX7: | |
426 case RegXMM0: | |
427 case RegXMM1: | |
428 case RegXMM2: | |
429 case RegXMM3: | |
430 case RegXMM4: | |
431 case RegXMM5: | |
432 case RegXMM6: | |
433 case RegXMM7: | |
434 case RegXMM8: | |
435 case RegXMM9: | |
436 case RegXMM10: | |
437 case RegXMM11: | |
438 case RegXMM12: | |
439 case RegXMM13: | |
440 case RegXMM14: | |
441 case RegXMM15: | |
442 CharAdvance(&buf, &buf_size, | |
443 SNPRINTF(buf, buf_size, "%%%s", | |
444 NaClOpKindName(kind) + strlen("Reg"))); | |
445 break; | |
446 case Const_1: | |
447 CharAdvance(&buf, &buf_size, | |
448 SNPRINTF(buf, buf_size, "1")); | |
449 break; | |
450 default: | |
451 CharAdvance(&buf, &buf_size, | |
452 SNPRINTF(buf, buf_size, "???")); | |
453 break; | |
454 } | |
455 if (is_implicit) { | |
456 CharAdvance(&buf, &buf_size, | |
457 SNPRINTF(buf, buf_size, "}")); | |
458 } | |
459 *((char**)(inst->operands[i].format_string)) = strdup(buffer); | |
460 } | |
461 } | |
462 | |
463 /* Define the prefix name for the given opcode, for the given run mode. */ | |
464 static void NaClEncodeModedPrefixName(const uint8_t byte, const char* name, | |
465 const NaClRunMode mode) { | |
466 if (NACL_FLAGS_run_mode == mode) { | |
467 NaClPrefixTable[byte] = name; | |
468 } | |
469 } | |
470 | |
471 /* Define the prefix name for the given opcode, for all run modes. */ | |
472 static void NaClEncodePrefixName(const uint8_t byte, const char* name) { | |
473 NaClEncodeModedPrefixName(byte, name, NACL_FLAGS_run_mode); | |
474 } | |
475 | |
476 /* Change the current opcode prefix to the given value. */ | |
477 void NaClDefInstPrefix(const NaClInstPrefix prefix) { | |
478 current_opcode_prefix = prefix; | |
479 } | |
480 | |
481 void NaClResetToDefaultInstPrefix(void) { | |
482 NaClDefInstPrefix(default_opcode_prefix); | |
483 } | |
484 | |
485 NaClModeledInst* NaClGetDefInst(void) { | |
486 return current_inst; | |
487 } | |
488 | |
489 /* Check if an E_Operand operand has been repeated, since it should | |
490 * never appear for more than one argument. If repeated, generate an | |
491 * appropriate error message and terminate. | |
492 */ | |
493 static void NaClCheckIfERepeated(int index) { | |
494 int i; | |
495 for (i = 0; i < index; ++i) { | |
496 const NaClOp* operand = ¤t_inst->operands[i]; | |
497 switch (operand->kind) { | |
498 case Mmx_E_Operand: | |
499 case Xmm_E_Operand: | |
500 case Xmm_Eo_Operand: | |
501 case E_Operand: | |
502 case Eb_Operand: | |
503 case Ew_Operand: | |
504 case Ev_Operand: | |
505 case Eo_Operand: | |
506 case Edq_Operand: | |
507 NaClFatalOp(index, "Can't use E Operand more than once"); | |
508 break; | |
509 default: | |
510 break; | |
511 } | |
512 } | |
513 } | |
514 | |
515 /* Called if operand is a G_Operand. Checks that the opcode doesn't specify | |
516 * that the REG field of modrm is an opcode, since G_Operand doesn't make | |
517 * sense in such cases. | |
518 */ | |
519 static void NaClCheckIfOpcodeInModRm(int index) { | |
520 if ((current_inst->flags & NACL_IFLAG(OpcodeInModRm)) && | |
521 (NACL_EMPTY_OPFLAGS == (current_inst->operands[index].flags & | |
522 NACL_IFLAG(AllowGOperandWithOpcodeInModRm)))) { | |
523 NaClFatalOp(index, | |
524 "Can't use G Operand, bits being used for opcode in modrm"); | |
525 } | |
526 } | |
527 | |
528 /* Check if an G_Operand operand has been repeated, since it should | |
529 * never appear for more than one argument. If repeated, generate an | |
530 * appropriate error message and terminate. | |
531 */ | |
532 static void NaClCheckIfGRepeated(int index) { | |
533 int i; | |
534 for (i = 0; i < index; ++i) { | |
535 const NaClOp* operand = ¤t_inst->operands[i]; | |
536 switch (operand->kind) { | |
537 case Mmx_G_Operand: | |
538 case Xmm_G_Operand: | |
539 case Xmm_Go_Operand: | |
540 case G_Operand: | |
541 case Gb_Operand: | |
542 case Gw_Operand: | |
543 case Gv_Operand: | |
544 case Go_Operand: | |
545 case Gdq_Operand: | |
546 NaClFatalOp(index, "Can't use G Operand more than once"); | |
547 break; | |
548 default: | |
549 break; | |
550 } | |
551 } | |
552 } | |
553 | |
554 /* Check if an I_Operand/J_OPerand operand has been repeated, since it should | |
555 * never appear for more than one argument (both come from the immediate field | |
556 * of the instruction). If repeated, generate an appropriate error message | |
557 * and terminate. | |
558 */ | |
559 static void NaClCheckIfIRepeated(int index) { | |
560 int i; | |
561 for (i = 0; i < index; ++i) { | |
562 const NaClOp* operand = ¤t_inst->operands[i]; | |
563 switch (operand->kind) { | |
564 case I_Operand: | |
565 case Ib_Operand: | |
566 case Iw_Operand: | |
567 case Iv_Operand: | |
568 case Io_Operand: | |
569 NaClFatalOp(index, "Can't use I_Operand more than once"); | |
570 break; | |
571 case J_Operand: | |
572 case Jb_Operand: | |
573 case Jv_Operand: | |
574 NaClFatalOp(index, "Can't use both I_Operand and J_Operand"); | |
575 break; | |
576 default: | |
577 break; | |
578 } | |
579 } | |
580 } | |
581 | |
582 /* Returns the set of operand size flags defined for the given instruction. */ | |
583 NaClIFlags NaClOperandSizes(NaClModeledInst* inst) { | |
584 NaClIFlags flags = inst->flags & (NACL_IFLAG(OperandSize_b) | | |
585 NACL_IFLAG(OperandSize_w) | | |
586 NACL_IFLAG(OperandSize_v) | | |
587 NACL_IFLAG(OperandSize_o)); | |
588 /* Note: if no sizes specified, assume all sizes possible. */ | |
589 if (NACL_EMPTY_IFLAGS == flags) { | |
590 flags = NACL_IFLAG(OperandSize_b) | | |
591 NACL_IFLAG(OperandSize_w) | | |
592 NACL_IFLAG(OperandSize_v) | | |
593 NACL_IFLAG(OperandSize_o); | |
594 } | |
595 return flags; | |
596 } | |
597 | |
598 /* Check that the operand being defined (via the given index), does not | |
599 * specify any inconsistent flags. | |
600 */ | |
601 static void NaClApplySanityChecksToOp(int index) { | |
602 const NaClOp* operand = ¤t_inst->operands[index]; | |
603 const NaClIFlags operand_sizes = NaClOperandSizes(current_inst); | |
604 | |
605 if (!apply_sanity_checks) return; | |
606 | |
607 /* Check that operand is consistent with other operands defined, or flags | |
608 * defined on the opcode. | |
609 */ | |
610 switch (operand->kind) { | |
611 case E_Operand: | |
612 NaClCheckIfERepeated(index); | |
613 break; | |
614 case Eb_Operand: | |
615 if (NACL_IFLAG(OperandSize_b) == operand_sizes) { | |
616 /* Singlton set already specifies size, so no need for extra | |
617 * size specification. | |
618 */ | |
619 NaClFatalOp(index, | |
620 "Size implied by OperandSize_b, use E_Operand instead"); | |
621 } | |
622 NaClCheckIfERepeated(index); | |
623 break; | |
624 case Ew_Operand: | |
625 if (NACL_IFLAG(OperandSize_w) == operand_sizes) { | |
626 /* Singlton set already specifies size, so no need for extra | |
627 * size specification. | |
628 */ | |
629 NaClFatalOp(index, | |
630 "Size implied by OperandSize_w, use E_Operand instead"); | |
631 } | |
632 NaClCheckIfERepeated(index); | |
633 break; | |
634 case Ev_Operand: | |
635 if (NACL_IFLAG(OperandSize_v) == operand_sizes) { | |
636 /* Singlton set already specifies size, so no need for extra | |
637 * size specification. | |
638 */ | |
639 NaClFatalOp(index, | |
640 "Size implied by OperandSize_v, use E_Operand instead"); | |
641 } | |
642 NaClCheckIfERepeated(index); | |
643 break; | |
644 case Eo_Operand: | |
645 if (NACL_IFLAG(OperandSize_o) == operand_sizes) { | |
646 /* Singlton set already specifies size, so no need for extra | |
647 * size specification. | |
648 */ | |
649 NaClFatalOp(index, | |
650 "Size implied by OperandSize_o, use E_Operand instead"); | |
651 } | |
652 NaClCheckIfERepeated(index); | |
653 break; | |
654 case Edq_Operand: | |
655 NaClCheckIfERepeated(index); | |
656 break; | |
657 case Mmx_E_Operand: | |
658 case Xmm_E_Operand: | |
659 NaClCheckIfERepeated(index); | |
660 break; | |
661 case Xmm_Eo_Operand: | |
662 if (NACL_IFLAG(OperandSize_o) == operand_sizes) { | |
663 /* Singlton set already specifies size, so no need for extra | |
664 * size specification. | |
665 */ | |
666 NaClFatalOp | |
667 (index, | |
668 "Size implied by OperandSize_o, use Xmm_E_Operand instead"); | |
669 } | |
670 NaClCheckIfERepeated(index); | |
671 break; | |
672 case G_Operand: | |
673 NaClCheckIfGRepeated(index); | |
674 NaClCheckIfOpcodeInModRm(index); | |
675 break; | |
676 case Gb_Operand: | |
677 if (NACL_IFLAG(OperandSize_b) == operand_sizes) { | |
678 /* Singlton set already specifies size, so no need for extra | |
679 * size specification. | |
680 */ | |
681 NaClFatalOp(index, | |
682 "Size implied by OperandSize_b, use G_Operand instead"); | |
683 } | |
684 NaClCheckIfGRepeated(index); | |
685 NaClCheckIfOpcodeInModRm(index); | |
686 break; | |
687 case Gw_Operand: | |
688 if (NACL_IFLAG(OperandSize_w) == operand_sizes) { | |
689 /* Singlton set already specifies size, so no need for extra | |
690 * size specification. | |
691 */ | |
692 NaClFatalOp(index, | |
693 "Size implied by OperandSize_w, use G_Operand instead"); | |
694 } | |
695 NaClCheckIfGRepeated(index); | |
696 NaClCheckIfOpcodeInModRm(index); | |
697 break; | |
698 case Gv_Operand: | |
699 if (NACL_IFLAG(OperandSize_v) == operand_sizes) { | |
700 /* Singlton set already specifies size, so no need for extra | |
701 * size specification. | |
702 */ | |
703 NaClFatalOp(index, | |
704 "Size implied by OperandSize_v, use G_Operand instead"); | |
705 } | |
706 NaClCheckIfGRepeated(index); | |
707 NaClCheckIfOpcodeInModRm(index); | |
708 break; | |
709 case Go_Operand: | |
710 if (NACL_IFLAG(OperandSize_o) == operand_sizes) { | |
711 /* Singlton set already specifies size, so no need for extra | |
712 * size specification. | |
713 */ | |
714 NaClFatalOp(index, | |
715 "Size implied by OperandSize_o, use G_Operand instead"); | |
716 } | |
717 NaClCheckIfGRepeated(index); | |
718 NaClCheckIfOpcodeInModRm(index); | |
719 break; | |
720 case Gdq_Operand: | |
721 NaClCheckIfGRepeated(index); | |
722 NaClCheckIfOpcodeInModRm(index); | |
723 break; | |
724 case Mmx_G_Operand: | |
725 case Xmm_G_Operand: | |
726 NaClCheckIfGRepeated(index); | |
727 NaClCheckIfOpcodeInModRm(index); | |
728 break; | |
729 case Xmm_Go_Operand: | |
730 if (NACL_IFLAG(OperandSize_o) == operand_sizes) { | |
731 /* Singlton set already specifies size, so no need for extra | |
732 * size specification. | |
733 */ | |
734 NaClFatalOp | |
735 (index, | |
736 "Size implied by OperandSize_o, use Xmm_G_Operand instead"); | |
737 } | |
738 NaClCheckIfGRepeated(index); | |
739 NaClCheckIfOpcodeInModRm(index); | |
740 break; | |
741 case I_Operand: | |
742 NaClCheckIfIRepeated(index); | |
743 break; | |
744 case Ib_Operand: | |
745 if (NACL_IFLAG(OperandSize_b) == operand_sizes) { | |
746 /* Singlton set already specifies size, so no need for extra | |
747 * size specification. | |
748 */ | |
749 NaClFatalOp(index, | |
750 "Size implied by OperandSize_b, use I_Operand instead"); | |
751 } | |
752 if (current_inst->flags & NACL_IFLAG(OpcodeHasImmed_b)) { | |
753 NaClFatalOp(index, | |
754 "Size implied by OpcodeHasImmed_b, use I_Operand instead"); | |
755 } | |
756 NaClCheckIfIRepeated(index); | |
757 break; | |
758 case Iw_Operand: | |
759 if (NACL_IFLAG(OperandSize_w) == operand_sizes) { | |
760 /* Singlton set already specifies size, so no need for extra | |
761 * size specification. | |
762 */ | |
763 NaClFatalOp(index, | |
764 "Size implied by OperandSize_w, use I_Operand instead"); | |
765 } | |
766 if (current_inst->flags & NACL_IFLAG(OpcodeHasImmed_w)) { | |
767 NaClFatalOp(index, | |
768 "Size implied by OpcodeHasImmed_w, use I_Operand instead"); | |
769 } | |
770 NaClCheckIfIRepeated(index); | |
771 break; | |
772 case Iv_Operand: | |
773 if (NACL_IFLAG(OperandSize_v) == operand_sizes) { | |
774 /* Singlton set already specifies size, so no need for extra | |
775 * size specification. | |
776 */ | |
777 NaClFatalOp(index, | |
778 "Size implied by OperandSize_v, use I_Operand instead"); | |
779 } | |
780 if (current_inst->flags & NACL_IFLAG(OpcodeHasImmed_v)) { | |
781 NaClFatalOp(index, | |
782 "Size implied by OpcodeHasImmed_v, use I_Operand instead"); | |
783 } | |
784 NaClCheckIfIRepeated(index); | |
785 break; | |
786 case Io_Operand: | |
787 if (NACL_IFLAG(OperandSize_o) == operand_sizes) { | |
788 /* Singlton set already specifies size, so no need for extra | |
789 * size specification. | |
790 */ | |
791 NaClFatalOp(index, | |
792 "Size implied by OperandSize_o, use I_Operand instead"); | |
793 } | |
794 if (current_inst->flags & NACL_IFLAG(OpcodeHasImmed_o)) { | |
795 NaClFatalOp(index, | |
796 "Size implied by OpcodeHasImmed_o, use I_Operand instead"); | |
797 } | |
798 NaClCheckIfIRepeated(index); | |
799 break; | |
800 default: | |
801 break; | |
802 } | |
803 } | |
804 | |
805 /* Define the next operand of the current opcode to have | |
806 * the given kind and flags. | |
807 */ | |
808 static void NaClDefOpInternal(NaClOpKind kind, NaClOpFlags flags) { | |
809 int index; | |
810 assert(NULL != current_inst); | |
811 if (tables.operands_size >= NACL_MAX_OPERANDS_TOTAL) { | |
812 NaClFatal("Out of operand space. " | |
813 "Increase size of NACL_MAX_OPERANDS_TOTAL!"); | |
814 } | |
815 tables.operands_size++; | |
816 index = current_inst->num_operands++; | |
817 current_inst->operands[index].kind = kind; | |
818 current_inst->operands[index].flags = flags; | |
819 current_inst->operands[index].format_string = NULL; | |
820 } | |
821 | |
822 static void NaClInstallCurrentIntoOpcodeMrm(const NaClInstPrefix prefix, | |
823 const uint8_t opcode, | |
824 int mrm_index) { | |
825 DEBUG(NaClLog(LOG_INFO, " Installing into [%x][%s][%d]\n", | |
826 opcode, NaClInstPrefixName(prefix), mrm_index)); | |
827 if (NULL == NaClInstMrmTable[opcode][prefix][mrm_index]) { | |
828 NaClInstMrmTable[opcode][prefix][mrm_index] = current_inst_mrm; | |
829 } else { | |
830 NaClMrmInst* next = NaClInstMrmTable[opcode][prefix][mrm_index]; | |
831 while (NULL != next->next) { | |
832 next = next->next; | |
833 } | |
834 next->next = current_inst_mrm; | |
835 } | |
836 } | |
837 | |
838 /* Removes the current_inst_mrm from the corresponding instruction table. | |
839 * Used when Opcode32Only or Opcode64Only flag is added, and | |
840 * the flag doesn't match the subarchitecture being modeled. | |
841 */ | |
842 static void NaClRemoveCurrentInstMrmFromInstTable(void) { | |
843 uint8_t opcode = current_inst->opcode[current_inst->num_opcode_bytes - 1]; | |
844 NaClModeledInst* prev = NULL; | |
845 NaClModeledInst* next = tables.inst_table[opcode][current_inst->prefix]; | |
846 while (NULL != next) { | |
847 if (current_inst == next) { | |
848 /* Found - remove! */ | |
849 if (NULL == prev) { | |
850 tables.inst_table[opcode][current_inst->prefix] = next->next_rule; | |
851 } else { | |
852 prev->next_rule = next->next_rule; | |
853 } | |
854 return; | |
855 } else { | |
856 prev = next; | |
857 next = next->next_rule; | |
858 } | |
859 } | |
860 } | |
861 | |
862 /* Removes the current_inst_mrm from the corresponding | |
863 * NaClInstMrmTable. | |
864 * | |
865 * Used when Opcode32Only or Opcode64Only flag is added, and | |
866 * the flag doesn't match the subarchitecture being modeled. | |
867 */ | |
868 static void NaClRemoveCurrentInstMrmFromInstMrmTable(void) { | |
869 /* Be sure to try opcode in first operand (if applicable), | |
870 * and the default list NACL_NO_MODRM_OPCODE, in case | |
871 * the operand hasn't been processed yet. | |
872 */ | |
873 int mrm_opcode = NACL_NO_MODRM_OPCODE; | |
874 if (current_inst->flags & NACL_IFLAG(OpcodeInModRm)) { | |
875 mrm_opcode = NaClGetOpcodeInModRm(current_inst->opcode_ext); | |
876 } | |
877 | |
878 while (1) { | |
879 uint8_t opcode = current_inst->opcode[current_inst->num_opcode_bytes - 1]; | |
880 NaClMrmInst* prev = NULL; | |
881 NaClMrmInst* next = | |
882 NaClInstMrmTable[opcode][current_inst->prefix][mrm_opcode]; | |
883 DEBUG(NaClLog(LOG_INFO, "Removing [%02x][%s][%d]?", | |
884 opcode, NaClInstPrefixName(current_inst->prefix), | |
885 mrm_opcode)); | |
886 while (NULL != next) { | |
887 if (current_inst_mrm == next) { | |
888 /* Found - remove! */ | |
889 if (NULL == prev) { | |
890 NaClInstMrmTable[opcode][current_inst->prefix][mrm_opcode] = | |
891 next->next; | |
892 } else { | |
893 prev->next = next->next; | |
894 } | |
895 return; | |
896 } else { | |
897 prev = next; | |
898 next = next->next; | |
899 } | |
900 } | |
901 if (mrm_opcode == NACL_NO_MODRM_OPCODE) return; | |
902 mrm_opcode = NACL_NO_MODRM_OPCODE; | |
903 } | |
904 } | |
905 | |
906 static void NaClMoveCurrentToMrmIndex(int mrm_index) { | |
907 /* First remove from default location. */ | |
908 uint8_t opcode = current_inst->opcode[current_inst->num_opcode_bytes - 1]; | |
909 NaClMrmInst* prev = NULL; | |
910 NaClMrmInst* next = | |
911 NaClInstMrmTable[opcode][current_opcode_prefix] | |
912 [NACL_NO_MODRM_OPCODE]; | |
913 while (current_inst_mrm != next) { | |
914 if (next == NULL) return; | |
915 prev = next; | |
916 next = next->next; | |
917 } | |
918 if (NULL == prev) { | |
919 NaClInstMrmTable[opcode][current_opcode_prefix] | |
920 [NACL_NO_MODRM_OPCODE] = | |
921 next->next; | |
922 } else { | |
923 prev->next = next->next; | |
924 } | |
925 current_inst_mrm = next; | |
926 current_inst_mrm->next = NULL; | |
927 NaClInstallCurrentIntoOpcodeMrm(current_opcode_prefix, opcode, mrm_index); | |
928 } | |
929 | |
930 static void NaClPrintlnOpFlags(struct Gio* g, NaClOpFlags flags) { | |
931 int i; | |
932 for (i = 0; i < NaClOpFlagEnumSize; ++i) { | |
933 if (flags & NACL_OPFLAG(i)) { | |
934 gprintf(g, " %s", NaClOpFlagName(i)); | |
935 } | |
936 } | |
937 gprintf(g, "\n"); | |
938 } | |
939 | |
940 static void NaClApplySanityChecksToInst(void); | |
941 | |
942 void NaClDefOpcodeExtension(int opcode) { | |
943 uint8_t byte_opcode; | |
944 byte_opcode = (uint8_t) opcode; | |
945 if ((opcode < 0) || (opcode > 7)) { | |
946 NaClFatalInst("Attempted to define opcode extension not in range [0..7]"); | |
947 } | |
948 if (NACL_EMPTY_IFLAGS == | |
949 (current_inst->flags & NACL_IFLAG(OpcodeInModRm))) { | |
950 NaClFatalInst( | |
951 "Opcode extension in [0..7], but not OpcodeInModRm"); | |
952 } | |
953 DEBUG(NaClLog(LOG_INFO, "Defining opcode extension %d\n", opcode)); | |
954 NaClMoveCurrentToMrmIndex(byte_opcode); | |
955 NaClSetOpcodeInModRm(byte_opcode, ¤t_inst->opcode_ext); | |
956 } | |
957 | |
958 void NaClDefineOpcodeModRmRmExtension(int value) { | |
959 uint8_t byte_opcode = (uint8_t) value; | |
960 if ((value < 0) || (value > 7)) { | |
961 NaClFatalInst("Attempted to defined Opcode modrm rm extension " | |
962 "not in range [0..7]"); | |
963 } | |
964 if (NACL_EMPTY_IFLAGS == | |
965 (current_inst->flags & NACL_IFLAG(OpcodeInModRm))) { | |
966 NaClFatalInst( | |
967 "Opcode modrm rm extension in [0..7], but not OpcodeInModRm"); | |
968 } | |
969 DEBUG(NaClLog(LOG_INFO, "Defining modrm r/m opcode extension %d", value)); | |
970 NaClAddIFlags(NACL_IFLAG(OpcodeInModRmRm)); | |
971 if (current_inst->num_opcode_bytes + 1 < NACL_MAX_ALL_OPCODE_BYTES) { | |
972 NaClSetOpcodeInModRmRm(byte_opcode, ¤t_inst->opcode_ext); | |
973 } else { | |
974 NaClFatalInst("No room for opcode modrm rm extension"); | |
975 } | |
976 } | |
977 | |
978 void NaClDefOpcodeRegisterValue(int r) { | |
979 uint8_t byte_r; | |
980 byte_r = (uint8_t) r; | |
981 if ((r < 0) || (r > 7)) { | |
982 NaClFatalInst("Attempted to define an embedded opcode register value " | |
983 "not in range [0.. 7]"); | |
984 } | |
985 if (NACL_EMPTY_IFLAGS == | |
986 (current_inst->flags & NACL_IFLAG(OpcodePlusR))) { | |
987 NaClFatalInst( | |
988 "Attempted to define opcode register value when not OpcodePlusR"); | |
989 } | |
990 NaClSetOpcodePlusR(byte_r, ¤t_inst->opcode_ext); | |
991 } | |
992 | |
993 /* Same as previous function, except that sanity checks | |
994 * are applied to see if inconsistent information is | |
995 * being defined. | |
996 */ | |
997 void NaClDefOp( | |
998 NaClOpKind kind, | |
999 NaClOpFlags flags) { | |
1000 int index = current_inst->num_operands; | |
1001 DEBUG(NaClLog(LOG_INFO, " %s:", NaClOpKindName(kind)); | |
1002 NaClPrintlnOpFlags(NaClLogGetGio(), flags)); | |
1003 /* If one of the M_Operands, make sure that the ModRm mod field isn't 0x3, | |
1004 * so that we don't return registers. | |
1005 * If one specifies an operand that implies the use of a ModRm byte, add | |
1006 * the corresponding flag. | |
1007 * Note: See section A.2.5 of Intel manual (above) for an explanation of the | |
1008 * ModRm mod field being any value except 0x3, for values having an | |
1009 * explicit memory operand. | |
1010 */ | |
1011 switch (kind) { | |
1012 case M_Operand: | |
1013 case Mb_Operand: | |
1014 case Mw_Operand: | |
1015 case Mv_Operand: | |
1016 case Mo_Operand: | |
1017 case Mdq_Operand: | |
1018 case Mpw_Operand: | |
1019 case Mpv_Operand: | |
1020 case Mpo_Operand: | |
1021 NaClAddIFlags(NACL_IFLAG(OpcodeUsesModRm) | NACL_IFLAG(ModRmModIsnt0x3)); | |
1022 break; | |
1023 case Mmx_N_Operand: | |
1024 kind = Mmx_E_Operand; | |
1025 NaClAddIFlags(NACL_IFLAG(OpcodeUsesModRm) | NACL_IFLAG(ModRmModIs0x3)); | |
1026 /* Automatically fall to the next case. */ | |
1027 case E_Operand: | |
1028 case Eb_Operand: | |
1029 case Ew_Operand: | |
1030 case Ev_Operand: | |
1031 case Eo_Operand: | |
1032 case Edq_Operand: | |
1033 case G_Operand: | |
1034 case Gb_Operand: | |
1035 case Gw_Operand: | |
1036 case Gv_Operand: | |
1037 case Go_Operand: | |
1038 case Gdq_Operand: | |
1039 case Mmx_G_Operand: | |
1040 case Mmx_Gd_Operand: | |
1041 case Xmm_E_Operand: | |
1042 case Xmm_Eo_Operand: | |
1043 case Xmm_G_Operand: | |
1044 case Xmm_Go_Operand: | |
1045 NaClAddIFlags(NACL_IFLAG(OpcodeUsesModRm)); | |
1046 break; | |
1047 default: | |
1048 break; | |
1049 } | |
1050 /* Define and apply sanity checks. */ | |
1051 NaClDefOpInternal(kind, flags); | |
1052 NaClApplySanityChecksToOp(index); | |
1053 } | |
1054 | |
1055 void NaClAddOpFlags(uint8_t operand_index, NaClOpFlags more_flags) { | |
1056 DEBUG( | |
1057 struct Gio* g = NaClLogGetGio(); | |
1058 gprintf(g, "Adding flags:"); | |
1059 NaClPrintlnOpFlags(g, more_flags)); | |
1060 if (operand_index < current_inst->num_operands) { | |
1061 NaClAddBits(current_inst->operands[operand_index].flags, more_flags); | |
1062 NaClApplySanityChecksToOp(operand_index); | |
1063 } else { | |
1064 NaClFatalOp((int) operand_index, "NaClAddOpFlags: index out of range\n"); | |
1065 } | |
1066 } | |
1067 | |
1068 void NaClRemoveOpFlags(uint8_t operand_index, NaClOpFlags more_flags) { | |
1069 DEBUG(NaClLog(LOG_INFO, "Removing flags:"); | |
1070 NaClPrintlnOpFlags(NaClLogGetGio(), more_flags)); | |
1071 if (operand_index < current_inst->num_operands) { | |
1072 NaClRemoveBits(current_inst->operands[operand_index].flags, more_flags); | |
1073 NaClApplySanityChecksToOp(operand_index); | |
1074 } else { | |
1075 NaClFatalOp((int) operand_index, "NaClRemoveOpFlags: index out of range\n"); | |
1076 } | |
1077 } | |
1078 | |
1079 void NaClAddOpFormat(uint8_t operand_index, const char* format) { | |
1080 DEBUG(NaClLog(LOG_INFO, "Adding format[%"NACL_PRIu8"]: '%s'\n", | |
1081 operand_index, format)); | |
1082 if (operand_index < current_inst->num_operands) { | |
1083 current_inst->operands[operand_index].format_string = | |
1084 strdup(format); | |
1085 } else { | |
1086 NaClFatalOp((int) operand_index, "NaClAddOpFormat: index out of range\n"); | |
1087 } | |
1088 } | |
1089 | |
1090 /* Returns true if the given opcode flags are consistent | |
1091 * with the value of NACL_FLAGS_run_mode. | |
1092 */ | |
1093 static Bool NaClIFlagsMatchesRunMode(NaClIFlags flags) { | |
1094 if (flags & NACL_IFLAG(Opcode32Only)) { | |
1095 if (flags & NACL_IFLAG(Opcode64Only)) { | |
1096 NaClFatal("Can't specify both Opcode32Only and Opcode64Only"); | |
1097 } | |
1098 return NACL_FLAGS_run_mode == X86_32; | |
1099 } else if (flags & NACL_IFLAG(Opcode64Only)) { | |
1100 return NACL_FLAGS_run_mode == X86_64; | |
1101 } else if (flags & NACL_IFLAG(Opcode32Only)) { | |
1102 return NACL_FLAGS_run_mode == X86_32; | |
1103 } else { | |
1104 return TRUE; | |
1105 } | |
1106 } | |
1107 | |
1108 /* Check that the flags defined for an opcode make sense. */ | |
1109 static void NaClApplySanityChecksToInst(void) { | |
1110 const NaClIFlags operand_sizes = NaClOperandSizes(current_inst); | |
1111 if (!apply_sanity_checks) return; | |
1112 if ((current_inst->flags & NACL_IFLAG(Opcode32Only)) && | |
1113 (current_inst->flags & NACL_IFLAG(Opcode64Only))) { | |
1114 NaClFatalInst("Can't be both Opcode32Only and Opcode64Only"); | |
1115 } | |
1116 /* Fix case where both OperandSize_w and SizeIgnoresData16 are specified. */ | |
1117 if ((current_inst->flags & NACL_IFLAG(OperandSize_w)) && | |
1118 (current_inst->flags & NACL_IFLAG(SizeIgnoresData16))) { | |
1119 NaClRemoveBits(current_inst->flags, NACL_IFLAG(OperandSize_w)); | |
1120 } | |
1121 if ((current_inst->flags & NACL_IFLAG(OperandSize_b)) && | |
1122 (current_inst->flags & (NACL_IFLAG(OperandSize_w) | | |
1123 NACL_IFLAG(OperandSize_v) | | |
1124 NACL_IFLAG(OperandSize_o) | | |
1125 NACL_IFLAG(OperandSizeDefaultIs64) | | |
1126 NACL_IFLAG(OperandSizeForce64)))) { | |
1127 NaClFatalInst( | |
1128 "Can't specify other operand sizes when specifying OperandSize_b"); | |
1129 } | |
1130 if ((current_inst->flags & NACL_IFLAG(OpcodeInModRm)) && | |
1131 (current_inst->flags & NACL_IFLAG(OpcodePlusR))) { | |
1132 NaClFatalInst( | |
1133 "Can't specify both OpcodeInModRm and OpcodePlusR"); | |
1134 } | |
1135 if ((current_inst->flags & NACL_IFLAG(OpcodeHasImmed_b)) && | |
1136 (operand_sizes == NACL_IFLAG(OperandSize_b))) { | |
1137 NaClFatalInst( | |
1138 "Size implied by OperandSize_b, use OpcodeHasImmed " | |
1139 "rather than OpcodeHasImmed_b"); | |
1140 } | |
1141 if ((current_inst->flags & NACL_IFLAG(OpcodeHasImmed_w)) && | |
1142 (operand_sizes == NACL_IFLAG(OperandSize_w))) { | |
1143 NaClFatalInst( | |
1144 "Size implied by OperandSize_w, use OpcodeHasImmed " | |
1145 "rather than OpcodeHasImmed_w"); | |
1146 } | |
1147 if ((current_inst->flags & NACL_IFLAG(OpcodeHasImmed_v)) && | |
1148 (operand_sizes == NACL_IFLAG(OperandSize_v))) { | |
1149 NaClFatalInst( | |
1150 "Size implied by OperandSize_v, use OpcodeHasImmed " | |
1151 "rather than OpcodeHasImmed_v"); | |
1152 } | |
1153 if ((current_inst->flags & NACL_IFLAG(ModRmModIs0x3)) && | |
1154 (NACL_EMPTY_IFLAGS == (current_inst->flags & | |
1155 (NACL_IFLAG(OpcodeUsesModRm) | | |
1156 NACL_IFLAG(OpcodeInModRm))))) { | |
1157 NaClFatalInst( | |
1158 "Can't specify ModRmModIs0x3 unless Opcode has modrm byte"); | |
1159 } | |
1160 if ((current_inst->flags & NACL_IFLAG(ModRmModIs0x3)) && | |
1161 (current_inst->flags & NACL_IFLAG(ModRmModIsnt0x3))) { | |
1162 NaClFatalInst( | |
1163 "Can't specify ModRmModIs0x3 and ModRmModIsnt0x3"); | |
1164 } | |
1165 } | |
1166 | |
1167 static void NaClDefBytes(uint8_t opcode) { | |
1168 uint8_t index; | |
1169 current_inst->prefix = current_opcode_prefix; | |
1170 | |
1171 /* Start by clearing all entries. */ | |
1172 for (index = 0; index < NACL_MAX_ALL_OPCODE_BYTES; ++index) { | |
1173 current_inst->opcode[index] = 0x00; | |
1174 } | |
1175 | |
1176 /* Now fill in non-final bytes. */ | |
1177 index = 0; | |
1178 switch (current_opcode_prefix) { | |
1179 case NoPrefix: | |
1180 break; | |
1181 case Prefix0F: | |
1182 case Prefix660F: | |
1183 case PrefixF20F: | |
1184 case PrefixF30F: | |
1185 current_inst->opcode[0] = 0x0F; | |
1186 index = 1; | |
1187 break; | |
1188 case Prefix0F0F: | |
1189 current_inst->opcode[0] = 0x0F; | |
1190 current_inst->opcode[1] = 0x0F; | |
1191 index = 2; | |
1192 break; | |
1193 case Prefix0F38: | |
1194 case Prefix660F38: | |
1195 case PrefixF20F38: | |
1196 current_inst->opcode[0] = 0x0F; | |
1197 current_inst->opcode[1] = 0x38; | |
1198 index = 2; | |
1199 break; | |
1200 case Prefix0F3A: | |
1201 case Prefix660F3A: | |
1202 current_inst->opcode[0] = 0x0F; | |
1203 current_inst->opcode[1] = 0x3A; | |
1204 index = 2; | |
1205 break; | |
1206 case PrefixD8: | |
1207 current_inst->opcode[0] = 0xD8; | |
1208 index = 1; | |
1209 break; | |
1210 case PrefixD9: | |
1211 current_inst->opcode[0] = 0xD9; | |
1212 index = 1; | |
1213 break; | |
1214 case PrefixDA: | |
1215 current_inst->opcode[0] = 0xDA; | |
1216 index = 1; | |
1217 break; | |
1218 case PrefixDB: | |
1219 current_inst->opcode[0] = 0xDB; | |
1220 index = 1; | |
1221 break; | |
1222 case PrefixDC: | |
1223 current_inst->opcode[0] = 0xDC; | |
1224 index = 1; | |
1225 break; | |
1226 case PrefixDD: | |
1227 current_inst->opcode[0] = 0xDD; | |
1228 index = 1; | |
1229 break; | |
1230 case PrefixDE: | |
1231 current_inst->opcode[0] = 0xDE; | |
1232 index = 1; | |
1233 break; | |
1234 case PrefixDF: | |
1235 current_inst->opcode[0] = 0xDF; | |
1236 index = 1; | |
1237 break; | |
1238 default: | |
1239 NaClFatal("Unrecognized opcode prefix in NaClDefBytes"); | |
1240 break; | |
1241 } | |
1242 | |
1243 /* Now add final byte. */ | |
1244 current_inst->opcode[index] = opcode; | |
1245 current_inst->num_opcode_bytes = index + 1; | |
1246 } | |
1247 | |
1248 static void NaClPrintInstDescriptor(struct Gio* out, | |
1249 const NaClInstPrefix prefix, | |
1250 const int opcode, | |
1251 const int modrm_index) { | |
1252 if (NACL_NO_MODRM_OPCODE == modrm_index) { | |
1253 gprintf(out, "%s 0x%02x: ", | |
1254 NaClInstPrefixName(prefix), opcode); | |
1255 } else { | |
1256 gprintf(out, "%s 0x%02x /%x: ", | |
1257 NaClInstPrefixName(prefix), opcode, modrm_index); | |
1258 } | |
1259 } | |
1260 | |
1261 static void VerifyModRmOpcodeRange(NaClInstPrefix prefix, | |
1262 uint8_t opcode, | |
1263 uint8_t modrm_opcode) { | |
1264 if (modrm_opcode > NACL_NO_MODRM_OPCODE) { | |
1265 NaClPrintInstDescriptor(NaClLogGetGio(), prefix, opcode, modrm_opcode); | |
1266 NaClFatal("Illegal modrm opcode specification when defined opcode choices"); | |
1267 } | |
1268 } | |
1269 | |
1270 void NaClDefPrefixInstMrmChoices_32_64(const NaClInstPrefix prefix, | |
1271 const uint8_t opcode, | |
1272 const uint8_t modrm_opcode, | |
1273 const int count_32, | |
1274 const int count_64) { | |
1275 VerifyModRmOpcodeRange(prefix, opcode, modrm_opcode); | |
1276 if (NaClInstCount[opcode][prefix][modrm_opcode] != | |
1277 NACL_DEFAULT_CHOICE_COUNT) { | |
1278 NaClPrintInstDescriptor(NaClLogGetGio(), prefix, opcode, modrm_opcode); | |
1279 NaClFatal("Redefining NaClOpcode choice count"); | |
1280 } | |
1281 if (NACL_FLAGS_run_mode == X86_32) { | |
1282 NaClInstCount[opcode][prefix][modrm_opcode] = count_32; | |
1283 } else if (NACL_FLAGS_run_mode == X86_64) { | |
1284 NaClInstCount[opcode][prefix][modrm_opcode] = count_64; | |
1285 } | |
1286 } | |
1287 | |
1288 void NaClDefPrefixInstChoices(const NaClInstPrefix prefix, | |
1289 const uint8_t opcode, | |
1290 const int count) { | |
1291 NaClDefPrefixInstChoices_32_64(prefix, opcode, count, count); | |
1292 } | |
1293 | |
1294 void NaClDefPrefixInstMrmChoices(const NaClInstPrefix prefix, | |
1295 const uint8_t opcode, | |
1296 const uint8_t modrm_opcode, | |
1297 const int count) { | |
1298 NaClDefPrefixInstMrmChoices_32_64(prefix, opcode, modrm_opcode, | |
1299 count, count); | |
1300 } | |
1301 | |
1302 void NaClDefPrefixInstChoices_32_64(const NaClInstPrefix prefix, | |
1303 const uint8_t opcode, | |
1304 const int count_32, | |
1305 const int count_64) { | |
1306 NaClDefPrefixInstMrmChoices_32_64(prefix, opcode, NACL_NO_MODRM_OPCODE, | |
1307 count_32, count_64); | |
1308 } | |
1309 | |
1310 /* Adds opcode flags corresponding to REP/REPNE flags if defined by | |
1311 * the prefix. | |
1312 */ | |
1313 static void NaClAddRepPrefixFlagsIfApplicable(void) { | |
1314 switch (current_opcode_prefix) { | |
1315 case Prefix660F: | |
1316 case Prefix660F38: | |
1317 case Prefix660F3A: | |
1318 NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeAllowsData16) | | |
1319 NACL_IFLAG(SizeIgnoresData16)); | |
1320 break; | |
1321 case PrefixF20F: | |
1322 case PrefixF20F38: | |
1323 NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeAllowsRepne)); | |
1324 break; | |
1325 case PrefixF30F: | |
1326 NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeAllowsRep)); | |
1327 break; | |
1328 default: | |
1329 break; | |
1330 } | |
1331 } | |
1332 | |
1333 /* Define the next opcode (instruction), initializing with | |
1334 * no operands. | |
1335 */ | |
1336 static void NaClDefInstInternal( | |
1337 const uint8_t opcode, | |
1338 const NaClInstType insttype, | |
1339 NaClIFlags flags, | |
1340 const NaClMnemonic name, | |
1341 Bool no_install) { | |
1342 /* TODO(karl) If we can deduce a more specific prefix that | |
1343 * must be used, due to the flags associated with the opcode, | |
1344 * then put on the more specific prefix list. This will make | |
1345 * the defining of instructions easier, in that the caller doesn't | |
1346 * need to specify the prefix to use. | |
1347 */ | |
1348 | |
1349 /* Before starting, install an opcode sequence if applicable. */ | |
1350 if (NULL != current_cand_inst_node) { | |
1351 current_inst_node = current_cand_inst_node; | |
1352 } | |
1353 current_cand_inst_node = NULL; | |
1354 | |
1355 /* Before starting, expand appropriate implicit flag assumnptions. */ | |
1356 if (flags & NACL_IFLAG(OpcodeLtC0InModRm)) { | |
1357 NaClAddBits(flags, NACL_IFLAG(OpcodeInModRm) | NACL_IFLAG(ModRmModIsnt0x3)); | |
1358 } | |
1359 | |
1360 DEBUG(NaClLog(LOG_INFO, "Define %s %"NACL_PRIx8": %s(%02x)\n", | |
1361 NaClInstPrefixName(current_opcode_prefix), | |
1362 opcode, NaClMnemonicName(name), name); | |
1363 NaClIFlagsPrint(NaClLogGetGio(), flags)); | |
1364 | |
1365 if (NaClMnemonicEnumSize <= name) { | |
1366 NaClFatal("Badly defined mnemonic name"); | |
1367 } | |
1368 | |
1369 if (kNaClInstTypeRange <= insttype) { | |
1370 NaClFatal("Badly defined inst type"); | |
1371 } | |
1372 | |
1373 /* Create opcode and initialize */ | |
1374 current_inst_mrm = (NaClMrmInst*) malloc(sizeof(NaClMrmInst)); | |
1375 if (NULL == current_inst_mrm) { | |
1376 NaClFatal("NaClDefInst: malloc failed"); | |
1377 } | |
1378 DEBUG(NaClLog(LOG_INFO, | |
1379 "current = %p\n", (void*) current_inst_mrm)); | |
1380 current_inst_mrm->next = NULL; | |
1381 current_inst = &(current_inst_mrm->inst); | |
1382 NaClDefBytes(opcode); | |
1383 current_inst->insttype = insttype; | |
1384 current_inst->flags = NACL_EMPTY_IFLAGS; | |
1385 current_inst->name = name; | |
1386 current_inst->opcode_ext = 0; | |
1387 current_inst->next_rule = NULL; | |
1388 | |
1389 /* undefine all operands. */ | |
1390 current_inst->num_operands = 0; | |
1391 current_inst->operands = tables.operands + tables.operands_size; | |
1392 | |
1393 NaClAddIFlags(flags); | |
1394 | |
1395 NaClAddRepPrefixFlagsIfApplicable(); | |
1396 | |
1397 NaClApplySanityChecksToInst(); | |
1398 | |
1399 if (no_install || !NaClIFlagsMatchesRunMode(flags)) { | |
1400 return; | |
1401 } | |
1402 | |
1403 if (NULL == current_inst_node) { | |
1404 /* Install NaClOpcode. */ | |
1405 DEBUG(NaClLog(LOG_INFO, " standard install\n")); | |
1406 if (NULL == tables.inst_table[opcode][current_opcode_prefix]) { | |
1407 tables.inst_table[opcode][current_opcode_prefix] = current_inst; | |
1408 } else { | |
1409 NaClModeledInst* next = tables.inst_table[opcode][current_opcode_prefix]; | |
1410 while (NULL != next->next_rule) { | |
1411 next = next->next_rule; | |
1412 } | |
1413 next->next_rule = current_inst; | |
1414 } | |
1415 /* Install assuming no modrm opcode. Let NaClDefOp move if needed. */ | |
1416 NaClInstallCurrentIntoOpcodeMrm(current_opcode_prefix, opcode, | |
1417 NACL_NO_MODRM_OPCODE); | |
1418 } else if (NULL == current_inst_node->matching_inst) { | |
1419 DEBUG(NaClLog(LOG_INFO, " instruction sequence install\n")); | |
1420 current_inst_node->matching_inst = current_inst; | |
1421 } else { | |
1422 NaClFatalInst( | |
1423 "Can't define more than one opcode for the same opcode sequence"); | |
1424 } | |
1425 } | |
1426 | |
1427 void NaClDefInst( | |
1428 const uint8_t opcode, | |
1429 const NaClInstType insttype, | |
1430 NaClIFlags flags, | |
1431 const NaClMnemonic name) { | |
1432 NaClDefInstInternal(opcode, insttype, flags, name, FALSE); | |
1433 } | |
1434 | |
1435 /* Simple (fast hack) routine to extract a byte value from a character string. | |
1436 */ | |
1437 static int NaClExtractByte(const char* chars, const char* opcode_seq) { | |
1438 char buffer[3]; | |
1439 int i; | |
1440 for (i = 0; i < 2; ++i) { | |
1441 char ch = *(chars++); | |
1442 if ('\0' == ch) { | |
1443 NaClLog(LOG_ERROR, | |
1444 "Odd number of characters in opcode sequence: '%s'\n", | |
1445 opcode_seq); | |
1446 NaClFatal("Fix before continuing!"); | |
1447 } | |
1448 buffer[i] = ch; | |
1449 } | |
1450 buffer[2] = '\0'; | |
1451 return strtoul(buffer, NULL, 16); | |
1452 } | |
1453 | |
1454 static NaClModeledInstNode* NaClNewInstNode(uint8_t byte) { | |
1455 NaClModeledInstNode* root = | |
1456 (NaClModeledInstNode*) malloc(sizeof(NaClModeledInstNode)); | |
1457 root->matching_byte = byte; | |
1458 root->matching_inst = NULL; | |
1459 root->success = NULL; | |
1460 root->fail = NULL; | |
1461 return root; | |
1462 } | |
1463 | |
1464 /* Install an opcode sequence into the instruction trie. */ | |
1465 static void NaClDefInstSeq(const char* opcode_seq) { | |
1466 /* Next is a (reference) pointer to the next node. The reference | |
1467 * is used so that we can easily update the trie when we add nodes. | |
1468 */ | |
1469 NaClModeledInstNode** next = &tables.inst_node_root; | |
1470 /* Last is the last visited node in trie that is still matching | |
1471 * the opcode sequence being added. | |
1472 */ | |
1473 NaClModeledInstNode* last = NULL; | |
1474 /* Index is the position of the next byte in the opcode sequence. */ | |
1475 int index = 0; | |
1476 | |
1477 /* First check that opcode sequence not defined twice without a corresponding | |
1478 * call to NaClDefInst. | |
1479 */ | |
1480 if (NULL != current_cand_inst_node) { | |
1481 NaClLog(LOG_ERROR, | |
1482 "Multiple definitions for opcode sequence: '%s'\n", opcode_seq); | |
1483 NaClFatal("Fix before continuing!"); | |
1484 } | |
1485 | |
1486 /* Now install into lookup trie. */ | |
1487 while (opcode_seq[index]) { | |
1488 uint8_t byte = (uint8_t) NaClExtractByte(opcode_seq + index, opcode_seq); | |
1489 if (index >= 2 * NACL_MAX_BYTES_PER_X86_INSTRUCTION) { | |
1490 NaClLog(LOG_ERROR, | |
1491 "Too many bytes specified for opcode sequence: '%s'\n", | |
1492 opcode_seq); | |
1493 NaClFatal("Fix before continuing!\n"); | |
1494 } | |
1495 if ((NULL == *next) || (byte < (*next)->matching_byte)) { | |
1496 /* byte not in trie, add. */ | |
1497 NaClModeledInstNode* node = NaClNewInstNode(byte); | |
1498 node->fail = *next; | |
1499 *next = node; | |
1500 } | |
1501 if (byte == (*next)->matching_byte) { | |
1502 last = *next; | |
1503 next = &((*next)->success); | |
1504 index += 2; | |
1505 } else { | |
1506 next = &((*next)->fail); | |
1507 } | |
1508 } | |
1509 /* Last points to matching node, make it candidate instruction. */ | |
1510 current_cand_inst_node = last; | |
1511 } | |
1512 | |
1513 /* Apply checks to current instruction flags, and update model as | |
1514 * appropriate. | |
1515 */ | |
1516 static void NaClRecheckIFlags(void) { | |
1517 if (!NaClIFlagsMatchesRunMode(current_inst->flags)) { | |
1518 NaClRemoveCurrentInstMrmFromInstTable(); | |
1519 NaClRemoveCurrentInstMrmFromInstMrmTable(); | |
1520 } | |
1521 /* If the instruction has an opcode in modrm, then it uses modrm. */ | |
1522 if (NACL_EMPTY_IFLAGS != (current_inst->flags & NACL_IFLAG(OpcodeInModRm))) { | |
1523 NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeUsesModRm)); | |
1524 } | |
1525 /* If the instruction allows a two byte value, add DATA16 flag. */ | |
1526 if (NACL_EMPTY_IFLAGS != (current_inst->flags & | |
1527 (NACL_IFLAG(OperandSize_w) | | |
1528 NACL_IFLAG(OpcodeHasImmed_z)))) { | |
1529 NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeAllowsData16)); | |
1530 } | |
1531 /* If the instruction uses the modrm rm field as an opcode value, | |
1532 * it also requires that the modrm mod field is 0x3. | |
1533 */ | |
1534 if (current_inst->flags & NACL_IFLAG(OpcodeInModRmRm)) { | |
1535 NaClAddBits(current_inst->flags, NACL_IFLAG(ModRmModIs0x3)); | |
1536 } | |
1537 NaClApplySanityChecksToInst(); | |
1538 } | |
1539 | |
1540 void NaClAddIFlags(NaClIFlags more_flags) { | |
1541 DEBUG( | |
1542 struct Gio* g = NaClLogGetGio(); | |
1543 NaClLog(LOG_INFO, "Adding instruction flags: "); | |
1544 NaClIFlagsPrint(g, more_flags); | |
1545 gprintf(g, "\n")); | |
1546 NaClAddBits(current_inst->flags, more_flags); | |
1547 NaClRecheckIFlags(); | |
1548 } | |
1549 | |
1550 void NaClRemoveIFlags(NaClIFlags less_flags) { | |
1551 DEBUG( | |
1552 struct Gio* g = NaClLogGetGio(); | |
1553 NaClLog(LOG_INFO, "Removing instruction flags: "); | |
1554 NaClIFlagsPrint(g, less_flags); | |
1555 gprintf(g, "\n")); | |
1556 NaClRemoveBits(current_inst->flags, less_flags); | |
1557 NaClRecheckIFlags(); | |
1558 } | |
1559 | |
1560 void NaClDelaySanityChecks(void) { | |
1561 apply_sanity_checks = FALSE; | |
1562 } | |
1563 | |
1564 void NaClApplySanityChecks(void) { | |
1565 apply_sanity_checks = TRUE; | |
1566 if (NULL != current_inst) { | |
1567 int i; | |
1568 NaClApplySanityChecksToInst(); | |
1569 for (i = 0; i < current_inst->num_operands; i++) { | |
1570 NaClApplySanityChecksToOp(i); | |
1571 } | |
1572 } | |
1573 } | |
1574 | |
1575 static void NaClInitInstTables(void) { | |
1576 int i; | |
1577 NaClInstPrefix prefix; | |
1578 int j; | |
1579 /* Before starting, verify that we have defined NaClOpcodeFlags | |
1580 * and NaClOpFlags big enough to hold the flags associated with it. | |
1581 */ | |
1582 assert(NaClIFlagEnumSize <= sizeof(NaClIFlags) * 8); | |
1583 assert(NaClOpFlagEnumSize <= sizeof(NaClOpFlags) * 8); | |
1584 assert(NaClDisallowsFlagEnumSize <= sizeof(NaClDisallowsFlags) * 8); | |
1585 | |
1586 for (i = 0; i < NCDTABLESIZE; ++i) { | |
1587 for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) { | |
1588 tables.inst_table[i][prefix] = NULL; | |
1589 for (j = 0; j <= NACL_NO_MODRM_OPCODE; ++j) { | |
1590 NaClInstCount[i][prefix][j] = NACL_DEFAULT_CHOICE_COUNT; | |
1591 } | |
1592 } | |
1593 NaClPrefixTable[i] = "0"; | |
1594 } | |
1595 NaClDefInstPrefix(NoPrefix); | |
1596 NaClDefInstInternal(0x0, NACLi_INVALID, 0, InstInvalid, TRUE); | |
1597 tables.undefined_inst = current_inst; | |
1598 } | |
1599 | |
1600 static void NaClDefPrefixBytes(void) { | |
1601 NaClEncodePrefixName(kValueSEGES, "kPrefixSEGES"); | |
1602 NaClEncodePrefixName(kValueSEGCS, "kPrefixSEGCS"); | |
1603 NaClEncodePrefixName(kValueSEGSS, "kPrefixSEGSS"); | |
1604 NaClEncodePrefixName(kValueSEGDS, "kPrefixSEGDS"); | |
1605 NaClEncodePrefixName(kValueSEGFS, "kPrefixSEGFS"); | |
1606 NaClEncodePrefixName(kValueSEGGS, "kPrefixSEGGS"); | |
1607 NaClEncodePrefixName(kValueDATA16, "kPrefixDATA16"); | |
1608 NaClEncodePrefixName(kValueADDR16, "kPrefixADDR16"); | |
1609 NaClEncodePrefixName(kValueLOCK, "kPrefixLOCK"); | |
1610 NaClEncodePrefixName(kValueREPNE, "kPrefixREPNE"); | |
1611 NaClEncodePrefixName(kValueREP, "kPrefixREP"); | |
1612 | |
1613 if (NACL_FLAGS_run_mode == X86_64) { | |
1614 int i; | |
1615 for (i = 0; i < 16; ++i) { | |
1616 NaClEncodePrefixName(0x40+i, "kPrefixREX"); | |
1617 } | |
1618 } | |
1619 } | |
1620 | |
1621 /* Define the given character sequence, associated with the given byte | |
1622 * opcode and instruction mnemonic, as a nop. | |
1623 */ | |
1624 static void NaClDefNopLikeSeq(const char* sequence, uint8_t opcode, | |
1625 NaClMnemonic name ) { | |
1626 NaClDefInstSeq(sequence); | |
1627 NaClDefInst(opcode, NACLi_386, NACL_EMPTY_IFLAGS, name); | |
1628 } | |
1629 | |
1630 /* Define the given character sequence, associated with the given byte | |
1631 * opcode, as a nop. | |
1632 */ | |
1633 static void NaClDefNopSeq(const char* sequence, uint8_t opcode) { | |
1634 NaClDefNopLikeSeq(sequence, opcode, InstNop); | |
1635 } | |
1636 | |
1637 static void NaClDefNops(void) { | |
1638 /* Note: The following could be recognized as nops, but are already | |
1639 * parsed and accepted by the validator. | |
1640 * | |
1641 * 89 f6 mov %esi, %esi | |
1642 * 8d742600 lea %esi, [%rsi] | |
1643 * 8d7600 lea %esi, [%rsi] | |
1644 * 8d b6 00 00 00 00 lea %esi, [%rsi] | |
1645 * 8d b4 26 00 00 00 00 lea %esi, [%rsi] | |
1646 * 8d bc 27 00 00 00 00 lea %edi, [%rdi] | |
1647 * 8d bf 00 00 00 00 lea %edi, [%rdi] | |
1648 * 0f 1f 00 nop | |
1649 * 0f 1f 40 00 nop | |
1650 * 0f 1f 44 00 00 nop | |
1651 * 0f 1f 80 00 00 00 00 nop | |
1652 * 0f 1f 84 00 00 00 00 00 nop | |
1653 */ | |
1654 /* Note: For performance reasons, the function NaClMaybeHardCodedNop in | |
1655 * src/trusted/validator/x86/decoder/nc_inst_state.c | |
1656 * has been tuned to not look for these Nop instructions, unless | |
1657 * the opcode byte sequence is one of "90", "0f1f", or "0f0b". If you add | |
1658 * any nop instruction that doesn't meet this criteria, be sure | |
1659 * to update NaClMaybeHardCodedNop accordingly. | |
1660 */ | |
1661 /* nop */ | |
1662 NaClDefNopSeq("90", 0x90); | |
1663 NaClDefNopSeq("6690", 0x90); | |
1664 NaClDefNopLikeSeq("f390", 0x90, InstPause); | |
1665 /* nop [%[re]ax] */ | |
1666 NaClDefNopSeq("0f1f00", 0x1f); | |
1667 /* nop [%[re]ax+0] */ | |
1668 NaClDefNopSeq("0f1f4000", 0x1f); | |
1669 /* nop [%[re]ax*1+0] */ | |
1670 NaClDefNopSeq("0f1f440000", 0x1f); | |
1671 /* nop [%[re]ax+%[re]ax*1+0] */ | |
1672 NaClDefNopSeq("660f1f440000", 0x1f); | |
1673 /* nop [%[re]ax+0] */ | |
1674 NaClDefNopSeq("0f1f8000000000", 0x1f); | |
1675 /* nop [%[re]ax+%[re]ax*1+0] */ | |
1676 NaClDefNopSeq("0f1f840000000000", 0x1f); | |
1677 /* nop [%[re]ax+%[re]ax+1+0] */ | |
1678 NaClDefNopSeq("660f1f840000000000", 0x1f); | |
1679 /* nop %cs:[%re]ax+%[re]ax*1+0] */ | |
1680 NaClDefNopSeq("662e0f1f840000000000", 0x1f); | |
1681 /* nop %cs:[%re]ax+%[re]ax*1+0] */ | |
1682 NaClDefNopSeq("66662e0f1f840000000000", 0x1f); | |
1683 /* nop %cs:[%re]ax+%[re]ax*1+0] */ | |
1684 NaClDefNopSeq("6666662e0f1f840000000000", 0x1f); | |
1685 /* nop %cs:[%re]ax+%[re]ax*1+0] */ | |
1686 NaClDefNopSeq("666666662e0f1f840000000000", 0x1f); | |
1687 /* nop %cs:[%re]ax+%[re]ax*1+0] */ | |
1688 NaClDefNopSeq("66666666662e0f1f840000000000", 0x1f); | |
1689 /* nop %cs:[%re]ax+%[re]ax*1+0] */ | |
1690 NaClDefNopSeq("6666666666662e0f1f840000000000", 0x1f); | |
1691 /* UD2 */ | |
1692 NaClDefNopLikeSeq("0f0b", 0x0b, InstUd2); | |
1693 } | |
1694 | |
1695 /* Build the set of x64 opcode (instructions). */ | |
1696 static void NaClBuildInstTables(void) { | |
1697 struct NaClSymbolTable* st = NaClSymbolTableCreate(5, NULL); | |
1698 | |
1699 /* Create common (global) symbol table with instruction set presumptions. */ | |
1700 NaClSymbolTablePutText( | |
1701 "sp", ((X86_32 == NACL_FLAGS_run_mode) ? "esp" : "rsp"), st); | |
1702 NaClSymbolTablePutText( | |
1703 "ip", ((X86_32 == NACL_FLAGS_run_mode) ? "eip" : "rip"), st); | |
1704 NaClSymbolTablePutText( | |
1705 "bp", ((X86_32 == NACL_FLAGS_run_mode) ? "ebp" : "rbp"), st); | |
1706 | |
1707 NaClInitInstTables(); | |
1708 NaClDefPrefixBytes(); | |
1709 NaClDefOneByteInsts(st); | |
1710 NaClDef0FInsts(st); | |
1711 NaClDefSseInsts(st); | |
1712 NaClDefX87Insts(st); | |
1713 NaClDefNops(); | |
1714 | |
1715 NaClSymbolTableDestroy(st); | |
1716 } | |
1717 | |
1718 static int NaClInstMrmListLength(NaClMrmInst* next) { | |
1719 int count = 0; | |
1720 while (NULL != next) { | |
1721 ++count; | |
1722 next = next->next; | |
1723 } | |
1724 return count; | |
1725 } | |
1726 | |
1727 static void NaClFatalChoiceCount(const int expected, | |
1728 const int found, | |
1729 const NaClInstPrefix prefix, | |
1730 const int opcode, | |
1731 const int modrm_index, | |
1732 NaClMrmInst* insts) { | |
1733 struct Gio* g = NaClLogGetGio(); | |
1734 NaClPrintInstDescriptor(g, prefix, opcode, modrm_index); | |
1735 NaClLog(LOG_ERROR, "Expected %d rules but found %d:\n", expected, found); | |
1736 while (NULL != insts) { | |
1737 NaClModeledInstPrint(g, &(insts->inst)); | |
1738 insts = insts->next; | |
1739 } | |
1740 NaClFatal("fix before continuing...\n"); | |
1741 } | |
1742 | |
1743 /* Verify that the number of possible choies for each prefix:opcode matches | |
1744 * what was explicitly defined. | |
1745 */ | |
1746 static void NaClVerifyInstCounts(void) { | |
1747 int i, j; | |
1748 NaClInstPrefix prefix; | |
1749 for (i = 0; i < NCDTABLESIZE; ++i) { | |
1750 for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) { | |
1751 for (j = 0; j < NACL_MODRM_OPCODE_SIZE; ++j) { | |
1752 NaClMrmInst* insts = NaClInstMrmTable[i][prefix][j]; | |
1753 int found = NaClInstMrmListLength(insts); | |
1754 int expected = NaClInstCount[i][prefix][j]; | |
1755 if (expected == NACL_DEFAULT_CHOICE_COUNT) { | |
1756 if (found > 1) { | |
1757 NaClFatalChoiceCount(1, found, prefix, i, j, insts); | |
1758 } | |
1759 } else if (expected != found) { | |
1760 NaClFatalChoiceCount(expected, found, prefix, i, j, insts); | |
1761 } | |
1762 } | |
1763 } | |
1764 } | |
1765 } | |
1766 | |
1767 /* Removes X86-32 specific flags from the given instruction. */ | |
1768 static void NaClInstRemove32Stuff(NaClModeledInst* inst) { | |
1769 NaClRemoveBits(inst->flags, NACL_IFLAG(Opcode32Only)); | |
1770 } | |
1771 | |
1772 /* Removes X86-64 specific flags from the given instruction. */ | |
1773 static void NaClInstRemove64Stuff(NaClModeledInst* inst) { | |
1774 NaClRemoveBits(inst->flags, | |
1775 NACL_IFLAG(OpcodeRex) | | |
1776 NACL_IFLAG(OpcodeUsesRexW) | | |
1777 NACL_IFLAG(OpcodeHasRexR) | | |
1778 NACL_IFLAG(Opcode64Only) | | |
1779 NACL_IFLAG(OperandSize_o) | | |
1780 NACL_IFLAG(AddressSize_o) | | |
1781 NACL_IFLAG(OperandSizeDefaultIs64) | | |
1782 NACL_IFLAG(OperandSizeForce64)); | |
1783 } | |
1784 | |
1785 /* Simplifies the instructions if possible. Mostly removes flags that | |
1786 * don't correspond to the run mode. | |
1787 */ | |
1788 static void NaClSimplifyIfApplicable(void) { | |
1789 int i; | |
1790 for (i = 0; i < NCDTABLESIZE; ++i) { | |
1791 NaClInstPrefix prefix; | |
1792 for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) { | |
1793 NaClModeledInst* next = tables.inst_table[i][prefix]; | |
1794 while (NULL != next) { | |
1795 if (X86_64 != NACL_FLAGS_run_mode) { | |
1796 NaClInstRemove64Stuff(next); | |
1797 } | |
1798 if (X86_32 != NACL_FLAGS_run_mode) { | |
1799 NaClInstRemove32Stuff(next); | |
1800 } | |
1801 /* Remove size only flags, since already compiled into tables. */ | |
1802 NaClRemoveBits(next->flags, | |
1803 NACL_IFLAG(Opcode64Only) | NACL_IFLAG(Opcode32Only)); | |
1804 next = next->next_rule; | |
1805 } | |
1806 } | |
1807 } | |
1808 } | |
1809 | |
1810 /* Prints out the set of defined instruction flags. */ | |
1811 static void NaClIFlagsPrintInternal(struct Gio* f, NaClIFlags flags) { | |
1812 if (flags) { | |
1813 int i; | |
1814 Bool first = TRUE; | |
1815 for (i = 0; i < NaClIFlagEnumSize; ++i) { | |
1816 if (flags & NACL_IFLAG(i)) { | |
1817 if (first) { | |
1818 first = FALSE; | |
1819 } else { | |
1820 gprintf(f, " | "); | |
1821 } | |
1822 gprintf(f, "NACL_IFLAG(%s)", NaClIFlagName(i)); | |
1823 } | |
1824 } | |
1825 } else { | |
1826 gprintf(f, "NACL_EMPTY_IFLAGS"); | |
1827 } | |
1828 } | |
1829 | |
1830 /* Prints out the set of defined Operand flags. */ | |
1831 static void NaClOpFlagsPrintInternal(struct Gio* f, NaClOpFlags flags) { | |
1832 if (flags) { | |
1833 NaClOpFlag i; | |
1834 Bool first = TRUE; | |
1835 for (i = 0; i < NaClOpFlagEnumSize; ++i) { | |
1836 if (flags & NACL_OPFLAG(i)) { | |
1837 if (first) { | |
1838 first = FALSE; | |
1839 } else { | |
1840 gprintf(f, " | "); | |
1841 } | |
1842 gprintf(f, "NACL_OPFLAG(%s)", NaClOpFlagName(i)); | |
1843 } | |
1844 } | |
1845 } else { | |
1846 gprintf(f, "NACL_EMPTY_OPFLAGS"); | |
1847 } | |
1848 } | |
1849 | |
1850 /* Print out the opcode operand. */ | |
1851 static void NaClOpPrintInternal(struct Gio* f, const NaClOp* operand) { | |
1852 gprintf(f, "{ %s, ", NaClOpKindName(operand->kind)); | |
1853 NaClOpFlagsPrintInternal(f, operand->flags); | |
1854 gprintf(f, ", "); | |
1855 if (NULL == operand->format_string) { | |
1856 gprintf(f, "NULL"); | |
1857 } else { | |
1858 gprintf(f, "\"%s\"", operand->format_string); | |
1859 } | |
1860 gprintf(f, " },\n"); | |
1861 } | |
1862 | |
1863 /* Converts the (compressed) operand to the corresponding | |
1864 * index in tables.ops_compressed. | |
1865 */ | |
1866 size_t NaClOpOffset(const NaClOp* op) { | |
1867 /* Note: This function is innefficient, but doesn't slow things down | |
1868 * enough to worry about. Especially since this only effects the | |
1869 * generator. | |
1870 */ | |
1871 size_t i; | |
1872 for (i = 0; i <= tables.ops_compressed_size; ++i) { | |
1873 if (op == (tables.ops_compressed + i)) return i; | |
1874 } | |
1875 /* If reached, we have a bug! */ | |
1876 NaClFatal("Can't find offset for operand"); | |
1877 /* NOT REACHED */ | |
1878 return 0; | |
1879 } | |
1880 | |
1881 static void NaClPrintInstIndex(struct Gio* f, | |
1882 size_t index) { | |
1883 if (NACL_OPCODE_NULL_OFFSET == index) { | |
1884 gprintf(f, "NACL_OPCODE_NULL_OFFSET"); | |
1885 } else { | |
1886 gprintf(f, "%d", index); | |
1887 } | |
1888 } | |
1889 | |
1890 /* Print out the given opcode offset value corresponding to the | |
1891 * given instruction. | |
1892 */ | |
1893 static void NaClPrintInstOffset(struct Gio* f, | |
1894 const NaClModeledInst* inst) { | |
1895 NaClPrintInstIndex(f, NaClFindInstIndex(&tables, inst)); | |
1896 } | |
1897 | |
1898 /* Prints out the given instruction to the given file. If index >= 0, | |
1899 * print out a comment, with the value of index, before the printed | |
1900 * instruction. Lookahead is used to convert the next_rule pointer into | |
1901 * a symbolic reference using the name "g_Opcodes", plus the index defined by | |
1902 * the lookahead. Argument as_array_element is true if the element is | |
1903 * assumed to be in an array static initializer. | |
1904 */ | |
1905 static void NaClInstPrintInternal(struct Gio* f, Bool as_array_element, | |
1906 size_t index, const NaClModeledInst* inst) { | |
1907 gprintf(f, " /* %d */\n", index); | |
1908 gprintf(f, " { %s,\n", NaClInstTypeString(inst->insttype)); | |
1909 gprintf(f, " "); | |
1910 NaClIFlagsPrintInternal(f, inst->flags); | |
1911 gprintf(f, ",\n"); | |
1912 gprintf(f, " Inst%s, 0x%02x, ", NaClMnemonicName(inst->name), | |
1913 inst->opcode_ext); | |
1914 gprintf(f, "%u, %"NACL_PRIuS", ", | |
1915 inst->num_operands, NaClOpOffset(inst->operands)); | |
1916 NaClPrintInstOffset(f, inst->next_rule); | |
1917 gprintf(f, " }%c\n", as_array_element ? ',' : ';'); | |
1918 } | |
1919 | |
1920 /* Generate header information, based on the executable name in argv0, | |
1921 * and the file to be generated (defined by fname). | |
1922 */ | |
1923 static void NaClPrintHeader(struct Gio* f, const char* argv0, | |
1924 const char* fname) { | |
1925 gprintf(f, "/*\n"); | |
1926 gprintf(f, " * THIS FILE IS AUTO-GENERATED. DO NOT EDIT.\n"); | |
1927 gprintf(f, " * Compiled for %s.\n", NaClRunModeName(NACL_FLAGS_run_mode)); | |
1928 gprintf(f, " *\n"); | |
1929 gprintf(f, " * You must include ncopcode_desc.h before this file.\n"); | |
1930 gprintf(f, " */\n\n"); | |
1931 } | |
1932 | |
1933 /* Print out which bytes correspond to prefix bytes. */ | |
1934 static void NaClPrintPrefixTable(struct Gio* f) { | |
1935 int opc; | |
1936 gprintf(f, "static const uint32_t kNaClPrefixTable[NCDTABLESIZE] = {"); | |
1937 for (opc = 0; opc < NCDTABLESIZE; opc++) { | |
1938 if (0 == opc % 16) { | |
1939 gprintf(f, "\n /* 0x%02x-0x%02x */\n ", opc, opc + 15); | |
1940 } | |
1941 gprintf(f, "%s, ", NaClPrefixTable[opc]); | |
1942 } | |
1943 gprintf(f, "\n};\n\n"); | |
1944 } | |
1945 | |
1946 static int NaClCountInstNodes(const NaClModeledInstNode* root) { | |
1947 if (NULL == root) { | |
1948 return 0; | |
1949 } else { | |
1950 int count = 1; | |
1951 count += NaClCountInstNodes(root->success); | |
1952 count += NaClCountInstNodes(root->fail); | |
1953 return count; | |
1954 } | |
1955 } | |
1956 | |
1957 static void NaClPrintInstTrieEdge(const NaClModeledInstNode* edge, | |
1958 int* edge_index, | |
1959 struct Gio* f) { | |
1960 gprintf(f, " "); | |
1961 if (NULL == edge) { | |
1962 gprintf(f, "NULL"); | |
1963 } | |
1964 else { | |
1965 gprintf(f, "g_OpcodeSeq + %d", *edge_index); | |
1966 *edge_index += NaClCountInstNodes(edge); | |
1967 } | |
1968 gprintf(f, ",\n"); | |
1969 } | |
1970 | |
1971 static void NaClPrintInstTrieNode(const NaClModeledInstNode* root, | |
1972 int root_index, struct Gio* f) { | |
1973 if (NULL == root) { | |
1974 return; | |
1975 } else { | |
1976 int next_index = root_index + 1; | |
1977 gprintf(f, " /* %d */\n", root_index); | |
1978 gprintf(f, " { 0x%02x,\n ", root->matching_byte); | |
1979 NaClPrintInstOffset(f, root->matching_inst); | |
1980 gprintf(f, ",\n"); | |
1981 NaClPrintInstTrieEdge(root->success, &next_index, f); | |
1982 NaClPrintInstTrieEdge(root->fail, &next_index, f); | |
1983 gprintf(f, " },\n"); | |
1984 next_index = root_index + 1; | |
1985 NaClPrintInstTrieNode(root->success, next_index, f); | |
1986 next_index += NaClCountInstNodes(root->success); | |
1987 NaClPrintInstTrieNode(root->fail, next_index, f); | |
1988 } | |
1989 } | |
1990 | |
1991 /* Prints out the contents of the opcode sequence overrides into the | |
1992 * given file. | |
1993 */ | |
1994 static void NaClPrintInstSeqTrie(const NaClModeledInstNode* root, | |
1995 struct Gio* f) { | |
1996 /* Make sure trie isn't empty, since empty arrays create warning messages. */ | |
1997 int num_trie_nodes; | |
1998 if (root == NULL) root = NaClNewInstNode(0); | |
1999 num_trie_nodes = NaClCountInstNodes(root); | |
2000 gprintf(f, "static const NaClInstNode g_OpcodeSeq[%d] = {\n", num_trie_nodes); | |
2001 NaClPrintInstTrieNode(root, 0, f); | |
2002 gprintf(f, "};\n"); | |
2003 } | |
2004 | |
2005 /* Prints out the array of (compressed) operands. */ | |
2006 static void NaClPrintOperandTable(struct Gio* f) { | |
2007 size_t i; | |
2008 gprintf(f, "static const NaClOp g_Operands[%"NACL_PRIuS"] = {\n", | |
2009 tables.ops_compressed_size); | |
2010 for (i = 0; i < tables.ops_compressed_size; ++i) { | |
2011 gprintf(f," /* %"NACL_PRIuS" */ ", i); | |
2012 NaClOpPrintInternal(f, tables.ops_compressed+i); | |
2013 } | |
2014 gprintf(f, "};\n\n"); | |
2015 } | |
2016 | |
2017 static const size_t NaClOffsetsPerLine = 10; | |
2018 | |
2019 /* Print out instruction table. */ | |
2020 static void NaClPrintInstTable(struct Gio* f) { | |
2021 size_t i; | |
2022 gprintf(f, | |
2023 "static const NaClInst g_Opcodes[%d] = {\n", | |
2024 tables.inst_compressed_size); | |
2025 for (i = 0; i < tables.inst_compressed_size; ++i) { | |
2026 const NaClModeledInst* next = tables.inst_compressed[i]; | |
2027 NaClInstPrintInternal(f, TRUE, i, next); | |
2028 } | |
2029 gprintf(f, "};\n\n"); | |
2030 } | |
2031 | |
2032 /* Print lookup table of rules, based on prefix and opcode byte. */ | |
2033 static void NaClPrintLookupTable(struct Gio* f) { | |
2034 size_t i; | |
2035 NaClInstPrefix prefix; | |
2036 | |
2037 gprintf(f, "static const NaClPrefixOpcodeArrayOffset g_LookupTable[%d] = {", | |
2038 (int) tables.opcode_lookup_size); | |
2039 for (i = 0; i < tables.opcode_lookup_size; ++i) { | |
2040 if (0 == (i % NaClOffsetsPerLine)) { | |
2041 gprintf(f, "\n /* %5d */ ", (int) i); | |
2042 } | |
2043 NaClPrintInstIndex(f, tables.opcode_lookup[i]); | |
2044 gprintf(f, ", "); | |
2045 } | |
2046 gprintf(f, "};\n\n"); | |
2047 | |
2048 gprintf(f, "static const NaClPrefixOpcodeSelector " | |
2049 "g_PrefixOpcode[NaClInstPrefixEnumSize] = {\n"); | |
2050 for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) { | |
2051 gprintf(f, " /* %20s */ { %d , 0x%02x, 0x%02x },\n", | |
2052 NaClInstPrefixName(prefix), | |
2053 tables.opcode_lookup_entry[prefix], | |
2054 tables.opcode_lookup_first[prefix], | |
2055 tables.opcode_lookup_last[prefix]); | |
2056 } | |
2057 gprintf(f, "};\n\n"); | |
2058 } | |
2059 | |
2060 /* Print out the contents of the defined instructions into the given file. */ | |
2061 static void NaClPrintDecodeTables(struct Gio* f) { | |
2062 NaClPrintOperandTable(f); | |
2063 NaClPrintInstTable(f); | |
2064 NaClPrintLookupTable(f); | |
2065 NaClPrintPrefixTable(f); | |
2066 NaClPrintInstSeqTrie(tables.inst_node_root, f); | |
2067 } | |
2068 | |
2069 /* Print out the sequence of bytes used to encode an instruction sequence. */ | |
2070 static void PrintInstructionSequence( | |
2071 struct Gio* f, uint8_t* inst_sequence, int length) { | |
2072 int i; | |
2073 for (i = 0; i < length; ++i) { | |
2074 if (i > 0) gprintf(f, " "); | |
2075 gprintf(f, "%02x", inst_sequence[i]); | |
2076 } | |
2077 } | |
2078 | |
2079 /* Print out instruction sequences defined for the given (Trie) node, | |
2080 * and all of its descendants. | |
2081 * Note: To keep recursive base cases simple, we allow one more byte | |
2082 * in the instruction sequence that is actually possible. | |
2083 */ | |
2084 static void PrintHardCodedInstructionsNode( | |
2085 struct Gio* f, const NaClModeledInstNode* node, | |
2086 uint8_t inst_sequence[NACL_MAX_BYTES_PER_X86_INSTRUCTION+1], int length) { | |
2087 if (NULL == node) return; | |
2088 inst_sequence[length] = node->matching_byte; | |
2089 ++length; | |
2090 if (NACL_MAX_BYTES_PER_X86_INSTRUCTION < length) { | |
2091 struct Gio* glog = NaClLogGetGio(); | |
2092 NaClLog(LOG_ERROR, "%s", ""); | |
2093 PrintInstructionSequence(glog, inst_sequence, length); | |
2094 gprintf(glog, "\n"); | |
2095 NaClFatal("Hard coded instruction too long, aborting\n"); | |
2096 } | |
2097 if (NULL != node->matching_inst) { | |
2098 gprintf(f, " --- "); | |
2099 PrintInstructionSequence(f, inst_sequence, length); | |
2100 gprintf(f, " ---\n"); | |
2101 NaClModeledInstPrint(f, node->matching_inst); | |
2102 gprintf(f, "\n"); | |
2103 } | |
2104 PrintHardCodedInstructionsNode(f, node->success, inst_sequence, length); | |
2105 PrintHardCodedInstructionsNode(f, node->fail, inst_sequence, length-1); | |
2106 } | |
2107 | |
2108 /* Walks over specifically encoded instruction trie, and prints | |
2109 * out corresponding implemented instructions. | |
2110 */ | |
2111 static void NaClPrintHardCodedInstructions(struct Gio* f) { | |
2112 uint8_t inst_sequence[NACL_MAX_BYTES_PER_X86_INSTRUCTION+1]; | |
2113 PrintHardCodedInstructionsNode(f, tables.inst_node_root, inst_sequence, 0); | |
2114 } | |
2115 | |
2116 /* Prints out documentation on the modeled instruction set. */ | |
2117 static void NaClPrintInstructionSet(struct Gio* f) { | |
2118 NaClInstPrefix prefix; | |
2119 int i; | |
2120 gprintf(f, "*** Automatically generated file, do not edit! ***\n"); | |
2121 gprintf(f, "\n"); | |
2122 gprintf(f, "Target: %s\n", NaClRunModeName(NACL_FLAGS_run_mode)); | |
2123 gprintf(f, "\n"); | |
2124 gprintf(f, "*** Hard coded instructions ***\n"); | |
2125 gprintf(f, "\n"); | |
2126 NaClPrintHardCodedInstructions(f); | |
2127 | |
2128 for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) { | |
2129 Bool printed_rules = FALSE; | |
2130 gprintf(f, "*** %s ***\n", NaClInstPrefixName(prefix)); | |
2131 gprintf(f, "\n"); | |
2132 for (i = 0; i < NCDTABLESIZE; ++i) { | |
2133 Bool is_first = TRUE; | |
2134 const NaClModeledInst* inst = tables.inst_table[i][prefix]; | |
2135 while (NULL != inst) { | |
2136 if (is_first) { | |
2137 gprintf(f, " --- %02x ---\n", i); | |
2138 is_first = FALSE; | |
2139 } | |
2140 NaClModeledInstPrint(f, inst); | |
2141 printed_rules = TRUE; | |
2142 inst = inst->next_rule; | |
2143 } | |
2144 } | |
2145 if (printed_rules) gprintf(f, "\n"); | |
2146 } | |
2147 } | |
2148 | |
2149 /* Open the given file using the given directives (how). */ | |
2150 static void NaClMustOpen(struct GioFile* g, | |
2151 const char* fname, const char* how) { | |
2152 if (!GioFileCtor(g, fname, how)) { | |
2153 NaClLog(LOG_ERROR, "could not fopen(%s, %s)\n", fname, how); | |
2154 NaClFatal("exiting now"); | |
2155 } | |
2156 } | |
2157 | |
2158 /* Recognizes flags in argv, processes them, and then removes them. | |
2159 * Returns the updated value for argc. | |
2160 */ | |
2161 static int NaClGrokFlags(int argc, const char* argv[]) { | |
2162 int i; | |
2163 int new_argc; | |
2164 if (argc == 0) return 0; | |
2165 new_argc = 1; | |
2166 for (i = 1; i < argc; ++i) { | |
2167 if (0 == strcmp("-m32", argv[i])) { | |
2168 NACL_FLAGS_run_mode = X86_32; | |
2169 } else if (0 == strcmp("-m64", argv[i])) { | |
2170 NACL_FLAGS_run_mode = X86_64; | |
2171 } else if (GrokBoolFlag("-documentation", argv[i], | |
2172 &NACL_FLAGS_human_readable) || | |
2173 GrokBoolFlag("-validator_decoder", argv[i], | |
2174 &NACL_FLAGS_validator_decoder) || | |
2175 GrokBoolFlag("-nacl_subregs", argv[i], | |
2176 &NACL_FLAGS_nacl_subregs)) { | |
2177 continue; | |
2178 } else { | |
2179 argv[new_argc++] = argv[i]; | |
2180 } | |
2181 } | |
2182 return new_argc; | |
2183 } | |
2184 | |
2185 static void GenerateTables(struct Gio* f, const char* cmd, | |
2186 const char* filename) { | |
2187 if (NACL_FLAGS_human_readable) { | |
2188 NaClPrintInstructionSet(f); | |
2189 } else { | |
2190 /* Generate header file defining instruction set. */ | |
2191 NaClPrintHeader(f, cmd, filename); | |
2192 if (NACL_FLAGS_nacl_subregs) { | |
2193 if (NACL_FLAGS_run_mode == X86_64) { | |
2194 NaClPrintGpRegisterIndexes_64(f); | |
2195 } else { | |
2196 NaClPrintGpRegisterIndexes_32(f); | |
2197 } | |
2198 } else { | |
2199 NaClPrintDecodeTables(f); | |
2200 } | |
2201 } | |
2202 } | |
2203 | |
2204 /* Walk the trie of explicitly defined opcode sequences, and | |
2205 * fill in the operands description field if it hasn't been | |
2206 * explicitly defined. | |
2207 */ | |
2208 static void FillInTrieMissingOperandsDescs(NaClModeledInstNode* node) { | |
2209 NaClModeledInst* inst; | |
2210 if (NULL == node) return; | |
2211 inst = node->matching_inst; | |
2212 NaClFillOperandDescs(inst); | |
2213 FillInTrieMissingOperandsDescs(node->success); | |
2214 FillInTrieMissingOperandsDescs(node->fail); | |
2215 } | |
2216 | |
2217 /* Define the operands description field of each modeled | |
2218 * opcode instruction, if it hasn't explicitly been defined. | |
2219 */ | |
2220 static void FillInMissingOperandsDescs(void) { | |
2221 int i; | |
2222 NaClInstPrefix prefix; | |
2223 for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) { | |
2224 for (i = 0; i < NCDTABLESIZE; ++i) { | |
2225 NaClModeledInst* next = tables.inst_table[i][prefix]; | |
2226 while (NULL != next) { | |
2227 NaClFillOperandDescs(next); | |
2228 next = next->next_rule; | |
2229 } | |
2230 } | |
2231 } | |
2232 FillInTrieMissingOperandsDescs(tables.inst_node_root); | |
2233 } | |
2234 | |
2235 static void InitTables(void) { | |
2236 tables.inst_node_root = NULL; | |
2237 tables.operands_size = 0; | |
2238 tables.ops_compressed_size = 0; | |
2239 tables.opcode_lookup_size = 0; | |
2240 tables.inst_compressed_size = 0; | |
2241 tables.undefined_inst = 0; | |
2242 } | |
2243 | |
2244 int main(const int argc, const char* argv[]) { | |
2245 struct GioFile gfile; | |
2246 struct Gio* g = (struct Gio*) &gfile; | |
2247 int new_argc = NaClGrokFlags(argc, argv); | |
2248 if ((new_argc < 1) || (new_argc > 2) || | |
2249 (NACL_FLAGS_human_readable && NACL_FLAGS_nacl_subregs) || | |
2250 (NACL_FLAGS_run_mode == NaClRunModeSize)) { | |
2251 fprintf(stderr, | |
2252 "ERROR: usage: ncdecode_tablegen <architecture_flag> " | |
2253 "[-documentation | -validator_decoder -nacl_subregs] [file]\n"); | |
2254 return -1; | |
2255 } | |
2256 InitTables(); | |
2257 NaClLogModuleInit(); | |
2258 NaClBuildInstTables(); | |
2259 NaClSimplifyIfApplicable(); | |
2260 NaClVerifyInstCounts(); | |
2261 FillInMissingOperandsDescs(); | |
2262 | |
2263 if (NACL_FLAGS_validator_decoder) | |
2264 NaClNcvalInstSimplify(&tables); | |
2265 | |
2266 /* Don't compress if output is to be readable! Compression | |
2267 * ignores extra (redundant) data used by print routines of | |
2268 * modeled instructions, since this data is not needed at | |
2269 * runtime when the corresponding data is defined in the | |
2270 * parsed instruction. | |
2271 */ | |
2272 if (!NACL_FLAGS_human_readable) { | |
2273 NaClOpCompress(&tables); | |
2274 } | |
2275 | |
2276 if (new_argc == 1) { | |
2277 GioFileRefCtor(&gfile, stdout); | |
2278 GenerateTables(g, argv[0], "<stdout>"); | |
2279 } else { | |
2280 NaClMustOpen(&gfile, argv[1], "w"); | |
2281 GenerateTables(g, argv[0], argv[1]); | |
2282 } | |
2283 NaClLogModuleFini(); | |
2284 GioFileDtor(g); | |
2285 return 0; | |
2286 } | |
OLD | NEW |