Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1346)

Unified Diff: src/trusted/validator/x86/decoder/nc_inst_state_statics.c

Issue 625923004: Delete old x86 validator. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: rebase master Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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__ */
« no previous file with comments | « src/trusted/validator/x86/decoder/nc_inst_state_internal.h ('k') | src/trusted/validator/x86/decoder/nc_inst_state_tests.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698