| Index: src/trusted/validator/x86/decoder/nc_inst_trans.c
|
| diff --git a/src/trusted/validator/x86/decoder/nc_inst_trans.c b/src/trusted/validator/x86/decoder/nc_inst_trans.c
|
| deleted file mode 100644
|
| index 3e5b2189029845fdc16b27b1b8b5ac55e6738e2b..0000000000000000000000000000000000000000
|
| --- a/src/trusted/validator/x86/decoder/nc_inst_trans.c
|
| +++ /dev/null
|
| @@ -1,1631 +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.
|
| - */
|
| -
|
| -/*
|
| - * Translates the recognized opcode (instruction) in the instruction state
|
| - * into an opcode expression.
|
| - */
|
| -
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_inst_trans.h"
|
| -
|
| -#include <stdio.h>
|
| -#include <assert.h>
|
| -
|
| -#include "native_client/src/shared/platform/nacl_check.h"
|
| -#include "native_client/src/shared/platform/nacl_log.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h"
|
| -#include "native_client/src/trusted/validator/x86/nacl_regs.h"
|
| -
|
| -#include "native_client/src/trusted/validator/x86/decoder/ncop_exps_inl.c"
|
| -#include "native_client/src/trusted/validator/x86/decoder/ncopcode_desc_inl.c"
|
| -#include "native_client/src/trusted/validator/x86/x86_insts_inl.c"
|
| -
|
| -#if NACL_TARGET_SUBARCH == 64
|
| -# include "native_client/src/trusted/validator/x86/decoder/gen/nc_subregs_64.h"
|
| -#else
|
| -# include "native_client/src/trusted/validator/x86/decoder/gen/nc_subregs_32.h"
|
| -#endif
|
| -
|
| -/* To turn on debugging of instruction decoding, change value of
|
| - * DEBUGGING to 1.
|
| - */
|
| -#define DEBUGGING 0
|
| -
|
| -#include "native_client/src/shared/utils/debugging.h"
|
| -
|
| -/* Return the segment register to use, based on prefix specification,
|
| - * or reg_default if no prefix specified.
|
| - */
|
| -static NaClOpKind NaClGetSegmentPrefixReg(NaClInstState* state,
|
| - NaClOpKind reg_default) {
|
| - /* Note: We need to find the LAST segment prefix byte, since it overrides
|
| - * other segment prefix bytes, if multiple segment prefixes are specified.
|
| - */
|
| - if (32 == NACL_TARGET_SUBARCH) {
|
| - if (state->prefix_mask &
|
| - (kPrefixSEGCS | kPrefixSEGSS | kPrefixSEGFS |
|
| - kPrefixSEGGS | kPrefixSEGES | kPrefixSEGDS)) {
|
| - int i;
|
| - for (i = state->num_prefix_bytes - 1; (i >= 0); --i) {
|
| - switch (state->bytes.byte[i]) {
|
| - case kValueSEGCS:
|
| - return RegCS;
|
| - case kValueSEGSS:
|
| - return RegSS;
|
| - case kValueSEGFS:
|
| - return RegFS;
|
| - case kValueSEGGS:
|
| - return RegGS;
|
| - case kValueSEGES:
|
| - return RegES;
|
| - case kValueSEGDS:
|
| - return RegDS;
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - } else if (state->prefix_mask &
|
| - /* Only GS and FS matter in 64-bit mode. */
|
| - (kPrefixSEGGS | kPrefixSEGFS)) {
|
| - int i;
|
| - for (i = state->num_prefix_bytes - 1; (i >= 0); --i) {
|
| - /* for (i = 0; i < state->num_prefix_bytes; ++i) { */
|
| - switch (state->bytes.byte[i]) {
|
| - case kValueSEGFS:
|
| - return RegFS;
|
| - case kValueSEGGS:
|
| - return RegGS;
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - return reg_default;
|
| -}
|
| -
|
| -/* Return the segment register to use if DS is the default. */
|
| -static INLINE NaClOpKind NaClGetDsSegmentReg(NaClInstState* state) {
|
| - return NaClGetSegmentPrefixReg(state, RegDS);
|
| -}
|
| -
|
| -/* Return the segment register to use if ES is the default. */
|
| -static INLINE NaClOpKind NaClGetEsSegmentReg(NaClInstState* state) {
|
| - return NaClGetSegmentPrefixReg(state, RegES);
|
| -}
|
| -
|
| -/* Append the given expression node onto the given vector of expression
|
| - * nodes. Returns the appended expression node.
|
| - */
|
| -static INLINE NaClExp* NaClAppendExp(NaClExpKind kind,
|
| - uint64_t value,
|
| - NaClExpFlags flags,
|
| - NaClExpVector* vector) {
|
| - NaClExp* node;
|
| - assert(vector->number_expr_nodes < NACL_MAX_EXPS);
|
| - /* If this is not a register expression, we should have specified a size. */
|
| - CHECK(ExprRegister == kind || (0 != (flags & (NACL_EFLAG(ExprSize8) |
|
| - NACL_EFLAG(ExprSize16) |
|
| - NACL_EFLAG(ExprSize32) |
|
| - NACL_EFLAG(ExprSize48) |
|
| - NACL_EFLAG(ExprSize64)))));
|
| - node = &vector->node[vector->number_expr_nodes++];
|
| - node->kind = kind;
|
| - node->value = value;
|
| - node->flags = flags;
|
| - return node;
|
| -}
|
| -
|
| -/* Report the given message and quit because we don't know
|
| - * how to recover.
|
| - */
|
| -static void NaClLost(const char* message) {
|
| - NaClLog(LOG_ERROR, "FATAL: %s\n", message);
|
| - exit(1);
|
| -}
|
| -
|
| -/* An untranslateable error has been found. report and quit.
|
| - * Use the state to give useful information on where the
|
| - * translator was when the error occurred.
|
| - * Note: returns NULL of type NaClExp* so that callers can
|
| - * make control flow happy, for those cases where the compiler
|
| - * doesn't recognize that this function never returns.
|
| - */
|
| -static NaClExp* NaClFatal(const char* message,
|
| - NaClInstState* state) {
|
| - NaClLog(LOG_ERROR,
|
| - "FATAL: At %"NACL_PRIxNaClPcAddress", unable to translate: %s\n",
|
| - NaClInstStatePrintableAddress(state), message);
|
| - exit(1);
|
| - /* NOT REACHED */
|
| - return NULL;
|
| -}
|
| -
|
| -/* Returns the segment register encoded in the corresponding
|
| - * mnemonic name of the corresponding instruction.
|
| - */
|
| -static NaClOpKind NaClGetMnemonicSegmentRegister(NaClInstState* state) {
|
| - const NaClInst* inst = NaClInstStateInst(state);
|
| - switch (inst->name) {
|
| - case InstLds:
|
| - return RegDS;
|
| - case InstLes:
|
| - return RegES;
|
| - case InstLfs:
|
| - return RegFS;
|
| - case InstLgs:
|
| - return RegGS;
|
| - case InstLss:
|
| - return RegSS;
|
| - default:
|
| - break;
|
| - }
|
| - NaClFatal("Unable to determine segment regsiter from instruction name",
|
| - state);
|
| - /* NOT REACHED */
|
| - return RegUnknown;
|
| -}
|
| -
|
| -/* Append that we don't bother to translate the instruction argument,
|
| - * since it is NaCl illegal. Used to handle cases where we don't implement
|
| - * 16-bit modrm effective addresses.
|
| - */
|
| -static INLINE NaClExp* NaClAppendNaClIllegal(NaClInstState* state) {
|
| - return NaClAppendExp(ExprNaClIllegal, 0,
|
| - NACL_EFLAG(ExprSize16), &state->nodes);
|
| -}
|
| -
|
| -/* Append the given constant onto the given vector of expression
|
| - * nodes. Returns the appended expression node.
|
| - */
|
| -static INLINE NaClExp* NaClAppendConst(uint64_t value, NaClExpFlags flags,
|
| - NaClExpVector* vector) {
|
| - DEBUG(
|
| - NaClLog(LOG_INFO, "Append constant %"NACL_PRIx64" : ", value);
|
| - NaClPrintExpFlags(NaClLogGetGio(), flags);
|
| - gprintf(NaClLogGetGio(), "\n"));
|
| - return NaClAppendExp(ExprConstant, value, flags, vector);
|
| -}
|
| -
|
| -/* Define a type corresponding to the arrays NaClRegTable8,
|
| - * NaClRegTable16, NaClRegTable32, and NaClRegTable64.
|
| - */
|
| -typedef const NaClOpKind NaClRegTableGroup[NACL_REG_TABLE_SIZE];
|
| -
|
| -NaClOpKind NaClGet64For32BitReg(NaClOpKind reg32) {
|
| -#if NACL_TARGET_SUBARCH == 64
|
| - int i;
|
| - for (i = 0; i < NACL_REG_TABLE_SIZE; ++i) {
|
| - if (reg32 == NaClRegTable32[i]) {
|
| - return NaClRegTable64[i];
|
| - }
|
| - }
|
| -#endif
|
| - return RegUnknown;
|
| -}
|
| -
|
| -NaClOpKind NaClGet32For64BitReg(NaClOpKind reg64) {
|
| - int index = NaClGpReg64Index[reg64];
|
| - return (index == NACL_REGISTER_UNDEFINED)
|
| - ? RegUnknown
|
| - : NaClRegTable32[index];
|
| -}
|
| -
|
| -Bool NaClIs64Subreg(NaClInstState* state,
|
| - NaClOpKind subreg, NaClOpKind reg64) {
|
| - int index = NaClGpSubregIndex[subreg];
|
| - if (index == NACL_REGISTER_UNDEFINED) {
|
| - return FALSE;
|
| - } else {
|
| - int index64 = NaClGpReg64Index[reg64];
|
| - if (index64 == NACL_REGISTER_UNDEFINED) {
|
| - /* This shouldn't happen, so fail! */
|
| - return FALSE;
|
| - } else {
|
| - return index == index64;
|
| - }
|
| - }
|
| -}
|
| -
|
| -Bool NaClIs32To64RegPair(NaClOpKind reg32, NaClOpKind reg64) {
|
| - return reg64 == NaClGet64For32BitReg(reg32);
|
| -}
|
| -
|
| -/* Define the set of available registers, categorized by size.
|
| - * Note: The order is important, and is based on the indexing values used
|
| - * in the ModRm and SIB bytes (and the REX prefix if appropriate).
|
| - */
|
| -static NaClRegTableGroup* const NaClRegTable[] = {
|
| - &NaClRegTable8NoRex,
|
| - &NaClRegTable16,
|
| - &NaClRegTable32,
|
| - &NaClRegTable64,
|
| - &NaClRegTableMmx,
|
| - &NaClRegTableXmm,
|
| - &NaClRegTableC,
|
| - &NaClRegTableD,
|
| -};
|
| -
|
| -/* Define possible register categories. */
|
| -typedef enum NaClRegKind {
|
| - /* Note: the following all have register tables
|
| - * for the corresponding general purpose registers.
|
| - */
|
| - RegSize8,
|
| - RegSize16,
|
| - RegSize32,
|
| - RegSize64,
|
| - RegMMX,
|
| - RegXMM,
|
| - RegC,
|
| - RegD,
|
| - /* Note: sizes below this point don't define general
|
| - * purpose registers, and hence, don't have a lookup
|
| - * value in the register tables.
|
| - */
|
| - RegSize128,
|
| - RegSizeZ,
|
| - RegUndefined, /* Always returns RegUnknown. */
|
| -} NaClRegKind;
|
| -
|
| -static const char* const g_NaClRegKindName[] = {
|
| - "RegSize8",
|
| - "RegSize16",
|
| - "RegSize32",
|
| - "RegSize64",
|
| - "RegMMX",
|
| - "RegXMM",
|
| - "RegC",
|
| - "RegD",
|
| - "RegSize128",
|
| - "RegSizeZ",
|
| - "RegUndefined"
|
| -};
|
| -
|
| -const char* NaClRegKindName(NaClRegKind kind) {
|
| - return g_NaClRegKindName[kind];
|
| -}
|
| -
|
| -/* Define ModRm register categories. */
|
| -typedef enum NaClModRmRegKind {
|
| - ModRmGeneral,
|
| - ModRmMmx,
|
| - ModRmXmm,
|
| - ModRmCreg,
|
| - ModRmDreg,
|
| - /* Don't allow top level registers in Effective address. */
|
| - ModRmNoTopLevelRegisters
|
| -} NaClModRmRegKind;
|
| -
|
| -static const char* const g_NaClModRmRegKindName[] = {
|
| - "ModRmGeneral",
|
| - "ModRmMmx",
|
| - "ModRmXmm",
|
| - "ModRmCreg",
|
| - "ModRmDreg",
|
| - "ModRmNoTopLevelRegisters"
|
| -};
|
| -
|
| -/* Given an operand kind, return the size specification associated with
|
| - * the operand kind.
|
| - */
|
| -static NaClRegKind NaClGetOpKindRegKind(NaClOpKind kind) {
|
| - switch (kind) {
|
| - case Eb_Operand:
|
| - case Gb_Operand:
|
| - case Ib_Operand:
|
| - case Jb_Operand:
|
| - case Mb_Operand:
|
| - case Ob_Operand:
|
| - return RegSize8;
|
| - case Ew_Operand:
|
| - case Gw_Operand:
|
| - case Iw_Operand:
|
| - case Jw_Operand:
|
| - case Mw_Operand:
|
| - case Mpw_Operand:
|
| - case Ow_Operand:
|
| - return RegSize16;
|
| - case Ev_Operand:
|
| - case Gv_Operand:
|
| - case Iv_Operand:
|
| - case Jv_Operand:
|
| - case Mv_Operand:
|
| - case Mpv_Operand:
|
| - case Ov_Operand:
|
| - case Mmx_Gd_Operand:
|
| - return RegSize32;
|
| - case Eo_Operand:
|
| - case Go_Operand:
|
| - case Io_Operand:
|
| - case Mo_Operand:
|
| - case Mpo_Operand:
|
| - case Oo_Operand:
|
| - case Xmm_Eo_Operand:
|
| - case Xmm_Go_Operand:
|
| - case Mmx_E_Operand:
|
| - case Mmx_G_Operand:
|
| - return RegSize64;
|
| - case Edq_Operand:
|
| - case Gdq_Operand:
|
| - case Mdq_Operand:
|
| - case Xmm_E_Operand:
|
| - case Xmm_G_Operand:
|
| - return RegSize128;
|
| - case Seg_G_Operand:
|
| - return RegSizeZ;
|
| - default:
|
| - return RegUndefined;
|
| - }
|
| -}
|
| -
|
| -static NaClOpKind NaClLookupReg(NaClInstState* state,
|
| - NaClRegKind kind, int reg_index) {
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "Lookup register (rex=%"NACL_PRIx8") %s:%d\n",
|
| - state->rexprefix, NaClRegKindName(kind), reg_index));
|
| - if (32 == NACL_TARGET_SUBARCH && kind == RegSize64) {
|
| - NaClLost("Architecture doesn't define 64 bit registers");
|
| - } else if (RegSize128 <= kind) {
|
| - return RegUnknown;
|
| - }
|
| - if (64 == NACL_TARGET_SUBARCH && kind == RegSize8 && state->rexprefix) {
|
| - return NaClRegTable8Rex[reg_index];
|
| - }
|
| - return (*(NaClRegTable[kind]))[reg_index];
|
| -}
|
| -
|
| -/* Returns the (NaClExpFlag) size of the given register. */
|
| -static NaClExpFlags NaClGetRegSize(NaClOpKind register_name) {
|
| - switch (register_name) {
|
| - case RegAL:
|
| - case RegBL:
|
| - case RegCL:
|
| - case RegDL:
|
| - case RegAH:
|
| - case RegBH:
|
| - case RegCH:
|
| - case RegDH:
|
| - case RegDIL:
|
| - case RegSIL:
|
| - case RegBPL:
|
| - case RegSPL:
|
| - case RegR8B:
|
| - case RegR9B:
|
| - case RegR10B:
|
| - case RegR11B:
|
| - case RegR12B:
|
| - case RegR13B:
|
| - case RegR14B:
|
| - case RegR15B:
|
| - return NACL_EFLAG(ExprSize8);
|
| - case RegAX:
|
| - case RegBX:
|
| - case RegCX:
|
| - case RegDX:
|
| - case RegSI:
|
| - case RegDI:
|
| - case RegBP:
|
| - case RegSP:
|
| - case RegR8W:
|
| - case RegR9W:
|
| - case RegR10W:
|
| - case RegR11W:
|
| - case RegR12W:
|
| - case RegR13W:
|
| - case RegR14W:
|
| - case RegR15W:
|
| - return NACL_EFLAG(ExprSize16);
|
| - case RegEAX:
|
| - case RegEBX:
|
| - case RegECX:
|
| - case RegEDX:
|
| - case RegESI:
|
| - case RegEDI:
|
| - case RegEBP:
|
| - case RegESP:
|
| - case RegR8D:
|
| - case RegR9D:
|
| - case RegR10D:
|
| - case RegR11D:
|
| - case RegR12D:
|
| - case RegR13D:
|
| - case RegR14D:
|
| - case RegR15D:
|
| - return NACL_EFLAG(ExprSize32);
|
| - case RegCS:
|
| - case RegDS:
|
| - case RegSS:
|
| - case RegES:
|
| - case RegFS:
|
| - case RegGS:
|
| - return NACL_EFLAG(ExprSize16);
|
| - case RegEIP:
|
| - return NACL_EFLAG(ExprSize32);
|
| - case RegRIP:
|
| - return NACL_EFLAG(ExprSize64);
|
| - case RegRAX:
|
| - case RegRBX:
|
| - case RegRCX:
|
| - case RegRDX:
|
| - case RegRSI:
|
| - case RegRDI:
|
| - case RegRBP:
|
| - case RegRSP:
|
| - case RegR8:
|
| - case RegR9:
|
| - case RegR10:
|
| - case RegR11:
|
| - case RegR12:
|
| - case RegR13:
|
| - case RegR14:
|
| - case RegR15:
|
| - return NACL_EFLAG(ExprSize64);
|
| - default:
|
| - return 0;
|
| - }
|
| -}
|
| -
|
| -/* Appends the given kind of register onto the vector of expression nodes.
|
| - * Returns the appended register.
|
| - */
|
| -static INLINE NaClExp* NaClAppendReg(NaClOpKind r, NaClExpVector* vector) {
|
| - NaClExp* node;
|
| - DEBUG(NaClLog(LOG_INFO, "append register %s\n", NaClOpKindName(r)));
|
| - node = NaClAppendExp(ExprRegister, r, NaClGetRegSize(r), vector);
|
| - return node;
|
| -}
|
| -
|
| -/* Given the given register kind, and the corresponding index, append
|
| - * the appropriate register onto the vector of expression nodes.
|
| - * Returns the appended register
|
| - */
|
| -static INLINE NaClExp* NaClAppendRegKind(NaClInstState* state,
|
| - NaClRegKind kind, int reg_index) {
|
| - DEBUG(NaClLog(LOG_INFO, "NaClAppendRegKind(%d, %d) = %s\n",
|
| - (int) kind, reg_index, NaClRegKindName(kind)));
|
| - return NaClAppendReg(NaClLookupReg(state, kind, reg_index), &state->nodes);
|
| -}
|
| -
|
| -/* Given an operand of the corresponding opcode instruction of the
|
| - * given state, return what kind of register should be used, based
|
| - * on the operand size.
|
| - */
|
| -static NaClRegKind NaClExtractOpRegKind(NaClInstState* state,
|
| - const NaClOp* operand) {
|
| - NaClRegKind reg_kind = NaClGetOpKindRegKind(operand->kind);
|
| - switch (reg_kind) {
|
| - case RegSize8:
|
| - case RegSize16:
|
| - case RegSize32:
|
| - case RegSize64:
|
| - return reg_kind;
|
| - case RegSizeZ:
|
| - if (state->operand_size == 2) {
|
| - return RegSize16;
|
| - } else {
|
| - return RegSize32;
|
| - }
|
| - default:
|
| - /* Size not explicitly defined, pick up from operand size. */
|
| - if (state->inst->flags & NACL_IFLAG(OperandSize_b)) {
|
| - return RegSize8;
|
| - } else if (state->operand_size == 1) {
|
| - return RegSize8;
|
| - } else if (state->operand_size == 4) {
|
| - return RegSize32;
|
| - } else if (state->operand_size == 2) {
|
| - return RegSize16;
|
| - } else if (state->operand_size == 8) {
|
| - return RegSize64;
|
| - } else {
|
| - return RegSize32;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Given an address of the corresponding opcode instruction of the
|
| - * given state, return what kind of register should be used.
|
| - */
|
| -static INLINE NaClRegKind NaClExtractAddressRegKind(NaClInstState* state) {
|
| - if (state->address_size == 16) {
|
| - return RegSize16;
|
| - } else if (state->address_size == 64) {
|
| - return RegSize64;
|
| - } else {
|
| - return RegSize32;
|
| - }
|
| -}
|
| -
|
| -/* Given we want to translate an operand (of the form G_Operand),
|
| - * for the given register index, generate the corresponding register
|
| - * expression, and append it to the vector of expression nodes.
|
| - * Returns the appended register.
|
| - */
|
| -static NaClExp* NaClAppendOperandReg(
|
| - NaClInstState* state,
|
| - const NaClOp* operand,
|
| - int reg_index,
|
| - NaClModRmRegKind modrm_reg_kind) {
|
| - NaClRegKind reg_kind = RegSize32;
|
| - DEBUG(NaClLog(LOG_INFO, "modrm_reg_kind = %s\n",
|
| - g_NaClModRmRegKindName[modrm_reg_kind]));
|
| - switch (modrm_reg_kind) {
|
| - default:
|
| - case ModRmGeneral:
|
| - reg_kind = NaClExtractOpRegKind(state, operand);
|
| - break;
|
| - case ModRmMmx:
|
| - reg_kind = RegMMX;
|
| - break;
|
| - case ModRmXmm:
|
| - reg_kind = RegXMM;
|
| - break;
|
| - case ModRmCreg:
|
| - reg_kind = RegC;
|
| - break;
|
| - case ModRmDreg:
|
| - reg_kind = RegD;
|
| - break;
|
| - case ModRmNoTopLevelRegisters:
|
| - reg_kind = RegUndefined;
|
| - }
|
| - DEBUG(NaClLog(LOG_INFO, "Translate register %d, %s\n",
|
| - reg_index, g_NaClRegKindName[reg_kind]));
|
| - return NaClAppendRegKind(state, reg_kind, reg_index);
|
| -}
|
| -
|
| -static NaClExpFlags NaClGetAddressExprSizeFlagsForState(NaClInstState* state);
|
| -
|
| -static NaClExp* NaClAppendSegmentAddress(NaClInstState* state) {
|
| - NaClExpFlags flags = NaClGetAddressExprSizeFlagsForState(state);
|
| - return NaClAppendExp(ExprSegmentAddress, 0, flags, &state->nodes);
|
| -}
|
| -
|
| -/* Same as NaClAppendOperandReg, except that a segment register is combined with
|
| - * the indexed register to define a segment address.
|
| - */
|
| -static NaClExp* NaClAppendSegmentOpReg(
|
| - NaClInstState* state,
|
| - const NaClOp* operand,
|
| - NaClOpKind seg_register,
|
| - int reg_index,
|
| - NaClModRmRegKind modrm_reg_kind) {
|
| - NaClExp* results = NaClAppendSegmentAddress(state);
|
| - NaClAppendReg(seg_register, &state->nodes);
|
| - NaClAppendOperandReg(state, operand, reg_index, modrm_reg_kind);
|
| - return results;
|
| -}
|
| -
|
| -/* Returns the corresponding segment register for the given index (0..7) */
|
| -static NaClExp* NaClAppendModRmSegmentReg(NaClInstState* state) {
|
| - static NaClOpKind seg[8] = {
|
| - RegES,
|
| - RegCS,
|
| - RegSS,
|
| - RegDS,
|
| - RegFS,
|
| - RegGS,
|
| - /* These should not happen. */
|
| - RegUnknown,
|
| - RegUnknown
|
| - };
|
| - return NaClAppendReg(seg[modrm_regInline(state->modrm)], &state->nodes);
|
| -}
|
| -
|
| -/* For the given instruction state, and the corresponding 3-bit specification
|
| - * of a register, update it to a 4-bit specification, based on the REX.R bit.
|
| - */
|
| -static INLINE int NaClGetRexRReg(NaClInstState* state, int reg) {
|
| - DEBUG(NaClLog(LOG_INFO, "Get GenRexRRegister %d\n", reg));
|
| - if (NACL_TARGET_SUBARCH == 64 && (state->rexprefix & 0x4)) {
|
| - reg += 8;
|
| - }
|
| - return reg;
|
| -}
|
| -
|
| -/* For the given instruction state, and the corresponding 3-bit specification
|
| - * of a register, update it to a 4-bit specification, based on the REX.X bit.
|
| - */
|
| -static INLINE int NaClGetRexXReg(NaClInstState* state, int reg) {
|
| - DEBUG(NaClLog(LOG_INFO, "Get GenRexXRegister\n"));
|
| - if (NACL_TARGET_SUBARCH == 64 && (state->rexprefix & 0x2)) {
|
| - reg += 8;
|
| - }
|
| - return reg;
|
| -}
|
| -
|
| -/* For the given instruction state, and the corresponding 3-bit specification
|
| - * of a register, update it to a 4-bit specification, based on the REX.B bit.
|
| - */
|
| -static INLINE int NaClGetRexBReg(NaClInstState* state, int reg) {
|
| - DEBUG(NaClLog(LOG_INFO, "Get GenRexBRegister\n"));
|
| - if (NACL_TARGET_SUBARCH == 64 && (state->rexprefix & 0x1)) {
|
| - DEBUG(NaClLog(LOG_INFO, "rexprefix == %02x\n", state->rexprefix));
|
| - reg += 8;
|
| - }
|
| - return reg;
|
| -}
|
| -
|
| -/* Return the general purpose register associated with the modrm.reg
|
| - * field.
|
| - */
|
| -static INLINE int NaClGetGenRegRegister(NaClInstState* state) {
|
| - DEBUG(NaClLog(LOG_INFO, "Get GenRegRegister\n"));
|
| - return NaClGetRexRReg(state, modrm_regInline(state->modrm));
|
| -}
|
| -
|
| -/* Return the general purpose register associated with the modrm.rm
|
| - * field.
|
| - */
|
| -static INLINE int NaClGetGenRmRegister(NaClInstState* state) {
|
| - DEBUG(NaClLog(LOG_INFO, "Get GenRmRegister\n"));
|
| - return NaClGetRexBReg(state, modrm_rmInline(state->modrm));
|
| -}
|
| -
|
| -/* Get the register index from the difference of the opcode, and
|
| - * its opcode base.
|
| - */
|
| -static NaClExp* NaClAppendOpcodeBaseReg(
|
| - NaClInstState* state, const NaClOp* operand) {
|
| - int reg_index;
|
| - reg_index = NaClGetOpcodePlusR(state->inst->opcode_ext);
|
| - assert(reg_index >= 0 && reg_index < 8);
|
| - DEBUG(NaClLog(LOG_INFO, "Translate opcode base register %d\n", reg_index));
|
| - return NaClAppendRegKind(state, NaClExtractOpRegKind(state, operand),
|
| - NaClGetRexBReg(state, reg_index));
|
| -}
|
| -
|
| -/* Get the ST register defined from the difference of the opcode, and
|
| - * its opcode base.
|
| - */
|
| -static NaClExp* NaClAppendStOpcodeBaseReg(NaClInstState* state) {
|
| - int reg_index;
|
| - reg_index = NaClGetOpcodePlusR(state->inst->opcode_ext);
|
| - assert(reg_index >= 0 && reg_index < 8);
|
| - DEBUG(NaClLog(LOG_INFO, "Translate opcode base register %d\n", reg_index));
|
| - return NaClAppendReg(RegST0 + reg_index, &state->nodes);
|
| -}
|
| -
|
| -/* Model the extraction of a displacement value and the associated flags. */
|
| -typedef struct NaClDisplacement {
|
| - uint64_t value;
|
| - NaClExpFlags flags;
|
| -} NaClDisplacement;
|
| -
|
| -static INLINE void NaClInitializeDisplacement(
|
| - uint64_t value, NaClExpFlags flags,
|
| - NaClDisplacement* displacement) {
|
| - displacement->value = value;
|
| - displacement->flags = flags;
|
| -}
|
| -
|
| -/* Extract the binary value from the specified bytes of the instruction. */
|
| -static uint64_t NaClExtractUnsignedBinaryValue(NaClInstState* state,
|
| - int start_byte, int num_bytes) {
|
| - int i;
|
| - uint64_t value = 0;
|
| - for (i = 0; i < num_bytes; ++i) {
|
| - uint8_t byte = state->bytes.byte[start_byte + i];
|
| - value += (((uint64_t) byte) << (i * 8));
|
| - }
|
| - return value;
|
| -}
|
| -
|
| -static int64_t NaClExtractSignedBinaryValue(NaClInstState* state,
|
| - int start_byte, int num_bytes) {
|
| - /* Assumes little endian. */
|
| - uint8_t* address = &state->bytes.byte[start_byte];
|
| - switch (num_bytes) {
|
| - case 1:
|
| - return *(int8_t*) address;
|
| - case 2:
|
| - return *(int16_t*) address;
|
| - case 4:
|
| - return *(int32_t*) address;
|
| - default:
|
| - CHECK(0);
|
| - return -1;
|
| - }
|
| -}
|
| -
|
| -/* Given the number of bytes for a literal constant, return the corresponding
|
| - * expr node flags that represent the value of the parsed bytes.
|
| - */
|
| -static NaClExpFlags NaClGetExprSizeFlagForBytes(uint8_t num_bytes) {
|
| - switch (num_bytes) {
|
| - /* HACK a zero size immediate is generated for some addr16 instructions.
|
| - * We don't allow these instructions, but we do test decompiling them.
|
| - * TODO(ncbray) eliminate the bug or the test case.
|
| - */
|
| - case 0:
|
| - case 1:
|
| - return NACL_EFLAG(ExprSize8);
|
| - case 2:
|
| - return NACL_EFLAG(ExprSize16);
|
| - case 4:
|
| - return NACL_EFLAG(ExprSize32);
|
| - case 6:
|
| - return NACL_EFLAG(ExprSize48);
|
| - case 8:
|
| - return NACL_EFLAG(ExprSize64);
|
| - default:
|
| - CHECK(0);
|
| - return 0;
|
| - }
|
| -}
|
| -
|
| -/* Return the expr flag for the address size associated with the state. */
|
| -static NaClExpFlags NaClGetAddressExprSizeFlagsForState(NaClInstState* state) {
|
| - uint8_t size = NaClInstStateAddressSize(state);
|
| - return NaClGetExprSizeFlagForBytes(size / 8);
|
| -}
|
| -
|
| -/* Given the corresponding instruction state, return the
|
| - * corresponding displacement value, and any expression node
|
| - * flags that should be associated with the displacement value.
|
| - */
|
| -static void NaClExtractDisplacement(NaClInstState* state,
|
| - NaClDisplacement* displacement,
|
| - NaClExpFlags flags) {
|
| - DEBUG(NaClLog(LOG_INFO, "-> Extract displacement, flags = ");
|
| - NaClPrintExpFlags(NaClLogGetGio(), flags);
|
| - gprintf(NaClLogGetGio(), "\n"));
|
| - /* First compute the displacement value. */
|
| - displacement->value = NaClExtractUnsignedBinaryValue(state,
|
| - state->first_disp_byte,
|
| - state->num_disp_bytes);
|
| -
|
| - /* Now compute any appropriate flags to be associated with the value. */
|
| - displacement->flags = flags |
|
| - NaClGetExprSizeFlagForBytes(state->num_disp_bytes);
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "<- value = %"NACL_PRIx64", flags = ", displacement->value);
|
| - NaClPrintExpFlags(NaClLogGetGio(), displacement->flags);
|
| - gprintf(NaClLogGetGio(), "\n"));
|
| -}
|
| -
|
| -/* Append the displacement value of the given instruction state
|
| - * onto the vector of expression nodes. Returns the appended displacement
|
| - * value.
|
| - */
|
| -static NaClExp* NaClAppendDisplacement(NaClInstState* state) {
|
| - NaClDisplacement displacement;
|
| - DEBUG(NaClLog(LOG_INFO, "append displacement\n"));
|
| - NaClExtractDisplacement(state, &displacement, NACL_EFLAG(ExprSignedHex));
|
| - return NaClAppendConst(displacement.value, displacement.flags, &state->nodes);
|
| -}
|
| -
|
| -/* Get the binary value denoted by the immediate bytes of the state. */
|
| -static uint64_t NaClExtractUnsignedImmediate(NaClInstState* state) {
|
| - return NaClExtractUnsignedBinaryValue(state,
|
| - state->first_imm_byte,
|
| - state->num_imm_bytes);
|
| -}
|
| -
|
| -/* Get the binary value denoted by the 2nd immediate bytes of the state. */
|
| -static uint64_t NaClExtractUnsignedImmediate2(NaClInstState* state) {
|
| - return NaClExtractUnsignedBinaryValue(
|
| - state,
|
| - state->first_imm_byte + state->num_imm_bytes,
|
| - state->num_imm2_bytes);
|
| -}
|
| -
|
| -/* Get the binary value denoted by the immediate bytes of the state. */
|
| -static int64_t NaClExtractSignedImmediate(NaClInstState* state) {
|
| - return NaClExtractSignedBinaryValue(state,
|
| - state->first_imm_byte,
|
| - state->num_imm_bytes);
|
| -}
|
| -
|
| -/* Append the immediate value of the given instruction state onto
|
| - * The vector of expression nodes. Returns the appended immediate value.
|
| - */
|
| -static NaClExp* NaClAppendImmed(NaClInstState* state) {
|
| - NaClExpFlags flags;
|
| -
|
| - /* First compute the immediate value. */
|
| - uint64_t value;
|
| - DEBUG(NaClLog(LOG_INFO, "append immediate\n"));
|
| - value = NaClExtractUnsignedImmediate(state);
|
| -
|
| - /* Now compute any appropriate flags to be associated with the immediate
|
| - * value.
|
| - */
|
| - flags = NACL_EFLAG(ExprUnsignedHex) |
|
| - NaClGetExprSizeFlagForBytes(state->num_imm_bytes);
|
| -
|
| - /* Append the generated immediate value onto the vector. */
|
| - return NaClAppendConst(value, flags, &state->nodes);
|
| -}
|
| -
|
| -/* Append the second immediate value of the given instruction state onto
|
| - * the vector of expression nodes. Returns the appended immediate value.
|
| - */
|
| -static NaClExp* NaClAppendImmed2(NaClInstState* state) {
|
| - NaClExpFlags flags;
|
| -
|
| - /* First compute the immedaite value. */
|
| - uint64_t value;
|
| - DEBUG(NaClLog(LOG_INFO, "append 2nd immediate\n"));
|
| -
|
| - value = NaClExtractUnsignedImmediate2(state);
|
| -
|
| - /* Now compute any appropriate flags to be associated with the immediate
|
| - * value.
|
| - */
|
| - flags =
|
| - NACL_EFLAG(ExprUnsignedHex) |
|
| - NaClGetExprSizeFlagForBytes(state->num_imm2_bytes);
|
| -
|
| - /* Append the generated immediate value onto the vector. */
|
| - return NaClAppendConst(value, flags, &state->nodes);
|
| -}
|
| -
|
| -/* Append an ExprMemOffset node for the given state, and return
|
| - * the appended ndoe.
|
| - */
|
| -static NaClExp* NaClAppendMemOffsetNode(NaClInstState* state) {
|
| - NaClExpFlags flags = NaClGetAddressExprSizeFlagsForState(state);
|
| - NaClExp* root = NaClAppendExp(ExprMemOffset, 0, flags, &state->nodes);
|
| - DEBUG(NaClLog(LOG_INFO, "Build memoffset, flags = ");
|
| - NaClPrintExpFlags(NaClLogGetGio(), flags);
|
| - gprintf(NaClLogGetGio(), "\n"));
|
| - return root;
|
| -}
|
| -
|
| -/* Returns the segment register prefix node, or NULL if no such node is
|
| - * added.
|
| - */
|
| -static NaClExp* NaClAppendSegmentAddressNode(NaClInstState* state,
|
| - NaClOpKind reg_default) {
|
| - NaClExp* root = NULL;
|
| - NaClOpKind seg_reg = NaClGetSegmentPrefixReg(state, reg_default);
|
| - if (seg_reg != RegUnknown) {
|
| - NaClExp* n;
|
| - root = NaClAppendSegmentAddress(state);
|
| - n = NaClAppendReg(seg_reg, &state->nodes);
|
| - n->flags |= NACL_EFLAG(ExprUsed);
|
| - }
|
| - return root;
|
| -}
|
| -
|
| -/* Append the immediate value of the given instruction as the displacement
|
| - * of a memory offset.
|
| - */
|
| -static NaClExp* NaClAppendMemoryOffsetImmed(NaClInstState* state) {
|
| - NaClExpFlags flags;
|
| - uint64_t value;
|
| - NaClExp* root;
|
| - DEBUG(NaClLog(LOG_INFO, "append memory offset immediate\n"));
|
| - root = NaClAppendSegmentAddressNode(state, RegUnknown);
|
| - if (root == NULL) {
|
| - root = NaClAppendMemOffsetNode(state);
|
| - } else {
|
| - NaClAppendMemOffsetNode(state);
|
| - }
|
| - NaClAppendReg(RegUnknown, &state->nodes);
|
| - NaClAppendReg(RegUnknown, &state->nodes);
|
| - NaClAppendConst(1, NACL_EFLAG(ExprSize8), &state->nodes);
|
| - value = NaClExtractUnsignedImmediate(state);
|
| - DEBUG(NaClLog(LOG_INFO, "value = 0x%016"NACL_PRIx64"\n", value));
|
| - flags = NACL_EFLAG(ExprUnsignedHex) |
|
| - NaClGetExprSizeFlagForBytes(state->num_imm_bytes);
|
| - NaClAppendConst(value, flags, &state->nodes);
|
| - return root;
|
| -}
|
| -
|
| -static NaClExp* NaClAppendRelativeImmed(NaClInstState* state) {
|
| - NaClPcNumber jump_offset = (NaClPcNumber) NaClExtractSignedImmediate(state);
|
| - DEBUG(NaClLog(LOG_INFO, "append relative immediate\n"));
|
| - return NaClAppendConst(jump_offset,
|
| - NACL_EFLAG(ExprSignedHex) |
|
| - NaClGetExprSizeFlagForBytes(state->num_imm_bytes) |
|
| - NACL_EFLAG(ExprJumpTarget),
|
| - &state->nodes);
|
| -}
|
| -
|
| -/* Append a memory offset for the given memory offset defined by
|
| - * the formula "base + index*scale + displacement". If no index
|
| - * is used, its value should be RegUnknown. Argument displacement_flags
|
| - * are flags that should be associated with the generated displacement
|
| - * value
|
| - */
|
| -static NaClExp* NaClAppendMemoryOffset(NaClInstState* state,
|
| - NaClOpKind base,
|
| - NaClOpKind index,
|
| - uint8_t scale,
|
| - NaClDisplacement* displacement) {
|
| - NaClExp* root = NULL;
|
| - NaClOpKind seg_reg_default;
|
| - NaClExp* n;
|
| -
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "memory offset(%s + %s * %d + %"NACL_PRId64
|
| - " : %"NACL_PRIx32")\n",
|
| - NaClOpKindName(base),
|
| - NaClOpKindName(index),
|
| - scale,
|
| - displacement->value,
|
| - displacement->flags));
|
| -
|
| - if (32 == NACL_TARGET_SUBARCH) {
|
| - seg_reg_default = ((base == RegBP || base == RegEBP)
|
| - ? RegSS : NaClGetDsSegmentReg(state));
|
| - } else {
|
| - seg_reg_default = RegUnknown;
|
| - }
|
| - root = NaClAppendSegmentAddressNode(state, seg_reg_default);
|
| - if (NULL == root) {
|
| - root = NaClAppendMemOffsetNode(state);
|
| - } else {
|
| - NaClAppendMemOffsetNode(state);
|
| - }
|
| - n = NaClAppendReg(base, &state->nodes);
|
| - if (base != RegUnknown) {
|
| - n->flags |= NACL_EFLAG(ExprUsed);
|
| - }
|
| - n = NaClAppendReg(index, &state->nodes);
|
| - if (index == RegUnknown) {
|
| - /* Scale not applicable, check that value is 1. */
|
| - assert(scale == 1);
|
| - } else {
|
| - n->flags |= NACL_EFLAG(ExprUsed);
|
| - }
|
| - NaClAppendConst(scale, NACL_EFLAG(ExprSize8), &state->nodes);
|
| - NaClAppendConst(displacement->value, displacement->flags, &state->nodes);
|
| - DEBUG(NaClLog(LOG_INFO, "finished appending memory offset:\n"));
|
| - DEBUG(NaClExpVectorPrint(NaClLogGetGio(), state));
|
| - return root;
|
| -}
|
| -
|
| -/* Extract the base register from the SIB byte. */
|
| -static NaClOpKind NaClGetSibBase(NaClInstState* state) {
|
| - int base = sib_base(state->sib);
|
| - NaClOpKind base_reg = RegUnknown;
|
| - if (0x5 == base) {
|
| - switch (modrm_modInline(state->modrm)) {
|
| - case 0:
|
| - break;
|
| - case 1:
|
| - case 2:
|
| - if (NACL_TARGET_SUBARCH == 64) {
|
| - if (state->rexprefix & 0x1) {
|
| - base_reg = RegR13;
|
| - } else {
|
| - base_reg = RegRBP;
|
| - }
|
| - } else {
|
| - base_reg = RegEBP;
|
| - }
|
| - break;
|
| - default:
|
| - NaClFatal("SIB value", state);
|
| - }
|
| - } else {
|
| - NaClRegKind kind = NaClExtractAddressRegKind(state);
|
| - base_reg = NaClLookupReg(state, kind, NaClGetRexBReg(state, base));
|
| - }
|
| - return base_reg;
|
| -}
|
| -
|
| -/* Define the possible scaling factors that can be defined in the
|
| - * SIB byte of the parsed instruction.
|
| - */
|
| -static uint8_t nacl_sib_scale[4] = { 1, 2, 4, 8 };
|
| -
|
| -/* Extract out the expression defined by the SIB byte of the instruction
|
| - * in the given instruction state, and append it to the vector of
|
| - * expression nodes. Return the corresponding expression node that
|
| - * is the root of the appended expression.
|
| - */
|
| -static NaClExp* NaClAppendSib(NaClInstState* state) {
|
| - int index = sib_index(state->sib);
|
| - int scale = 1;
|
| - NaClRegKind kind = NaClExtractAddressRegKind(state);
|
| - NaClOpKind base_reg;
|
| - NaClOpKind index_reg = RegUnknown;
|
| - NaClDisplacement displacement;
|
| - DEBUG(NaClLog(LOG_INFO, "append sib: %02x\n", state->sib));
|
| - NaClInitializeDisplacement(0, 0, &displacement);
|
| - base_reg = NaClGetSibBase(state);
|
| - if (0x4 != index || NACL_TARGET_SUBARCH != 64 || (state->rexprefix & 0x2)) {
|
| - index_reg = NaClLookupReg(state, kind, NaClGetRexXReg(state, index));
|
| - scale = nacl_sib_scale[sib_ss(state->sib)];
|
| - }
|
| - if (state->num_disp_bytes > 0) {
|
| - NaClExtractDisplacement(state, &displacement,
|
| - NACL_EFLAG(ExprSignedHex));
|
| - } else {
|
| - displacement.flags = NACL_EFLAG(ExprSize8);
|
| - }
|
| - return NaClAppendMemoryOffset(state, base_reg, index_reg,
|
| - scale, &displacement);
|
| -}
|
| -
|
| -static void NaClAppendEDI(NaClInstState* state) {
|
| - switch (state->address_size) {
|
| - case 16:
|
| - NaClAppendReg(RegDI, &state->nodes);
|
| - break;
|
| - case 32:
|
| - NaClAppendReg(RegEDI, &state->nodes);
|
| - break;
|
| - case 64:
|
| - NaClAppendReg(RegRDI, &state->nodes);
|
| - break;
|
| - default:
|
| - NaClFatal("Address size for %EDI not correctly defined",
|
| - state);
|
| - break;
|
| - }
|
| -}
|
| -
|
| -static void NaClAppendESI(NaClInstState* state) {
|
| - switch (state->address_size) {
|
| - case 16:
|
| - NaClAppendReg(RegSI, &state->nodes);
|
| - break;
|
| - case 32:
|
| - NaClAppendReg(RegESI, &state->nodes);
|
| - break;
|
| - case 64:
|
| - NaClAppendReg(RegRSI, &state->nodes);
|
| - break;
|
| - default:
|
| - NaClFatal("Address size for %ESI not correctly defined", state);
|
| - break;
|
| - }
|
| -}
|
| -static void NaClAppendEBX(NaClInstState* state) {
|
| - switch (state->address_size) {
|
| - case 16:
|
| - NaClAppendReg(RegBX, &state->nodes);
|
| - break;
|
| - case 32:
|
| - NaClAppendReg(RegEBX, &state->nodes);
|
| - break;
|
| - case 64:
|
| - NaClAppendReg(RegRBX, &state->nodes);
|
| - break;
|
| - default:
|
| - NaClFatal("Address size for %EBX not correctly defined", state);
|
| - break;
|
| - }
|
| -}
|
| -
|
| -static NaClExp* NaClAppendDS_EDI(NaClInstState* state) {
|
| - NaClExp* results = NaClAppendSegmentAddress(state);
|
| - results->flags |= NACL_EFLAG(ExprDSrCase);
|
| - NaClAppendReg(NaClGetDsSegmentReg(state), &state->nodes);
|
| - NaClAppendEDI(state);
|
| - return results;
|
| -}
|
| -
|
| -static NaClExp* NaClAppendDS_ESI(NaClInstState* state) {
|
| - NaClExp* results = NaClAppendSegmentAddress(state);
|
| - results->flags |= NACL_EFLAG(ExprDSrCase);
|
| - NaClAppendReg(NaClGetDsSegmentReg(state), &state->nodes);
|
| - NaClAppendESI(state);
|
| - return results;
|
| -}
|
| -
|
| -static NaClExp* NaClAppendDS_EBX(NaClInstState* state) {
|
| - NaClExp* results = NaClAppendSegmentAddress(state);
|
| - results->flags |= NACL_EFLAG(ExprDSrCase);
|
| - NaClAppendReg(NaClGetDsSegmentReg(state), &state->nodes);
|
| - NaClAppendEBX(state);
|
| - return results;
|
| -}
|
| -
|
| -static NaClExp* NaClAppendES_EDI(NaClInstState* state) {
|
| - NaClExp* results = NaClAppendSegmentAddress(state);
|
| - results->flags |= NACL_EFLAG(ExprESrCase);
|
| - NaClAppendReg(NaClGetEsSegmentReg(state), &state->nodes);
|
| - NaClAppendEDI(state);
|
| - return results;
|
| -}
|
| -
|
| -/* Get the Effective address in the mod/rm byte, if the modrm.mod field
|
| - * is 00, and append it to the vector of expression nodes. Operand is
|
| - * the corresponding operand of the opcode associated with the instruction
|
| - * of the given state that corresponds to the effective address. Returns
|
| - * the root of the appended effective address.
|
| - */
|
| -static NaClExp* NaClAppendMod00EffectiveAddress(
|
| - NaClInstState* state, const NaClOp* operand) {
|
| - DEBUG(NaClLog(LOG_INFO, "Translate modrm(%02x).mod == 00\n", state->modrm));
|
| - if ((32 == NACL_TARGET_SUBARCH) &&
|
| - NaClHasBit(state->prefix_mask, kPrefixADDR16)) {
|
| - /* This code doesn't know how to translate 16-bit modrm effective addresses.
|
| - * However, such arguments are not nacl legal. Communicate this explicitly.
|
| - */
|
| - return NaClAppendNaClIllegal(state);
|
| - }
|
| - switch (modrm_rmInline(state->modrm)) {
|
| - case 4:
|
| - return NaClAppendSib(state);
|
| - case 5:
|
| - if (NACL_TARGET_SUBARCH == 64) {
|
| - NaClDisplacement displacement;
|
| - NaClExtractDisplacement(state, &displacement,
|
| - NACL_EFLAG(ExprSignedHex));
|
| - return NaClAppendMemoryOffset(state,
|
| - RegRIP,
|
| - RegUnknown,
|
| - 1,
|
| - &displacement);
|
| - } else {
|
| - return NaClAppendDisplacement(state);
|
| - }
|
| - default: {
|
| - NaClDisplacement displacement;
|
| - NaClInitializeDisplacement(0, NACL_EFLAG(ExprSize8), &displacement);
|
| - return NaClAppendMemoryOffset(state,
|
| - NaClLookupReg(
|
| - state,
|
| - NaClExtractAddressRegKind(state),
|
| - NaClGetGenRmRegister(state)),
|
| - RegUnknown,
|
| - 1,
|
| - &displacement);
|
| - }
|
| - }
|
| - /* NOT REACHED */
|
| - return NULL;
|
| -}
|
| -
|
| -/* Get the Effective address in the mod/rm byte, if the modrm.mod field
|
| - * is 01, and append it to the vector of expression nodes. Operand is
|
| - * the corresponding operand of the opcode associated with the instruction
|
| - * of the given state that corresponds to the effective address. Returns
|
| - * the root of the appended effective address.
|
| - */
|
| -static NaClExp* NaClAppendMod01EffectiveAddress(
|
| - NaClInstState* state, const NaClOp* operand) {
|
| - DEBUG(NaClLog(LOG_INFO, "Translate modrm(%02x).mod == 01\n", state->modrm));
|
| - if ((32 == NACL_TARGET_SUBARCH) &&
|
| - NaClHasBit(state->prefix_mask, kPrefixADDR16)) {
|
| - /* This code doesn't know how to translate 16-bit modrm effective addresses.
|
| - * However, such arguments are not nacl legal. Communicate this explicitly.
|
| - */
|
| - return NaClAppendNaClIllegal(state);
|
| - }
|
| - if (4 == modrm_rmInline(state->modrm)) {
|
| - return NaClAppendSib(state);
|
| - } else {
|
| - NaClDisplacement displacement;
|
| - NaClExtractDisplacement(state, &displacement, NACL_EFLAG(ExprSignedHex));
|
| - return NaClAppendMemoryOffset(state,
|
| - NaClLookupReg(
|
| - state,
|
| - NaClExtractAddressRegKind(state),
|
| - NaClGetGenRmRegister(state)),
|
| - RegUnknown,
|
| - 1,
|
| - &displacement);
|
| - }
|
| -}
|
| -
|
| -/* Get the Effective address in the mod/rm byte, if the modrm.mod field
|
| - * is 10, and append it to the vector of expression nodes. Operand is
|
| - * the corresponding operand of the opcode associated with the instruction
|
| - * of the given state that corresponds to the effective address. Returns
|
| - * the root of the appended effective address.
|
| - */
|
| -static NaClExp* NaClAppendMod10EffectiveAddress(
|
| - NaClInstState* state, const NaClOp* operand) {
|
| - DEBUG(NaClLog(LOG_INFO, "Translate modrm(%02x).mod == 10\n", state->modrm));
|
| - if ((32 == NACL_TARGET_SUBARCH) &&
|
| - NaClHasBit(state->prefix_mask, kPrefixADDR16)) {
|
| - /* This code doesn't know how to translate 16-bit modrm effective addresses.
|
| - * However, such arguments are not nacl legal. Communicate this explicitly.
|
| - */
|
| - return NaClAppendNaClIllegal(state);
|
| - }
|
| - if (4 == modrm_rmInline(state->modrm)) {
|
| - return NaClAppendSib(state);
|
| - } else {
|
| - NaClDisplacement displacement;
|
| - NaClOpKind base =
|
| - NaClLookupReg(state,
|
| - NaClExtractAddressRegKind(state),
|
| - NaClGetGenRmRegister(state));
|
| - NaClExtractDisplacement(state, &displacement, NACL_EFLAG(ExprSignedHex));
|
| - return NaClAppendMemoryOffset(state, base, RegUnknown, 1, &displacement);
|
| - }
|
| -}
|
| -
|
| -/* Get the Effective address in the mod/rm byte, if the modrm.mod field
|
| - * is 11, and append it to the vector of expression nodes. Operand is
|
| - * the corresponding operand of the opcode associated with the instruction
|
| - * of the given state that corresponds to the effective address. Returns
|
| - * the root of the appended effective address.
|
| - */
|
| -static NaClExp* NaClAppendMod11EffectiveAddress(
|
| - NaClInstState* state, const NaClOp* operand,
|
| - NaClModRmRegKind modrm_reg_kind) {
|
| - DEBUG(NaClLog(LOG_INFO, "Translate modrm(%02x).mod == 11, %s\n",
|
| - state->modrm, g_NaClModRmRegKindName[modrm_reg_kind]));
|
| - return NaClAppendOperandReg(state,
|
| - operand,
|
| - NaClGetGenRmRegister(state), modrm_reg_kind);
|
| -}
|
| -
|
| -static NaClExp* NaClAppendBasedOnSize(NaClOpKind reg_2b,
|
| - NaClOpKind reg_4b,
|
| - NaClOpKind reg_8b,
|
| - NaClInstState* state) {
|
| - switch (state->operand_size) {
|
| - case 2:
|
| - return NaClAppendReg(reg_2b, &state->nodes);
|
| - case 4:
|
| - return NaClAppendReg(reg_4b, &state->nodes);
|
| - case 8:
|
| - return NaClAppendReg(reg_8b, &state->nodes);
|
| - default:
|
| - return NaClFatal("can't translate register group: operand size not valid",
|
| - state);
|
| - }
|
| -}
|
| -
|
| -static NaClExp* NaClAppendBasedOnAddressSize(NaClOpKind reg_2b,
|
| - NaClOpKind reg_4b,
|
| - NaClOpKind reg_8b,
|
| - NaClInstState* state) {
|
| - switch (state->address_size) {
|
| - case 16:
|
| - return NaClAppendReg(reg_2b, &state->nodes);
|
| - case 32:
|
| - return NaClAppendReg(reg_4b, &state->nodes);
|
| - case 64:
|
| - return NaClAppendReg(reg_8b, &state->nodes);
|
| - default:
|
| - return NaClFatal("can't translate register group: address size not valid",
|
| - state);
|
| - }
|
| -}
|
| -
|
| -/* Compute the effect address using the Mod/Rm and SIB bytes. */
|
| -static NaClExp* NaClAppendEffectiveAddress(
|
| - NaClInstState* state, const NaClOp* operand,
|
| - NaClModRmRegKind modrm_reg_kind) {
|
| - switch(modrm_modInline(state->modrm)) {
|
| - case 0:
|
| - return NaClAppendMod00EffectiveAddress(state, operand);
|
| - case 1:
|
| - return NaClAppendMod01EffectiveAddress(state, operand);
|
| - case 2:
|
| - return NaClAppendMod10EffectiveAddress(state, operand);
|
| - case 3:
|
| - return NaClAppendMod11EffectiveAddress(state, operand, modrm_reg_kind);
|
| - default:
|
| - break;
|
| - }
|
| - return NaClFatal("Operand", state);
|
| -}
|
| -
|
| -/* Given the corresponding operand of the opcode associated with the
|
| - * instruction of the given state, append the corresponding expression
|
| - * nodes that it corresponds to. Returns the root of the corresponding
|
| - * appended expression tree.
|
| - */
|
| -static NaClExp* NaClAppendOperand(NaClInstState* state,
|
| - const NaClOp* operand) {
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "append operand %s\n", NaClOpKindName(operand->kind)));
|
| - switch (operand->kind) {
|
| - case A_Operand:
|
| - return NaClAppendImmed(state);
|
| - case E_Operand:
|
| - case Eb_Operand:
|
| - case Ew_Operand:
|
| - case Ev_Operand:
|
| - case Eo_Operand:
|
| - case Edq_Operand:
|
| - /* TODO(karl) Should we add limitations that simple registers
|
| - * not allowed in M_Operand cases?
|
| - */
|
| - case M_Operand:
|
| - case Mb_Operand:
|
| - case Mw_Operand:
|
| - case Mv_Operand:
|
| - case Mo_Operand:
|
| - case Mdq_Operand: {
|
| - NaClExp* address =
|
| - NaClAppendEffectiveAddress(state, operand, ModRmGeneral);
|
| - /* Near operands are jump addresses. Mark them as such. */
|
| - if (operand->flags & NACL_OPFLAG(OperandNear)) {
|
| - address->flags |= NACL_EFLAG(ExprJumpTarget);
|
| - }
|
| - return address;
|
| - }
|
| - break;
|
| - case G_Operand:
|
| - case Gb_Operand:
|
| - case Gw_Operand:
|
| - case Gv_Operand:
|
| - case Go_Operand:
|
| - case Gdq_Operand:
|
| - return NaClAppendOperandReg(state, operand, NaClGetGenRegRegister(state),
|
| - ModRmGeneral);
|
| - case Seg_G_Operand:
|
| - return NaClAppendSegmentOpReg(
|
| - state, operand, NaClGetMnemonicSegmentRegister(state),
|
| - NaClGetGenRegRegister(state), ModRmGeneral);
|
| - case G_OpcodeBase:
|
| - return NaClAppendOpcodeBaseReg(state, operand);
|
| - case I_Operand:
|
| - case Ib_Operand:
|
| - case Iw_Operand:
|
| - case Iv_Operand:
|
| - case Io_Operand:
|
| - return NaClAppendImmed(state);
|
| - case I2_Operand:
|
| - return NaClAppendImmed2(state);
|
| - case J_Operand:
|
| - case Jb_Operand:
|
| - case Jw_Operand:
|
| - case Jv_Operand:
|
| - /* TODO(karl) use operand flags OperandNear and OperandRelative to decide
|
| - * how to process the J operand (see Intel manual for call statement).
|
| - */
|
| - return NaClAppendRelativeImmed(state);
|
| - case Mmx_Gd_Operand:
|
| - case Mmx_G_Operand:
|
| - return NaClAppendOperandReg(state, operand, NaClGetGenRegRegister(state),
|
| - ModRmMmx);
|
| - case Mmx_E_Operand:
|
| - return NaClAppendEffectiveAddress(state, operand, ModRmMmx);
|
| - case Xmm_G_Operand:
|
| - case Xmm_Go_Operand:
|
| - return NaClAppendOperandReg(state, operand, NaClGetGenRegRegister(state),
|
| - ModRmXmm);
|
| - case Xmm_E_Operand:
|
| - case Xmm_Eo_Operand:
|
| - return NaClAppendEffectiveAddress(state, operand, ModRmXmm);
|
| - case C_Operand:
|
| - return NaClAppendEffectiveAddress(state, operand, ModRmCreg);
|
| - case D_Operand:
|
| - return NaClAppendEffectiveAddress(state, operand, ModRmDreg);
|
| - case O_Operand:
|
| - case Ob_Operand:
|
| - case Ow_Operand:
|
| - case Ov_Operand:
|
| - case Oo_Operand:
|
| - return NaClAppendMemoryOffsetImmed(state);
|
| - case St_Operand:
|
| - return NaClAppendStOpcodeBaseReg(state);
|
| - case RegUnknown:
|
| - case RegAL:
|
| - case RegBL:
|
| - case RegCL:
|
| - case RegDL:
|
| - case RegAH:
|
| - case RegBH:
|
| - case RegCH:
|
| - case RegDH:
|
| - case RegDIL:
|
| - case RegSIL:
|
| - case RegBPL:
|
| - case RegSPL:
|
| - case RegR8B:
|
| - case RegR9B:
|
| - case RegR10B:
|
| - case RegR11B:
|
| - case RegR12B:
|
| - case RegR13B:
|
| - case RegR14B:
|
| - case RegR15B:
|
| - case RegAX:
|
| - case RegBX:
|
| - case RegCX:
|
| - case RegDX:
|
| - case RegSI:
|
| - case RegDI:
|
| - case RegBP:
|
| - case RegSP:
|
| - case RegR8W:
|
| - case RegR9W:
|
| - case RegR10W:
|
| - case RegR11W:
|
| - case RegR12W:
|
| - case RegR13W:
|
| - case RegR14W:
|
| - case RegR15W:
|
| - case RegEAX:
|
| - case RegEBX:
|
| - case RegECX:
|
| - case RegEDX:
|
| - case RegESI:
|
| - case RegEDI:
|
| - case RegEBP:
|
| - case RegESP:
|
| - case RegR8D:
|
| - case RegR9D:
|
| - case RegR10D:
|
| - case RegR11D:
|
| - case RegR12D:
|
| - case RegR13D:
|
| - case RegR14D:
|
| - case RegR15D:
|
| - case RegCS:
|
| - case RegDS:
|
| - case RegSS:
|
| - case RegES:
|
| - case RegFS:
|
| - case RegGS:
|
| - case RegCR0:
|
| - case RegCR1:
|
| - case RegCR2:
|
| - case RegCR3:
|
| - case RegCR4:
|
| - case RegCR5:
|
| - case RegCR6:
|
| - case RegCR7:
|
| - case RegCR8:
|
| - case RegCR9:
|
| - case RegCR10:
|
| - case RegCR11:
|
| - case RegCR12:
|
| - case RegCR13:
|
| - case RegCR14:
|
| - case RegCR15:
|
| - case RegDR0:
|
| - case RegDR1:
|
| - case RegDR2:
|
| - case RegDR3:
|
| - case RegDR4:
|
| - case RegDR5:
|
| - case RegDR6:
|
| - case RegDR7:
|
| - case RegDR8:
|
| - case RegDR9:
|
| - case RegDR10:
|
| - case RegDR11:
|
| - case RegDR12:
|
| - case RegDR13:
|
| - case RegDR14:
|
| - case RegDR15:
|
| - case RegEFLAGS:
|
| - case RegRFLAGS:
|
| - case RegEIP:
|
| - case RegRIP:
|
| - case RegRAX:
|
| - case RegRBX:
|
| - case RegRCX:
|
| - case RegRDX:
|
| - case RegRSI:
|
| - case RegRDI:
|
| - case RegRBP:
|
| - case RegRSP:
|
| - case RegR8:
|
| - case RegR9:
|
| - case RegR10:
|
| - case RegR11:
|
| - case RegR12:
|
| - case RegR13:
|
| - case RegR14:
|
| - case RegR15:
|
| - case RegST0:
|
| - case RegST1:
|
| - case RegST2:
|
| - case RegST3:
|
| - case RegST4:
|
| - case RegST5:
|
| - case RegST6:
|
| - case RegST7:
|
| - case RegMMX1:
|
| - case RegMMX2:
|
| - case RegMMX3:
|
| - case RegMMX4:
|
| - case RegMMX5:
|
| - case RegMMX6:
|
| - case RegMMX7:
|
| - case RegXMM0:
|
| - case RegXMM1:
|
| - case RegXMM2:
|
| - case RegXMM3:
|
| - case RegXMM4:
|
| - case RegXMM5:
|
| - case RegXMM6:
|
| - case RegXMM7:
|
| - case RegXMM8:
|
| - case RegXMM9:
|
| - case RegXMM10:
|
| - case RegXMM11:
|
| - case RegXMM12:
|
| - case RegXMM13:
|
| - case RegXMM14:
|
| - case RegXMM15:
|
| - return NaClAppendReg(operand->kind, &state->nodes);
|
| - case RegREIP:
|
| - return NaClAppendReg(state->address_size == 64 ? RegRIP : RegEIP,
|
| - &state->nodes);
|
| -
|
| - case RegREAX:
|
| - return NaClAppendBasedOnSize(RegAX, RegEAX, RegRAX, state);
|
| - case RegREBX:
|
| - return NaClAppendBasedOnSize(RegBX, RegEBX, RegRBX, state);
|
| - case RegRECX:
|
| - return NaClAppendBasedOnSize(RegCX, RegECX, RegRCX, state);
|
| - case RegREDX:
|
| - return NaClAppendBasedOnSize(RegDX, RegEDX, RegRDX, state);
|
| - case RegRESP:
|
| - return NaClAppendBasedOnSize(RegSP, RegESP, RegRSP, state);
|
| - case RegREBP:
|
| - return NaClAppendBasedOnSize(RegBP, RegEBP, RegRBP, state);
|
| - case RegRESI:
|
| - return NaClAppendBasedOnSize(RegSI, RegESI, RegRSI, state);
|
| - case RegREDI:
|
| - return NaClAppendBasedOnSize(RegDI, RegEDI, RegRSI, state);
|
| - case RegREAXa:
|
| - return NaClAppendBasedOnAddressSize(RegAX, RegEAX, RegRAX, state);
|
| -
|
| - case RegDS_ESI:
|
| - return NaClAppendDS_ESI(state);
|
| - case RegDS_EDI:
|
| - return NaClAppendDS_EDI(state);
|
| - case RegDS_EBX:
|
| - return NaClAppendDS_EBX(state);
|
| - case RegES_EDI:
|
| - return NaClAppendES_EDI(state);
|
| -
|
| - case S_Operand:
|
| - return NaClAppendModRmSegmentReg(state);
|
| -
|
| - case Const_1:
|
| - return NaClAppendConst(1,
|
| - NACL_EFLAG(ExprSize8) | NACL_EFLAG(ExprUnsignedHex),
|
| - &state->nodes);
|
| - default:
|
| - /* Give up, use the default of undefined. */
|
| - break;
|
| - }
|
| - return NaClFatal("Operand", state);
|
| -}
|
| -
|
| -/* Given that the given expression node is the root of the expression
|
| - * tree generated by translating the given operand, transfer over
|
| - * any appropriate flags (such as set/use information).
|
| - */
|
| -static NaClExp* NaClAddOpSetUse(NaClExp* node, const NaClOp* operand) {
|
| - if (operand->flags & NACL_OPFLAG(OpSet)) {
|
| - node->flags |= NACL_EFLAG(ExprSet);
|
| - }
|
| - if (operand->flags & NACL_OPFLAG(OpUse)) {
|
| - node->flags |= NACL_EFLAG(ExprUsed);
|
| - }
|
| - if (operand->flags & NACL_OPFLAG(OpAddress)) {
|
| - node->flags |= NACL_EFLAG(ExprAddress);
|
| - }
|
| - return node;
|
| -}
|
| -
|
| -void NaClBuildExpVector(struct NaClInstState* state) {
|
| - uint8_t i;
|
| - uint8_t num_ops;
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "building expression vector for pc = %"NACL_PRIxNaClPcAddress
|
| - ":\n", state->inst_addr));
|
| - num_ops = NaClGetInstNumberOperandsInline(state->inst);
|
| - for (i = 0; i < num_ops; i++) {
|
| - NaClExp* n;
|
| - const NaClOp* op = NaClGetInstOperandInline(state->decoder_tables,
|
| - state->inst, i);
|
| - DEBUG(NaClLog(LOG_INFO, "translating operand %d:\n", i));
|
| - n = NaClAppendExp(OperandReference, i,
|
| - NACL_EFLAG(ExprSize8) | NACL_EFLAG(ExprUnsignedInt),
|
| - &state->nodes);
|
| - if (op->flags & NACL_OPFLAG(OpImplicit)) {
|
| - n->flags |= NACL_EFLAG(ExprImplicit);
|
| - }
|
| - NaClAddOpSetUse(NaClAppendOperand(state, op), op);
|
| - DEBUG(NaClExpVectorPrint(NaClLogGetGio(), state));
|
| - }
|
| -}
|
|
|