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 |