Chromium Code Reviews| Index: src/trusted/validator_x86/nc_inst_state_statics.c |
| =================================================================== |
| --- src/trusted/validator_x86/nc_inst_state_statics.c (revision 4929) |
| +++ src/trusted/validator_x86/nc_inst_state_statics.c (working copy) |
| @@ -5,17 +5,14 @@ |
| */ |
| /* |
| - * Defines an instruction (decoder), based on the current location of |
| - * the instruction iterator. The instruction decoder takes a list |
| - * of candidate opcode (instruction) patterns, and searches for the |
| - * first candidate that matches the requirements of the opcode pattern. |
| + * This file contains includes, static functions, and constants that are used |
| + * in nc_inst_state.c, but have been factored out and put into this file, so |
| + * that we can test them. That is, to allow nc_inst_state.c and |
| + * nc_inst_state_Tests.cc to use them. |
| */ |
|
Brad Chen
2011/04/25 21:47:27
It would probably make sense to put in a #define p
Karl
2011/06/24 18:15:00
Done.
|
| #include <stdio.h> |
| #include <assert.h> |
| - |
| -#include "native_client/src/trusted/validator_x86/nc_inst_state.h" |
| - |
| #include "native_client/src/shared/platform/nacl_log.h" |
| #include "native_client/src/trusted/validator_x86/nc_inst_iter.h" |
| #include "native_client/src/trusted/validator_x86/nc_inst_state_internal.h" |
| @@ -28,14 +25,12 @@ |
| #else |
| #include "gen/native_client/src/trusted/validator_x86/nc_opcode_table.h" |
| #endif |
| +#include "native_client/src/trusted/validator_x86/RexPrefixes.h" |
| -/* To turn on debugging of instruction decoding, change value of |
| - * DEBUGGING to 1. |
| - */ |
| -#define DEBUGGING 0 |
| - |
| #include "native_client/src/shared/utils/debugging.h" |
| +EXTERN_C_BEGIN |
| + |
| /* Given the current location of the instruction iterator, initialize |
| * the given state (to match). |
| */ |
| @@ -73,22 +68,22 @@ |
| * instruction of the given state. |
| */ |
| static int NaClExtractOpSize(NaClInstState* state) { |
| - if (state->inst->flags & NACL_IFLAG(OperandSize_b)) { |
| + if (NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSize_b))) { |
| return 1; |
| } |
| if (NACL_TARGET_SUBARCH == 64) { |
| - if ((state->rexprefix && state->rexprefix & 0x8) || |
| - (state->inst->flags & NACL_IFLAG(OperandSizeForce64))) { |
| + if ((state->rexprefix && NaClRexW(state->rexprefix)) || |
| + (NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSizeForce64)))) { |
| return 8; |
| } |
| } |
| - if ((state->prefix_mask & kPrefixDATA16) && |
| + if (NaClHasBit(state->prefix_mask, kPrefixDATA16) && |
| (NACL_EMPTY_IFLAGS == |
| (state->inst->flags & NACL_IFLAG(SizeIgnoresData16)))) { |
| return 2; |
| } |
| if ((NACL_TARGET_SUBARCH == 64) && |
| - (state->inst->flags & NACL_IFLAG(OperandSizeDefaultIs64))) { |
| + NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSizeDefaultIs64))) { |
| return 8; |
| } |
| return 4; |
| @@ -99,9 +94,9 @@ |
| */ |
| static int NaClExtractAddressSize(NaClInstState* state) { |
| if (NACL_TARGET_SUBARCH == 64) { |
| - return (state->prefix_mask & kPrefixADDR16) ? 32 : 64; |
| + return NaClHasBit(state->prefix_mask, kPrefixADDR16) ? 32 : 64; |
| } else { |
| - return (state->prefix_mask & kPrefixADDR16) ? 16 : 32; |
| + return NaClHasBit(state->prefix_mask, kPrefixADDR16) ? 16 : 32; |
| } |
| } |
| @@ -183,28 +178,12 @@ |
| * prefix to occur anywhere. |
| */ |
| if (rex_index >= 0) { |
| - return (rex_index + 1) == state->num_prefix_bytes; |
| + return (Bool) ((rex_index + 1) == state->num_prefix_bytes); |
| } |
| } |
| return TRUE; |
| } |
| -/* Structure holding the results of consuming the opcode bytes of the |
| - * instruction. |
| - */ |
| -typedef struct { |
| - /* The (last) byte of the matched opcode. */ |
| - uint8_t opcode_byte; |
| - /* The most specific prefix that the opcode bytes can match |
| - * (or OpcodePrefixEnumSize if no such patterns exist). |
| - */ |
| - NaClInstPrefix matched_prefix; |
| - /* The number of bytes to subtract from the instruction length, |
| - * the next time GetNextNaClInstCandidates is called. |
| - */ |
| - uint8_t next_length_adjustment; |
| -} NaClInstPrefixDescriptor; |
| - |
| /* Assuming we have matched the byte sequence OF 38, consume the corresponding |
| * following (instruction) opcode byte, returning the most specific prefix the |
| * patterns can match (or NaClInstPrefixEnumSize if no such patterns exist); |
| @@ -220,17 +199,23 @@ |
| } |
| desc->opcode_byte = NCInstBytesRead(&state->bytes); |
| - if (state->prefix_mask & kPrefixREPNE) { |
| - desc->matched_prefix = PrefixF20F38; |
| + DEBUG(NaClLog(LOG_INFO, "Consume inst byte %02"NACL_PRIx8".\n", |
| + desc->opcode_byte)); |
| + if (NaClExcludesBit(state->prefix_mask, kPrefixREP)) { |
| + if (NaClHasBit(state->prefix_mask, kPrefixREPNE)) { |
| + /* Note: Flag OpcodeAllowsData16 will explicitly clarify |
| + * ambigous case of both REP and DATA16 prefixes. |
| + */ |
| + desc->matched_prefix = PrefixF20F38; |
| + } else if (NaClHasBit(state->prefix_mask, kPrefixDATA16)) { |
| + desc->matched_prefix = Prefix660F38; |
| + } else { |
| + desc->matched_prefix = Prefix0F38; |
| + } |
| + return; |
| } |
| - else if (state->prefix_mask & kPrefixDATA16) { |
| - desc->matched_prefix = Prefix660F38; |
| - } else if ((state->prefix_mask & ~kPrefixREX) == 0) { |
| - desc->matched_prefix = Prefix0F38; |
| - } else { |
| - /* Other prefixes like F3 cause an undefined instruction error. */ |
| - desc->matched_prefix = NaClInstPrefixEnumSize; |
| - } |
| + /* If reached, can't match special prefixes, fail. */ |
| + desc->matched_prefix = NaClInstPrefixEnumSize; |
| } |
| /* Assuming we have matched the byte sequence OF 3A, consume the corresponding |
| @@ -248,14 +233,19 @@ |
| } |
| desc->opcode_byte = NCInstBytesRead(&state->bytes); |
| - if (state->prefix_mask & kPrefixDATA16) { |
| - desc->matched_prefix = Prefix660F3A; |
| - } else if ((state->prefix_mask & ~kPrefixREX) == 0) { |
| - desc->matched_prefix = Prefix0F3A; |
| - } else { |
| - /* Other prefixes like F3 cause an undefined instruction error. */ |
| - desc->matched_prefix = NaClInstPrefixEnumSize; |
| + DEBUG(NaClLog(LOG_INFO, "Consume inst byte %02"NACL_PRIx8".\n", |
| + desc->opcode_byte)); |
| + if (NaClExcludesBit(state->prefix_mask, kPrefixREP) && |
| + NaClExcludesBit(state->prefix_mask, kPrefixREPNE)) { |
| + if (NaClHasBit(state->prefix_mask, kPrefixDATA16)) { |
| + desc->matched_prefix = Prefix660F3A; |
| + } else { |
| + desc->matched_prefix = Prefix0F3A; |
| + } |
| + return; |
| } |
| + /* If reached, can't match special prefixes, fail. */ |
| + desc->matched_prefix = NaClInstPrefixEnumSize; |
| } |
| /* Assuming we have matched byte OF, consume the corresponding |
| @@ -265,15 +255,29 @@ |
| */ |
| static void NaClConsume0FXXNaClInstBytes(NaClInstState* state, |
| NaClInstPrefixDescriptor* desc) { |
| - if (state->prefix_mask & kPrefixREPNE) { |
| - desc->matched_prefix = PrefixF20F; |
| - } else if (state->prefix_mask & kPrefixREP) { |
| - desc->matched_prefix = PrefixF30F; |
| - } else if (state->prefix_mask & kPrefixDATA16) { |
| - desc->matched_prefix = Prefix660F; |
| + if (NaClHasBit(state->prefix_mask, kPrefixREPNE)) { |
| + if (NaClExcludesBit(state->prefix_mask, kPrefixREP)) { |
| + /* Note: Flag OpcodeAllowsData16 will explicitly clarify |
| + * ambigous case of both REPNE and DATA16 prefixes. |
| + */ |
| + desc->matched_prefix = PrefixF20F; |
| + return; |
| + } |
| } else { |
| - desc->matched_prefix = Prefix0F; |
| + if (NaClHasBit(state->prefix_mask, kPrefixREP)) { |
| + /* Note: Flag OpcodeAllowsData16 will explicitly clarify |
| + * ambigous case of both REP and DATA16 prefixes. |
| + */ |
| + desc->matched_prefix = PrefixF30F; |
| + } else if (NaClHasBit(state->prefix_mask, kPrefixDATA16)) { |
| + desc->matched_prefix = Prefix660F; |
| + } else { |
| + desc->matched_prefix = Prefix0F; |
| + } |
| + return; |
| } |
| + /* If reached, can't match special prefixes, fail. */ |
| + desc->matched_prefix = NaClInstPrefixEnumSize; |
| } |
| /* Consume one of the x87 instructions that begin with D8-Df, and |
| @@ -283,9 +287,12 @@ |
| NaClInstPrefixDescriptor* desc) { |
| if (state->bytes.length < state->length_limit) { |
| /* Can be two byte opcode. */ |
| - desc->matched_prefix = PrefixD8 + |
| - (((unsigned) desc->opcode_byte) - 0xD8); |
| + desc->matched_prefix = |
| + (NaClInstPrefix) (PrefixD8 + |
| + (((unsigned) desc->opcode_byte) - 0xD8)); |
| desc->opcode_byte = NCInstBytesRead(&state->bytes); |
| + DEBUG(NaClLog(LOG_INFO, "Consume inst byte %02"NACL_PRIx8".\n", |
| + desc->opcode_byte)); |
| return; |
| } |
| @@ -309,10 +316,14 @@ |
| if (state->bytes.length >= state->length_limit) return; |
| desc->opcode_byte = NCInstBytesRead(&state->bytes); |
| + DEBUG(NaClLog(LOG_INFO, "Consume inst byte %02"NACL_PRIx8".\n", |
| + desc->opcode_byte)); |
| switch (desc->opcode_byte) { |
| case 0x0F: |
| if (state->bytes.length >= state->length_limit) return; |
| desc->opcode_byte = NCInstBytesRead(&state->bytes); |
| + DEBUG(NaClLog(LOG_INFO, "Consume inst byte %02"NACL_PRIx8".\n", |
| + desc->opcode_byte)); |
| switch (desc->opcode_byte) { |
| case 0x38: |
| NaClConsume0F38XXNaClInstBytes(state, desc); |
| @@ -358,13 +369,13 @@ |
| NaClIFlags good = 1; |
| switch (state->operand_size) { |
| case 2: |
| - good = (state->inst->flags & NACL_IFLAG(OperandSize_w)); |
| + good = NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSize_w)); |
| break; |
| case 4: |
| - good = (state->inst->flags & NACL_IFLAG(OperandSize_v)); |
| + good = NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSize_v)); |
| break; |
| case 8: |
| - good = (state->inst->flags & NACL_IFLAG(OperandSize_o)); |
| + good = NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSize_o)); |
| break; |
| default: |
| good = 0; |
| @@ -394,13 +405,13 @@ |
| NaClIFlags good = 1; |
| switch (state->address_size) { |
| case 16: |
| - good = (state->inst->flags & NACL_IFLAG(AddressSize_w)); |
| + good = NaClHasBit(state->inst->flags, NACL_IFLAG(AddressSize_w)); |
| break; |
| case 32: |
| - good = (state->inst->flags & NACL_IFLAG(AddressSize_v)); |
| + good = NaClHasBit(state->inst->flags, NACL_IFLAG(AddressSize_v)); |
| break; |
| case 64: |
| - good = (state->inst->flags & NACL_IFLAG(AddressSize_o)); |
| + good = NaClHasBit(state->inst->flags, NACL_IFLAG(AddressSize_o)); |
| break; |
| default: |
| good = 0; |
| @@ -422,7 +433,7 @@ |
| /* Returns true if the instruction requires a ModRm bytes. */ |
| static Bool NaClInstRequiresModRm(NaClInstState* state) { |
| - return |
| + return (Bool) |
| (NACL_EMPTY_IFLAGS != |
| (state->inst->flags & NACL_IFLAG(OpcodeUsesModRm))); |
| } |
| @@ -448,17 +459,17 @@ |
| * is 0x3. Others only allow values where the ModRm mod field isn't 0x3. |
| */ |
| if (modrm_mod(byte) == 0x3) { |
| - if (state->inst->flags & NACL_IFLAG(ModRmModIsnt0x3)) { |
| + if (NaClHasBit(state->inst->flags, NACL_IFLAG(ModRmModIsnt0x3))) { |
| DEBUG(NaClLog(LOG_INFO, "Can't match, modrm mod field is 0x3\n")); |
| return FALSE; |
| } |
| } else { |
| - if (state->inst->flags & NACL_IFLAG(ModRmModIs0x3)) { |
| + if (NaClHasBit(state->inst->flags, NACL_IFLAG(ModRmModIs0x3))) { |
| DEBUG(NaClLog(LOG_INFO, "Can't match, modrm mod field not 0x3\n")); |
| return FALSE; |
| } |
| } |
| - if ((state->inst->flags & NACL_IFLAG(ModRmRegSOperand)) && |
| + if ((NaClHasBit(state->inst->flags, NACL_IFLAG(ModRmRegSOperand))) && |
| (modrm_reg(byte) > 5)) { |
| DEBUG(NaClLog(LOG_INFO, |
| "Can't match, modrm reg field doesn't index segment\n")); |
| @@ -505,8 +516,9 @@ |
| * addressing. Hence, required for all but 16-bit addressing, when |
| * the right modrm bytes are specified. |
| */ |
| - return NaClInstRequiresModRm(state) && (16 != state->address_size) && |
| - (modrm_rm(state->modrm) == 0x04 && modrm_mod(state->modrm) != 0x3); |
| + return (Bool) |
| + (NaClInstRequiresModRm(state) && (16 != state->address_size) && |
| + (modrm_rm(state->modrm) == 0x04 && modrm_mod(state->modrm) != 0x3)); |
| } |
| /* Consume the SIB byte of the instruction, if applicable. Aborts the pattern |
| @@ -861,151 +873,4 @@ |
| } |
| } |
| -/* Given the current location of the (relative) pc of the given instruction |
| - * iterator, update the given state to hold the (found) matched opcode |
| - * (instruction) pattern. If no matching pattern exists, set the state |
| - * to a matched undefined opcode (instruction) pattern. In all cases, |
| - * update the state to hold all information on the matched bytes of the |
| - * instruction. Note: The iterator expects that the opcode field is |
| - * changed from NULL to non-NULL by this fuction. |
| - */ |
| -void NaClDecodeInst(NaClInstIter* iter, NaClInstState* state) { |
| - uint8_t opcode_length = 0; |
| - const NaClInst* cand_insts; |
| - Bool found_match = FALSE; |
| - /* Start by consuming the prefix bytes, and getting the possible |
| - * candidate opcode (instruction) patterns that can match, based |
| - * on the consumed opcode bytes. |
| - */ |
| - NaClInstStateInit(iter, state); |
| - if (NaClConsumeOpcodeSequence(state)) { |
| - found_match = TRUE; |
| - } else if (NaClConsumePrefixBytes(state)) { |
| - NaClInstPrefixDescriptor prefix_desc; |
| - Bool continue_loop = TRUE; |
| - NaClConsumeInstBytes(state, &prefix_desc); |
| - opcode_length = state->bytes.length; |
| - while (continue_loop) { |
| - /* Try matching all possible candidates, in the order they are specified |
| - * (from the most specific prefix match, to the least specific prefix |
| - * match). Quit when the first pattern is matched. |
| - */ |
| - if (prefix_desc.matched_prefix == NaClInstPrefixEnumSize) { |
| - continue_loop = FALSE; |
| - } else { |
| - cand_insts = NaClGetNextInstCandidates(state, &prefix_desc, |
| - &opcode_length); |
| - while (cand_insts != NULL) { |
| - NaClClearInstState(state, opcode_length); |
| - state->inst = cand_insts; |
| - DEBUG(NaClLog(LOG_INFO, "try opcode pattern:\n")); |
| - DEBUG(NaClInstPrint(NaClLogGetGio(), state->inst)); |
| - if (NaClConsumeAndCheckOperandSize(state) && |
| - NaClConsumeAndCheckAddressSize(state) && |
| - NaClConsumeModRm(state) && |
| - NaClConsumeSib(state) && |
| - NaClConsumeDispBytes(state) && |
| - NaClConsumeImmediateBytes(state) && |
| - NaClValidatePrefixFlags(state)) { |
| - if (state->inst->flags & NACL_IFLAG(Opcode0F0F) && |
| - /* Note: If all of the above code worked correctly, |
| - * there should be no need for the following test. |
| - * However, just to be safe, it is added. |
| - */ |
| - (state->num_imm_bytes == 1)) { |
| - /* Special 3DNOW instructions where opcode is in parsed |
| - * immediate byte at end of instruction. Look up in table, |
| - * and replace if found. Otherwise, let the default 0F0F lookup |
| - * act as the matching (invalid) instruction. |
| - */ |
| - const NaClInst* cand_inst; |
| - uint8_t opcode_byte = state->bytes.byte[state->first_imm_byte]; |
| - DEBUG(NaClLog(LOG_INFO, |
| - "NaClConsume immediate byte opcode char: %" |
| - NACL_PRIx8"\n", opcode_byte)); |
| - cand_inst = g_OpcodeTable[Prefix0F0F][opcode_byte]; |
| - if (NULL != cand_inst) { |
| - state->inst = cand_inst; |
| - DEBUG(NaClLog(LOG_INFO, "Replace with 3DNOW opcode:\n")); |
| - DEBUG(NaClInstPrint(NaClLogGetGio(), state->inst)); |
| - } |
| - } |
| - /* found a match, exit loop. */ |
| - found_match = TRUE; |
| - continue_loop = FALSE; |
| - break; |
| - } else { |
| - /* match failed, try next candidate pattern. */ |
| - cand_insts = cand_insts->next_rule; |
| - } |
| - } |
| - DEBUG(if (! found_match) { |
| - NaClLog(LOG_INFO, "no more candidates for this prefix\n"); |
| - }); |
| - } |
| - } |
| - } |
| - |
| - /* If we did not match a defined opcode, match the undefined opcode, |
| - * forcing field opcode to be non-NULL. |
| - */ |
| - if (!found_match) { |
| - DEBUG(NaClLog(LOG_INFO, "no instruction found, converting to undefined\n")); |
| - |
| - /* Can't figure out instruction, give up. */ |
| - NaClClearInstState(state, opcode_length); |
| - state->inst = &g_Undefined_Opcode; |
| - if (state->bytes.length == 0 && state->bytes.length < state->length_limit) { |
| - /* Make sure we eat at least one byte. */ |
| - NCInstBytesRead(&state->bytes); |
| - } |
| - } |
| -} |
| - |
| -const NaClInst* NaClInstStateInst(NaClInstState* state) { |
| - return state->inst; |
| -} |
| - |
| -NaClPcAddress NaClInstStateVpc(NaClInstState* state) { |
| - return state->vpc; |
| -} |
| - |
| -NaClExpVector* NaClInstStateExpVector(NaClInstState* state) { |
| - if (!state->nodes.is_defined) { |
| - state->nodes.is_defined = TRUE; |
| - NaClBuildExpVector(state); |
| - } |
| - return &state->nodes; |
| -} |
| - |
| -Bool NaClInstStateIsValid(NaClInstState* state) { |
| - return InstInvalid != state->inst->name; |
| -} |
| - |
| -uint8_t NaClInstStateLength(NaClInstState* state) { |
| - return state->bytes.length; |
| -} |
| - |
| -uint8_t NaClInstStateByte(NaClInstState* state, uint8_t index) { |
| - assert(index < state->bytes.length); |
| - return state->bytes.byte[index]; |
| -} |
| - |
| -uint8_t NaClInstStateOperandSize(NaClInstState* state) { |
| - return state->operand_size; |
| -} |
| - |
| -uint8_t NaClInstStateAddressSize(NaClInstState* state) { |
| - return state->address_size; |
| -} |
| - |
| -void NaClChangeOpcodesToXedsModel() { |
| - /* Changes opcodes to match xed. That is change: |
| - * 0f0f..1c: Pf2iw $Pq, $Qq => 0f0f..2c: Pf2iw $Pq, $Qq |
| - * 0f0f..1d: Pf2id $Pq, $Qq => 0f0f..2d: Pf2id $Pq, $Qq |
| - */ |
| - g_OpcodeTable[Prefix0F0F][0x2c] = g_OpcodeTable[Prefix0F0F][0x1c]; |
| - g_OpcodeTable[Prefix0F0F][0x1c] = NULL; |
| - g_OpcodeTable[Prefix0F0F][0x2d] = g_OpcodeTable[Prefix0F0F][0x1d]; |
| - g_OpcodeTable[Prefix0F0F][0x1d] = NULL; |
| -} |
| +EXTERN_C_END |