| 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,17 @@
|
| */
|
|
|
| /*
|
| - * 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.
|
| */
|
|
|
| +#ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NC_INST_STATE_STATICS_C__
|
| +#define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NC_INST_STATE_STATICS_C__
|
| +
|
| #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 +28,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 +71,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 +97,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 +181,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 +202,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 +236,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 +258,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 +290,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 +319,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 +372,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 +408,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 +436,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 +462,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 +519,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 +876,6 @@
|
| }
|
| }
|
|
|
| -/* 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");
|
| - });
|
| - }
|
| - }
|
| - }
|
| +EXTERN_C_END
|
|
|
| - /* 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;
|
| -}
|
| +#endif /* NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_NC_INST_STATE_STATICS_C__ */
|
|
|