2 * Copyright (c) 2012 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.
8 * ncdecode.c - table driven decoder for Native Client
10 * Most x86 decoders I've looked at are big case statements. While
11 * this organization is fairly transparent and obvious, it tends to
12 * lead to messy control flow (gotos, etc.) that make the decoder
13 * more complicated, hence harder to maintain and harder to validate.
15 * This decoder is table driven, which will hopefully result in
16 * substantially less code. Although the code+tables may be more
17 * lines of code than a decoder built around a switch statement,
18 * the smaller amount of actual procedural code and the regular
19 * structure of the tables should make it easier to understand,
20 * debug, and easier to become confident the decoder is correct.
22 * As it is specialized to Native Client, this decoder can also
23 * benefit from any exclusions or simplifications we decide to
24 * make in the dialect of x86 machine code accepted by Native
25 * Client. Any such simplifications should ultimately be easily
26 * recognized by inspection of the decoder configuration tables.
27 * ALSO, the decoder mostly needs to worry about accurate
28 * instruction lengths and finding opcodes. It does not need
29 * to completely resolve the operands of all instructions.
32 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h"
33 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_aux.h"
38 #if NACL_TARGET_SUBARCH == 64
39 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdecodetab_64.h"
41 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdecodetab_32.h"
44 /* To turn on debugging of instruction decoding, change value of
49 #include "native_client/src/shared/utils/debugging.h"
51 #include "native_client/src/trusted/validator/x86/ncinstbuffer_inl.c"
52 #include "native_client/src/trusted/validator/x86/x86_insts_inl.c"
54 /* Generates a print name for the given NCDecodeImmediateType. */
55 static const char* NCDecodeImmediateTypeName(NCDecodeImmediateType type) {
58 case IMM_UNKNOWN: return "IMM_UNKNOWN";
59 case IMM_NONE: return "IMM_NONE";
60 case IMM_FIXED1: return "IMM_FIXED1";
61 case IMM_FIXED2: return "IMM_FIXED2";
62 case IMM_FIXED3: return "IMM_FIXED3";
63 case IMM_FIXED4: return "IMM_FIXED4";
64 case IMM_DATAV: return "IMM_DATAV";
65 case IMM_ADDRV: return "IMM_ADDRV";
66 case IMM_GROUP3_F6: return "IMM_GROUP3_F6";
67 case IMM_GROUP3_F7: return "IMM_GROUP3_F7";
68 case IMM_FARPTR: return "IMM_FARPTR";
69 case IMM_MOV_DATAV: return "IMM_MOV_DATAV";
76 /* Prints out the contents of the given OpInfo. Should only be called
77 * inside a DEBUG macro (i.e. for debugging only).
79 static void PrintOpInfo(const struct OpInfo* info) {
80 DEBUG_OR_ERASE(printf("opinfo(%s, hasmrm=%u, immtype=%s, opinmrm=%d)\n",
81 NaClInstTypeString(info->insttype),
83 NCDecodeImmediateTypeName(info->immtype),
87 /* later this will make decoding x87 instructions a bit more concise. */
88 static const struct OpInfo* kDecodeX87Op[8] = { kDecode87D8,
97 static Bool NullDecoderAction(const struct NCDecoderInst* dinst) {
98 UNREFERENCED_PARAMETER(dinst);
101 static void NullDecoderMethod(struct NCDecoderState* dstate) {
102 UNREFERENCED_PARAMETER(dstate);
105 /* API to virtual methods of a decoder state. */
106 void NCDecoderStateNewSegment(NCDecoderState* tthis) {
107 (tthis->new_segment_fn)(tthis);
110 static Bool NCDecoderStateApplyAction(NCDecoderState* tthis,
111 NCDecoderInst* dinst) {
112 return (tthis->action_fn)(dinst);
115 static void NCDecoderStateSegmentationError(NCDecoderState* tthis) {
116 (tthis->segmentation_error_fn)(tthis);
119 static void NCDecoderStateInternalError(NCDecoderState* tthis) {
120 (tthis->internal_error_fn)(tthis);
123 /* Error Condition Handling */
124 static void ErrorSegmentation(NCDecoderInst* dinst) {
125 NCDecoderState* dstate = dinst->dstate;
126 NaClErrorReporter* reporter = dstate->error_reporter;
127 (*reporter->printf)(dstate->error_reporter, "ErrorSegmentation\n");
128 /* When the decoder is used by the NaCl validator */
129 /* the validator provides an error handler that does */
130 /* the necessary bookeeping to track these errors. */
131 NCDecoderStateSegmentationError(dstate);
134 static void ErrorInternal(NCDecoderInst* dinst) {
135 NCDecoderState* dstate = dinst->dstate;
136 NaClErrorReporter* reporter = dstate->error_reporter;
137 (*reporter->printf)(reporter, "ErrorInternal\n");
138 /* When the decoder is used by the NaCl validator */
139 /* the validator provides an error handler that does */
140 /* the necessary bookeeping to track these errors. */
141 NCDecoderStateInternalError(dstate);
144 /* Defines how to handle errors found while parsing the memory segment. */
145 static void NCRemainingMemoryInternalError(NCRemainingMemoryError error,
146 struct NCRemainingMemory* memory) {
147 /* Don't do anything for memory overflow! Let NCDecodeSegment generate
148 * the corresponding segmentation error. This allows us to back out overflow
149 * if a predefined nop is matched.
151 if (NCRemainingMemoryOverflow != error) {
152 NCDecoderState* dstate = (NCDecoderState*) memory->error_fn_state;
153 NCRemainingMemoryReportError(error, memory);
154 ErrorInternal(&dstate->inst_buffer[dstate->cur_inst_index]);
158 static INLINE void InitDecoder(struct NCDecoderInst* dinst) {
159 NCInstBytesInitInline(&dinst->inst.bytes);
160 dinst->inst.prefixbytes = 0;
161 dinst->inst.prefixmask = 0;
162 dinst->inst.opcode_prefixmask = 0;
163 dinst->inst.num_opbytes = 1; /* unless proven otherwise. */
164 dinst->inst.hassibbyte = 0;
166 dinst->inst.immtype = IMM_UNKNOWN;
167 dinst->inst.immbytes = 0;
168 dinst->inst.dispbytes = 0;
169 dinst->inst.rexprefix = 0;
170 dinst->inst.lock_prefix_index = kNoLockPrefixIndex;
171 dinst->opinfo = NULL;
174 /* Returns the number of bytes defined for the operand of the instruction. */
175 static int ExtractOperandSize(NCDecoderInst* dinst) {
176 if (NACL_TARGET_SUBARCH == 64 &&
177 dinst->inst.rexprefix && dinst->inst.rexprefix & 0x8) {
180 if (dinst->inst.prefixmask & kPrefixDATA16) {
186 /* at most four prefix bytes are allowed */
187 static void ConsumePrefixBytes(struct NCDecoderInst* dinst) {
190 uint32_t prefix_form;
192 for (ii = 0; ii < kMaxPrefixBytes; ++ii) {
193 nb = NCRemainingMemoryGetNext(&dinst->dstate->memory);
194 prefix_form = kPrefixTable[nb];
195 if (prefix_form == 0) return;
196 DEBUG( printf("Consume prefix[%d]: %02x => %x\n", ii, nb, prefix_form) );
197 dinst->inst.prefixmask |= prefix_form;
198 dinst->inst.prefixmask |= kPrefixTable[nb];
199 dinst->inst.prefixbytes += 1;
200 NCInstBytesReadInline(&dinst->inst.bytes);
201 DEBUG( printf(" prefix mask: %08x\n", dinst->inst.prefixmask) );
202 if (NACL_TARGET_SUBARCH == 64 && prefix_form == kPrefixREX) {
203 dinst->inst.rexprefix = nb;
204 /* REX prefix must be last prefix. */
207 if (prefix_form == kPrefixLOCK) {
208 /* Note: we don't have to worry about duplicates, since
209 * ValidatePrefixes in ncvalidate.c will not allow such
212 dinst->inst.lock_prefix_index = (uint8_t) ii;
217 static const struct OpInfo* GetExtendedOpInfo(NCDecoderInst* dinst,
220 pm = dinst->inst.prefixmask;
221 if ((pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) == 0) {
222 return &kDecode0FXXOp[opbyte2];
223 } else if (pm & kPrefixDATA16) {
224 dinst->inst.prefixmask &= ~kPrefixDATA16;
225 dinst->inst.opcode_prefixmask = kPrefixDATA16;
226 return &kDecode660FXXOp[opbyte2];
227 } else if (pm & kPrefixREPNE) {
228 dinst->inst.prefixmask &= ~kPrefixREPNE;
229 dinst->inst.opcode_prefixmask = kPrefixREPNE;
230 return &kDecodeF20FXXOp[opbyte2];
231 } else if (pm & kPrefixREP) {
232 dinst->inst.prefixmask &= ~kPrefixREP;
233 dinst->inst.opcode_prefixmask = kPrefixREP;
234 return &kDecodeF30FXXOp[opbyte2];
236 ErrorInternal(dinst);
237 return dinst->opinfo;
240 static void GetX87OpInfo(NCDecoderInst* dinst) {
241 /* WAIT is an x87 instruction but not in the coproc opcode space. */
242 uint8_t op1 = NCInstBytesByteInline(&dinst->inst_bytes,
243 dinst->inst.prefixbytes);
244 if (op1 < kFirstX87Opcode || op1 > kLastX87Opcode) {
245 if (op1 != kWAITOp) ErrorInternal(dinst);
248 dinst->opinfo = &kDecodeX87Op[op1 - kFirstX87Opcode][dinst->inst.mrm];
249 DEBUG( printf("NACL_X87 op1 = %02x, ", op1);
250 PrintOpInfo(dinst->opinfo) );
253 static void ConsumeOpcodeBytes(NCDecoderInst* dinst) {
254 uint8_t opcode = NCInstBytesReadInline(&dinst->inst.bytes);
255 dinst->opinfo = &kDecode1ByteOp[opcode];
256 DEBUG( printf("NACLi_1BYTE: opcode = %02x, ", opcode);
257 PrintOpInfo(dinst->opinfo) );
258 if (opcode == kTwoByteOpcodeByte1) {
259 uint8_t opcode2 = NCInstBytesReadInline(&dinst->inst.bytes);
260 dinst->opinfo = GetExtendedOpInfo(dinst, opcode2);
261 DEBUG( printf("NACLi_2BYTE: opcode2 = %02x, ", opcode2);
262 PrintOpInfo(dinst->opinfo) );
263 dinst->inst.num_opbytes = 2;
264 if (dinst->opinfo->insttype == NACLi_3BYTE) {
265 uint8_t opcode3 = NCInstBytesReadInline(&dinst->inst.bytes);
267 pm = dinst->inst.opcode_prefixmask;
268 dinst->inst.num_opbytes = 3;
270 DEBUG( printf("NACLi_3BYTE: opcode3 = %02x, ", opcode3) );
272 case 0x38: /* SSSE3, SSE4 */
273 if (pm & kPrefixDATA16) {
274 dinst->opinfo = &kDecode660F38Op[opcode3];
275 } else if (pm & kPrefixREPNE) {
276 dinst->opinfo = &kDecodeF20F38Op[opcode3];
277 } else if (pm == 0) {
278 dinst->opinfo = &kDecode0F38Op[opcode3];
280 /* Other prefixes like F3 cause an undefined instruction error. */
281 /* Note from decoder table that NACLi_3BYTE is only used with */
282 /* data16 and repne prefixes. */
283 ErrorInternal(dinst);
286 case 0x3A: /* SSSE3, SSE4 */
287 if (pm & kPrefixDATA16) {
288 dinst->opinfo = &kDecode660F3AOp[opcode3];
289 } else if (pm == 0) {
290 dinst->opinfo = &kDecode0F3AOp[opcode3];
292 /* Other prefixes like F3 cause an undefined instruction error. */
293 /* Note from decoder table that NACLi_3BYTE is only used with */
294 /* data16 and repne prefixes. */
295 ErrorInternal(dinst);
299 /* if this happens there is a decoding table bug */
300 ErrorInternal(dinst);
303 DEBUG( PrintOpInfo(dinst->opinfo) );
306 dinst->inst.immtype = dinst->opinfo->immtype;
309 static void ConsumeModRM(NCDecoderInst* dinst) {
310 if (dinst->opinfo->hasmrmbyte != 0) {
311 const uint8_t mrm = NCInstBytesReadInline(&dinst->inst.bytes);
312 DEBUG( printf("Mod/RM byte: %02x\n", mrm) );
313 dinst->inst.mrm = mrm;
314 if (dinst->opinfo->insttype == NACLi_X87 ||
315 dinst->opinfo->insttype == NACLi_X87_FSINCOS) {
318 if (dinst->opinfo->opinmrm) {
319 const struct OpInfo* mopinfo =
320 &kDecodeModRMOp[dinst->opinfo->opinmrm][modrm_opcodeInline(mrm)];
321 dinst->opinfo = mopinfo;
322 DEBUG( printf("NACLi_opinmrm: modrm.opcode = %x, ",
323 modrm_opcodeInline(mrm));
324 PrintOpInfo(dinst->opinfo) );
325 if (dinst->inst.immtype == IMM_UNKNOWN) {
327 dinst->inst.immtype = mopinfo->immtype;
329 /* handle weird case for 0xff TEST Ib/Iv */
330 if (modrm_opcodeInline(mrm) == 0) {
331 if (dinst->inst.immtype == IMM_GROUP3_F6) {
332 dinst->inst.immtype = IMM_FIXED1;
334 if (dinst->inst.immtype == IMM_GROUP3_F7) {
335 dinst->inst.immtype = IMM_DATAV;
338 DEBUG( printf(" immtype = %s\n",
339 NCDecodeImmediateTypeName(dinst->inst.immtype)) );
341 if (dinst->inst.prefixmask & kPrefixADDR16) {
342 switch (modrm_modInline(mrm)) {
344 if (modrm_rmInline(mrm) == 0x06) {
345 dinst->inst.dispbytes = 2; /* disp16 */
347 dinst->inst.dispbytes = 0;
351 dinst->inst.dispbytes = 1; /* disp8 */
354 dinst->inst.dispbytes = 2; /* disp16 */
357 dinst->inst.dispbytes = 0; /* no disp */
360 ErrorInternal(dinst);
362 dinst->inst.hassibbyte = 0;
364 switch (modrm_modInline(mrm)) {
366 if (modrm_rmInline(mrm) == 0x05) {
367 dinst->inst.dispbytes = 4; /* disp32 */
369 dinst->inst.dispbytes = 0;
373 dinst->inst.dispbytes = 1; /* disp8 */
376 dinst->inst.dispbytes = 4; /* disp32 */
379 dinst->inst.dispbytes = 0; /* no disp */
382 ErrorInternal(dinst);
384 dinst->inst.hassibbyte = ((modrm_rmInline(mrm) == 0x04) &&
385 (modrm_modInline(mrm) != 3));
388 DEBUG( printf(" dispbytes = %d, hasibbyte = %d\n",
389 dinst->inst.dispbytes, dinst->inst.hassibbyte) );
392 static INLINE void ConsumeSIB(NCDecoderInst* dinst) {
393 if (dinst->inst.hassibbyte != 0) {
394 const uint8_t sib = NCInstBytesReadInline(&dinst->inst.bytes);
395 if (sib_base(sib) == 0x05) {
396 switch (modrm_modInline(dinst->inst.mrm)) {
397 case 0: dinst->inst.dispbytes = 4; break;
398 case 1: dinst->inst.dispbytes = 1; break;
399 case 2: dinst->inst.dispbytes = 4; break;
402 ErrorInternal(dinst);
405 DEBUG( printf("sib byte: %02x, dispbytes = %d\n",
406 sib, dinst->inst.dispbytes) );
410 static INLINE void ConsumeID(NCDecoderInst* dinst) {
411 if (dinst->inst.immtype == IMM_UNKNOWN) {
412 ErrorInternal(dinst);
414 /* NOTE: NaCl allows at most one prefix byte (for 32-bit mode) */
415 if (dinst->inst.immtype == IMM_MOV_DATAV) {
416 dinst->inst.immbytes = ExtractOperandSize(dinst);
417 } else if (dinst->inst.prefixmask & kPrefixDATA16) {
418 dinst->inst.immbytes = kImmTypeToSize66[dinst->inst.immtype];
419 } else if (dinst->inst.prefixmask & kPrefixADDR16) {
420 dinst->inst.immbytes = kImmTypeToSize67[dinst->inst.immtype];
422 dinst->inst.immbytes = kImmTypeToSize[dinst->inst.immtype];
424 NCInstBytesReadBytesInline((ssize_t) dinst->inst.immbytes,
426 NCInstBytesReadBytesInline((ssize_t) dinst->inst.dispbytes,
428 DEBUG(printf("ID: %d disp bytes, %d imm bytes\n",
429 dinst->inst.dispbytes, dinst->inst.immbytes));
432 /* Actually this routine is special for 3DNow instructions */
433 static INLINE void MaybeGet3ByteOpInfo(NCDecoderInst* dinst) {
434 if (dinst->opinfo->insttype == NACLi_3DNOW) {
435 uint8_t opbyte1 = NCInstBytesByteInline(&dinst->inst_bytes,
436 dinst->inst.prefixbytes);
437 uint8_t opbyte2 = NCInstBytesByteInline(&dinst->inst_bytes,
438 dinst->inst.prefixbytes + 1);
439 if (opbyte1 == kTwoByteOpcodeByte1 &&
440 opbyte2 == k3DNowOpcodeByte2) {
442 NCInstBytesByteInline(&dinst->inst_bytes,
443 dinst->inst.bytes.length - 1);
444 dinst->opinfo = &kDecode0F0FOp[immbyte];
446 "NACLi_3DNOW: byte1 = %02x, byte2 = %02x, immbyte = %02x,\n ",
447 opbyte1, opbyte2, immbyte);
448 PrintOpInfo(dinst->opinfo) );
453 /* Gets an instruction nindex away from the given instruction.
454 * WARNING: Does not do bounds checking, other than rolling the
455 * index as needed to stay within the (circular) instruction buffer.
457 static NCDecoderInst* NCGetInstDiff(const NCDecoderInst* dinst,
459 /* Note: This code also handles increments, so that we can
460 * use the same code for both.
462 size_t index = (dinst->inst_index + nindex) % dinst->dstate->inst_buffer_size;
463 return &dinst->dstate->inst_buffer[index];
466 struct NCDecoderInst* PreviousInst(const NCDecoderInst* dinst,
468 if ((nindex > 0) && (((size_t) nindex) < dinst->inst_count)) {
469 return NCGetInstDiff(dinst, -nindex);
475 /* Initialize the decoder state fields, assuming constructor parameter
476 * fields mbase, vbase, size, inst_buffer, and inst_buffer_size have
479 static void NCDecoderStateInitFields(NCDecoderState* this) {
481 this->error_reporter = &kNCNullErrorReporter;
482 NCRemainingMemoryInit(this->mbase, this->size, &this->memory);
483 this->memory.error_fn = NCRemainingMemoryInternalError;
484 this->memory.error_fn_state = (void*) this;
485 for (dbindex = 0; dbindex < this->inst_buffer_size; ++dbindex) {
486 this->inst_buffer[dbindex].dstate = this;
487 this->inst_buffer[dbindex].inst_index = dbindex;
488 this->inst_buffer[dbindex].inst_count = 1;
489 this->inst_buffer[dbindex].inst_addr = 0;
490 this->inst_buffer[dbindex].unchanged = FALSE;
491 NCInstBytesInitMemory(&this->inst_buffer[dbindex].inst.bytes,
493 NCInstBytesPtrInit((NCInstBytesPtr*) &this->inst_buffer[dbindex].inst_bytes,
494 &this->inst_buffer[dbindex].inst.bytes);
496 this->cur_inst_index = 0;
499 void NCDecoderStateConstruct(NCDecoderState* this,
500 uint8_t* mbase, NaClPcAddress vbase,
502 NCDecoderInst* inst_buffer,
503 size_t inst_buffer_size) {
505 /* Start by setting up virtual functions. */
506 this->action_fn = NullDecoderAction;
507 this->new_segment_fn = NullDecoderMethod;
508 this->segmentation_error_fn = NullDecoderMethod;
509 this->internal_error_fn = NullDecoderMethod;
511 /* Initialize the user-provided fields. */
515 this->inst_buffer = inst_buffer;
516 this->inst_buffer_size = inst_buffer_size;
518 NCDecoderStateInitFields(this);
521 void NCDecoderStateDestruct(NCDecoderState* this) {
522 /* Currently, there is nothing to do. */
525 /* "Printable" means the value returned by this function can be used for
526 * printing user-readable output, but it should not be used to influence if the
527 * validation algorithm passes or fails. The validation algorithm should not
528 * depend on vbase - in other words, it should not depend on where the code is
529 * being mapped in memory.
531 static INLINE NaClPcAddress NCPrintableVLimit(NCDecoderState *dstate) {
532 return dstate->vbase + dstate->size;
535 /* Modify the current instruction pointer to point to the next instruction
536 * in the ring buffer. Reset the state of that next instruction.
538 static NCDecoderInst* IncrementInst(NCDecoderInst* inst) {
539 /* giving PreviousInst a positive number will get NextInst
540 * better to keep the buffer switching logic in one place
542 NCDecoderInst* next_inst = NCGetInstDiff(inst, 1);
543 next_inst->inst_addr = inst->inst_addr + inst->inst.bytes.length;
544 next_inst->dstate->cur_inst_index = next_inst->inst_index;
545 next_inst->inst_count = inst->inst_count + 1;
546 next_inst->unchanged = FALSE;
550 /* Get the i-th byte of the current instruction being parsed. */
551 static uint8_t GetInstByte(NCDecoderInst* dinst, ssize_t i) {
552 if (i < dinst->inst.bytes.length) {
553 return dinst->inst.bytes.byte[i];
555 return NCRemainingMemoryLookaheadInline(&dinst->dstate->memory,
556 i - dinst->inst.bytes.length);
560 /* Consume a predefined nop byte sequence, if a match can be found.
561 * Further, if found, replace the currently matched instruction with
562 * the consumed predefined nop.
564 static void ConsumePredefinedNop(NCDecoderInst* dinst) {
565 /* Do maximal match of possible nops */
567 struct OpInfo* matching_opinfo = NULL;
568 ssize_t matching_length = 0;
569 NCNopTrieNode* next = (NCNopTrieNode*) (kNcNopTrieNode + 0);
570 uint8_t byte = GetInstByte(dinst, pos);
571 while (NULL != next) {
572 if (byte == next->matching_byte) {
573 DEBUG(printf("NOP match byte: 0x%02x\n", (int) byte));
574 byte = GetInstByte(dinst, ++pos);
575 if (NULL != next->matching_opinfo) {
576 DEBUG(printf("NOP matched rule! %d\n", pos));
577 matching_opinfo = next->matching_opinfo;
578 matching_length = pos;
580 next = next->success;
585 if (NULL == matching_opinfo) {
586 DEBUG(printf("NOP match failed!\n"));
588 DEBUG(printf("NOP match succeeds! Using last matched rule.\n"));
589 NCRemainingMemoryResetInline(&dinst->dstate->memory);
591 NCInstBytesReadBytesInline(matching_length, &dinst->inst.bytes);
592 dinst->opinfo = matching_opinfo;
596 /* If we didn't find a good instruction, try to consume one of the
599 static void MaybeConsumePredefinedNop(NCDecoderInst* dinst) {
600 switch (dinst->opinfo->insttype) {
601 case NACLi_UNDEFINED:
604 ConsumePredefinedNop(dinst);
611 /* All of the actions needed to read one additional instruction into mstate.
613 void NCConsumeNextInstruction(struct NCDecoderInst* inst) {
614 DEBUG( printf("Decoding instruction at %"NACL_PRIxNaClPcAddress":\n",
617 ConsumePrefixBytes(inst);
618 ConsumeOpcodeBytes(inst);
622 MaybeGet3ByteOpInfo(inst);
623 MaybeConsumePredefinedNop(inst);
626 void NCDecoderStateSetErrorReporter(NCDecoderState* this,
627 NaClErrorReporter* reporter) {
628 switch (reporter->supported_reporter) {
629 case NaClNullErrorReporter:
630 case NCDecoderInstErrorReporter:
631 this->error_reporter = reporter;
638 "*** FATAL: using unsupported error reporter! ***\n"
639 "*** NCDecoderInstErrorReporter expected but found %s***\n",
640 NaClErrorReporterSupportedName(reporter->supported_reporter));
644 static void NCNullErrorPrintInst(NaClErrorReporter* self,
645 struct NCDecoderInst* inst) {}
647 NaClErrorReporter kNCNullErrorReporter = {
648 NaClNullErrorReporter,
650 NaClNullErrorPrintfV,
651 (NaClPrintInst) NCNullErrorPrintInst,
654 Bool NCDecoderStateDecode(NCDecoderState* this) {
655 NCDecoderInst* dinst = &this->inst_buffer[this->cur_inst_index];
656 DEBUG( printf("DecodeSegment(%p[%"NACL_PRIxNaClPcAddress"])\n",
657 (void*) this->memory.mpc, (NaClPcAddress) this->size) );
658 NCDecoderStateNewSegment(this);
659 while (dinst->inst_addr < this->size) {
660 NCConsumeNextInstruction(dinst);
661 if (this->memory.overflow_count) {
662 NaClPcAddress newpc = (NCPrintableInstructionAddress(dinst)
663 + dinst->inst.bytes.length);
664 (*this->error_reporter->printf)(
665 this->error_reporter,
666 "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress
667 " (read overflow of %d bytes)\n",
668 newpc, NCPrintableVLimit(this), this->memory.overflow_count);
669 ErrorSegmentation(dinst);
672 if (!NCDecoderStateApplyAction(this, dinst)) return FALSE;
673 /* get ready for next round */
674 dinst = IncrementInst(dinst);
679 /* Default action for a decoder state pair. */
680 static Bool NullNCDecoderStatePairAction(struct NCDecoderStatePair* tthis,
681 NCDecoderInst* old_inst,
682 NCDecoderInst* new_inst) {
686 void NCDecoderStatePairConstruct(NCDecoderStatePair* tthis,
687 NCDecoderState* old_dstate,
688 NCDecoderState* new_dstate,
689 NaClCopyInstructionFunc copy_func) {
690 tthis->old_dstate = old_dstate;
691 tthis->new_dstate = new_dstate;
692 tthis->action_fn = NullNCDecoderStatePairAction;
693 tthis->copy_func = copy_func;
696 void NCDecoderStatePairDestruct(NCDecoderStatePair* tthis) {
699 Bool NCDecoderStatePairDecode(NCDecoderStatePair* tthis) {
700 NCDecoderInst* old_dinst =
701 &tthis->old_dstate->inst_buffer[tthis->old_dstate->cur_inst_index];
702 NCDecoderInst* new_dinst =
703 &tthis->new_dstate->inst_buffer[tthis->new_dstate->cur_inst_index];
705 /* Verify that the size of the code segments is the same, and has not
708 if (tthis->old_dstate->size != tthis->new_dstate->size) {
709 /* If sizes differ, then they can't be the same, except for some
710 * (constant-sized) changes. Hence fail to decode.
712 ErrorSegmentation(new_dinst);
716 /* Since the sizes of the segments are the same, only one limit
717 * needs to be checked. Hence, we will track the limit of the new
720 DEBUG( printf("NCDecoderStatePairDecode(%"NACL_PRIxNaClPcAddress")\n",
721 (NaClPcAddress) tthis->new_dstate->size));
723 /* Initialize decoder statements for decoding segment, by calling
724 * the corresponding virtual in the decoder.
726 NCDecoderStateNewSegment(tthis->old_dstate);
727 NCDecoderStateNewSegment(tthis->new_dstate);
729 /* Walk through both instruction segments, checking that
730 * they decode similarly.
732 while (new_dinst->inst_addr < tthis->new_dstate->size) {
734 NCConsumeNextInstruction(old_dinst);
735 NCConsumeNextInstruction(new_dinst);
738 /* Verify that the instruction lengths match. */
739 if (old_dinst->inst.bytes.length !=
740 new_dinst->inst.bytes.length) {
741 ErrorInternal(new_dinst);
745 /* Verify that we haven't walked past the end of the segment
746 * in either decoder state.
748 * Note: Since instruction lengths are the same, and the
749 * segment lengths are the same, if overflow occurs on one
750 * segment, it must occur on the other.
752 if (new_dinst->inst_addr > tthis->new_dstate->size) {
753 NaClErrorReporter* reporter = new_dinst->dstate->error_reporter;
756 "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress"\n",
757 NCPrintableInstructionAddress(new_dinst),
758 NCPrintableVLimit(tthis->new_dstate));
759 ErrorSegmentation(new_dinst);
763 /* Apply the action to the instructions, and continue
764 * only if the action succeeds.
766 if (! (tthis->action_fn)(tthis, old_dinst, new_dinst)) {
770 /* Move to next instruction. */
771 old_dinst = IncrementInst(old_dinst);
772 new_dinst = IncrementInst(new_dinst);