Index: src/trusted/validator/x86/ncval_seg_sfi/ncdecode.c |
diff --git a/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.c b/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.c |
deleted file mode 100644 |
index 200e0c167b264d260aefc919bba04ede6e6be0c7..0000000000000000000000000000000000000000 |
--- a/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.c |
+++ /dev/null |
@@ -1,775 +0,0 @@ |
-/* |
- * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
- * Use of this source code is governed by a BSD-style license that can be |
- * found in the LICENSE file. |
- */ |
- |
-/* |
- * ncdecode.c - table driven decoder for Native Client |
- * |
- * Most x86 decoders I've looked at are big case statements. While |
- * this organization is fairly transparent and obvious, it tends to |
- * lead to messy control flow (gotos, etc.) that make the decoder |
- * more complicated, hence harder to maintain and harder to validate. |
- * |
- * This decoder is table driven, which will hopefully result in |
- * substantially less code. Although the code+tables may be more |
- * lines of code than a decoder built around a switch statement, |
- * the smaller amount of actual procedural code and the regular |
- * structure of the tables should make it easier to understand, |
- * debug, and easier to become confident the decoder is correct. |
- * |
- * As it is specialized to Native Client, this decoder can also |
- * benefit from any exclusions or simplifications we decide to |
- * make in the dialect of x86 machine code accepted by Native |
- * Client. Any such simplifications should ultimately be easily |
- * recognized by inspection of the decoder configuration tables. |
- * ALSO, the decoder mostly needs to worry about accurate |
- * instruction lengths and finding opcodes. It does not need |
- * to completely resolve the operands of all instructions. |
- */ |
- |
-#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h" |
-#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_aux.h" |
- |
-#include <stdio.h> |
-#include <assert.h> |
- |
-#if NACL_TARGET_SUBARCH == 64 |
-#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdecodetab_64.h" |
-#else |
-#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdecodetab_32.h" |
-#endif |
- |
-/* To turn on debugging of instruction decoding, change value of |
- * DEBUGGING to 1. |
- */ |
-#define DEBUGGING 0 |
- |
-#include "native_client/src/shared/utils/debugging.h" |
- |
-#include "native_client/src/trusted/validator/x86/ncinstbuffer_inl.c" |
-#include "native_client/src/trusted/validator/x86/x86_insts_inl.c" |
- |
-/* Generates a print name for the given NCDecodeImmediateType. */ |
-static const char* NCDecodeImmediateTypeName(NCDecodeImmediateType type) { |
- DEBUG_OR_ERASE( |
- switch(type) { |
- case IMM_UNKNOWN: return "IMM_UNKNOWN"; |
- case IMM_NONE: return "IMM_NONE"; |
- case IMM_FIXED1: return "IMM_FIXED1"; |
- case IMM_FIXED2: return "IMM_FIXED2"; |
- case IMM_FIXED3: return "IMM_FIXED3"; |
- case IMM_FIXED4: return "IMM_FIXED4"; |
- case IMM_DATAV: return "IMM_DATAV"; |
- case IMM_ADDRV: return "IMM_ADDRV"; |
- case IMM_GROUP3_F6: return "IMM_GROUP3_F6"; |
- case IMM_GROUP3_F7: return "IMM_GROUP3_F7"; |
- case IMM_FARPTR: return "IMM_FARPTR"; |
- case IMM_MOV_DATAV: return "IMM_MOV_DATAV"; |
- default: assert(0); |
- }); |
- /* NOTREACHED */ |
- return NULL; |
-} |
- |
-/* Prints out the contents of the given OpInfo. Should only be called |
- * inside a DEBUG macro (i.e. for debugging only). |
- */ |
-static void PrintOpInfo(const struct OpInfo* info) { |
- DEBUG_OR_ERASE(printf("opinfo(%s, hasmrm=%u, immtype=%s, opinmrm=%d)\n", |
- NaClInstTypeString(info->insttype), |
- info->hasmrmbyte, |
- NCDecodeImmediateTypeName(info->immtype), |
- info->opinmrm)); |
-} |
- |
-/* later this will make decoding x87 instructions a bit more concise. */ |
-static const struct OpInfo* kDecodeX87Op[8] = { kDecode87D8, |
- kDecode87D9, |
- kDecode87DA, |
- kDecode87DB, |
- kDecode87DC, |
- kDecode87DD, |
- kDecode87DE, |
- kDecode87DF }; |
- |
-static Bool NullDecoderAction(const struct NCDecoderInst* dinst) { |
- UNREFERENCED_PARAMETER(dinst); |
- return TRUE; |
-} |
-static void NullDecoderMethod(struct NCDecoderState* dstate) { |
- UNREFERENCED_PARAMETER(dstate); |
-} |
- |
-/* API to virtual methods of a decoder state. */ |
-void NCDecoderStateNewSegment(NCDecoderState* tthis) { |
- (tthis->new_segment_fn)(tthis); |
-} |
- |
-static Bool NCDecoderStateApplyAction(NCDecoderState* tthis, |
- NCDecoderInst* dinst) { |
- return (tthis->action_fn)(dinst); |
-} |
- |
-static void NCDecoderStateSegmentationError(NCDecoderState* tthis) { |
- (tthis->segmentation_error_fn)(tthis); |
-} |
- |
-static void NCDecoderStateInternalError(NCDecoderState* tthis) { |
- (tthis->internal_error_fn)(tthis); |
-} |
- |
-/* Error Condition Handling */ |
-static void ErrorSegmentation(NCDecoderInst* dinst) { |
- NCDecoderState* dstate = dinst->dstate; |
- NaClErrorReporter* reporter = dstate->error_reporter; |
- (*reporter->printf)(dstate->error_reporter, "ErrorSegmentation\n"); |
- /* When the decoder is used by the NaCl validator */ |
- /* the validator provides an error handler that does */ |
- /* the necessary bookeeping to track these errors. */ |
- NCDecoderStateSegmentationError(dstate); |
-} |
- |
-static void ErrorInternal(NCDecoderInst* dinst) { |
- NCDecoderState* dstate = dinst->dstate; |
- NaClErrorReporter* reporter = dstate->error_reporter; |
- (*reporter->printf)(reporter, "ErrorInternal\n"); |
- /* When the decoder is used by the NaCl validator */ |
- /* the validator provides an error handler that does */ |
- /* the necessary bookeeping to track these errors. */ |
- NCDecoderStateInternalError(dstate); |
-} |
- |
-/* Defines how to handle errors found while parsing the memory segment. */ |
-static void NCRemainingMemoryInternalError(NCRemainingMemoryError error, |
- struct NCRemainingMemory* memory) { |
- /* Don't do anything for memory overflow! Let NCDecodeSegment generate |
- * the corresponding segmentation error. This allows us to back out overflow |
- * if a predefined nop is matched. |
- */ |
- if (NCRemainingMemoryOverflow != error) { |
- NCDecoderState* dstate = (NCDecoderState*) memory->error_fn_state; |
- NCRemainingMemoryReportError(error, memory); |
- ErrorInternal(&dstate->inst_buffer[dstate->cur_inst_index]); |
- } |
-} |
- |
-static INLINE void InitDecoder(struct NCDecoderInst* dinst) { |
- NCInstBytesInitInline(&dinst->inst.bytes); |
- dinst->inst.prefixbytes = 0; |
- dinst->inst.prefixmask = 0; |
- dinst->inst.opcode_prefixmask = 0; |
- dinst->inst.num_opbytes = 1; /* unless proven otherwise. */ |
- dinst->inst.hassibbyte = 0; |
- dinst->inst.mrm = 0; |
- dinst->inst.immtype = IMM_UNKNOWN; |
- dinst->inst.immbytes = 0; |
- dinst->inst.dispbytes = 0; |
- dinst->inst.rexprefix = 0; |
- dinst->inst.lock_prefix_index = kNoLockPrefixIndex; |
- dinst->opinfo = NULL; |
-} |
- |
-/* Returns the number of bytes defined for the operand of the instruction. */ |
-static int ExtractOperandSize(NCDecoderInst* dinst) { |
- if (NACL_TARGET_SUBARCH == 64 && |
- dinst->inst.rexprefix && dinst->inst.rexprefix & 0x8) { |
- return 8; |
- } |
- if (dinst->inst.prefixmask & kPrefixDATA16) { |
- return 2; |
- } |
- return 4; |
-} |
- |
-/* at most four prefix bytes are allowed */ |
-static void ConsumePrefixBytes(struct NCDecoderInst* dinst) { |
- uint8_t nb; |
- int ii; |
- uint32_t prefix_form; |
- |
- for (ii = 0; ii < kMaxPrefixBytes; ++ii) { |
- nb = NCRemainingMemoryGetNext(&dinst->dstate->memory); |
- prefix_form = kPrefixTable[nb]; |
- if (prefix_form == 0) return; |
- DEBUG( printf("Consume prefix[%d]: %02x => %x\n", ii, nb, prefix_form) ); |
- dinst->inst.prefixmask |= prefix_form; |
- dinst->inst.prefixmask |= kPrefixTable[nb]; |
- dinst->inst.prefixbytes += 1; |
- NCInstBytesReadInline(&dinst->inst.bytes); |
- DEBUG( printf(" prefix mask: %08x\n", dinst->inst.prefixmask) ); |
- if (NACL_TARGET_SUBARCH == 64 && prefix_form == kPrefixREX) { |
- dinst->inst.rexprefix = nb; |
- /* REX prefix must be last prefix. */ |
- return; |
- } |
- if (prefix_form == kPrefixLOCK) { |
- /* Note: we don't have to worry about duplicates, since |
- * ValidatePrefixes in ncvalidate.c will not allow such |
- * a possibility. |
- */ |
- dinst->inst.lock_prefix_index = (uint8_t) ii; |
- } |
- } |
-} |
- |
-static const struct OpInfo* GetExtendedOpInfo(NCDecoderInst* dinst, |
- uint8_t opbyte2) { |
- uint32_t pm; |
- pm = dinst->inst.prefixmask; |
- if ((pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) == 0) { |
- return &kDecode0FXXOp[opbyte2]; |
- } else if (pm & kPrefixDATA16) { |
- dinst->inst.prefixmask &= ~kPrefixDATA16; |
- dinst->inst.opcode_prefixmask = kPrefixDATA16; |
- return &kDecode660FXXOp[opbyte2]; |
- } else if (pm & kPrefixREPNE) { |
- dinst->inst.prefixmask &= ~kPrefixREPNE; |
- dinst->inst.opcode_prefixmask = kPrefixREPNE; |
- return &kDecodeF20FXXOp[opbyte2]; |
- } else if (pm & kPrefixREP) { |
- dinst->inst.prefixmask &= ~kPrefixREP; |
- dinst->inst.opcode_prefixmask = kPrefixREP; |
- return &kDecodeF30FXXOp[opbyte2]; |
- } |
- ErrorInternal(dinst); |
- return dinst->opinfo; |
-} |
- |
-static void GetX87OpInfo(NCDecoderInst* dinst) { |
- /* WAIT is an x87 instruction but not in the coproc opcode space. */ |
- uint8_t op1 = NCInstBytesByteInline(&dinst->inst_bytes, |
- dinst->inst.prefixbytes); |
- if (op1 < kFirstX87Opcode || op1 > kLastX87Opcode) { |
- if (op1 != kWAITOp) ErrorInternal(dinst); |
- return; |
- } |
- dinst->opinfo = &kDecodeX87Op[op1 - kFirstX87Opcode][dinst->inst.mrm]; |
- DEBUG( printf("NACL_X87 op1 = %02x, ", op1); |
- PrintOpInfo(dinst->opinfo) ); |
-} |
- |
-static void ConsumeOpcodeBytes(NCDecoderInst* dinst) { |
- uint8_t opcode = NCInstBytesReadInline(&dinst->inst.bytes); |
- dinst->opinfo = &kDecode1ByteOp[opcode]; |
- DEBUG( printf("NACLi_1BYTE: opcode = %02x, ", opcode); |
- PrintOpInfo(dinst->opinfo) ); |
- if (opcode == kTwoByteOpcodeByte1) { |
- uint8_t opcode2 = NCInstBytesReadInline(&dinst->inst.bytes); |
- dinst->opinfo = GetExtendedOpInfo(dinst, opcode2); |
- DEBUG( printf("NACLi_2BYTE: opcode2 = %02x, ", opcode2); |
- PrintOpInfo(dinst->opinfo) ); |
- dinst->inst.num_opbytes = 2; |
- if (dinst->opinfo->insttype == NACLi_3BYTE) { |
- uint8_t opcode3 = NCInstBytesReadInline(&dinst->inst.bytes); |
- uint32_t pm; |
- pm = dinst->inst.opcode_prefixmask; |
- dinst->inst.num_opbytes = 3; |
- |
- DEBUG( printf("NACLi_3BYTE: opcode3 = %02x, ", opcode3) ); |
- switch (opcode2) { |
- case 0x38: /* SSSE3, SSE4 */ |
- if (pm & kPrefixDATA16) { |
- dinst->opinfo = &kDecode660F38Op[opcode3]; |
- } else if (pm & kPrefixREPNE) { |
- dinst->opinfo = &kDecodeF20F38Op[opcode3]; |
- } else if (pm == 0) { |
- dinst->opinfo = &kDecode0F38Op[opcode3]; |
- } else { |
- /* Other prefixes like F3 cause an undefined instruction error. */ |
- /* Note from decoder table that NACLi_3BYTE is only used with */ |
- /* data16 and repne prefixes. */ |
- ErrorInternal(dinst); |
- } |
- break; |
- case 0x3A: /* SSSE3, SSE4 */ |
- if (pm & kPrefixDATA16) { |
- dinst->opinfo = &kDecode660F3AOp[opcode3]; |
- } else if (pm == 0) { |
- dinst->opinfo = &kDecode0F3AOp[opcode3]; |
- } else { |
- /* Other prefixes like F3 cause an undefined instruction error. */ |
- /* Note from decoder table that NACLi_3BYTE is only used with */ |
- /* data16 and repne prefixes. */ |
- ErrorInternal(dinst); |
- } |
- break; |
- default: |
- /* if this happens there is a decoding table bug */ |
- ErrorInternal(dinst); |
- break; |
- } |
- DEBUG( PrintOpInfo(dinst->opinfo) ); |
- } |
- } |
- dinst->inst.immtype = dinst->opinfo->immtype; |
-} |
- |
-static void ConsumeModRM(NCDecoderInst* dinst) { |
- if (dinst->opinfo->hasmrmbyte != 0) { |
- const uint8_t mrm = NCInstBytesReadInline(&dinst->inst.bytes); |
- DEBUG( printf("Mod/RM byte: %02x\n", mrm) ); |
- dinst->inst.mrm = mrm; |
- if (dinst->opinfo->insttype == NACLi_X87 || |
- dinst->opinfo->insttype == NACLi_X87_FSINCOS) { |
- GetX87OpInfo(dinst); |
- } |
- if (dinst->opinfo->opinmrm) { |
- const struct OpInfo* mopinfo = |
- &kDecodeModRMOp[dinst->opinfo->opinmrm][modrm_opcodeInline(mrm)]; |
- dinst->opinfo = mopinfo; |
- DEBUG( printf("NACLi_opinmrm: modrm.opcode = %x, ", |
- modrm_opcodeInline(mrm)); |
- PrintOpInfo(dinst->opinfo) ); |
- if (dinst->inst.immtype == IMM_UNKNOWN) { |
- assert(0); |
- dinst->inst.immtype = mopinfo->immtype; |
- } |
- /* handle weird case for 0xff TEST Ib/Iv */ |
- if (modrm_opcodeInline(mrm) == 0) { |
- if (dinst->inst.immtype == IMM_GROUP3_F6) { |
- dinst->inst.immtype = IMM_FIXED1; |
- } |
- if (dinst->inst.immtype == IMM_GROUP3_F7) { |
- dinst->inst.immtype = IMM_DATAV; |
- } |
- } |
- DEBUG( printf(" immtype = %s\n", |
- NCDecodeImmediateTypeName(dinst->inst.immtype)) ); |
- } |
- if (dinst->inst.prefixmask & kPrefixADDR16) { |
- switch (modrm_modInline(mrm)) { |
- case 0: |
- if (modrm_rmInline(mrm) == 0x06) { |
- dinst->inst.dispbytes = 2; /* disp16 */ |
- } else { |
- dinst->inst.dispbytes = 0; |
- } |
- break; |
- case 1: |
- dinst->inst.dispbytes = 1; /* disp8 */ |
- break; |
- case 2: |
- dinst->inst.dispbytes = 2; /* disp16 */ |
- break; |
- case 3: |
- dinst->inst.dispbytes = 0; /* no disp */ |
- break; |
- default: |
- ErrorInternal(dinst); |
- } |
- dinst->inst.hassibbyte = 0; |
- } else { |
- switch (modrm_modInline(mrm)) { |
- case 0: |
- if (modrm_rmInline(mrm) == 0x05) { |
- dinst->inst.dispbytes = 4; /* disp32 */ |
- } else { |
- dinst->inst.dispbytes = 0; |
- } |
- break; |
- case 1: |
- dinst->inst.dispbytes = 1; /* disp8 */ |
- break; |
- case 2: |
- dinst->inst.dispbytes = 4; /* disp32 */ |
- break; |
- case 3: |
- dinst->inst.dispbytes = 0; /* no disp */ |
- break; |
- default: |
- ErrorInternal(dinst); |
- } |
- dinst->inst.hassibbyte = ((modrm_rmInline(mrm) == 0x04) && |
- (modrm_modInline(mrm) != 3)); |
- } |
- } |
- DEBUG( printf(" dispbytes = %d, hasibbyte = %d\n", |
- dinst->inst.dispbytes, dinst->inst.hassibbyte) ); |
-} |
- |
-static INLINE void ConsumeSIB(NCDecoderInst* dinst) { |
- if (dinst->inst.hassibbyte != 0) { |
- const uint8_t sib = NCInstBytesReadInline(&dinst->inst.bytes); |
- if (sib_base(sib) == 0x05) { |
- switch (modrm_modInline(dinst->inst.mrm)) { |
- case 0: dinst->inst.dispbytes = 4; break; |
- case 1: dinst->inst.dispbytes = 1; break; |
- case 2: dinst->inst.dispbytes = 4; break; |
- case 3: |
- default: |
- ErrorInternal(dinst); |
- } |
- } |
- DEBUG( printf("sib byte: %02x, dispbytes = %d\n", |
- sib, dinst->inst.dispbytes) ); |
- } |
-} |
- |
-static INLINE void ConsumeID(NCDecoderInst* dinst) { |
- if (dinst->inst.immtype == IMM_UNKNOWN) { |
- ErrorInternal(dinst); |
- } |
- /* NOTE: NaCl allows at most one prefix byte (for 32-bit mode) */ |
- if (dinst->inst.immtype == IMM_MOV_DATAV) { |
- dinst->inst.immbytes = ExtractOperandSize(dinst); |
- } else if (dinst->inst.prefixmask & kPrefixDATA16) { |
- dinst->inst.immbytes = kImmTypeToSize66[dinst->inst.immtype]; |
- } else if (dinst->inst.prefixmask & kPrefixADDR16) { |
- dinst->inst.immbytes = kImmTypeToSize67[dinst->inst.immtype]; |
- } else { |
- dinst->inst.immbytes = kImmTypeToSize[dinst->inst.immtype]; |
- } |
- NCInstBytesReadBytesInline((ssize_t) dinst->inst.immbytes, |
- &dinst->inst.bytes); |
- NCInstBytesReadBytesInline((ssize_t) dinst->inst.dispbytes, |
- &dinst->inst.bytes); |
- DEBUG(printf("ID: %d disp bytes, %d imm bytes\n", |
- dinst->inst.dispbytes, dinst->inst.immbytes)); |
-} |
- |
-/* Actually this routine is special for 3DNow instructions */ |
-static INLINE void MaybeGet3ByteOpInfo(NCDecoderInst* dinst) { |
- if (dinst->opinfo->insttype == NACLi_3DNOW) { |
- uint8_t opbyte1 = NCInstBytesByteInline(&dinst->inst_bytes, |
- dinst->inst.prefixbytes); |
- uint8_t opbyte2 = NCInstBytesByteInline(&dinst->inst_bytes, |
- dinst->inst.prefixbytes + 1); |
- if (opbyte1 == kTwoByteOpcodeByte1 && |
- opbyte2 == k3DNowOpcodeByte2) { |
- uint8_t immbyte = |
- NCInstBytesByteInline(&dinst->inst_bytes, |
- dinst->inst.bytes.length - 1); |
- dinst->opinfo = &kDecode0F0FOp[immbyte]; |
- DEBUG( printf( |
- "NACLi_3DNOW: byte1 = %02x, byte2 = %02x, immbyte = %02x,\n ", |
- opbyte1, opbyte2, immbyte); |
- PrintOpInfo(dinst->opinfo) ); |
- } |
- } |
-} |
- |
-/* Gets an instruction nindex away from the given instruction. |
- * WARNING: Does not do bounds checking, other than rolling the |
- * index as needed to stay within the (circular) instruction buffer. |
- */ |
-static NCDecoderInst* NCGetInstDiff(const NCDecoderInst* dinst, |
- int nindex) { |
- /* Note: This code also handles increments, so that we can |
- * use the same code for both. |
- */ |
- size_t index = (dinst->inst_index + nindex) % dinst->dstate->inst_buffer_size; |
- return &dinst->dstate->inst_buffer[index]; |
-} |
- |
-struct NCDecoderInst* PreviousInst(const NCDecoderInst* dinst, |
- int nindex) { |
- if ((nindex > 0) && (((size_t) nindex) < dinst->inst_count)) { |
- return NCGetInstDiff(dinst, -nindex); |
- } else { |
- return NULL; |
- } |
-} |
- |
-/* Initialize the decoder state fields, assuming constructor parameter |
- * fields mbase, vbase, size, inst_buffer, and inst_buffer_size have |
- * already been set. |
- */ |
-static void NCDecoderStateInitFields(NCDecoderState* this) { |
- size_t dbindex; |
- this->error_reporter = &kNCNullErrorReporter; |
- NCRemainingMemoryInit(this->mbase, this->size, &this->memory); |
- this->memory.error_fn = NCRemainingMemoryInternalError; |
- this->memory.error_fn_state = (void*) this; |
- for (dbindex = 0; dbindex < this->inst_buffer_size; ++dbindex) { |
- this->inst_buffer[dbindex].dstate = this; |
- this->inst_buffer[dbindex].inst_index = dbindex; |
- this->inst_buffer[dbindex].inst_count = 1; |
- this->inst_buffer[dbindex].inst_addr = 0; |
- this->inst_buffer[dbindex].unchanged = FALSE; |
- NCInstBytesInitMemory(&this->inst_buffer[dbindex].inst.bytes, |
- &this->memory); |
- NCInstBytesPtrInit((NCInstBytesPtr*) &this->inst_buffer[dbindex].inst_bytes, |
- &this->inst_buffer[dbindex].inst.bytes); |
- } |
- this->cur_inst_index = 0; |
-} |
- |
-void NCDecoderStateConstruct(NCDecoderState* this, |
- uint8_t* mbase, NaClPcAddress vbase, |
- NaClMemorySize size, |
- NCDecoderInst* inst_buffer, |
- size_t inst_buffer_size) { |
- |
- /* Start by setting up virtual functions. */ |
- this->action_fn = NullDecoderAction; |
- this->new_segment_fn = NullDecoderMethod; |
- this->segmentation_error_fn = NullDecoderMethod; |
- this->internal_error_fn = NullDecoderMethod; |
- |
- /* Initialize the user-provided fields. */ |
- this->mbase = mbase; |
- this->vbase = vbase; |
- this->size = size; |
- this->inst_buffer = inst_buffer; |
- this->inst_buffer_size = inst_buffer_size; |
- |
- NCDecoderStateInitFields(this); |
-} |
- |
-void NCDecoderStateDestruct(NCDecoderState* this) { |
- /* Currently, there is nothing to do. */ |
-} |
- |
-/* "Printable" means the value returned by this function can be used for |
- * printing user-readable output, but it should not be used to influence if the |
- * validation algorithm passes or fails. The validation algorithm should not |
- * depend on vbase - in other words, it should not depend on where the code is |
- * being mapped in memory. |
- */ |
-static INLINE NaClPcAddress NCPrintableVLimit(NCDecoderState *dstate) { |
- return dstate->vbase + dstate->size; |
-} |
- |
-/* Modify the current instruction pointer to point to the next instruction |
- * in the ring buffer. Reset the state of that next instruction. |
- */ |
-static NCDecoderInst* IncrementInst(NCDecoderInst* inst) { |
- /* giving PreviousInst a positive number will get NextInst |
- * better to keep the buffer switching logic in one place |
- */ |
- NCDecoderInst* next_inst = NCGetInstDiff(inst, 1); |
- next_inst->inst_addr = inst->inst_addr + inst->inst.bytes.length; |
- next_inst->dstate->cur_inst_index = next_inst->inst_index; |
- next_inst->inst_count = inst->inst_count + 1; |
- next_inst->unchanged = FALSE; |
- return next_inst; |
-} |
- |
-/* Get the i-th byte of the current instruction being parsed. */ |
-static uint8_t GetInstByte(NCDecoderInst* dinst, ssize_t i) { |
- if (i < dinst->inst.bytes.length) { |
- return dinst->inst.bytes.byte[i]; |
- } else { |
- return NCRemainingMemoryLookaheadInline(&dinst->dstate->memory, |
- i - dinst->inst.bytes.length); |
- } |
-} |
- |
-/* Consume a predefined nop byte sequence, if a match can be found. |
- * Further, if found, replace the currently matched instruction with |
- * the consumed predefined nop. |
- */ |
-static void ConsumePredefinedNop(NCDecoderInst* dinst) { |
- /* Do maximal match of possible nops */ |
- uint8_t pos = 0; |
- struct OpInfo* matching_opinfo = NULL; |
- ssize_t matching_length = 0; |
- NCNopTrieNode* next = (NCNopTrieNode*) (kNcNopTrieNode + 0); |
- uint8_t byte = GetInstByte(dinst, pos); |
- while (NULL != next) { |
- if (byte == next->matching_byte) { |
- DEBUG(printf("NOP match byte: 0x%02x\n", (int) byte)); |
- byte = GetInstByte(dinst, ++pos); |
- if (NULL != next->matching_opinfo) { |
- DEBUG(printf("NOP matched rule! %d\n", pos)); |
- matching_opinfo = next->matching_opinfo; |
- matching_length = pos; |
- } |
- next = next->success; |
- } else { |
- next = next->fail; |
- } |
- } |
- if (NULL == matching_opinfo) { |
- DEBUG(printf("NOP match failed!\n")); |
- } else { |
- DEBUG(printf("NOP match succeeds! Using last matched rule.\n")); |
- NCRemainingMemoryResetInline(&dinst->dstate->memory); |
- InitDecoder(dinst); |
- NCInstBytesReadBytesInline(matching_length, &dinst->inst.bytes); |
- dinst->opinfo = matching_opinfo; |
- } |
-} |
- |
-/* If we didn't find a good instruction, try to consume one of the |
- * predefined NOP's. |
- */ |
-static void MaybeConsumePredefinedNop(NCDecoderInst* dinst) { |
- switch (dinst->opinfo->insttype) { |
- case NACLi_UNDEFINED: |
- case NACLi_INVALID: |
- case NACLi_ILLEGAL: |
- ConsumePredefinedNop(dinst); |
- break; |
- default: |
- break; |
- } |
-} |
- |
-/* All of the actions needed to read one additional instruction into mstate. |
- */ |
-void NCConsumeNextInstruction(struct NCDecoderInst* inst) { |
- DEBUG( printf("Decoding instruction at %"NACL_PRIxNaClPcAddress":\n", |
- inst->inst_addr) ); |
- InitDecoder(inst); |
- ConsumePrefixBytes(inst); |
- ConsumeOpcodeBytes(inst); |
- ConsumeModRM(inst); |
- ConsumeSIB(inst); |
- ConsumeID(inst); |
- MaybeGet3ByteOpInfo(inst); |
- MaybeConsumePredefinedNop(inst); |
-} |
- |
-void NCDecoderStateSetErrorReporter(NCDecoderState* this, |
- NaClErrorReporter* reporter) { |
- switch (reporter->supported_reporter) { |
- case NaClNullErrorReporter: |
- case NCDecoderInstErrorReporter: |
- this->error_reporter = reporter; |
- return; |
- default: |
- break; |
- } |
- (*reporter->printf)( |
- reporter, |
- "*** FATAL: using unsupported error reporter! ***\n" |
- "*** NCDecoderInstErrorReporter expected but found %s***\n", |
- NaClErrorReporterSupportedName(reporter->supported_reporter)); |
- exit(1); |
-} |
- |
-static void NCNullErrorPrintInst(NaClErrorReporter* self, |
- struct NCDecoderInst* inst) {} |
- |
-NaClErrorReporter kNCNullErrorReporter = { |
- NaClNullErrorReporter, |
- NaClNullErrorPrintf, |
- NaClNullErrorPrintfV, |
- (NaClPrintInst) NCNullErrorPrintInst, |
-}; |
- |
-Bool NCDecoderStateDecode(NCDecoderState* this) { |
- NCDecoderInst* dinst = &this->inst_buffer[this->cur_inst_index]; |
- DEBUG( printf("DecodeSegment(%p[%"NACL_PRIxNaClPcAddress"])\n", |
- (void*) this->memory.mpc, (NaClPcAddress) this->size) ); |
- NCDecoderStateNewSegment(this); |
- while (dinst->inst_addr < this->size) { |
- NCConsumeNextInstruction(dinst); |
- if (this->memory.overflow_count) { |
- NaClPcAddress newpc = (NCPrintableInstructionAddress(dinst) |
- + dinst->inst.bytes.length); |
- (*this->error_reporter->printf)( |
- this->error_reporter, |
- "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress |
- " (read overflow of %d bytes)\n", |
- newpc, NCPrintableVLimit(this), this->memory.overflow_count); |
- ErrorSegmentation(dinst); |
- return FALSE; |
- } |
- if (!NCDecoderStateApplyAction(this, dinst)) return FALSE; |
- /* get ready for next round */ |
- dinst = IncrementInst(dinst); |
- } |
- return TRUE; |
-} |
- |
-/* Default action for a decoder state pair. */ |
-static Bool NullNCDecoderStatePairAction(struct NCDecoderStatePair* tthis, |
- NCDecoderInst* old_inst, |
- NCDecoderInst* new_inst) { |
- return TRUE; |
-} |
- |
-void NCDecoderStatePairConstruct(NCDecoderStatePair* tthis, |
- NCDecoderState* old_dstate, |
- NCDecoderState* new_dstate, |
- NaClCopyInstructionFunc copy_func) { |
- tthis->old_dstate = old_dstate; |
- tthis->new_dstate = new_dstate; |
- tthis->action_fn = NullNCDecoderStatePairAction; |
- tthis->copy_func = copy_func; |
-} |
- |
-void NCDecoderStatePairDestruct(NCDecoderStatePair* tthis) { |
-} |
- |
-Bool NCDecoderStatePairDecode(NCDecoderStatePair* tthis) { |
- NCDecoderInst* old_dinst = |
- &tthis->old_dstate->inst_buffer[tthis->old_dstate->cur_inst_index]; |
- NCDecoderInst* new_dinst = |
- &tthis->new_dstate->inst_buffer[tthis->new_dstate->cur_inst_index]; |
- |
- /* Verify that the size of the code segments is the same, and has not |
- * been changed. |
- */ |
- if (tthis->old_dstate->size != tthis->new_dstate->size) { |
- /* If sizes differ, then they can't be the same, except for some |
- * (constant-sized) changes. Hence fail to decode. |
- */ |
- ErrorSegmentation(new_dinst); |
- return FALSE; |
- } |
- |
- /* Since the sizes of the segments are the same, only one limit |
- * needs to be checked. Hence, we will track the limit of the new |
- * decoder state. |
- */ |
- DEBUG( printf("NCDecoderStatePairDecode(%"NACL_PRIxNaClPcAddress")\n", |
- (NaClPcAddress) tthis->new_dstate->size)); |
- |
- /* Initialize decoder statements for decoding segment, by calling |
- * the corresponding virtual in the decoder. |
- */ |
- NCDecoderStateNewSegment(tthis->old_dstate); |
- NCDecoderStateNewSegment(tthis->new_dstate); |
- |
- /* Walk through both instruction segments, checking that |
- * they decode similarly. |
- */ |
- while (new_dinst->inst_addr < tthis->new_dstate->size) { |
- |
- NCConsumeNextInstruction(old_dinst); |
- NCConsumeNextInstruction(new_dinst); |
- |
- |
- /* Verify that the instruction lengths match. */ |
- if (old_dinst->inst.bytes.length != |
- new_dinst->inst.bytes.length) { |
- ErrorInternal(new_dinst); |
- return FALSE; |
- } |
- |
- /* Verify that we haven't walked past the end of the segment |
- * in either decoder state. |
- * |
- * Note: Since instruction lengths are the same, and the |
- * segment lengths are the same, if overflow occurs on one |
- * segment, it must occur on the other. |
- */ |
- if (new_dinst->inst_addr > tthis->new_dstate->size) { |
- NaClErrorReporter* reporter = new_dinst->dstate->error_reporter; |
- (*reporter->printf)( |
- reporter, |
- "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress"\n", |
- NCPrintableInstructionAddress(new_dinst), |
- NCPrintableVLimit(tthis->new_dstate)); |
- ErrorSegmentation(new_dinst); |
- return FALSE; |
- } |
- |
- /* Apply the action to the instructions, and continue |
- * only if the action succeeds. |
- */ |
- if (! (tthis->action_fn)(tthis, old_dinst, new_dinst)) { |
- return FALSE; |
- } |
- |
- /* Move to next instruction. */ |
- old_dinst = IncrementInst(old_dinst); |
- new_dinst = IncrementInst(new_dinst); |
- } |
- return TRUE; |
-} |