| Index: src/trusted/validator/x86/decoder/nc_inst_state_statics.c
|
| diff --git a/src/trusted/validator/x86/decoder/nc_inst_state_statics.c b/src/trusted/validator/x86/decoder/nc_inst_state_statics.c
|
| deleted file mode 100644
|
| index a55d09946bf3d9434a38ca266d8b811cfc095536..0000000000000000000000000000000000000000
|
| --- a/src/trusted/validator/x86/decoder/nc_inst_state_statics.c
|
| +++ /dev/null
|
| @@ -1,1002 +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.
|
| - */
|
| -
|
| -/*
|
| - * 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_DECODER_NC_INST_STATE_STATICS_C__
|
| -#define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_DECODER_NC_INST_STATE_STATICS_C__
|
| -
|
| -#include <stdio.h>
|
| -#include <assert.h>
|
| -#include "native_client/src/shared/platform/nacl_log.h"
|
| -#include "native_client/src/shared/utils/debugging.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_inst_trans.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/ncopcode_desc.h"
|
| -#include "native_client/src/trusted/validator/x86/nc_segment.h"
|
| -
|
| -#include "native_client/src/trusted/validator/x86/ncinstbuffer_inl.c"
|
| -#include "native_client/src/trusted/validator/x86/x86_insts_inl.c"
|
| -
|
| -EXTERN_C_BEGIN
|
| -
|
| -/* Given the current location of the instruction iterator, initialize
|
| - * the given state (to match).
|
| - */
|
| -static void NaClInstStateInit(NaClInstIter* iter, NaClInstState* state) {
|
| - NaClMemorySize limit;
|
| - NCInstBytesInitInline(&state->bytes);
|
| - state->iter = iter;
|
| - state->decoder_tables = iter->decoder_tables;
|
| - state->inst_addr = iter->index;
|
| - limit = iter->segment->size - iter->index;
|
| - if (limit > NACL_MAX_BYTES_PER_X86_INSTRUCTION) {
|
| - limit = NACL_MAX_BYTES_PER_X86_INSTRUCTION;
|
| - }
|
| - state->length_limit = (uint8_t) limit;
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "length limit = %"NACL_PRIu8"\n", state->length_limit));
|
| - state->num_prefix_bytes = 0;
|
| - state->opcode_prefix = 0;
|
| - state->num_opcode_bytes = 0;
|
| - state->rexprefix = 0;
|
| - state->num_rex_prefixes = 0;
|
| - state->modrm = 0;
|
| - state->has_prefix_duplicates = FALSE;
|
| - state->has_ambig_segment_prefixes = FALSE;
|
| - state->has_sib = FALSE;
|
| - state->sib = 0;
|
| - state->num_disp_bytes = 0;
|
| - state->first_disp_byte = 0;
|
| - state->num_imm_bytes = 0;
|
| - state->first_imm_byte = 0;
|
| - state->num_imm2_bytes = 0;
|
| - state->prefix_mask = 0;
|
| - state->inst = NULL;
|
| - state->nodes.is_defined = FALSE;
|
| - state->nodes.number_expr_nodes = 0;
|
| - state->unchanged = FALSE;
|
| -}
|
| -
|
| -/* Returns true if data 66 prefix is specified for the instruction,
|
| - * and the isntruction doesn't ignore the data 66 prefix.
|
| - */
|
| -#define NACL_PREFIX_INST_DATA66(state) \
|
| - (NaClHasBit((state)->prefix_mask, kPrefixDATA16) && \
|
| - (NACL_EMPTY_IFLAGS == \
|
| - ((state)->inst->flags & NACL_IFLAG(SizeIgnoresData16))))
|
| -
|
| -/* Computes the number of bytes defined for operands of the matched
|
| - * instruction of the given state. Returns 0 if the operand size could
|
| - * not be computed, due to ambiguities in the prefix bytes.
|
| - */
|
| -static int NaClExtractOpSize(NaClInstState* state) {
|
| - if (NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSize_b))) {
|
| - return 1;
|
| - }
|
| - if (NACL_TARGET_SUBARCH == 64) {
|
| - if (NaClRexW(state->rexprefix)) {
|
| - if (NACL_PREFIX_INST_DATA66(state))
|
| - /* According to the AMD and INTEL manuals, if both prefix 66 and
|
| - * rex.w is specified, the rex.w should be used. However, rather
|
| - * than tempt fate, we disallow this combination of prefixes for
|
| - * any such instruction, since the same effect can be achieved
|
| - * without the 66 prefix.
|
| - */
|
| - return 0;
|
| - return 8;
|
| - }
|
| - if (NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSizeForce64))) {
|
| - return 8;
|
| - }
|
| - if (NACL_PREFIX_INST_DATA66(state))
|
| - return 2;
|
| - else if (NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSizeDefaultIs64)))
|
| - return 8;
|
| - else
|
| - return 4;
|
| - } else if (NACL_PREFIX_INST_DATA66(state))
|
| - return 2;
|
| - else
|
| - return 4;
|
| -}
|
| -
|
| -/* Computes the number of bits defined for addresses of the matched
|
| - * instruction of the given state.
|
| - */
|
| -static int NaClExtractAddressSize(NaClInstState* state) {
|
| - if (NACL_TARGET_SUBARCH == 64) {
|
| - return NaClHasBit(state->prefix_mask, kPrefixADDR16) ? 32 : 64;
|
| - } else {
|
| - return NaClHasBit(state->prefix_mask, kPrefixADDR16) ? 16 : 32;
|
| - }
|
| -}
|
| -
|
| -/* Manual implies only 4 bytes is allowed, but I have found up to 6.
|
| - * Why don't we allow any number, so long as (1) There is room for
|
| - * at least one opcode byte, and (2) we don't exceed the max bytes.
|
| - */
|
| -static const int kNaClMaximumPrefixBytes =
|
| - NACL_MAX_BYTES_PER_X86_INSTRUCTION - 1;
|
| -
|
| -/* Captures ambiguous segment prefix forms. Used to make
|
| - * detection of multiple prefix segment bytes.
|
| - */
|
| -static const uint32_t segment_prefix_forms =
|
| - kPrefixSEGCS | kPrefixSEGSS | kPrefixSEGFS |
|
| - kPrefixSEGGS | kPrefixSEGES | kPrefixSEGDS;
|
| -
|
| -/* Match any prefix bytes that can be associated with the instruction
|
| - * currently being matched.
|
| - */
|
| -static Bool NaClConsumePrefixBytes(NaClInstState* state) {
|
| - uint8_t next_byte;
|
| - int i;
|
| - uint32_t prefix_form;
|
| - for (i = 0; i < kNaClMaximumPrefixBytes; ++i) {
|
| - /* Quit early if no more bytes in segment. */
|
| - if (state->bytes.length >= state->length_limit) break;
|
| -
|
| - /* Look up the corresponding prefix bit associated
|
| - * with the next byte in the segment, and record it.
|
| - */
|
| - next_byte = NCRemainingMemoryLookaheadInline(state->bytes.memory,0);
|
| - prefix_form = state->decoder_tables->prefix_mask[next_byte];
|
| - if (prefix_form == 0) break;
|
| - next_byte = NCInstBytesReadInline(&state->bytes);
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Consume prefix[%d]: %02"NACL_PRIx8" => %"NACL_PRIx32"\n",
|
| - i, next_byte, prefix_form));
|
| - /* Before updating prefix mask, determine if the prefix byte is
|
| - * a duplicate.
|
| - */
|
| - if ((state->prefix_mask & prefix_form)) {
|
| - state->has_prefix_duplicates = TRUE;
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "duplicate prefix %02"NACL_PRIx8" detected.\n", next_byte));
|
| - } else if ((prefix_form & segment_prefix_forms) &&
|
| - (state->prefix_mask & segment_prefix_forms)) {
|
| - state->has_ambig_segment_prefixes = TRUE;
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "ambiguos segment prefix %02"NACL_PRIx8" detected.\n",
|
| - next_byte));
|
| - }
|
| - state->prefix_mask |= prefix_form;
|
| - ++state->num_prefix_bytes;
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - " prefix mask: %08"NACL_PRIx32"\n", state->prefix_mask));
|
| -
|
| - /* If the prefix byte is a REX prefix, record its value, since
|
| - * bits 5-8 of this prefix bit may be needed later.
|
| - */
|
| - if ((NACL_TARGET_SUBARCH == 64) && prefix_form == kPrefixREX) {
|
| - state->rexprefix = next_byte;
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - " rexprefix = %02"NACL_PRIx8"\n", state->rexprefix));
|
| - ++state->num_rex_prefixes;
|
| - }
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -/* 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);
|
| - */
|
| -static void NaClConsume0F38XXNaClInstBytes(NaClInstState* state,
|
| - NaClInstPrefixDescriptor* desc) {
|
| - /* Fail if there are no more bytes. Otherwise, read the next
|
| - * byte.
|
| - */
|
| - if (state->bytes.length >= state->length_limit) {
|
| - desc->matched_prefix = NaClInstPrefixEnumSize;
|
| - return;
|
| - }
|
| -
|
| - desc->opcode_byte = NCInstBytesReadInline(&state->bytes);
|
| - 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;
|
| - desc->opcode_prefix = kValueREPNE;
|
| - } else if (NaClHasBit(state->prefix_mask, kPrefixDATA16)) {
|
| - desc->matched_prefix = Prefix660F38;
|
| - desc->opcode_prefix = kValueDATA16;
|
| - } else {
|
| - desc->matched_prefix = Prefix0F38;
|
| - }
|
| - return;
|
| - }
|
| - /* If reached, can't match special prefixes, fail. */
|
| - desc->matched_prefix = NaClInstPrefixEnumSize;
|
| -}
|
| -
|
| -/* Assuming we have matched the byte sequence OF 3A, consume the corresponding
|
| - * following (instruction) opcode byte, returning the most specific prefix the
|
| - * patterns can match (or NaClInstPrefixEnumSize if no such patterns exist).
|
| - */
|
| -static void NaClConsume0F3AXXNaClInstBytes(NaClInstState* state,
|
| - NaClInstPrefixDescriptor* desc) {
|
| - /* Fail if there are no more bytes. Otherwise, read the next
|
| - * byte and choose appropriate prefix.
|
| - */
|
| - if (state->bytes.length >= state->length_limit) {
|
| - desc->matched_prefix = NaClInstPrefixEnumSize;
|
| - return;
|
| - }
|
| -
|
| - desc->opcode_byte = NCInstBytesReadInline(&state->bytes);
|
| - 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;
|
| - desc->opcode_prefix = kValueDATA16;
|
| - } 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
|
| - * following (instruction) opcode byte, returning the most specific
|
| - * prefix the patterns can match (or NaClInstPrefixEnumSize if no such
|
| - * patterns exist).
|
| - */
|
| -static void NaClConsume0FXXNaClInstBytes(NaClInstState* state,
|
| - NaClInstPrefixDescriptor* desc) {
|
| - 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;
|
| - desc->opcode_prefix = kValueREPNE;
|
| - return;
|
| - }
|
| - } else {
|
| - if (NaClHasBit(state->prefix_mask, kPrefixREP)) {
|
| - /* Note: Flag OpcodeAllowsData16 will explicitly clarify
|
| - * ambigous case of both REP and DATA16 prefixes.
|
| - */
|
| - desc->matched_prefix = PrefixF30F;
|
| - desc->opcode_prefix = kValueREP;
|
| - } else if (NaClHasBit(state->prefix_mask, kPrefixDATA16)) {
|
| - desc->matched_prefix = Prefix660F;
|
| - desc->opcode_prefix = kValueDATA16;
|
| - } 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
|
| - * match the most specific prefix pattern the opcode bytes can match.
|
| - */
|
| -static void NaClConsumeX87NaClInstBytes(NaClInstState* state,
|
| - NaClInstPrefixDescriptor* desc) {
|
| - if (state->bytes.length < state->length_limit) {
|
| - /* Can be two byte opcode. */
|
| - desc->matched_prefix =
|
| - (NaClInstPrefix) (PrefixD8 +
|
| - (((unsigned) desc->opcode_byte) - 0xD8));
|
| - desc->opcode_byte = NCInstBytesReadInline(&state->bytes);
|
| - DEBUG(NaClLog(LOG_INFO, "Consume inst byte %02"NACL_PRIx8".\n",
|
| - desc->opcode_byte));
|
| - return;
|
| - }
|
| -
|
| - /* If reached, can only be single byte opcode, match as such. */
|
| - desc->matched_prefix = NoPrefix;
|
| -}
|
| -
|
| -/* Consume the opcode bytes, and return the most specific prefix pattern
|
| - * the opcode bytes can match (or NaClInstPrefixEnumSize if no such pattern
|
| - * exists).
|
| - */
|
| -static void NaClConsumeInstBytes(NaClInstState* state,
|
| - NaClInstPrefixDescriptor* desc) {
|
| -
|
| - /* Initialize descriptor to the fail state. */
|
| - desc->opcode_prefix = 0;
|
| - desc->opcode_byte = 0x0;
|
| - desc->matched_prefix = NaClInstPrefixEnumSize;
|
| - desc->next_length_adjustment = 0;
|
| -
|
| - /* Be sure that we don't exceed the segment length. */
|
| - if (state->bytes.length >= state->length_limit) return;
|
| -
|
| - desc->opcode_byte = NCInstBytesReadInline(&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 = NCInstBytesReadInline(&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);
|
| - break;
|
| - case 0x3a:
|
| - NaClConsume0F3AXXNaClInstBytes(state, desc);
|
| - break;
|
| - default:
|
| - NaClConsume0FXXNaClInstBytes(state, desc);
|
| - break;
|
| - }
|
| - break;
|
| - case 0xD8:
|
| - case 0xD9:
|
| - case 0xDA:
|
| - case 0xDB:
|
| - case 0xDC:
|
| - case 0xDD:
|
| - case 0xDE:
|
| - case 0xDF:
|
| - NaClConsumeX87NaClInstBytes(state, desc);
|
| - break;
|
| - default:
|
| - desc->matched_prefix = NoPrefix;
|
| - break;
|
| - }
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "matched prefix = %s\n",
|
| - NaClInstPrefixName(desc->matched_prefix)));
|
| -}
|
| -
|
| -/* Compute the operand and address sizes for the instruction. Then, verify
|
| - * that the opcode (instruction) pattern allows for such sizes. Aborts
|
| - * the pattern match if any problems.
|
| - */
|
| -static Bool NaClConsumeAndCheckOperandSize(NaClInstState* state) {
|
| - /* Get and check that operand size is defined. */
|
| - state->operand_size = NaClExtractOpSize(state);
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "operand size = %"NACL_PRIu8"\n", state->operand_size));
|
| - if (0 == state->operand_size) {
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Fails: operand size is zero.\n"));
|
| - return FALSE;
|
| - }
|
| -
|
| - /* Check if instruction has flags specifying legal sizes. If so,
|
| - * make sure that the size matches.
|
| - */
|
| - if (state->inst->flags &
|
| - (NACL_IFLAG(OperandSize_w) | NACL_IFLAG(OperandSize_v) |
|
| - NACL_IFLAG(OperandSize_o))) {
|
| - NaClIFlags good = 1;
|
| - switch (state->operand_size) {
|
| - case 2:
|
| - good = NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSize_w));
|
| - break;
|
| - case 4:
|
| - good = NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSize_v));
|
| - break;
|
| - case 8:
|
| - good = NaClHasBit(state->inst->flags, NACL_IFLAG(OperandSize_o));
|
| - break;
|
| - default:
|
| - good = 0;
|
| - break;
|
| - }
|
| - if (!good) {
|
| - /* The flags associated with the opcode (instruction) don't
|
| - * allow the computed sizes, abort the match of the instruction.
|
| - */
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Operand size %"NACL_PRIu8
|
| - " doesn't match flag requirement!\n",
|
| - state->operand_size));
|
| - return FALSE;
|
| - }
|
| -
|
| - /* Do special check for case where Rex.w and data 66 specified, and
|
| - * the data 66 isn't part of the opcode prefix. In such cases, we
|
| - * disallow both, since they are conflicting operand size specifications.
|
| - */
|
| - if (NaClRexW(state->rexprefix) &&
|
| - NaClHasBit(state->prefix_mask, kPrefixDATA16) &&
|
| - /* The following checks that both 16 and 64 bit operand
|
| - * sizes are allowed.
|
| - */
|
| - NaClHasBits(state->inst->flags,
|
| - NACL_IFLAG(OperandSize_w) |
|
| - NACL_IFLAG(OperandSize_o)) &&
|
| - /* This clause allows cases where the 66 prefix changes
|
| - * the opcode rather than the operand size. Both flags are
|
| - * set iff the 66 modifies the opcode. See function
|
| - * NaClAddRepPrefixFlagsIfApplicable in generator/ncdecode_tablegen.c
|
| - * for details.
|
| - */
|
| - !NaClHasBits(state->inst->flags,
|
| - NACL_IFLAG(OpcodeAllowsData16) |
|
| - NACL_IFLAG(SizeIgnoresData16))) {
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Can't specify both data prefix 66 and Rex.w\n"));
|
| - return FALSE;
|
| - }
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -static Bool NaClConsumeAndCheckAddressSize(NaClInstState* state) {
|
| - state->address_size = NaClExtractAddressSize(state);
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Address size = %"NACL_PRIu8"\n", state->address_size));
|
| - if (state->inst->flags &
|
| - (NACL_IFLAG(AddressSize_w) | NACL_IFLAG(AddressSize_v) |
|
| - NACL_IFLAG(AddressSize_o))) {
|
| - NaClIFlags good = 1;
|
| - switch (state->address_size) {
|
| - case 16:
|
| - good = NaClHasBit(state->inst->flags, NACL_IFLAG(AddressSize_w));
|
| - break;
|
| - case 32:
|
| - good = NaClHasBit(state->inst->flags, NACL_IFLAG(AddressSize_v));
|
| - break;
|
| - case 64:
|
| - good = NaClHasBit(state->inst->flags, NACL_IFLAG(AddressSize_o));
|
| - break;
|
| - default:
|
| - good = 0;
|
| - break;
|
| - }
|
| - if (!good) {
|
| - /* The flags associated with the opcode (instruction) don't
|
| - * allow the computed sizes, abort the match of the instruction.
|
| - */
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Address size %"NACL_PRIu8
|
| - " doesn't match flag requirement!\n",
|
| - state->address_size));
|
| - return FALSE;
|
| - }
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -/* Returns true if the instruction requires a ModRm bytes. */
|
| -static Bool NaClInstRequiresModRm(NaClInstState* state) {
|
| - return (Bool)
|
| - (NACL_EMPTY_IFLAGS !=
|
| - (state->inst->flags & NACL_IFLAG(OpcodeUsesModRm)));
|
| -}
|
| -
|
| -/* Consume the Mod/Rm byte of the instruction, if applicable.
|
| - * Aborts the pattern match if any problems.
|
| - */
|
| -static Bool NaClConsumeModRm(NaClInstState* state) {
|
| - /* First check if the opcode (instruction) pattern specifies that
|
| - * a Mod/Rm byte is needed, and that reading it will not walk
|
| - * past the end of the code segment.
|
| - */
|
| - if (NaClInstRequiresModRm(state)) {
|
| - uint8_t byte;
|
| - /* Has modrm byte. */
|
| - if (state->bytes.length >= state->length_limit) {
|
| - DEBUG(NaClLog(LOG_INFO, "Can't read mod/rm, no more bytes!\n"));
|
| - return FALSE;
|
| - }
|
| - byte = NCInstBytesPeekInline(&state->bytes, 0);
|
| -
|
| - /* Note: Some instructions only allow values where the ModRm mod field
|
| - * is 0x3. Others only allow values where the ModRm mod field isn't 0x3.
|
| - */
|
| - if (modrm_modInline(byte) == 0x3) {
|
| - 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 (NaClHasBit(state->inst->flags, NACL_IFLAG(ModRmModIs0x3))) {
|
| - DEBUG(NaClLog(LOG_INFO, "Can't match, modrm mod field not 0x3\n"));
|
| - return FALSE;
|
| - }
|
| - }
|
| - if ((NaClHasBit(state->inst->flags, NACL_IFLAG(ModRmRegSOperand))) &&
|
| - (modrm_regInline(byte) > 5)) {
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Can't match, modrm reg field doesn't index segment\n"));
|
| - return FALSE;
|
| - }
|
| - state->modrm = NCInstBytesReadInline(&state->bytes);
|
| - state->num_disp_bytes = 0;
|
| - state->first_disp_byte = 0;
|
| - state->sib = 0;
|
| - state->has_sib = FALSE;
|
| - DEBUG(NaClLog(LOG_INFO, "consume modrm = %02"NACL_PRIx8"\n", state->modrm));
|
| -
|
| - /* Consume the remaining opcode value in the mod/rm byte
|
| - * if applicable.
|
| - */
|
| - if (state->inst->flags & NACL_IFLAG(OpcodeInModRm)) {
|
| - const NaClInst* inst = state->inst;
|
| - if (modrm_opcodeInline(state->modrm) !=
|
| - NaClGetOpcodeInModRm(inst->opcode_ext)) {
|
| - DEBUG(
|
| - NaClLog(LOG_INFO,
|
| - "Discarding, opcode in mrm byte (%02"NACL_PRIx8") "
|
| - "does not match\n",
|
| - modrm_opcodeInline(state->modrm)));
|
| - return FALSE;
|
| - }
|
| - if (state->inst->flags & NACL_IFLAG(OpcodeInModRmRm)) {
|
| - if (modrm_rmInline(state->modrm) !=
|
| - NaClGetOpcodeInModRmRm(inst->opcode_ext)) {
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Discarding, opcode in mrm rm field (%02"NACL_PRIx8") "
|
| - "does not match\n",
|
| - modrm_rmInline(state->modrm)));
|
| - return FALSE;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -/* Returns true if the instruction requires a SIB bytes. */
|
| -static Bool NaClInstRequiresSib(NaClInstState* state) {
|
| - /* Note: in 64-bit mode, 64-bit addressing is treated the same as 32-bit
|
| - * addressing. Hence, required for all but 16-bit addressing, when
|
| - * the right modrm bytes are specified.
|
| - */
|
| - return (Bool)
|
| - (NaClInstRequiresModRm(state) && (16 != state->address_size) &&
|
| - (modrm_rmInline(state->modrm) ==
|
| - 0x04 && modrm_modInline(state->modrm) != 0x3));
|
| -}
|
| -
|
| -/* Consume the SIB byte of the instruction, if applicable. Aborts the pattern
|
| - * match if any problems are found.
|
| - */
|
| -static Bool NaClConsumeSib(NaClInstState* state) {
|
| - /* First check that the opcode (instruction) pattern specifies that
|
| - * a SIB byte is needed, and that reading it will not walk past
|
| - * the end of the code segment.
|
| - */
|
| - state->sib = 0;
|
| - state->has_sib = NaClInstRequiresSib(state);
|
| - DEBUG(NaClLog(LOG_INFO, "has sib = %d\n", (int) state->has_sib));
|
| - if (state->has_sib) {
|
| - if (state->bytes.length >= state->length_limit) {
|
| - DEBUG(NaClLog(LOG_INFO, "Can't consume sib, no more bytes!\n"));
|
| - return FALSE;
|
| - }
|
| - /* Read the SIB byte and record. */
|
| - state->sib = NCInstBytesReadInline(&state->bytes);
|
| - DEBUG(NaClLog(LOG_INFO, "sib = %02"NACL_PRIx8"\n", state->sib));
|
| - if (sib_base(state->sib) == 0x05 && modrm_modInline(state->modrm) > 2) {
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Sib byte implies modrm.mod field <= 2, match fails\n"));
|
| - return FALSE;
|
| - }
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -static int NaClGetNumDispBytes(NaClInstState* state) {
|
| - if (NaClInstRequiresModRm(state)) {
|
| - if (16 == state->address_size) {
|
| - /* Corresponding to table 2-1 of the Intel manual. */
|
| - switch (modrm_modInline(state->modrm)) {
|
| - case 0x0:
|
| - if (modrm_rmInline(state->modrm) == 0x06) {
|
| - return 4; /* disp16 */
|
| - }
|
| - break;
|
| - case 0x1:
|
| - return 1; /* disp8 */
|
| - case 0x2:
|
| - return 2; /* disp16 */
|
| - default:
|
| - break;
|
| - }
|
| - } else {
|
| - /* Note: in 64-bit mode, 64-bit addressing is treated the same as 32-bit
|
| - * addressing. Hence, this section covers the 32-bit addressing.
|
| - */
|
| - switch(modrm_modInline(state->modrm)) {
|
| - case 0x0:
|
| - if (modrm_rmInline(state->modrm) == 0x05) {
|
| - return 4; /* disp32 */
|
| - } else if (state->has_sib && sib_base(state->sib) == 0x5) {
|
| - return 4;
|
| - }
|
| - break;
|
| - case 0x1:
|
| - return 1; /* disp8 */
|
| - case 0x2:
|
| - return 4; /* disp32 */
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -/* Consume the needed displacement bytes, if applicable. Abort the
|
| - * pattern match if any problems are found.
|
| - */
|
| -static Bool NaClConsumeDispBytes(NaClInstState* state) {
|
| - /* First check if the opcode (instruction) pattern specifies that
|
| - * displacement bytes should be read, and that reading it will not
|
| - * walk past the end of the code segment.
|
| - */
|
| - state->num_disp_bytes = NaClGetNumDispBytes(state);
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "num disp bytes = %"NACL_PRIu8"\n", state->num_disp_bytes));
|
| - state->first_disp_byte = state->bytes.length;
|
| - if (state->num_disp_bytes > 0) {
|
| - int new_length = state->bytes.length + state->num_disp_bytes;
|
| - if (new_length > state->length_limit) {
|
| - DEBUG(NaClLog(LOG_INFO, "Can't consume disp, no more bytes!\n"));
|
| - return FALSE;
|
| - }
|
| - /* Read the displacement bytes. */
|
| - state->first_disp_byte = state->bytes.length;
|
| - NCInstBytesReadBytesInline(state->num_disp_bytes, &state->bytes);
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -/* Returns the number of immediate bytes to parse. */
|
| -static int NaClGetNumImmedBytes(NaClInstState* state) {
|
| - /* First see if immediate bytes is specified. */
|
| - if (0 == NaClHasBit(state->inst->flags,
|
| - (NACL_IFLAG(OpcodeHasImmed) |
|
| - NACL_IFLAG(OpcodeHasImmed_v) |
|
| - NACL_IFLAG(OpcodeHasImmed_b) |
|
| - NACL_IFLAG(OpcodeHasImmed_w) |
|
| - NACL_IFLAG(OpcodeHasImmed_o) |
|
| - NACL_IFLAG(OpcodeHasImmed_Addr) |
|
| - NACL_IFLAG(OpcodeHasImmed_z) |
|
| - NACL_IFLAG(OpcodeHasImmed_p)))) return 0;
|
| -
|
| - /* Now handle specific requests. */
|
| - if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed)) {
|
| - return state->operand_size;
|
| - }
|
| - if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed_v)) {
|
| - return 4;
|
| - } else if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed_b)) {
|
| - return 1;
|
| - } else if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed_w)) {
|
| - return 2;
|
| - } else if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed_p)) {
|
| - return 6;
|
| - } else if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed_o)) {
|
| - return 8;
|
| - } else if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed_Addr)) {
|
| - return NaClExtractAddressSize(state) / 8;
|
| - } else if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed_z)) {
|
| - if (state->operand_size == 2) {
|
| - return 2;
|
| - } else {
|
| - return 4;
|
| - }
|
| - } else {
|
| - return 0;
|
| - }
|
| -}
|
| -
|
| -/* Returns the number of immedidate bytes to parse if a second immediate
|
| - * number appears in the instruction (zero if no second immediate value).
|
| - */
|
| -static int NaClGetNumImmed2Bytes(NaClInstState* state) {
|
| - if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed2_b)) {
|
| - return 1;
|
| - } else if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed2_w)) {
|
| - return 2;
|
| - } else if (state->inst->flags & NACL_IFLAG(OpcodeHasImmed2_v)) {
|
| - return 4;
|
| - } else {
|
| - return 0;
|
| - }
|
| -}
|
| -
|
| -/* Consume the needed immediate bytes, if applicable. Abort the
|
| - * pattern match if any problems are found.
|
| - */
|
| -static Bool NaClConsumeImmediateBytes(NaClInstState* state) {
|
| - /* find out how many immediate bytes are expected. */
|
| - state->num_imm_bytes = NaClGetNumImmedBytes(state);
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "num immediate bytes = %"NACL_PRIu8"\n", state->num_imm_bytes));
|
| - state->first_imm_byte = 0;
|
| - if (state->num_imm_bytes > 0) {
|
| - int new_length;
|
| - /* Before reading immediate bytes, be sure that we won't walk
|
| - * past the end of the code segment.
|
| - */
|
| - new_length = state->bytes.length + state->num_imm_bytes;
|
| - if (new_length > state->length_limit) {
|
| - DEBUG(NaClLog(LOG_INFO, "Can't consume immediate, no more bytes!\n"));
|
| - return FALSE;
|
| - }
|
| - /* Read the immediate bytes. */
|
| - state->first_imm_byte = state->bytes.length;
|
| - NCInstBytesReadBytesInline(state->num_imm_bytes, &state->bytes);
|
| - }
|
| - /* Before returning, see if second immediate value specified. */
|
| - state->num_imm2_bytes = NaClGetNumImmed2Bytes(state);
|
| - DEBUG(NaClLog(LOG_INFO, "num immediate 2 bytes = %"NACL_PRIu8"\n",
|
| - state->num_imm2_bytes));
|
| - if (state->num_imm2_bytes > 0) {
|
| - int new_length;
|
| - /* Before reading immediate bytes, be sure that we don't walk
|
| - * past the end of the code segment.
|
| - */
|
| - new_length = state->bytes.length + state->num_imm2_bytes;
|
| - if (new_length > state->length_limit) {
|
| - DEBUG(NaClLog(LOG_INFO, "Can't consume 2nd immediate, no more bytes!\n"));
|
| - return FALSE;
|
| - }
|
| - /* Read the immediate bytes. */
|
| - NCInstBytesReadBytesInline(state->num_imm2_bytes, &state->bytes);
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -/* Validate that any opcode (instruction) pattern prefix assumptions are
|
| - * met by prefix bits. If not, abort the pattern match.
|
| - */
|
| -static Bool NaClValidatePrefixFlags(NaClInstState* state) {
|
| - /* Check lock prefix assumptions. */
|
| - if (state->prefix_mask & kPrefixLOCK) {
|
| - if (state->inst->flags & NACL_IFLAG(OpcodeLockable)) {
|
| - /* Only allow if all destination operands are memory stores. */
|
| - uint32_t i;
|
| - Bool has_lockable_dest = FALSE;
|
| - NaClExpVector* vector = NaClInstStateExpVector(state);
|
| - DEBUG(NaClLog(LOG_INFO, "checking if lock valid on:\n");
|
| - NaClExpVectorPrint(NaClLogGetGio(), state));
|
| - for (i = 0; i < vector->number_expr_nodes; ++i) {
|
| - NaClExp* node = &vector->node[i];
|
| - DEBUG(NaClLog(LOG_INFO, " checking node %d\n", i));
|
| - if ((NACL_EMPTY_EFLAGS != (node->flags & NACL_EFLAG(ExprSet))) &&
|
| - (node->kind == ExprMemOffset)) {
|
| - has_lockable_dest = TRUE;
|
| - break;
|
| - }
|
| - }
|
| - if (!has_lockable_dest) {
|
| - DEBUG(NaClLog(LOG_INFO, "Instruction doesn't allow lock prefix "
|
| - "on non-memory destination"));
|
| - return FALSE;
|
| - }
|
| - } else {
|
| - DEBUG(NaClLog(LOG_INFO, "Instruction doesn't allow lock prefix\n"));
|
| - return FALSE;
|
| - }
|
| - }
|
| - /* Check REX prefix assumptions. */
|
| - if (NACL_TARGET_SUBARCH == 64 &&
|
| - (state->prefix_mask & kPrefixREX)) {
|
| - if (state->inst->flags &
|
| - (NACL_IFLAG(OpcodeUsesRexW) | NACL_IFLAG(OpcodeHasRexR) |
|
| - NACL_IFLAG(OpcodeRex))) {
|
| - if (((state->inst->flags & NACL_IFLAG(OpcodeUsesRexW)) &&
|
| - 0 == (state->rexprefix & 0x8)) ||
|
| - ((state->inst->flags & NACL_IFLAG(OpcodeHasRexR)) &&
|
| - 0 == (state->rexprefix & 0x4))) {
|
| - DEBUG(NaClLog(LOG_INFO, "can't match REX prefix requirement\n"));
|
| - return FALSE;
|
| - }
|
| - }
|
| - }
|
| - return TRUE;
|
| -}
|
| -
|
| -/* Move back to point just after the prefix sequence (defined by
|
| - * inst_length).
|
| - */
|
| -static void NaClClearInstState(NaClInstState* state, uint8_t inst_length) {
|
| - if (state->bytes.length != inst_length) {
|
| - NCInstBytesResetInline(&state->bytes);
|
| - NCInstBytesReadBytesInline(inst_length, &state->bytes);
|
| - }
|
| - state->modrm = 0;
|
| - state->has_sib = FALSE;
|
| - state->sib = 0;
|
| - state->num_disp_bytes = 0;
|
| - state->first_disp_byte = 0;
|
| - state->num_imm_bytes = 0;
|
| - state->first_imm_byte = 0;
|
| - state->num_imm2_bytes = 0;
|
| - state->operand_size = 32;
|
| - state->address_size = 32;
|
| - state->nodes.is_defined = FALSE;
|
| - state->nodes.number_expr_nodes = 0;
|
| -}
|
| -
|
| -/* Move back to the beginning of the instruction, so that we can reparse. */
|
| -static void NaClResetInstState(NaClInstState* state) {
|
| - if (state->bytes.length > 0) {
|
| - NCInstBytesResetInline(&state->bytes);
|
| - }
|
| - state->num_prefix_bytes = 0;
|
| - state->opcode_prefix = 0;
|
| - state->num_opcode_bytes = 0;
|
| - state->rexprefix = 0;
|
| - state->num_rex_prefixes = 0;
|
| - state->modrm = 0;
|
| - state->has_prefix_duplicates = FALSE;
|
| - state->has_ambig_segment_prefixes = FALSE;
|
| - state->has_sib = FALSE;
|
| - state->sib = 0;
|
| - state->num_disp_bytes = 0;
|
| - state->first_disp_byte = 0;
|
| - state->num_imm_bytes = 0;
|
| - state->first_imm_byte = 0;
|
| - state->num_imm2_bytes = 0;
|
| - state->prefix_mask = 0;
|
| - state->inst = NULL;
|
| - state->nodes.is_defined = FALSE;
|
| - state->nodes.number_expr_nodes = 0;
|
| -}
|
| -
|
| -/* Get the corresponding instruction for the given offset. */
|
| -static const NaClInst* NaClGetOpcodeInst(const NaClDecodeTables *tables,
|
| - NaClOpcodeArrayOffset offset) {
|
| - return (NACL_OPCODE_NULL_OFFSET == offset)
|
| - ? NULL
|
| - : &tables->opcodes_table[offset];
|
| -}
|
| -
|
| -/* Get the corresponding instruction for the given prefix and opcode. */
|
| -static const NaClInst* NaClGetPrefixOpcodeInst(const NaClDecodeTables *tables,
|
| - NaClInstPrefix prefix,
|
| - uint8_t opcode) {
|
| - const NaClPrefixOpcodeSelector* selector = &tables->opcode_selectors[prefix];
|
| - if ((opcode >= selector->first_opcode) &&
|
| - (opcode <= selector->last_opcode)) {
|
| - return NaClGetOpcodeInst(
|
| - tables,
|
| - tables->opcode_entries[
|
| - selector->table_offset + (opcode - selector->first_opcode)]);
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -/*
|
| - * Given the opcode prefix descriptor, return the list of candidate opcodes to
|
| - * try and match against the byte stream in the given state. Before returning,
|
| - * this function automatically advances the opcode prefix descriptor to describe
|
| - * the next list to use if the returned list doesn't provide any matches.
|
| - *
|
| - * Parameters:
|
| - * state - The state of the instruction being decoded.
|
| - * desc - The description of how the opcode bytes have been matched.
|
| - * The value passed in is the currrent match, the value at exit is
|
| - * the value to be used the next time this function is called (to
|
| - * get the next set of possible instructions).
|
| - * opcode_length - The length (in bytes) of the opcode for the returned
|
| - * candidate opcodes.
|
| - */
|
| -static const NaClInst* NaClGetNextInstCandidates(
|
| - NaClInstState* state, NaClInstPrefixDescriptor* desc,
|
| - uint8_t* inst_length) {
|
| - const NaClInst* cand_insts;
|
| - if (desc->next_length_adjustment) {
|
| - (*inst_length) += desc->next_length_adjustment;
|
| - desc->opcode_byte = state->bytes.byte[*inst_length - 1];
|
| - }
|
| - cand_insts = NaClGetPrefixOpcodeInst(state->decoder_tables,
|
| - desc->matched_prefix,
|
| - desc->opcode_byte);
|
| - DEBUG(NaClLog(LOG_INFO, "Lookup candidates using [%s][%x]\n",
|
| - NaClInstPrefixName(desc->matched_prefix), desc->opcode_byte));
|
| - switch (desc->matched_prefix) {
|
| - case Prefix660F:
|
| - desc->matched_prefix = Prefix0F;
|
| - desc->opcode_prefix = 0;
|
| - break;
|
| - case Prefix660F38:
|
| - desc->matched_prefix = Prefix0F38;
|
| - desc->opcode_prefix = 0;
|
| - break;
|
| - case Prefix660F3A:
|
| - desc->matched_prefix = Prefix0F3A;
|
| - desc->opcode_prefix = 0;
|
| - break;
|
| - case PrefixD8:
|
| - case PrefixD9:
|
| - case PrefixDA:
|
| - case PrefixDB:
|
| - case PrefixDC:
|
| - case PrefixDD:
|
| - case PrefixDE:
|
| - case PrefixDF:
|
| - desc->matched_prefix = NoPrefix;
|
| - desc->next_length_adjustment = -1;
|
| - break;
|
| - default:
|
| - /* No more simplier prefices, give up search after current lookup. */
|
| - desc->matched_prefix = NaClInstPrefixEnumSize;
|
| - break;
|
| - }
|
| - return cand_insts;
|
| -}
|
| -
|
| -static Bool NaClConsumeHardCodedNop(NaClInstState* state) {
|
| - uint8_t next_byte;
|
| - const NaClInstNode* next;
|
| - uint8_t next_length = 0;
|
| - const NaClInst* matching_inst = NULL;
|
| - uint8_t matching_length = 0;
|
| -
|
| - next_byte = NCInstByteInline(&state->bytes, next_length);
|
| - next = state->decoder_tables->hard_coded;
|
| -
|
| - /* Find maximal match in trie. */
|
| - while (NULL != next) {
|
| - if (next_byte == next->matching_byte) {
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "NaClConsume opcode char: %"NACL_PRIx8"\n", next_byte));
|
| - next_length++;
|
| - if (NACL_OPCODE_NULL_OFFSET != next->matching_inst) {
|
| - matching_inst = NaClGetOpcodeInst(state->decoder_tables,
|
| - next->matching_inst);
|
| - matching_length = next_length;
|
| - }
|
| - if (next_length < state->length_limit) {
|
| - next = next->success;
|
| - if (next != NULL) {
|
| - next_byte = NCInstByteInline(&state->bytes, next_length);
|
| - }
|
| - } else {
|
| - break;
|
| - }
|
| - } else if (next->matching_byte < next_byte) {
|
| - next = next->fail;
|
| - } else {
|
| - break;
|
| - }
|
| - }
|
| - if (NULL == matching_inst) {
|
| - return FALSE;
|
| - } else {
|
| - /* TODO(karl) Make this more general. Currently assumes that no
|
| - * additional processing (other than opcode selection) is needed.
|
| - * This is currently safe only because all instructions modeled
|
| - * using opcode sequences have no (useful) operands, and hence
|
| - * no additional information is needed.
|
| - */
|
| - NaClResetInstState(state);
|
| - state->inst = matching_inst;
|
| - NCInstBytesReadBytesInline(matching_length, &state->bytes);
|
| - DEBUG(NaClLog(LOG_INFO, "matched inst sequence [%d]!\n", matching_length));
|
| - return TRUE;
|
| - }
|
| -}
|
| -
|
| -EXTERN_C_END
|
| -
|
| -#endif /* NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_X86_DECODER_NC_INST_STATE_STATICS_C__ */
|
|
|