| Index: src/trusted/validator/x86/decoder/generator/ncdecode_tablegen.c
|
| diff --git a/src/trusted/validator/x86/decoder/generator/ncdecode_tablegen.c b/src/trusted/validator/x86/decoder/generator/ncdecode_tablegen.c
|
| deleted file mode 100644
|
| index 6cd38be56d2253a34cf771653978a4ab6f08aba9..0000000000000000000000000000000000000000
|
| --- a/src/trusted/validator/x86/decoder/generator/ncdecode_tablegen.c
|
| +++ /dev/null
|
| @@ -1,2286 +0,0 @@
|
| -/*
|
| - * Copyright (c) 2011 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.
|
| - */
|
| -
|
| -/*
|
| - * New table driven generator for a decoder of x86 code.
|
| - *
|
| - * Note: Most of the organization of this document is based on the
|
| - * NaClOpcode Map appendix of one of the following documents:
|
| -
|
| - * (1) "Intel 64 and IA-32 Architectures
|
| - * Software Developer's Manual (volumes 1, 2a, and 2b; documents
|
| - * 253665.pdf, 253666.pdf, and 253667.pdf)".
|
| - *
|
| - * (2) "Intel 80386 Reference Programmer's Manual" (document
|
| - * http://pdos.csail.mit.edu/6.828/2004/readings/i386/toc.htm).
|
| - */
|
| -
|
| -#ifndef NACL_TRUSTED_BUT_NOT_TCB
|
| -#error("This file is not meant for use in the TCB")
|
| -#endif
|
| -
|
| -#include <stdio.h>
|
| -#include <stdlib.h>
|
| -#include <assert.h>
|
| -#include <string.h>
|
| -
|
| -#include "native_client/src/trusted/validator/x86/decoder/generator/ncdecode_tablegen.h"
|
| -
|
| -
|
| -#include "native_client/src/include/portability.h"
|
| -#include "native_client/src/include/portability_io.h"
|
| -#include "native_client/src/shared/utils/flags.h"
|
| -#include "native_client/src/shared/platform/nacl_log.h"
|
| -#include "native_client/src/trusted/validator/x86/x86_insts.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/generator/gen/nacl_disallows.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/generator/nacl_regsgen.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/generator/ncdecode_forms.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/generator/ncdecode_st.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/generator/ncval_simplify.h"
|
| -#include "native_client/src/trusted/validator/x86/decoder/generator/nc_compress.h"
|
| -
|
| -/* To turn on debugging of instruction decoding, change value of
|
| - * DEBUGGING to 1.
|
| - */
|
| -#define DEBUGGING 0
|
| -
|
| -#include "native_client/src/shared/utils/debugging.h"
|
| -
|
| -/* Define the default buffer size to use. */
|
| -#define BUFFER_SIZE 256
|
| -
|
| -/* Model an NaClInst, sorted by OpcodeInModRm values. */
|
| -typedef struct NaClMrmInst {
|
| - NaClModeledInst inst;
|
| - struct NaClMrmInst* next;
|
| -} NaClMrmInst;
|
| -
|
| -/* Note: in general all errors in this module will be fatal.
|
| - * To debug: use gdb or your favorite debugger.
|
| - */
|
| -void NaClFatal(const char* s) {
|
| - NaClLog(LOG_FATAL, "Error: %s\n", s);
|
| - NaClLog(LOG_FATAL, "Fatal: cannot recover\n");
|
| - exit(-1);
|
| -}
|
| -
|
| -/* Returns the print name of the given run mode. */
|
| -static const char* NaClRunModeName(NaClRunMode mode) {
|
| - switch (mode) {
|
| - case X86_32: return "x86-32 bit mode";
|
| - case X86_64: return "x86-64 bit mode";
|
| - default: assert(0);
|
| - }
|
| -
|
| - /* NOTREACHED */
|
| - return NULL;
|
| -}
|
| -
|
| -/* Defines if we should simplify the instructions to
|
| - * what is needed by the validator.
|
| - */
|
| -static Bool NACL_FLAGS_validator_decoder = FALSE;
|
| -
|
| -/* Defines the run mode files that should be generated. */
|
| -NaClRunMode NACL_FLAGS_run_mode = NaClRunModeSize;
|
| -
|
| -/* Defines whether the output of the instruction set should
|
| - * be as a header file, or human readable (for documentation).
|
| - */
|
| -static Bool NACL_FLAGS_human_readable = FALSE;
|
| -
|
| -/* Defines whether the output should be instruction modeling tables,
|
| - * or hardware registers.
|
| - */
|
| -static Bool NACL_FLAGS_nacl_subregs = FALSE;
|
| -
|
| -/* Holds the current instruction prefix. */
|
| -static NaClInstPrefix current_opcode_prefix = NoPrefix;
|
| -
|
| -/* Holds the default instruction prefix. */
|
| -static NaClInstPrefix default_opcode_prefix = NoPrefix;
|
| -
|
| -/* Holds the current instruction being built. */
|
| -static NaClModeledInst* current_inst = NULL;
|
| -
|
| -/* Holds the current opcode sequence to be associated with the next
|
| - * defined opcode.
|
| - */
|
| -static NaClModeledInstNode* current_inst_node = NULL;
|
| -
|
| -/* Holds the candidate for the current_inst_node, when
|
| - * NaClDefInst is called.
|
| - */
|
| -static NaClModeledInstNode* current_cand_inst_node = NULL;
|
| -
|
| -/* Holds the current instruction with mrm extention being built. */
|
| -static NaClMrmInst* current_inst_mrm = NULL;
|
| -
|
| -/* Holds tables used to generate/compress the modeled instructions. */
|
| -NaClInstTables tables;
|
| -
|
| -/* True if we are to apply sanity checks as we define operantions. */
|
| -static Bool apply_sanity_checks = TRUE;
|
| -
|
| -#define NACL_DEFAULT_CHOICE_COUNT (-1)
|
| -
|
| -#define NACL_NO_MODRM_OPCODE 8
|
| -
|
| -#define NACL_MODRM_OPCODE_SIZE (NACL_NO_MODRM_OPCODE + 1)
|
| -
|
| -/* Holds the expected number of entries in the defined instructions.
|
| - * Note: the last index corresponds to the modrm opcode, or
|
| - * NACL_NO_MODRM_OPCODE if no modrm opcode.
|
| - */
|
| -static int NaClInstCount[NCDTABLESIZE]
|
| - [NaClInstPrefixEnumSize][NACL_MODRM_OPCODE_SIZE];
|
| -
|
| -static NaClMrmInst* NaClInstMrmTable[NCDTABLESIZE]
|
| - [NaClInstPrefixEnumSize][NACL_MODRM_OPCODE_SIZE];
|
| -
|
| -/* Holds encodings of prefix bytes. */
|
| -static const char* NaClPrefixTable[NCDTABLESIZE];
|
| -
|
| -
|
| -/* Prints out the opcode prefix being defined, the opcode pattern
|
| - * being defined, and the given error message. Then aborts the
|
| - * execution of the program.
|
| - */
|
| -static void NaClFatalInst(const char* message) {
|
| - NaClLog(LOG_INFO, "Prefix: %s\n", NaClInstPrefixName(current_opcode_prefix));
|
| - NaClModeledInstPrint(NaClLogGetGio(), current_inst);
|
| - NaClFatal(message);
|
| -}
|
| -
|
| -/* Prints out what operand is currently being defined, followed by the given
|
| - * error message. Then aborts the execution of the program.
|
| - */
|
| -static void NaClFatalOp(int index, const char* message) {
|
| - if (0 <= index && index <= current_inst->num_operands) {
|
| - NaClLog(LOG_ERROR, "On operand %d: %s\n", index,
|
| - NaClOpKindName(current_inst->operands[index].kind));
|
| - } else {
|
| - NaClLog(LOG_ERROR, "On operand %d:\n", index);
|
| - }
|
| - NaClFatalInst(message);
|
| -}
|
| -
|
| -/* Advance the buffer/buffer_size values by count characters. */
|
| -static void CharAdvance(char** buffer, size_t* buffer_size, size_t count) {
|
| - *buffer += count;
|
| - *buffer_size += count;
|
| -}
|
| -
|
| -/* Generates a (malloc allocated) string describing the form for the
|
| - * operands.
|
| - * Note: This code used to be part of the validator (runtime) library.
|
| - * By moving it here, we remove this code, and runtime cost, from
|
| - * the validator runtime.
|
| - */
|
| -static void NaClFillOperandDescs(NaClModeledInst* inst) {
|
| - char buffer[BUFFER_SIZE];
|
| - int i;
|
| -
|
| - /* Make sure inst is defined before trying to fix. */
|
| - if (NULL == inst) return;
|
| -
|
| - for (i = 0; i < inst->num_operands; ++i) {
|
| - char* buf = buffer;
|
| - size_t buf_size = BUFFER_SIZE;
|
| - Bool is_implicit = (NACL_EMPTY_OPFLAGS != (inst->operands[i].flags &
|
| - NACL_OPFLAG(OpImplicit)));
|
| - NaClOpKind kind = inst->operands[i].kind;
|
| -
|
| - if (NULL != inst->operands[i].format_string) continue;
|
| -
|
| - buffer[0] = '\0'; /* just in case there isn't any operands. */
|
| - if (is_implicit) {
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "{"));
|
| - }
|
| - switch (kind) {
|
| - case A_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$A"));
|
| - break;
|
| - case E_Operand:
|
| - case Eb_Operand:
|
| - case Ew_Operand:
|
| - case Ev_Operand:
|
| - case Eo_Operand:
|
| - case Edq_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$E"));
|
| - break;
|
| - case G_Operand:
|
| - case Gb_Operand:
|
| - case Gw_Operand:
|
| - case Gv_Operand:
|
| - case Go_Operand:
|
| - case Gdq_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$G"));
|
| - break;
|
| - case Seg_G_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$SegG"));
|
| - break;
|
| - case G_OpcodeBase:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$/r"));
|
| - break;
|
| - case I_Operand:
|
| - case Ib_Operand:
|
| - case Iw_Operand:
|
| - case Iv_Operand:
|
| - case Io_Operand:
|
| - case I2_Operand:
|
| - case J_Operand:
|
| - case Jb_Operand:
|
| - case Jw_Operand:
|
| - case Jv_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$I"));
|
| - break;
|
| - case M_Operand:
|
| - case Mb_Operand:
|
| - case Mw_Operand:
|
| - case Mv_Operand:
|
| - case Mo_Operand:
|
| - case Mdq_Operand:
|
| - /* Special case $Ma, which adds two operands. */
|
| - if ((i > 0) && (NULL != inst->operands[i-1].format_string) &&
|
| - (0 == strcmp(inst->operands[i-1].format_string, "$Ma"))) {
|
| - /* Don't add a format string in this case. */
|
| - continue;
|
| - } else {
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$M"));
|
| - }
|
| - break;
|
| - case Mpw_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "m16:16"));
|
| - break;
|
| - case Mpv_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "m16:32"));
|
| - break;
|
| - case Mpo_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "m16:64"));
|
| - break;
|
| - case Mmx_E_Operand:
|
| - case Mmx_N_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$E(mmx)"));
|
| - break;
|
| - case Mmx_G_Operand:
|
| - case Mmx_Gd_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$G(mmx)"));
|
| - break;
|
| - case Xmm_E_Operand:
|
| - case Xmm_Eo_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$E(xmm)"));
|
| - break;
|
| - case Xmm_G_Operand:
|
| - case Xmm_Go_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$G(xmm)"));
|
| - break;
|
| - case O_Operand:
|
| - case Ob_Operand:
|
| - case Ow_Operand:
|
| - case Ov_Operand:
|
| - case Oo_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "$O"));
|
| - break;
|
| - case S_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "%%Sreg"));
|
| - break;
|
| - case C_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "%%Creg"));
|
| - break;
|
| - case D_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "%%Dreg"));
|
| - break;
|
| - case St_Operand:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "%%st"));
|
| - break;
|
| - 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 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 RegREIP:
|
| - case RegREAX:
|
| - case RegREBX:
|
| - case RegRECX:
|
| - case RegREDX:
|
| - case RegRESP:
|
| - case RegREBP:
|
| - case RegRESI:
|
| - case RegREDI:
|
| - case RegDS_EDI:
|
| - case RegDS_EBX:
|
| - case RegES_EDI:
|
| - case RegST0:
|
| - case RegST1:
|
| - case RegST2:
|
| - case RegST3:
|
| - case RegST4:
|
| - case RegST5:
|
| - case RegST6:
|
| - case RegST7:
|
| - case RegMMX0:
|
| - 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:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "%%%s",
|
| - NaClOpKindName(kind) + strlen("Reg")));
|
| - break;
|
| - case Const_1:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "1"));
|
| - break;
|
| - default:
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "???"));
|
| - break;
|
| - }
|
| - if (is_implicit) {
|
| - CharAdvance(&buf, &buf_size,
|
| - SNPRINTF(buf, buf_size, "}"));
|
| - }
|
| - *((char**)(inst->operands[i].format_string)) = strdup(buffer);
|
| - }
|
| -}
|
| -
|
| -/* Define the prefix name for the given opcode, for the given run mode. */
|
| -static void NaClEncodeModedPrefixName(const uint8_t byte, const char* name,
|
| - const NaClRunMode mode) {
|
| - if (NACL_FLAGS_run_mode == mode) {
|
| - NaClPrefixTable[byte] = name;
|
| - }
|
| -}
|
| -
|
| -/* Define the prefix name for the given opcode, for all run modes. */
|
| -static void NaClEncodePrefixName(const uint8_t byte, const char* name) {
|
| - NaClEncodeModedPrefixName(byte, name, NACL_FLAGS_run_mode);
|
| -}
|
| -
|
| -/* Change the current opcode prefix to the given value. */
|
| -void NaClDefInstPrefix(const NaClInstPrefix prefix) {
|
| - current_opcode_prefix = prefix;
|
| -}
|
| -
|
| -void NaClResetToDefaultInstPrefix(void) {
|
| - NaClDefInstPrefix(default_opcode_prefix);
|
| -}
|
| -
|
| -NaClModeledInst* NaClGetDefInst(void) {
|
| - return current_inst;
|
| -}
|
| -
|
| -/* Check if an E_Operand operand has been repeated, since it should
|
| - * never appear for more than one argument. If repeated, generate an
|
| - * appropriate error message and terminate.
|
| - */
|
| -static void NaClCheckIfERepeated(int index) {
|
| - int i;
|
| - for (i = 0; i < index; ++i) {
|
| - const NaClOp* operand = ¤t_inst->operands[i];
|
| - switch (operand->kind) {
|
| - case Mmx_E_Operand:
|
| - case Xmm_E_Operand:
|
| - case Xmm_Eo_Operand:
|
| - case E_Operand:
|
| - case Eb_Operand:
|
| - case Ew_Operand:
|
| - case Ev_Operand:
|
| - case Eo_Operand:
|
| - case Edq_Operand:
|
| - NaClFatalOp(index, "Can't use E Operand more than once");
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Called if operand is a G_Operand. Checks that the opcode doesn't specify
|
| - * that the REG field of modrm is an opcode, since G_Operand doesn't make
|
| - * sense in such cases.
|
| - */
|
| -static void NaClCheckIfOpcodeInModRm(int index) {
|
| - if ((current_inst->flags & NACL_IFLAG(OpcodeInModRm)) &&
|
| - (NACL_EMPTY_OPFLAGS == (current_inst->operands[index].flags &
|
| - NACL_IFLAG(AllowGOperandWithOpcodeInModRm)))) {
|
| - NaClFatalOp(index,
|
| - "Can't use G Operand, bits being used for opcode in modrm");
|
| - }
|
| -}
|
| -
|
| -/* Check if an G_Operand operand has been repeated, since it should
|
| - * never appear for more than one argument. If repeated, generate an
|
| - * appropriate error message and terminate.
|
| - */
|
| -static void NaClCheckIfGRepeated(int index) {
|
| - int i;
|
| - for (i = 0; i < index; ++i) {
|
| - const NaClOp* operand = ¤t_inst->operands[i];
|
| - switch (operand->kind) {
|
| - case Mmx_G_Operand:
|
| - case Xmm_G_Operand:
|
| - case Xmm_Go_Operand:
|
| - case G_Operand:
|
| - case Gb_Operand:
|
| - case Gw_Operand:
|
| - case Gv_Operand:
|
| - case Go_Operand:
|
| - case Gdq_Operand:
|
| - NaClFatalOp(index, "Can't use G Operand more than once");
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Check if an I_Operand/J_OPerand operand has been repeated, since it should
|
| - * never appear for more than one argument (both come from the immediate field
|
| - * of the instruction). If repeated, generate an appropriate error message
|
| - * and terminate.
|
| - */
|
| -static void NaClCheckIfIRepeated(int index) {
|
| - int i;
|
| - for (i = 0; i < index; ++i) {
|
| - const NaClOp* operand = ¤t_inst->operands[i];
|
| - switch (operand->kind) {
|
| - case I_Operand:
|
| - case Ib_Operand:
|
| - case Iw_Operand:
|
| - case Iv_Operand:
|
| - case Io_Operand:
|
| - NaClFatalOp(index, "Can't use I_Operand more than once");
|
| - break;
|
| - case J_Operand:
|
| - case Jb_Operand:
|
| - case Jv_Operand:
|
| - NaClFatalOp(index, "Can't use both I_Operand and J_Operand");
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Returns the set of operand size flags defined for the given instruction. */
|
| -NaClIFlags NaClOperandSizes(NaClModeledInst* inst) {
|
| - NaClIFlags flags = inst->flags & (NACL_IFLAG(OperandSize_b) |
|
| - NACL_IFLAG(OperandSize_w) |
|
| - NACL_IFLAG(OperandSize_v) |
|
| - NACL_IFLAG(OperandSize_o));
|
| - /* Note: if no sizes specified, assume all sizes possible. */
|
| - if (NACL_EMPTY_IFLAGS == flags) {
|
| - flags = NACL_IFLAG(OperandSize_b) |
|
| - NACL_IFLAG(OperandSize_w) |
|
| - NACL_IFLAG(OperandSize_v) |
|
| - NACL_IFLAG(OperandSize_o);
|
| - }
|
| - return flags;
|
| -}
|
| -
|
| -/* Check that the operand being defined (via the given index), does not
|
| - * specify any inconsistent flags.
|
| - */
|
| -static void NaClApplySanityChecksToOp(int index) {
|
| - const NaClOp* operand = ¤t_inst->operands[index];
|
| - const NaClIFlags operand_sizes = NaClOperandSizes(current_inst);
|
| -
|
| - if (!apply_sanity_checks) return;
|
| -
|
| - /* Check that operand is consistent with other operands defined, or flags
|
| - * defined on the opcode.
|
| - */
|
| - switch (operand->kind) {
|
| - case E_Operand:
|
| - NaClCheckIfERepeated(index);
|
| - break;
|
| - case Eb_Operand:
|
| - if (NACL_IFLAG(OperandSize_b) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_b, use E_Operand instead");
|
| - }
|
| - NaClCheckIfERepeated(index);
|
| - break;
|
| - case Ew_Operand:
|
| - if (NACL_IFLAG(OperandSize_w) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_w, use E_Operand instead");
|
| - }
|
| - NaClCheckIfERepeated(index);
|
| - break;
|
| - case Ev_Operand:
|
| - if (NACL_IFLAG(OperandSize_v) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_v, use E_Operand instead");
|
| - }
|
| - NaClCheckIfERepeated(index);
|
| - break;
|
| - case Eo_Operand:
|
| - if (NACL_IFLAG(OperandSize_o) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_o, use E_Operand instead");
|
| - }
|
| - NaClCheckIfERepeated(index);
|
| - break;
|
| - case Edq_Operand:
|
| - NaClCheckIfERepeated(index);
|
| - break;
|
| - case Mmx_E_Operand:
|
| - case Xmm_E_Operand:
|
| - NaClCheckIfERepeated(index);
|
| - break;
|
| - case Xmm_Eo_Operand:
|
| - if (NACL_IFLAG(OperandSize_o) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp
|
| - (index,
|
| - "Size implied by OperandSize_o, use Xmm_E_Operand instead");
|
| - }
|
| - NaClCheckIfERepeated(index);
|
| - break;
|
| - case G_Operand:
|
| - NaClCheckIfGRepeated(index);
|
| - NaClCheckIfOpcodeInModRm(index);
|
| - break;
|
| - case Gb_Operand:
|
| - if (NACL_IFLAG(OperandSize_b) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_b, use G_Operand instead");
|
| - }
|
| - NaClCheckIfGRepeated(index);
|
| - NaClCheckIfOpcodeInModRm(index);
|
| - break;
|
| - case Gw_Operand:
|
| - if (NACL_IFLAG(OperandSize_w) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_w, use G_Operand instead");
|
| - }
|
| - NaClCheckIfGRepeated(index);
|
| - NaClCheckIfOpcodeInModRm(index);
|
| - break;
|
| - case Gv_Operand:
|
| - if (NACL_IFLAG(OperandSize_v) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_v, use G_Operand instead");
|
| - }
|
| - NaClCheckIfGRepeated(index);
|
| - NaClCheckIfOpcodeInModRm(index);
|
| - break;
|
| - case Go_Operand:
|
| - if (NACL_IFLAG(OperandSize_o) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_o, use G_Operand instead");
|
| - }
|
| - NaClCheckIfGRepeated(index);
|
| - NaClCheckIfOpcodeInModRm(index);
|
| - break;
|
| - case Gdq_Operand:
|
| - NaClCheckIfGRepeated(index);
|
| - NaClCheckIfOpcodeInModRm(index);
|
| - break;
|
| - case Mmx_G_Operand:
|
| - case Xmm_G_Operand:
|
| - NaClCheckIfGRepeated(index);
|
| - NaClCheckIfOpcodeInModRm(index);
|
| - break;
|
| - case Xmm_Go_Operand:
|
| - if (NACL_IFLAG(OperandSize_o) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp
|
| - (index,
|
| - "Size implied by OperandSize_o, use Xmm_G_Operand instead");
|
| - }
|
| - NaClCheckIfGRepeated(index);
|
| - NaClCheckIfOpcodeInModRm(index);
|
| - break;
|
| - case I_Operand:
|
| - NaClCheckIfIRepeated(index);
|
| - break;
|
| - case Ib_Operand:
|
| - if (NACL_IFLAG(OperandSize_b) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_b, use I_Operand instead");
|
| - }
|
| - if (current_inst->flags & NACL_IFLAG(OpcodeHasImmed_b)) {
|
| - NaClFatalOp(index,
|
| - "Size implied by OpcodeHasImmed_b, use I_Operand instead");
|
| - }
|
| - NaClCheckIfIRepeated(index);
|
| - break;
|
| - case Iw_Operand:
|
| - if (NACL_IFLAG(OperandSize_w) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_w, use I_Operand instead");
|
| - }
|
| - if (current_inst->flags & NACL_IFLAG(OpcodeHasImmed_w)) {
|
| - NaClFatalOp(index,
|
| - "Size implied by OpcodeHasImmed_w, use I_Operand instead");
|
| - }
|
| - NaClCheckIfIRepeated(index);
|
| - break;
|
| - case Iv_Operand:
|
| - if (NACL_IFLAG(OperandSize_v) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_v, use I_Operand instead");
|
| - }
|
| - if (current_inst->flags & NACL_IFLAG(OpcodeHasImmed_v)) {
|
| - NaClFatalOp(index,
|
| - "Size implied by OpcodeHasImmed_v, use I_Operand instead");
|
| - }
|
| - NaClCheckIfIRepeated(index);
|
| - break;
|
| - case Io_Operand:
|
| - if (NACL_IFLAG(OperandSize_o) == operand_sizes) {
|
| - /* Singlton set already specifies size, so no need for extra
|
| - * size specification.
|
| - */
|
| - NaClFatalOp(index,
|
| - "Size implied by OperandSize_o, use I_Operand instead");
|
| - }
|
| - if (current_inst->flags & NACL_IFLAG(OpcodeHasImmed_o)) {
|
| - NaClFatalOp(index,
|
| - "Size implied by OpcodeHasImmed_o, use I_Operand instead");
|
| - }
|
| - NaClCheckIfIRepeated(index);
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| -}
|
| -
|
| -/* Define the next operand of the current opcode to have
|
| - * the given kind and flags.
|
| - */
|
| -static void NaClDefOpInternal(NaClOpKind kind, NaClOpFlags flags) {
|
| - int index;
|
| - assert(NULL != current_inst);
|
| - if (tables.operands_size >= NACL_MAX_OPERANDS_TOTAL) {
|
| - NaClFatal("Out of operand space. "
|
| - "Increase size of NACL_MAX_OPERANDS_TOTAL!");
|
| - }
|
| - tables.operands_size++;
|
| - index = current_inst->num_operands++;
|
| - current_inst->operands[index].kind = kind;
|
| - current_inst->operands[index].flags = flags;
|
| - current_inst->operands[index].format_string = NULL;
|
| -}
|
| -
|
| -static void NaClInstallCurrentIntoOpcodeMrm(const NaClInstPrefix prefix,
|
| - const uint8_t opcode,
|
| - int mrm_index) {
|
| - DEBUG(NaClLog(LOG_INFO, " Installing into [%x][%s][%d]\n",
|
| - opcode, NaClInstPrefixName(prefix), mrm_index));
|
| - if (NULL == NaClInstMrmTable[opcode][prefix][mrm_index]) {
|
| - NaClInstMrmTable[opcode][prefix][mrm_index] = current_inst_mrm;
|
| - } else {
|
| - NaClMrmInst* next = NaClInstMrmTable[opcode][prefix][mrm_index];
|
| - while (NULL != next->next) {
|
| - next = next->next;
|
| - }
|
| - next->next = current_inst_mrm;
|
| - }
|
| -}
|
| -
|
| -/* Removes the current_inst_mrm from the corresponding instruction table.
|
| - * Used when Opcode32Only or Opcode64Only flag is added, and
|
| - * the flag doesn't match the subarchitecture being modeled.
|
| - */
|
| -static void NaClRemoveCurrentInstMrmFromInstTable(void) {
|
| - uint8_t opcode = current_inst->opcode[current_inst->num_opcode_bytes - 1];
|
| - NaClModeledInst* prev = NULL;
|
| - NaClModeledInst* next = tables.inst_table[opcode][current_inst->prefix];
|
| - while (NULL != next) {
|
| - if (current_inst == next) {
|
| - /* Found - remove! */
|
| - if (NULL == prev) {
|
| - tables.inst_table[opcode][current_inst->prefix] = next->next_rule;
|
| - } else {
|
| - prev->next_rule = next->next_rule;
|
| - }
|
| - return;
|
| - } else {
|
| - prev = next;
|
| - next = next->next_rule;
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Removes the current_inst_mrm from the corresponding
|
| - * NaClInstMrmTable.
|
| - *
|
| - * Used when Opcode32Only or Opcode64Only flag is added, and
|
| - * the flag doesn't match the subarchitecture being modeled.
|
| - */
|
| -static void NaClRemoveCurrentInstMrmFromInstMrmTable(void) {
|
| - /* Be sure to try opcode in first operand (if applicable),
|
| - * and the default list NACL_NO_MODRM_OPCODE, in case
|
| - * the operand hasn't been processed yet.
|
| - */
|
| - int mrm_opcode = NACL_NO_MODRM_OPCODE;
|
| - if (current_inst->flags & NACL_IFLAG(OpcodeInModRm)) {
|
| - mrm_opcode = NaClGetOpcodeInModRm(current_inst->opcode_ext);
|
| - }
|
| -
|
| - while (1) {
|
| - uint8_t opcode = current_inst->opcode[current_inst->num_opcode_bytes - 1];
|
| - NaClMrmInst* prev = NULL;
|
| - NaClMrmInst* next =
|
| - NaClInstMrmTable[opcode][current_inst->prefix][mrm_opcode];
|
| - DEBUG(NaClLog(LOG_INFO, "Removing [%02x][%s][%d]?",
|
| - opcode, NaClInstPrefixName(current_inst->prefix),
|
| - mrm_opcode));
|
| - while (NULL != next) {
|
| - if (current_inst_mrm == next) {
|
| - /* Found - remove! */
|
| - if (NULL == prev) {
|
| - NaClInstMrmTable[opcode][current_inst->prefix][mrm_opcode] =
|
| - next->next;
|
| - } else {
|
| - prev->next = next->next;
|
| - }
|
| - return;
|
| - } else {
|
| - prev = next;
|
| - next = next->next;
|
| - }
|
| - }
|
| - if (mrm_opcode == NACL_NO_MODRM_OPCODE) return;
|
| - mrm_opcode = NACL_NO_MODRM_OPCODE;
|
| - }
|
| -}
|
| -
|
| -static void NaClMoveCurrentToMrmIndex(int mrm_index) {
|
| - /* First remove from default location. */
|
| - uint8_t opcode = current_inst->opcode[current_inst->num_opcode_bytes - 1];
|
| - NaClMrmInst* prev = NULL;
|
| - NaClMrmInst* next =
|
| - NaClInstMrmTable[opcode][current_opcode_prefix]
|
| - [NACL_NO_MODRM_OPCODE];
|
| - while (current_inst_mrm != next) {
|
| - if (next == NULL) return;
|
| - prev = next;
|
| - next = next->next;
|
| - }
|
| - if (NULL == prev) {
|
| - NaClInstMrmTable[opcode][current_opcode_prefix]
|
| - [NACL_NO_MODRM_OPCODE] =
|
| - next->next;
|
| - } else {
|
| - prev->next = next->next;
|
| - }
|
| - current_inst_mrm = next;
|
| - current_inst_mrm->next = NULL;
|
| - NaClInstallCurrentIntoOpcodeMrm(current_opcode_prefix, opcode, mrm_index);
|
| -}
|
| -
|
| -static void NaClPrintlnOpFlags(struct Gio* g, NaClOpFlags flags) {
|
| - int i;
|
| - for (i = 0; i < NaClOpFlagEnumSize; ++i) {
|
| - if (flags & NACL_OPFLAG(i)) {
|
| - gprintf(g, " %s", NaClOpFlagName(i));
|
| - }
|
| - }
|
| - gprintf(g, "\n");
|
| -}
|
| -
|
| -static void NaClApplySanityChecksToInst(void);
|
| -
|
| -void NaClDefOpcodeExtension(int opcode) {
|
| - uint8_t byte_opcode;
|
| - byte_opcode = (uint8_t) opcode;
|
| - if ((opcode < 0) || (opcode > 7)) {
|
| - NaClFatalInst("Attempted to define opcode extension not in range [0..7]");
|
| - }
|
| - if (NACL_EMPTY_IFLAGS ==
|
| - (current_inst->flags & NACL_IFLAG(OpcodeInModRm))) {
|
| - NaClFatalInst(
|
| - "Opcode extension in [0..7], but not OpcodeInModRm");
|
| - }
|
| - DEBUG(NaClLog(LOG_INFO, "Defining opcode extension %d\n", opcode));
|
| - NaClMoveCurrentToMrmIndex(byte_opcode);
|
| - NaClSetOpcodeInModRm(byte_opcode, ¤t_inst->opcode_ext);
|
| -}
|
| -
|
| -void NaClDefineOpcodeModRmRmExtension(int value) {
|
| - uint8_t byte_opcode = (uint8_t) value;
|
| - if ((value < 0) || (value > 7)) {
|
| - NaClFatalInst("Attempted to defined Opcode modrm rm extension "
|
| - "not in range [0..7]");
|
| - }
|
| - if (NACL_EMPTY_IFLAGS ==
|
| - (current_inst->flags & NACL_IFLAG(OpcodeInModRm))) {
|
| - NaClFatalInst(
|
| - "Opcode modrm rm extension in [0..7], but not OpcodeInModRm");
|
| - }
|
| - DEBUG(NaClLog(LOG_INFO, "Defining modrm r/m opcode extension %d", value));
|
| - NaClAddIFlags(NACL_IFLAG(OpcodeInModRmRm));
|
| - if (current_inst->num_opcode_bytes + 1 < NACL_MAX_ALL_OPCODE_BYTES) {
|
| - NaClSetOpcodeInModRmRm(byte_opcode, ¤t_inst->opcode_ext);
|
| - } else {
|
| - NaClFatalInst("No room for opcode modrm rm extension");
|
| - }
|
| -}
|
| -
|
| -void NaClDefOpcodeRegisterValue(int r) {
|
| - uint8_t byte_r;
|
| - byte_r = (uint8_t) r;
|
| - if ((r < 0) || (r > 7)) {
|
| - NaClFatalInst("Attempted to define an embedded opcode register value "
|
| - "not in range [0.. 7]");
|
| - }
|
| - if (NACL_EMPTY_IFLAGS ==
|
| - (current_inst->flags & NACL_IFLAG(OpcodePlusR))) {
|
| - NaClFatalInst(
|
| - "Attempted to define opcode register value when not OpcodePlusR");
|
| - }
|
| - NaClSetOpcodePlusR(byte_r, ¤t_inst->opcode_ext);
|
| -}
|
| -
|
| -/* Same as previous function, except that sanity checks
|
| - * are applied to see if inconsistent information is
|
| - * being defined.
|
| - */
|
| -void NaClDefOp(
|
| - NaClOpKind kind,
|
| - NaClOpFlags flags) {
|
| - int index = current_inst->num_operands;
|
| - DEBUG(NaClLog(LOG_INFO, " %s:", NaClOpKindName(kind));
|
| - NaClPrintlnOpFlags(NaClLogGetGio(), flags));
|
| - /* If one of the M_Operands, make sure that the ModRm mod field isn't 0x3,
|
| - * so that we don't return registers.
|
| - * If one specifies an operand that implies the use of a ModRm byte, add
|
| - * the corresponding flag.
|
| - * Note: See section A.2.5 of Intel manual (above) for an explanation of the
|
| - * ModRm mod field being any value except 0x3, for values having an
|
| - * explicit memory operand.
|
| - */
|
| - switch (kind) {
|
| - case M_Operand:
|
| - case Mb_Operand:
|
| - case Mw_Operand:
|
| - case Mv_Operand:
|
| - case Mo_Operand:
|
| - case Mdq_Operand:
|
| - case Mpw_Operand:
|
| - case Mpv_Operand:
|
| - case Mpo_Operand:
|
| - NaClAddIFlags(NACL_IFLAG(OpcodeUsesModRm) | NACL_IFLAG(ModRmModIsnt0x3));
|
| - break;
|
| - case Mmx_N_Operand:
|
| - kind = Mmx_E_Operand;
|
| - NaClAddIFlags(NACL_IFLAG(OpcodeUsesModRm) | NACL_IFLAG(ModRmModIs0x3));
|
| - /* Automatically fall to the next case. */
|
| - case E_Operand:
|
| - case Eb_Operand:
|
| - case Ew_Operand:
|
| - case Ev_Operand:
|
| - case Eo_Operand:
|
| - case Edq_Operand:
|
| - case G_Operand:
|
| - case Gb_Operand:
|
| - case Gw_Operand:
|
| - case Gv_Operand:
|
| - case Go_Operand:
|
| - case Gdq_Operand:
|
| - case Mmx_G_Operand:
|
| - case Mmx_Gd_Operand:
|
| - case Xmm_E_Operand:
|
| - case Xmm_Eo_Operand:
|
| - case Xmm_G_Operand:
|
| - case Xmm_Go_Operand:
|
| - NaClAddIFlags(NACL_IFLAG(OpcodeUsesModRm));
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - /* Define and apply sanity checks. */
|
| - NaClDefOpInternal(kind, flags);
|
| - NaClApplySanityChecksToOp(index);
|
| -}
|
| -
|
| -void NaClAddOpFlags(uint8_t operand_index, NaClOpFlags more_flags) {
|
| - DEBUG(
|
| - struct Gio* g = NaClLogGetGio();
|
| - gprintf(g, "Adding flags:");
|
| - NaClPrintlnOpFlags(g, more_flags));
|
| - if (operand_index < current_inst->num_operands) {
|
| - NaClAddBits(current_inst->operands[operand_index].flags, more_flags);
|
| - NaClApplySanityChecksToOp(operand_index);
|
| - } else {
|
| - NaClFatalOp((int) operand_index, "NaClAddOpFlags: index out of range\n");
|
| - }
|
| -}
|
| -
|
| -void NaClRemoveOpFlags(uint8_t operand_index, NaClOpFlags more_flags) {
|
| - DEBUG(NaClLog(LOG_INFO, "Removing flags:");
|
| - NaClPrintlnOpFlags(NaClLogGetGio(), more_flags));
|
| - if (operand_index < current_inst->num_operands) {
|
| - NaClRemoveBits(current_inst->operands[operand_index].flags, more_flags);
|
| - NaClApplySanityChecksToOp(operand_index);
|
| - } else {
|
| - NaClFatalOp((int) operand_index, "NaClRemoveOpFlags: index out of range\n");
|
| - }
|
| -}
|
| -
|
| -void NaClAddOpFormat(uint8_t operand_index, const char* format) {
|
| - DEBUG(NaClLog(LOG_INFO, "Adding format[%"NACL_PRIu8"]: '%s'\n",
|
| - operand_index, format));
|
| - if (operand_index < current_inst->num_operands) {
|
| - current_inst->operands[operand_index].format_string =
|
| - strdup(format);
|
| - } else {
|
| - NaClFatalOp((int) operand_index, "NaClAddOpFormat: index out of range\n");
|
| - }
|
| -}
|
| -
|
| -/* Returns true if the given opcode flags are consistent
|
| - * with the value of NACL_FLAGS_run_mode.
|
| - */
|
| -static Bool NaClIFlagsMatchesRunMode(NaClIFlags flags) {
|
| - if (flags & NACL_IFLAG(Opcode32Only)) {
|
| - if (flags & NACL_IFLAG(Opcode64Only)) {
|
| - NaClFatal("Can't specify both Opcode32Only and Opcode64Only");
|
| - }
|
| - return NACL_FLAGS_run_mode == X86_32;
|
| - } else if (flags & NACL_IFLAG(Opcode64Only)) {
|
| - return NACL_FLAGS_run_mode == X86_64;
|
| - } else if (flags & NACL_IFLAG(Opcode32Only)) {
|
| - return NACL_FLAGS_run_mode == X86_32;
|
| - } else {
|
| - return TRUE;
|
| - }
|
| -}
|
| -
|
| -/* Check that the flags defined for an opcode make sense. */
|
| -static void NaClApplySanityChecksToInst(void) {
|
| - const NaClIFlags operand_sizes = NaClOperandSizes(current_inst);
|
| - if (!apply_sanity_checks) return;
|
| - if ((current_inst->flags & NACL_IFLAG(Opcode32Only)) &&
|
| - (current_inst->flags & NACL_IFLAG(Opcode64Only))) {
|
| - NaClFatalInst("Can't be both Opcode32Only and Opcode64Only");
|
| - }
|
| - /* Fix case where both OperandSize_w and SizeIgnoresData16 are specified. */
|
| - if ((current_inst->flags & NACL_IFLAG(OperandSize_w)) &&
|
| - (current_inst->flags & NACL_IFLAG(SizeIgnoresData16))) {
|
| - NaClRemoveBits(current_inst->flags, NACL_IFLAG(OperandSize_w));
|
| - }
|
| - if ((current_inst->flags & NACL_IFLAG(OperandSize_b)) &&
|
| - (current_inst->flags & (NACL_IFLAG(OperandSize_w) |
|
| - NACL_IFLAG(OperandSize_v) |
|
| - NACL_IFLAG(OperandSize_o) |
|
| - NACL_IFLAG(OperandSizeDefaultIs64) |
|
| - NACL_IFLAG(OperandSizeForce64)))) {
|
| - NaClFatalInst(
|
| - "Can't specify other operand sizes when specifying OperandSize_b");
|
| - }
|
| - if ((current_inst->flags & NACL_IFLAG(OpcodeInModRm)) &&
|
| - (current_inst->flags & NACL_IFLAG(OpcodePlusR))) {
|
| - NaClFatalInst(
|
| - "Can't specify both OpcodeInModRm and OpcodePlusR");
|
| - }
|
| - if ((current_inst->flags & NACL_IFLAG(OpcodeHasImmed_b)) &&
|
| - (operand_sizes == NACL_IFLAG(OperandSize_b))) {
|
| - NaClFatalInst(
|
| - "Size implied by OperandSize_b, use OpcodeHasImmed "
|
| - "rather than OpcodeHasImmed_b");
|
| - }
|
| - if ((current_inst->flags & NACL_IFLAG(OpcodeHasImmed_w)) &&
|
| - (operand_sizes == NACL_IFLAG(OperandSize_w))) {
|
| - NaClFatalInst(
|
| - "Size implied by OperandSize_w, use OpcodeHasImmed "
|
| - "rather than OpcodeHasImmed_w");
|
| - }
|
| - if ((current_inst->flags & NACL_IFLAG(OpcodeHasImmed_v)) &&
|
| - (operand_sizes == NACL_IFLAG(OperandSize_v))) {
|
| - NaClFatalInst(
|
| - "Size implied by OperandSize_v, use OpcodeHasImmed "
|
| - "rather than OpcodeHasImmed_v");
|
| - }
|
| - if ((current_inst->flags & NACL_IFLAG(ModRmModIs0x3)) &&
|
| - (NACL_EMPTY_IFLAGS == (current_inst->flags &
|
| - (NACL_IFLAG(OpcodeUsesModRm) |
|
| - NACL_IFLAG(OpcodeInModRm))))) {
|
| - NaClFatalInst(
|
| - "Can't specify ModRmModIs0x3 unless Opcode has modrm byte");
|
| - }
|
| - if ((current_inst->flags & NACL_IFLAG(ModRmModIs0x3)) &&
|
| - (current_inst->flags & NACL_IFLAG(ModRmModIsnt0x3))) {
|
| - NaClFatalInst(
|
| - "Can't specify ModRmModIs0x3 and ModRmModIsnt0x3");
|
| - }
|
| -}
|
| -
|
| -static void NaClDefBytes(uint8_t opcode) {
|
| - uint8_t index;
|
| - current_inst->prefix = current_opcode_prefix;
|
| -
|
| - /* Start by clearing all entries. */
|
| - for (index = 0; index < NACL_MAX_ALL_OPCODE_BYTES; ++index) {
|
| - current_inst->opcode[index] = 0x00;
|
| - }
|
| -
|
| - /* Now fill in non-final bytes. */
|
| - index = 0;
|
| - switch (current_opcode_prefix) {
|
| - case NoPrefix:
|
| - break;
|
| - case Prefix0F:
|
| - case Prefix660F:
|
| - case PrefixF20F:
|
| - case PrefixF30F:
|
| - current_inst->opcode[0] = 0x0F;
|
| - index = 1;
|
| - break;
|
| - case Prefix0F0F:
|
| - current_inst->opcode[0] = 0x0F;
|
| - current_inst->opcode[1] = 0x0F;
|
| - index = 2;
|
| - break;
|
| - case Prefix0F38:
|
| - case Prefix660F38:
|
| - case PrefixF20F38:
|
| - current_inst->opcode[0] = 0x0F;
|
| - current_inst->opcode[1] = 0x38;
|
| - index = 2;
|
| - break;
|
| - case Prefix0F3A:
|
| - case Prefix660F3A:
|
| - current_inst->opcode[0] = 0x0F;
|
| - current_inst->opcode[1] = 0x3A;
|
| - index = 2;
|
| - break;
|
| - case PrefixD8:
|
| - current_inst->opcode[0] = 0xD8;
|
| - index = 1;
|
| - break;
|
| - case PrefixD9:
|
| - current_inst->opcode[0] = 0xD9;
|
| - index = 1;
|
| - break;
|
| - case PrefixDA:
|
| - current_inst->opcode[0] = 0xDA;
|
| - index = 1;
|
| - break;
|
| - case PrefixDB:
|
| - current_inst->opcode[0] = 0xDB;
|
| - index = 1;
|
| - break;
|
| - case PrefixDC:
|
| - current_inst->opcode[0] = 0xDC;
|
| - index = 1;
|
| - break;
|
| - case PrefixDD:
|
| - current_inst->opcode[0] = 0xDD;
|
| - index = 1;
|
| - break;
|
| - case PrefixDE:
|
| - current_inst->opcode[0] = 0xDE;
|
| - index = 1;
|
| - break;
|
| - case PrefixDF:
|
| - current_inst->opcode[0] = 0xDF;
|
| - index = 1;
|
| - break;
|
| - default:
|
| - NaClFatal("Unrecognized opcode prefix in NaClDefBytes");
|
| - break;
|
| - }
|
| -
|
| - /* Now add final byte. */
|
| - current_inst->opcode[index] = opcode;
|
| - current_inst->num_opcode_bytes = index + 1;
|
| -}
|
| -
|
| -static void NaClPrintInstDescriptor(struct Gio* out,
|
| - const NaClInstPrefix prefix,
|
| - const int opcode,
|
| - const int modrm_index) {
|
| - if (NACL_NO_MODRM_OPCODE == modrm_index) {
|
| - gprintf(out, "%s 0x%02x: ",
|
| - NaClInstPrefixName(prefix), opcode);
|
| - } else {
|
| - gprintf(out, "%s 0x%02x /%x: ",
|
| - NaClInstPrefixName(prefix), opcode, modrm_index);
|
| - }
|
| -}
|
| -
|
| -static void VerifyModRmOpcodeRange(NaClInstPrefix prefix,
|
| - uint8_t opcode,
|
| - uint8_t modrm_opcode) {
|
| - if (modrm_opcode > NACL_NO_MODRM_OPCODE) {
|
| - NaClPrintInstDescriptor(NaClLogGetGio(), prefix, opcode, modrm_opcode);
|
| - NaClFatal("Illegal modrm opcode specification when defined opcode choices");
|
| - }
|
| -}
|
| -
|
| -void NaClDefPrefixInstMrmChoices_32_64(const NaClInstPrefix prefix,
|
| - const uint8_t opcode,
|
| - const uint8_t modrm_opcode,
|
| - const int count_32,
|
| - const int count_64) {
|
| - VerifyModRmOpcodeRange(prefix, opcode, modrm_opcode);
|
| - if (NaClInstCount[opcode][prefix][modrm_opcode] !=
|
| - NACL_DEFAULT_CHOICE_COUNT) {
|
| - NaClPrintInstDescriptor(NaClLogGetGio(), prefix, opcode, modrm_opcode);
|
| - NaClFatal("Redefining NaClOpcode choice count");
|
| - }
|
| - if (NACL_FLAGS_run_mode == X86_32) {
|
| - NaClInstCount[opcode][prefix][modrm_opcode] = count_32;
|
| - } else if (NACL_FLAGS_run_mode == X86_64) {
|
| - NaClInstCount[opcode][prefix][modrm_opcode] = count_64;
|
| - }
|
| -}
|
| -
|
| -void NaClDefPrefixInstChoices(const NaClInstPrefix prefix,
|
| - const uint8_t opcode,
|
| - const int count) {
|
| - NaClDefPrefixInstChoices_32_64(prefix, opcode, count, count);
|
| -}
|
| -
|
| -void NaClDefPrefixInstMrmChoices(const NaClInstPrefix prefix,
|
| - const uint8_t opcode,
|
| - const uint8_t modrm_opcode,
|
| - const int count) {
|
| - NaClDefPrefixInstMrmChoices_32_64(prefix, opcode, modrm_opcode,
|
| - count, count);
|
| -}
|
| -
|
| -void NaClDefPrefixInstChoices_32_64(const NaClInstPrefix prefix,
|
| - const uint8_t opcode,
|
| - const int count_32,
|
| - const int count_64) {
|
| - NaClDefPrefixInstMrmChoices_32_64(prefix, opcode, NACL_NO_MODRM_OPCODE,
|
| - count_32, count_64);
|
| -}
|
| -
|
| -/* Adds opcode flags corresponding to REP/REPNE flags if defined by
|
| - * the prefix.
|
| - */
|
| -static void NaClAddRepPrefixFlagsIfApplicable(void) {
|
| - switch (current_opcode_prefix) {
|
| - case Prefix660F:
|
| - case Prefix660F38:
|
| - case Prefix660F3A:
|
| - NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeAllowsData16) |
|
| - NACL_IFLAG(SizeIgnoresData16));
|
| - break;
|
| - case PrefixF20F:
|
| - case PrefixF20F38:
|
| - NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeAllowsRepne));
|
| - break;
|
| - case PrefixF30F:
|
| - NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeAllowsRep));
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| -}
|
| -
|
| -/* Define the next opcode (instruction), initializing with
|
| - * no operands.
|
| - */
|
| -static void NaClDefInstInternal(
|
| - const uint8_t opcode,
|
| - const NaClInstType insttype,
|
| - NaClIFlags flags,
|
| - const NaClMnemonic name,
|
| - Bool no_install) {
|
| - /* TODO(karl) If we can deduce a more specific prefix that
|
| - * must be used, due to the flags associated with the opcode,
|
| - * then put on the more specific prefix list. This will make
|
| - * the defining of instructions easier, in that the caller doesn't
|
| - * need to specify the prefix to use.
|
| - */
|
| -
|
| - /* Before starting, install an opcode sequence if applicable. */
|
| - if (NULL != current_cand_inst_node) {
|
| - current_inst_node = current_cand_inst_node;
|
| - }
|
| - current_cand_inst_node = NULL;
|
| -
|
| - /* Before starting, expand appropriate implicit flag assumnptions. */
|
| - if (flags & NACL_IFLAG(OpcodeLtC0InModRm)) {
|
| - NaClAddBits(flags, NACL_IFLAG(OpcodeInModRm) | NACL_IFLAG(ModRmModIsnt0x3));
|
| - }
|
| -
|
| - DEBUG(NaClLog(LOG_INFO, "Define %s %"NACL_PRIx8": %s(%02x)\n",
|
| - NaClInstPrefixName(current_opcode_prefix),
|
| - opcode, NaClMnemonicName(name), name);
|
| - NaClIFlagsPrint(NaClLogGetGio(), flags));
|
| -
|
| - if (NaClMnemonicEnumSize <= name) {
|
| - NaClFatal("Badly defined mnemonic name");
|
| - }
|
| -
|
| - if (kNaClInstTypeRange <= insttype) {
|
| - NaClFatal("Badly defined inst type");
|
| - }
|
| -
|
| - /* Create opcode and initialize */
|
| - current_inst_mrm = (NaClMrmInst*) malloc(sizeof(NaClMrmInst));
|
| - if (NULL == current_inst_mrm) {
|
| - NaClFatal("NaClDefInst: malloc failed");
|
| - }
|
| - DEBUG(NaClLog(LOG_INFO,
|
| - "current = %p\n", (void*) current_inst_mrm));
|
| - current_inst_mrm->next = NULL;
|
| - current_inst = &(current_inst_mrm->inst);
|
| - NaClDefBytes(opcode);
|
| - current_inst->insttype = insttype;
|
| - current_inst->flags = NACL_EMPTY_IFLAGS;
|
| - current_inst->name = name;
|
| - current_inst->opcode_ext = 0;
|
| - current_inst->next_rule = NULL;
|
| -
|
| - /* undefine all operands. */
|
| - current_inst->num_operands = 0;
|
| - current_inst->operands = tables.operands + tables.operands_size;
|
| -
|
| - NaClAddIFlags(flags);
|
| -
|
| - NaClAddRepPrefixFlagsIfApplicable();
|
| -
|
| - NaClApplySanityChecksToInst();
|
| -
|
| - if (no_install || !NaClIFlagsMatchesRunMode(flags)) {
|
| - return;
|
| - }
|
| -
|
| - if (NULL == current_inst_node) {
|
| - /* Install NaClOpcode. */
|
| - DEBUG(NaClLog(LOG_INFO, " standard install\n"));
|
| - if (NULL == tables.inst_table[opcode][current_opcode_prefix]) {
|
| - tables.inst_table[opcode][current_opcode_prefix] = current_inst;
|
| - } else {
|
| - NaClModeledInst* next = tables.inst_table[opcode][current_opcode_prefix];
|
| - while (NULL != next->next_rule) {
|
| - next = next->next_rule;
|
| - }
|
| - next->next_rule = current_inst;
|
| - }
|
| - /* Install assuming no modrm opcode. Let NaClDefOp move if needed. */
|
| - NaClInstallCurrentIntoOpcodeMrm(current_opcode_prefix, opcode,
|
| - NACL_NO_MODRM_OPCODE);
|
| - } else if (NULL == current_inst_node->matching_inst) {
|
| - DEBUG(NaClLog(LOG_INFO, " instruction sequence install\n"));
|
| - current_inst_node->matching_inst = current_inst;
|
| - } else {
|
| - NaClFatalInst(
|
| - "Can't define more than one opcode for the same opcode sequence");
|
| - }
|
| -}
|
| -
|
| -void NaClDefInst(
|
| - const uint8_t opcode,
|
| - const NaClInstType insttype,
|
| - NaClIFlags flags,
|
| - const NaClMnemonic name) {
|
| - NaClDefInstInternal(opcode, insttype, flags, name, FALSE);
|
| -}
|
| -
|
| -/* Simple (fast hack) routine to extract a byte value from a character string.
|
| - */
|
| -static int NaClExtractByte(const char* chars, const char* opcode_seq) {
|
| - char buffer[3];
|
| - int i;
|
| - for (i = 0; i < 2; ++i) {
|
| - char ch = *(chars++);
|
| - if ('\0' == ch) {
|
| - NaClLog(LOG_ERROR,
|
| - "Odd number of characters in opcode sequence: '%s'\n",
|
| - opcode_seq);
|
| - NaClFatal("Fix before continuing!");
|
| - }
|
| - buffer[i] = ch;
|
| - }
|
| - buffer[2] = '\0';
|
| - return strtoul(buffer, NULL, 16);
|
| -}
|
| -
|
| -static NaClModeledInstNode* NaClNewInstNode(uint8_t byte) {
|
| - NaClModeledInstNode* root =
|
| - (NaClModeledInstNode*) malloc(sizeof(NaClModeledInstNode));
|
| - root->matching_byte = byte;
|
| - root->matching_inst = NULL;
|
| - root->success = NULL;
|
| - root->fail = NULL;
|
| - return root;
|
| -}
|
| -
|
| -/* Install an opcode sequence into the instruction trie. */
|
| -static void NaClDefInstSeq(const char* opcode_seq) {
|
| - /* Next is a (reference) pointer to the next node. The reference
|
| - * is used so that we can easily update the trie when we add nodes.
|
| - */
|
| - NaClModeledInstNode** next = &tables.inst_node_root;
|
| - /* Last is the last visited node in trie that is still matching
|
| - * the opcode sequence being added.
|
| - */
|
| - NaClModeledInstNode* last = NULL;
|
| - /* Index is the position of the next byte in the opcode sequence. */
|
| - int index = 0;
|
| -
|
| - /* First check that opcode sequence not defined twice without a corresponding
|
| - * call to NaClDefInst.
|
| - */
|
| - if (NULL != current_cand_inst_node) {
|
| - NaClLog(LOG_ERROR,
|
| - "Multiple definitions for opcode sequence: '%s'\n", opcode_seq);
|
| - NaClFatal("Fix before continuing!");
|
| - }
|
| -
|
| - /* Now install into lookup trie. */
|
| - while (opcode_seq[index]) {
|
| - uint8_t byte = (uint8_t) NaClExtractByte(opcode_seq + index, opcode_seq);
|
| - if (index >= 2 * NACL_MAX_BYTES_PER_X86_INSTRUCTION) {
|
| - NaClLog(LOG_ERROR,
|
| - "Too many bytes specified for opcode sequence: '%s'\n",
|
| - opcode_seq);
|
| - NaClFatal("Fix before continuing!\n");
|
| - }
|
| - if ((NULL == *next) || (byte < (*next)->matching_byte)) {
|
| - /* byte not in trie, add. */
|
| - NaClModeledInstNode* node = NaClNewInstNode(byte);
|
| - node->fail = *next;
|
| - *next = node;
|
| - }
|
| - if (byte == (*next)->matching_byte) {
|
| - last = *next;
|
| - next = &((*next)->success);
|
| - index += 2;
|
| - } else {
|
| - next = &((*next)->fail);
|
| - }
|
| - }
|
| - /* Last points to matching node, make it candidate instruction. */
|
| - current_cand_inst_node = last;
|
| -}
|
| -
|
| -/* Apply checks to current instruction flags, and update model as
|
| - * appropriate.
|
| - */
|
| -static void NaClRecheckIFlags(void) {
|
| - if (!NaClIFlagsMatchesRunMode(current_inst->flags)) {
|
| - NaClRemoveCurrentInstMrmFromInstTable();
|
| - NaClRemoveCurrentInstMrmFromInstMrmTable();
|
| - }
|
| - /* If the instruction has an opcode in modrm, then it uses modrm. */
|
| - if (NACL_EMPTY_IFLAGS != (current_inst->flags & NACL_IFLAG(OpcodeInModRm))) {
|
| - NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeUsesModRm));
|
| - }
|
| - /* If the instruction allows a two byte value, add DATA16 flag. */
|
| - if (NACL_EMPTY_IFLAGS != (current_inst->flags &
|
| - (NACL_IFLAG(OperandSize_w) |
|
| - NACL_IFLAG(OpcodeHasImmed_z)))) {
|
| - NaClAddBits(current_inst->flags, NACL_IFLAG(OpcodeAllowsData16));
|
| - }
|
| - /* If the instruction uses the modrm rm field as an opcode value,
|
| - * it also requires that the modrm mod field is 0x3.
|
| - */
|
| - if (current_inst->flags & NACL_IFLAG(OpcodeInModRmRm)) {
|
| - NaClAddBits(current_inst->flags, NACL_IFLAG(ModRmModIs0x3));
|
| - }
|
| - NaClApplySanityChecksToInst();
|
| -}
|
| -
|
| -void NaClAddIFlags(NaClIFlags more_flags) {
|
| - DEBUG(
|
| - struct Gio* g = NaClLogGetGio();
|
| - NaClLog(LOG_INFO, "Adding instruction flags: ");
|
| - NaClIFlagsPrint(g, more_flags);
|
| - gprintf(g, "\n"));
|
| - NaClAddBits(current_inst->flags, more_flags);
|
| - NaClRecheckIFlags();
|
| -}
|
| -
|
| -void NaClRemoveIFlags(NaClIFlags less_flags) {
|
| - DEBUG(
|
| - struct Gio* g = NaClLogGetGio();
|
| - NaClLog(LOG_INFO, "Removing instruction flags: ");
|
| - NaClIFlagsPrint(g, less_flags);
|
| - gprintf(g, "\n"));
|
| - NaClRemoveBits(current_inst->flags, less_flags);
|
| - NaClRecheckIFlags();
|
| -}
|
| -
|
| -void NaClDelaySanityChecks(void) {
|
| - apply_sanity_checks = FALSE;
|
| -}
|
| -
|
| -void NaClApplySanityChecks(void) {
|
| - apply_sanity_checks = TRUE;
|
| - if (NULL != current_inst) {
|
| - int i;
|
| - NaClApplySanityChecksToInst();
|
| - for (i = 0; i < current_inst->num_operands; i++) {
|
| - NaClApplySanityChecksToOp(i);
|
| - }
|
| - }
|
| -}
|
| -
|
| -static void NaClInitInstTables(void) {
|
| - int i;
|
| - NaClInstPrefix prefix;
|
| - int j;
|
| - /* Before starting, verify that we have defined NaClOpcodeFlags
|
| - * and NaClOpFlags big enough to hold the flags associated with it.
|
| - */
|
| - assert(NaClIFlagEnumSize <= sizeof(NaClIFlags) * 8);
|
| - assert(NaClOpFlagEnumSize <= sizeof(NaClOpFlags) * 8);
|
| - assert(NaClDisallowsFlagEnumSize <= sizeof(NaClDisallowsFlags) * 8);
|
| -
|
| - for (i = 0; i < NCDTABLESIZE; ++i) {
|
| - for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) {
|
| - tables.inst_table[i][prefix] = NULL;
|
| - for (j = 0; j <= NACL_NO_MODRM_OPCODE; ++j) {
|
| - NaClInstCount[i][prefix][j] = NACL_DEFAULT_CHOICE_COUNT;
|
| - }
|
| - }
|
| - NaClPrefixTable[i] = "0";
|
| - }
|
| - NaClDefInstPrefix(NoPrefix);
|
| - NaClDefInstInternal(0x0, NACLi_INVALID, 0, InstInvalid, TRUE);
|
| - tables.undefined_inst = current_inst;
|
| -}
|
| -
|
| -static void NaClDefPrefixBytes(void) {
|
| - NaClEncodePrefixName(kValueSEGES, "kPrefixSEGES");
|
| - NaClEncodePrefixName(kValueSEGCS, "kPrefixSEGCS");
|
| - NaClEncodePrefixName(kValueSEGSS, "kPrefixSEGSS");
|
| - NaClEncodePrefixName(kValueSEGDS, "kPrefixSEGDS");
|
| - NaClEncodePrefixName(kValueSEGFS, "kPrefixSEGFS");
|
| - NaClEncodePrefixName(kValueSEGGS, "kPrefixSEGGS");
|
| - NaClEncodePrefixName(kValueDATA16, "kPrefixDATA16");
|
| - NaClEncodePrefixName(kValueADDR16, "kPrefixADDR16");
|
| - NaClEncodePrefixName(kValueLOCK, "kPrefixLOCK");
|
| - NaClEncodePrefixName(kValueREPNE, "kPrefixREPNE");
|
| - NaClEncodePrefixName(kValueREP, "kPrefixREP");
|
| -
|
| - if (NACL_FLAGS_run_mode == X86_64) {
|
| - int i;
|
| - for (i = 0; i < 16; ++i) {
|
| - NaClEncodePrefixName(0x40+i, "kPrefixREX");
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Define the given character sequence, associated with the given byte
|
| - * opcode and instruction mnemonic, as a nop.
|
| - */
|
| -static void NaClDefNopLikeSeq(const char* sequence, uint8_t opcode,
|
| - NaClMnemonic name ) {
|
| - NaClDefInstSeq(sequence);
|
| - NaClDefInst(opcode, NACLi_386, NACL_EMPTY_IFLAGS, name);
|
| -}
|
| -
|
| -/* Define the given character sequence, associated with the given byte
|
| - * opcode, as a nop.
|
| - */
|
| -static void NaClDefNopSeq(const char* sequence, uint8_t opcode) {
|
| - NaClDefNopLikeSeq(sequence, opcode, InstNop);
|
| -}
|
| -
|
| -static void NaClDefNops(void) {
|
| - /* Note: The following could be recognized as nops, but are already
|
| - * parsed and accepted by the validator.
|
| - *
|
| - * 89 f6 mov %esi, %esi
|
| - * 8d742600 lea %esi, [%rsi]
|
| - * 8d7600 lea %esi, [%rsi]
|
| - * 8d b6 00 00 00 00 lea %esi, [%rsi]
|
| - * 8d b4 26 00 00 00 00 lea %esi, [%rsi]
|
| - * 8d bc 27 00 00 00 00 lea %edi, [%rdi]
|
| - * 8d bf 00 00 00 00 lea %edi, [%rdi]
|
| - * 0f 1f 00 nop
|
| - * 0f 1f 40 00 nop
|
| - * 0f 1f 44 00 00 nop
|
| - * 0f 1f 80 00 00 00 00 nop
|
| - * 0f 1f 84 00 00 00 00 00 nop
|
| - */
|
| - /* Note: For performance reasons, the function NaClMaybeHardCodedNop in
|
| - * src/trusted/validator/x86/decoder/nc_inst_state.c
|
| - * has been tuned to not look for these Nop instructions, unless
|
| - * the opcode byte sequence is one of "90", "0f1f", or "0f0b". If you add
|
| - * any nop instruction that doesn't meet this criteria, be sure
|
| - * to update NaClMaybeHardCodedNop accordingly.
|
| - */
|
| - /* nop */
|
| - NaClDefNopSeq("90", 0x90);
|
| - NaClDefNopSeq("6690", 0x90);
|
| - NaClDefNopLikeSeq("f390", 0x90, InstPause);
|
| - /* nop [%[re]ax] */
|
| - NaClDefNopSeq("0f1f00", 0x1f);
|
| - /* nop [%[re]ax+0] */
|
| - NaClDefNopSeq("0f1f4000", 0x1f);
|
| - /* nop [%[re]ax*1+0] */
|
| - NaClDefNopSeq("0f1f440000", 0x1f);
|
| - /* nop [%[re]ax+%[re]ax*1+0] */
|
| - NaClDefNopSeq("660f1f440000", 0x1f);
|
| - /* nop [%[re]ax+0] */
|
| - NaClDefNopSeq("0f1f8000000000", 0x1f);
|
| - /* nop [%[re]ax+%[re]ax*1+0] */
|
| - NaClDefNopSeq("0f1f840000000000", 0x1f);
|
| - /* nop [%[re]ax+%[re]ax+1+0] */
|
| - NaClDefNopSeq("660f1f840000000000", 0x1f);
|
| - /* nop %cs:[%re]ax+%[re]ax*1+0] */
|
| - NaClDefNopSeq("662e0f1f840000000000", 0x1f);
|
| - /* nop %cs:[%re]ax+%[re]ax*1+0] */
|
| - NaClDefNopSeq("66662e0f1f840000000000", 0x1f);
|
| - /* nop %cs:[%re]ax+%[re]ax*1+0] */
|
| - NaClDefNopSeq("6666662e0f1f840000000000", 0x1f);
|
| - /* nop %cs:[%re]ax+%[re]ax*1+0] */
|
| - NaClDefNopSeq("666666662e0f1f840000000000", 0x1f);
|
| - /* nop %cs:[%re]ax+%[re]ax*1+0] */
|
| - NaClDefNopSeq("66666666662e0f1f840000000000", 0x1f);
|
| - /* nop %cs:[%re]ax+%[re]ax*1+0] */
|
| - NaClDefNopSeq("6666666666662e0f1f840000000000", 0x1f);
|
| - /* UD2 */
|
| - NaClDefNopLikeSeq("0f0b", 0x0b, InstUd2);
|
| -}
|
| -
|
| -/* Build the set of x64 opcode (instructions). */
|
| -static void NaClBuildInstTables(void) {
|
| - struct NaClSymbolTable* st = NaClSymbolTableCreate(5, NULL);
|
| -
|
| - /* Create common (global) symbol table with instruction set presumptions. */
|
| - NaClSymbolTablePutText(
|
| - "sp", ((X86_32 == NACL_FLAGS_run_mode) ? "esp" : "rsp"), st);
|
| - NaClSymbolTablePutText(
|
| - "ip", ((X86_32 == NACL_FLAGS_run_mode) ? "eip" : "rip"), st);
|
| - NaClSymbolTablePutText(
|
| - "bp", ((X86_32 == NACL_FLAGS_run_mode) ? "ebp" : "rbp"), st);
|
| -
|
| - NaClInitInstTables();
|
| - NaClDefPrefixBytes();
|
| - NaClDefOneByteInsts(st);
|
| - NaClDef0FInsts(st);
|
| - NaClDefSseInsts(st);
|
| - NaClDefX87Insts(st);
|
| - NaClDefNops();
|
| -
|
| - NaClSymbolTableDestroy(st);
|
| -}
|
| -
|
| -static int NaClInstMrmListLength(NaClMrmInst* next) {
|
| - int count = 0;
|
| - while (NULL != next) {
|
| - ++count;
|
| - next = next->next;
|
| - }
|
| - return count;
|
| -}
|
| -
|
| -static void NaClFatalChoiceCount(const int expected,
|
| - const int found,
|
| - const NaClInstPrefix prefix,
|
| - const int opcode,
|
| - const int modrm_index,
|
| - NaClMrmInst* insts) {
|
| - struct Gio* g = NaClLogGetGio();
|
| - NaClPrintInstDescriptor(g, prefix, opcode, modrm_index);
|
| - NaClLog(LOG_ERROR, "Expected %d rules but found %d:\n", expected, found);
|
| - while (NULL != insts) {
|
| - NaClModeledInstPrint(g, &(insts->inst));
|
| - insts = insts->next;
|
| - }
|
| - NaClFatal("fix before continuing...\n");
|
| -}
|
| -
|
| -/* Verify that the number of possible choies for each prefix:opcode matches
|
| - * what was explicitly defined.
|
| - */
|
| -static void NaClVerifyInstCounts(void) {
|
| - int i, j;
|
| - NaClInstPrefix prefix;
|
| - for (i = 0; i < NCDTABLESIZE; ++i) {
|
| - for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) {
|
| - for (j = 0; j < NACL_MODRM_OPCODE_SIZE; ++j) {
|
| - NaClMrmInst* insts = NaClInstMrmTable[i][prefix][j];
|
| - int found = NaClInstMrmListLength(insts);
|
| - int expected = NaClInstCount[i][prefix][j];
|
| - if (expected == NACL_DEFAULT_CHOICE_COUNT) {
|
| - if (found > 1) {
|
| - NaClFatalChoiceCount(1, found, prefix, i, j, insts);
|
| - }
|
| - } else if (expected != found) {
|
| - NaClFatalChoiceCount(expected, found, prefix, i, j, insts);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Removes X86-32 specific flags from the given instruction. */
|
| -static void NaClInstRemove32Stuff(NaClModeledInst* inst) {
|
| - NaClRemoveBits(inst->flags, NACL_IFLAG(Opcode32Only));
|
| -}
|
| -
|
| -/* Removes X86-64 specific flags from the given instruction. */
|
| -static void NaClInstRemove64Stuff(NaClModeledInst* inst) {
|
| - NaClRemoveBits(inst->flags,
|
| - NACL_IFLAG(OpcodeRex) |
|
| - NACL_IFLAG(OpcodeUsesRexW) |
|
| - NACL_IFLAG(OpcodeHasRexR) |
|
| - NACL_IFLAG(Opcode64Only) |
|
| - NACL_IFLAG(OperandSize_o) |
|
| - NACL_IFLAG(AddressSize_o) |
|
| - NACL_IFLAG(OperandSizeDefaultIs64) |
|
| - NACL_IFLAG(OperandSizeForce64));
|
| -}
|
| -
|
| -/* Simplifies the instructions if possible. Mostly removes flags that
|
| - * don't correspond to the run mode.
|
| - */
|
| -static void NaClSimplifyIfApplicable(void) {
|
| - int i;
|
| - for (i = 0; i < NCDTABLESIZE; ++i) {
|
| - NaClInstPrefix prefix;
|
| - for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) {
|
| - NaClModeledInst* next = tables.inst_table[i][prefix];
|
| - while (NULL != next) {
|
| - if (X86_64 != NACL_FLAGS_run_mode) {
|
| - NaClInstRemove64Stuff(next);
|
| - }
|
| - if (X86_32 != NACL_FLAGS_run_mode) {
|
| - NaClInstRemove32Stuff(next);
|
| - }
|
| - /* Remove size only flags, since already compiled into tables. */
|
| - NaClRemoveBits(next->flags,
|
| - NACL_IFLAG(Opcode64Only) | NACL_IFLAG(Opcode32Only));
|
| - next = next->next_rule;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Prints out the set of defined instruction flags. */
|
| -static void NaClIFlagsPrintInternal(struct Gio* f, NaClIFlags flags) {
|
| - if (flags) {
|
| - int i;
|
| - Bool first = TRUE;
|
| - for (i = 0; i < NaClIFlagEnumSize; ++i) {
|
| - if (flags & NACL_IFLAG(i)) {
|
| - if (first) {
|
| - first = FALSE;
|
| - } else {
|
| - gprintf(f, " | ");
|
| - }
|
| - gprintf(f, "NACL_IFLAG(%s)", NaClIFlagName(i));
|
| - }
|
| - }
|
| - } else {
|
| - gprintf(f, "NACL_EMPTY_IFLAGS");
|
| - }
|
| -}
|
| -
|
| -/* Prints out the set of defined Operand flags. */
|
| -static void NaClOpFlagsPrintInternal(struct Gio* f, NaClOpFlags flags) {
|
| - if (flags) {
|
| - NaClOpFlag i;
|
| - Bool first = TRUE;
|
| - for (i = 0; i < NaClOpFlagEnumSize; ++i) {
|
| - if (flags & NACL_OPFLAG(i)) {
|
| - if (first) {
|
| - first = FALSE;
|
| - } else {
|
| - gprintf(f, " | ");
|
| - }
|
| - gprintf(f, "NACL_OPFLAG(%s)", NaClOpFlagName(i));
|
| - }
|
| - }
|
| - } else {
|
| - gprintf(f, "NACL_EMPTY_OPFLAGS");
|
| - }
|
| -}
|
| -
|
| -/* Print out the opcode operand. */
|
| -static void NaClOpPrintInternal(struct Gio* f, const NaClOp* operand) {
|
| - gprintf(f, "{ %s, ", NaClOpKindName(operand->kind));
|
| - NaClOpFlagsPrintInternal(f, operand->flags);
|
| - gprintf(f, ", ");
|
| - if (NULL == operand->format_string) {
|
| - gprintf(f, "NULL");
|
| - } else {
|
| - gprintf(f, "\"%s\"", operand->format_string);
|
| - }
|
| - gprintf(f, " },\n");
|
| -}
|
| -
|
| -/* Converts the (compressed) operand to the corresponding
|
| - * index in tables.ops_compressed.
|
| - */
|
| -size_t NaClOpOffset(const NaClOp* op) {
|
| - /* Note: This function is innefficient, but doesn't slow things down
|
| - * enough to worry about. Especially since this only effects the
|
| - * generator.
|
| - */
|
| - size_t i;
|
| - for (i = 0; i <= tables.ops_compressed_size; ++i) {
|
| - if (op == (tables.ops_compressed + i)) return i;
|
| - }
|
| - /* If reached, we have a bug! */
|
| - NaClFatal("Can't find offset for operand");
|
| - /* NOT REACHED */
|
| - return 0;
|
| -}
|
| -
|
| -static void NaClPrintInstIndex(struct Gio* f,
|
| - size_t index) {
|
| - if (NACL_OPCODE_NULL_OFFSET == index) {
|
| - gprintf(f, "NACL_OPCODE_NULL_OFFSET");
|
| - } else {
|
| - gprintf(f, "%d", index);
|
| - }
|
| -}
|
| -
|
| -/* Print out the given opcode offset value corresponding to the
|
| - * given instruction.
|
| - */
|
| -static void NaClPrintInstOffset(struct Gio* f,
|
| - const NaClModeledInst* inst) {
|
| - NaClPrintInstIndex(f, NaClFindInstIndex(&tables, inst));
|
| -}
|
| -
|
| -/* Prints out the given instruction to the given file. If index >= 0,
|
| - * print out a comment, with the value of index, before the printed
|
| - * instruction. Lookahead is used to convert the next_rule pointer into
|
| - * a symbolic reference using the name "g_Opcodes", plus the index defined by
|
| - * the lookahead. Argument as_array_element is true if the element is
|
| - * assumed to be in an array static initializer.
|
| - */
|
| -static void NaClInstPrintInternal(struct Gio* f, Bool as_array_element,
|
| - size_t index, const NaClModeledInst* inst) {
|
| - gprintf(f, " /* %d */\n", index);
|
| - gprintf(f, " { %s,\n", NaClInstTypeString(inst->insttype));
|
| - gprintf(f, " ");
|
| - NaClIFlagsPrintInternal(f, inst->flags);
|
| - gprintf(f, ",\n");
|
| - gprintf(f, " Inst%s, 0x%02x, ", NaClMnemonicName(inst->name),
|
| - inst->opcode_ext);
|
| - gprintf(f, "%u, %"NACL_PRIuS", ",
|
| - inst->num_operands, NaClOpOffset(inst->operands));
|
| - NaClPrintInstOffset(f, inst->next_rule);
|
| - gprintf(f, " }%c\n", as_array_element ? ',' : ';');
|
| -}
|
| -
|
| -/* Generate header information, based on the executable name in argv0,
|
| - * and the file to be generated (defined by fname).
|
| - */
|
| -static void NaClPrintHeader(struct Gio* f, const char* argv0,
|
| - const char* fname) {
|
| - gprintf(f, "/*\n");
|
| - gprintf(f, " * THIS FILE IS AUTO-GENERATED. DO NOT EDIT.\n");
|
| - gprintf(f, " * Compiled for %s.\n", NaClRunModeName(NACL_FLAGS_run_mode));
|
| - gprintf(f, " *\n");
|
| - gprintf(f, " * You must include ncopcode_desc.h before this file.\n");
|
| - gprintf(f, " */\n\n");
|
| -}
|
| -
|
| -/* Print out which bytes correspond to prefix bytes. */
|
| -static void NaClPrintPrefixTable(struct Gio* f) {
|
| - int opc;
|
| - gprintf(f, "static const uint32_t kNaClPrefixTable[NCDTABLESIZE] = {");
|
| - for (opc = 0; opc < NCDTABLESIZE; opc++) {
|
| - if (0 == opc % 16) {
|
| - gprintf(f, "\n /* 0x%02x-0x%02x */\n ", opc, opc + 15);
|
| - }
|
| - gprintf(f, "%s, ", NaClPrefixTable[opc]);
|
| - }
|
| - gprintf(f, "\n};\n\n");
|
| -}
|
| -
|
| -static int NaClCountInstNodes(const NaClModeledInstNode* root) {
|
| - if (NULL == root) {
|
| - return 0;
|
| - } else {
|
| - int count = 1;
|
| - count += NaClCountInstNodes(root->success);
|
| - count += NaClCountInstNodes(root->fail);
|
| - return count;
|
| - }
|
| -}
|
| -
|
| -static void NaClPrintInstTrieEdge(const NaClModeledInstNode* edge,
|
| - int* edge_index,
|
| - struct Gio* f) {
|
| - gprintf(f, " ");
|
| - if (NULL == edge) {
|
| - gprintf(f, "NULL");
|
| - }
|
| - else {
|
| - gprintf(f, "g_OpcodeSeq + %d", *edge_index);
|
| - *edge_index += NaClCountInstNodes(edge);
|
| - }
|
| - gprintf(f, ",\n");
|
| -}
|
| -
|
| -static void NaClPrintInstTrieNode(const NaClModeledInstNode* root,
|
| - int root_index, struct Gio* f) {
|
| - if (NULL == root) {
|
| - return;
|
| - } else {
|
| - int next_index = root_index + 1;
|
| - gprintf(f, " /* %d */\n", root_index);
|
| - gprintf(f, " { 0x%02x,\n ", root->matching_byte);
|
| - NaClPrintInstOffset(f, root->matching_inst);
|
| - gprintf(f, ",\n");
|
| - NaClPrintInstTrieEdge(root->success, &next_index, f);
|
| - NaClPrintInstTrieEdge(root->fail, &next_index, f);
|
| - gprintf(f, " },\n");
|
| - next_index = root_index + 1;
|
| - NaClPrintInstTrieNode(root->success, next_index, f);
|
| - next_index += NaClCountInstNodes(root->success);
|
| - NaClPrintInstTrieNode(root->fail, next_index, f);
|
| - }
|
| -}
|
| -
|
| -/* Prints out the contents of the opcode sequence overrides into the
|
| - * given file.
|
| - */
|
| -static void NaClPrintInstSeqTrie(const NaClModeledInstNode* root,
|
| - struct Gio* f) {
|
| - /* Make sure trie isn't empty, since empty arrays create warning messages. */
|
| - int num_trie_nodes;
|
| - if (root == NULL) root = NaClNewInstNode(0);
|
| - num_trie_nodes = NaClCountInstNodes(root);
|
| - gprintf(f, "static const NaClInstNode g_OpcodeSeq[%d] = {\n", num_trie_nodes);
|
| - NaClPrintInstTrieNode(root, 0, f);
|
| - gprintf(f, "};\n");
|
| -}
|
| -
|
| -/* Prints out the array of (compressed) operands. */
|
| -static void NaClPrintOperandTable(struct Gio* f) {
|
| - size_t i;
|
| - gprintf(f, "static const NaClOp g_Operands[%"NACL_PRIuS"] = {\n",
|
| - tables.ops_compressed_size);
|
| - for (i = 0; i < tables.ops_compressed_size; ++i) {
|
| - gprintf(f," /* %"NACL_PRIuS" */ ", i);
|
| - NaClOpPrintInternal(f, tables.ops_compressed+i);
|
| - }
|
| - gprintf(f, "};\n\n");
|
| -}
|
| -
|
| -static const size_t NaClOffsetsPerLine = 10;
|
| -
|
| -/* Print out instruction table. */
|
| -static void NaClPrintInstTable(struct Gio* f) {
|
| - size_t i;
|
| - gprintf(f,
|
| - "static const NaClInst g_Opcodes[%d] = {\n",
|
| - tables.inst_compressed_size);
|
| - for (i = 0; i < tables.inst_compressed_size; ++i) {
|
| - const NaClModeledInst* next = tables.inst_compressed[i];
|
| - NaClInstPrintInternal(f, TRUE, i, next);
|
| - }
|
| - gprintf(f, "};\n\n");
|
| -}
|
| -
|
| -/* Print lookup table of rules, based on prefix and opcode byte. */
|
| -static void NaClPrintLookupTable(struct Gio* f) {
|
| - size_t i;
|
| - NaClInstPrefix prefix;
|
| -
|
| - gprintf(f, "static const NaClPrefixOpcodeArrayOffset g_LookupTable[%d] = {",
|
| - (int) tables.opcode_lookup_size);
|
| - for (i = 0; i < tables.opcode_lookup_size; ++i) {
|
| - if (0 == (i % NaClOffsetsPerLine)) {
|
| - gprintf(f, "\n /* %5d */ ", (int) i);
|
| - }
|
| - NaClPrintInstIndex(f, tables.opcode_lookup[i]);
|
| - gprintf(f, ", ");
|
| - }
|
| - gprintf(f, "};\n\n");
|
| -
|
| - gprintf(f, "static const NaClPrefixOpcodeSelector "
|
| - "g_PrefixOpcode[NaClInstPrefixEnumSize] = {\n");
|
| - for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) {
|
| - gprintf(f, " /* %20s */ { %d , 0x%02x, 0x%02x },\n",
|
| - NaClInstPrefixName(prefix),
|
| - tables.opcode_lookup_entry[prefix],
|
| - tables.opcode_lookup_first[prefix],
|
| - tables.opcode_lookup_last[prefix]);
|
| - }
|
| - gprintf(f, "};\n\n");
|
| -}
|
| -
|
| -/* Print out the contents of the defined instructions into the given file. */
|
| -static void NaClPrintDecodeTables(struct Gio* f) {
|
| - NaClPrintOperandTable(f);
|
| - NaClPrintInstTable(f);
|
| - NaClPrintLookupTable(f);
|
| - NaClPrintPrefixTable(f);
|
| - NaClPrintInstSeqTrie(tables.inst_node_root, f);
|
| -}
|
| -
|
| -/* Print out the sequence of bytes used to encode an instruction sequence. */
|
| -static void PrintInstructionSequence(
|
| - struct Gio* f, uint8_t* inst_sequence, int length) {
|
| - int i;
|
| - for (i = 0; i < length; ++i) {
|
| - if (i > 0) gprintf(f, " ");
|
| - gprintf(f, "%02x", inst_sequence[i]);
|
| - }
|
| -}
|
| -
|
| -/* Print out instruction sequences defined for the given (Trie) node,
|
| - * and all of its descendants.
|
| - * Note: To keep recursive base cases simple, we allow one more byte
|
| - * in the instruction sequence that is actually possible.
|
| - */
|
| -static void PrintHardCodedInstructionsNode(
|
| - struct Gio* f, const NaClModeledInstNode* node,
|
| - uint8_t inst_sequence[NACL_MAX_BYTES_PER_X86_INSTRUCTION+1], int length) {
|
| - if (NULL == node) return;
|
| - inst_sequence[length] = node->matching_byte;
|
| - ++length;
|
| - if (NACL_MAX_BYTES_PER_X86_INSTRUCTION < length) {
|
| - struct Gio* glog = NaClLogGetGio();
|
| - NaClLog(LOG_ERROR, "%s", "");
|
| - PrintInstructionSequence(glog, inst_sequence, length);
|
| - gprintf(glog, "\n");
|
| - NaClFatal("Hard coded instruction too long, aborting\n");
|
| - }
|
| - if (NULL != node->matching_inst) {
|
| - gprintf(f, " --- ");
|
| - PrintInstructionSequence(f, inst_sequence, length);
|
| - gprintf(f, " ---\n");
|
| - NaClModeledInstPrint(f, node->matching_inst);
|
| - gprintf(f, "\n");
|
| - }
|
| - PrintHardCodedInstructionsNode(f, node->success, inst_sequence, length);
|
| - PrintHardCodedInstructionsNode(f, node->fail, inst_sequence, length-1);
|
| -}
|
| -
|
| -/* Walks over specifically encoded instruction trie, and prints
|
| - * out corresponding implemented instructions.
|
| - */
|
| -static void NaClPrintHardCodedInstructions(struct Gio* f) {
|
| - uint8_t inst_sequence[NACL_MAX_BYTES_PER_X86_INSTRUCTION+1];
|
| - PrintHardCodedInstructionsNode(f, tables.inst_node_root, inst_sequence, 0);
|
| -}
|
| -
|
| -/* Prints out documentation on the modeled instruction set. */
|
| -static void NaClPrintInstructionSet(struct Gio* f) {
|
| - NaClInstPrefix prefix;
|
| - int i;
|
| - gprintf(f, "*** Automatically generated file, do not edit! ***\n");
|
| - gprintf(f, "\n");
|
| - gprintf(f, "Target: %s\n", NaClRunModeName(NACL_FLAGS_run_mode));
|
| - gprintf(f, "\n");
|
| - gprintf(f, "*** Hard coded instructions ***\n");
|
| - gprintf(f, "\n");
|
| - NaClPrintHardCodedInstructions(f);
|
| -
|
| - for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) {
|
| - Bool printed_rules = FALSE;
|
| - gprintf(f, "*** %s ***\n", NaClInstPrefixName(prefix));
|
| - gprintf(f, "\n");
|
| - for (i = 0; i < NCDTABLESIZE; ++i) {
|
| - Bool is_first = TRUE;
|
| - const NaClModeledInst* inst = tables.inst_table[i][prefix];
|
| - while (NULL != inst) {
|
| - if (is_first) {
|
| - gprintf(f, " --- %02x ---\n", i);
|
| - is_first = FALSE;
|
| - }
|
| - NaClModeledInstPrint(f, inst);
|
| - printed_rules = TRUE;
|
| - inst = inst->next_rule;
|
| - }
|
| - }
|
| - if (printed_rules) gprintf(f, "\n");
|
| - }
|
| -}
|
| -
|
| -/* Open the given file using the given directives (how). */
|
| -static void NaClMustOpen(struct GioFile* g,
|
| - const char* fname, const char* how) {
|
| - if (!GioFileCtor(g, fname, how)) {
|
| - NaClLog(LOG_ERROR, "could not fopen(%s, %s)\n", fname, how);
|
| - NaClFatal("exiting now");
|
| - }
|
| -}
|
| -
|
| -/* Recognizes flags in argv, processes them, and then removes them.
|
| - * Returns the updated value for argc.
|
| - */
|
| -static int NaClGrokFlags(int argc, const char* argv[]) {
|
| - int i;
|
| - int new_argc;
|
| - if (argc == 0) return 0;
|
| - new_argc = 1;
|
| - for (i = 1; i < argc; ++i) {
|
| - if (0 == strcmp("-m32", argv[i])) {
|
| - NACL_FLAGS_run_mode = X86_32;
|
| - } else if (0 == strcmp("-m64", argv[i])) {
|
| - NACL_FLAGS_run_mode = X86_64;
|
| - } else if (GrokBoolFlag("-documentation", argv[i],
|
| - &NACL_FLAGS_human_readable) ||
|
| - GrokBoolFlag("-validator_decoder", argv[i],
|
| - &NACL_FLAGS_validator_decoder) ||
|
| - GrokBoolFlag("-nacl_subregs", argv[i],
|
| - &NACL_FLAGS_nacl_subregs)) {
|
| - continue;
|
| - } else {
|
| - argv[new_argc++] = argv[i];
|
| - }
|
| - }
|
| - return new_argc;
|
| -}
|
| -
|
| -static void GenerateTables(struct Gio* f, const char* cmd,
|
| - const char* filename) {
|
| - if (NACL_FLAGS_human_readable) {
|
| - NaClPrintInstructionSet(f);
|
| - } else {
|
| - /* Generate header file defining instruction set. */
|
| - NaClPrintHeader(f, cmd, filename);
|
| - if (NACL_FLAGS_nacl_subregs) {
|
| - if (NACL_FLAGS_run_mode == X86_64) {
|
| - NaClPrintGpRegisterIndexes_64(f);
|
| - } else {
|
| - NaClPrintGpRegisterIndexes_32(f);
|
| - }
|
| - } else {
|
| - NaClPrintDecodeTables(f);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/* Walk the trie of explicitly defined opcode sequences, and
|
| - * fill in the operands description field if it hasn't been
|
| - * explicitly defined.
|
| - */
|
| -static void FillInTrieMissingOperandsDescs(NaClModeledInstNode* node) {
|
| - NaClModeledInst* inst;
|
| - if (NULL == node) return;
|
| - inst = node->matching_inst;
|
| - NaClFillOperandDescs(inst);
|
| - FillInTrieMissingOperandsDescs(node->success);
|
| - FillInTrieMissingOperandsDescs(node->fail);
|
| -}
|
| -
|
| -/* Define the operands description field of each modeled
|
| - * opcode instruction, if it hasn't explicitly been defined.
|
| - */
|
| -static void FillInMissingOperandsDescs(void) {
|
| - int i;
|
| - NaClInstPrefix prefix;
|
| - for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) {
|
| - for (i = 0; i < NCDTABLESIZE; ++i) {
|
| - NaClModeledInst* next = tables.inst_table[i][prefix];
|
| - while (NULL != next) {
|
| - NaClFillOperandDescs(next);
|
| - next = next->next_rule;
|
| - }
|
| - }
|
| - }
|
| - FillInTrieMissingOperandsDescs(tables.inst_node_root);
|
| -}
|
| -
|
| -static void InitTables(void) {
|
| - tables.inst_node_root = NULL;
|
| - tables.operands_size = 0;
|
| - tables.ops_compressed_size = 0;
|
| - tables.opcode_lookup_size = 0;
|
| - tables.inst_compressed_size = 0;
|
| - tables.undefined_inst = 0;
|
| -}
|
| -
|
| -int main(const int argc, const char* argv[]) {
|
| - struct GioFile gfile;
|
| - struct Gio* g = (struct Gio*) &gfile;
|
| - int new_argc = NaClGrokFlags(argc, argv);
|
| - if ((new_argc < 1) || (new_argc > 2) ||
|
| - (NACL_FLAGS_human_readable && NACL_FLAGS_nacl_subregs) ||
|
| - (NACL_FLAGS_run_mode == NaClRunModeSize)) {
|
| - fprintf(stderr,
|
| - "ERROR: usage: ncdecode_tablegen <architecture_flag> "
|
| - "[-documentation | -validator_decoder -nacl_subregs] [file]\n");
|
| - return -1;
|
| - }
|
| - InitTables();
|
| - NaClLogModuleInit();
|
| - NaClBuildInstTables();
|
| - NaClSimplifyIfApplicable();
|
| - NaClVerifyInstCounts();
|
| - FillInMissingOperandsDescs();
|
| -
|
| - if (NACL_FLAGS_validator_decoder)
|
| - NaClNcvalInstSimplify(&tables);
|
| -
|
| - /* Don't compress if output is to be readable! Compression
|
| - * ignores extra (redundant) data used by print routines of
|
| - * modeled instructions, since this data is not needed at
|
| - * runtime when the corresponding data is defined in the
|
| - * parsed instruction.
|
| - */
|
| - if (!NACL_FLAGS_human_readable) {
|
| - NaClOpCompress(&tables);
|
| - }
|
| -
|
| - if (new_argc == 1) {
|
| - GioFileRefCtor(&gfile, stdout);
|
| - GenerateTables(g, argv[0], "<stdout>");
|
| - } else {
|
| - NaClMustOpen(&gfile, argv[1], "w");
|
| - GenerateTables(g, argv[0], argv[1]);
|
| - }
|
| - NaClLogModuleFini();
|
| - GioFileDtor(g);
|
| - return 0;
|
| -}
|
|
|