| Index: src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.c
 | 
| diff --git a/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.c b/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.c
 | 
| deleted file mode 100644
 | 
| index 28a66dd0d1b5f565e3b363652a86b74a89623b08..0000000000000000000000000000000000000000
 | 
| --- a/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.c
 | 
| +++ /dev/null
 | 
| @@ -1,1086 +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.
 | 
| - */
 | 
| -
 | 
| -/*
 | 
| - * ncvalidate.c
 | 
| - * Validate x86 instructions for Native Client
 | 
| - *
 | 
| - */
 | 
| -
 | 
| -#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.h"
 | 
| -
 | 
| -#include <stdio.h>
 | 
| -#include <stdlib.h>
 | 
| -#include <errno.h>
 | 
| -#include <string.h>
 | 
| -#include <assert.h>
 | 
| -
 | 
| -#include "native_client/src/include/portability.h"
 | 
| -#include "native_client/src/shared/platform/nacl_check.h"
 | 
| -#include "native_client/src/trusted/validator/x86/halt_trim.h"
 | 
| -#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h"
 | 
| -#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_internaltypes.h"
 | 
| -
 | 
| -#include "native_client/src/trusted/validator/x86/ncinstbuffer_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/ncval_seg_sfi/gen/ncbadprefixmask_64.h"
 | 
| -#else
 | 
| -#include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncbadprefixmask_32.h"
 | 
| -#endif
 | 
| -
 | 
| -/* debugging stuff */
 | 
| -#define DEBUGGING 0
 | 
| -#if DEBUGGING
 | 
| -#define dprint(args)        do { printf args; } while (0)
 | 
| -#else
 | 
| -#define dprint(args)        do { if (0) { printf args; } } while (0)
 | 
| -/* allows DCE but compiler can still do format string checks */
 | 
| -#endif  /* DEBUGGING */
 | 
| -
 | 
| -/* TODO(bradchen) verbosity needs to be controllable via commandline flags */
 | 
| -#define VERBOSE 1
 | 
| -#if VERBOSE
 | 
| -#define vprint(vstate, args) \
 | 
| -  do { \
 | 
| -    NaClErrorReporter* reporter = vstate->dstate.error_reporter; \
 | 
| -    (*reporter->printf) args;                                    \
 | 
| -  } while (0)
 | 
| -#else
 | 
| -#define vprint(vstate, args) \
 | 
| -  do { \
 | 
| -    if (0) { \
 | 
| -      NaClErrorReporter* reporter = vstate->dstate.error_reporter; \
 | 
| -      (*reporter->printf) args;                                    \
 | 
| -    } \
 | 
| -  } while (0)
 | 
| -/* allows DCE but compiler can still do format string checks */
 | 
| -#endif  /* VERBOSE */
 | 
| -
 | 
| -static const uint8_t kNaClFullStop = 0xf4;   /* x86 HALT opcode */
 | 
| -
 | 
| -/* Define how many diagnostic error messages are printed by the validator.
 | 
| - * A value of zero generates no diagnostics.
 | 
| - * A value >0 allows up to that many diagnostic error messages.
 | 
| - * A negative value prints all diagnostic error messages.
 | 
| - */
 | 
| -static int kMaxDiagnostics = 0;
 | 
| -
 | 
| -/* This flag controls a mode for testing only in which inter-instruction
 | 
| - * checks are disabled.
 | 
| - */
 | 
| -static Bool NACL_FLAG_unsafe_single_inst32_mode = FALSE;
 | 
| -
 | 
| -int NCValidatorGetMaxDiagnostics(void) {
 | 
| -  return kMaxDiagnostics;
 | 
| -}
 | 
| -
 | 
| -void NCValidatorSetMaxDiagnostics(int new_value) {
 | 
| -  kMaxDiagnostics = new_value;
 | 
| -}
 | 
| -
 | 
| -int NCValidatorDidStubOut(struct NCValidatorState *vstate) {
 | 
| -  return vstate->stats.didstubout;
 | 
| -}
 | 
| -
 | 
| -/* This function is intended to only be called by ValidatePrintInstructionError
 | 
| - * and ValidatePrintOffsetError.
 | 
| - */
 | 
| -static void ValidatePrintError(const NaClPcAddress addr,
 | 
| -                               const char *msg,
 | 
| -                               struct NCValidatorState *vstate) {
 | 
| -  if (vstate->num_diagnostics != 0) {
 | 
| -    NaClErrorReporter* reporter = vstate->dstate.error_reporter;
 | 
| -    (*reporter->printf)(
 | 
| -        reporter,
 | 
| -        "VALIDATOR: %"NACL_PRIxNaClPcAddress": %s\n", addr, msg);
 | 
| -    --(vstate->num_diagnostics);
 | 
| -    if (vstate->num_diagnostics == 0) {
 | 
| -      (*reporter->printf)(
 | 
| -          reporter,
 | 
| -          "VALIDATOR: Error limit reached, turning off diagnostics!\n");
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -static void ValidatePrintInstructionError(const struct NCDecoderInst *dinst,
 | 
| -                                          const char *msg,
 | 
| -                                          struct NCValidatorState *vstate) {
 | 
| -  ValidatePrintError(NCPrintableInstructionAddress(dinst), msg, vstate);
 | 
| -}
 | 
| -
 | 
| -static void ValidatePrintOffsetError(const NaClPcAddress addr,
 | 
| -                                     const char *msg,
 | 
| -                                     struct NCValidatorState *vstate) {
 | 
| -  ValidatePrintError(vstate->iadrbase + addr, msg, vstate);
 | 
| -}
 | 
| -
 | 
| -/* The low-level implementation for stubbing out an instruction. Always use
 | 
| - * this function to (ultimately) stub out instructions. This makes it possible
 | 
| - * to detect when the validator modifies the code.
 | 
| - */
 | 
| -static void NCStubOutMem(struct NCValidatorState *vstate, void *ptr,
 | 
| -                         size_t num) {
 | 
| -  vstate->stats.didstubout = 1;
 | 
| -  memset(ptr, kNaClFullStop, num);
 | 
| -}
 | 
| -
 | 
| -void NCBadInstructionError(const struct NCDecoderInst *dinst,
 | 
| -                           const char *msg) {
 | 
| -  NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
 | 
| -  ValidatePrintInstructionError(dinst, msg, vstate);
 | 
| -  if (vstate->do_stub_out) {
 | 
| -    NCStubOutMem(vstate, dinst->dstate->memory.mpc,
 | 
| -                 dinst->dstate->memory.read_length);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/* opcode histogram */
 | 
| -#if VERBOSE == 1
 | 
| -void OpcodeHisto(const uint8_t byte1, struct NCValidatorState *vstate) {
 | 
| -  vstate->opcodehisto[byte1] += 1;
 | 
| -}
 | 
| -
 | 
| -static void InitOpcodeHisto(struct NCValidatorState *vstate) {
 | 
| -  int i;
 | 
| -  for (i = 0; i < 256; i += 1) vstate->opcodehisto[i] = 0;
 | 
| -}
 | 
| -
 | 
| -static void PrintOpcodeHisto(struct NCValidatorState *vstate) {
 | 
| -  int i;
 | 
| -  int printed_in_this_row = 0;
 | 
| -  NaClErrorReporter* reporter = vstate->dstate.error_reporter;
 | 
| -  if (!VERBOSE) return;
 | 
| -  (*reporter->printf)(reporter, "\nOpcode Histogram;\n");
 | 
| -  for (i = 0; i < 256; ++i) {
 | 
| -    if (0 != vstate->opcodehisto[i]) {
 | 
| -      (*reporter->printf)(reporter, "%d\t0x%02x\t", vstate->opcodehisto[i], i);
 | 
| -      ++printed_in_this_row;
 | 
| -      if (printed_in_this_row > 3) {
 | 
| -        printed_in_this_row = 0;
 | 
| -        (*reporter->printf)(reporter, "\n");
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -  if (0 != printed_in_this_row) {
 | 
| -    (*reporter->printf)(reporter, "\n");
 | 
| -  }
 | 
| -}
 | 
| -#else
 | 
| -#define OpcodeHisto(b, v)
 | 
| -#define InitOpcodeHisto(v)
 | 
| -#define PrintOpcodeHisto(f, v)
 | 
| -#endif /* VERBOSE == 1 */
 | 
| -
 | 
| -/* statistics code */
 | 
| -static void NCStatsInst(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.instructions += 1;
 | 
| -}
 | 
| -
 | 
| -static void NCStatsCheckTarget(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.checktarget += 1;
 | 
| -}
 | 
| -
 | 
| -static void NCStatsTargetIndirect(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.targetindirect += 1;
 | 
| -}
 | 
| -
 | 
| -static void NCStatsSawFailure(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.sawfailure = 1;
 | 
| -}
 | 
| -
 | 
| -void NCStatsInternalError(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.internalerrors += 1;
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -void NCStatsBadAlignment(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.badalignment += 1;
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -static void NCStatsSegFault(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.segfaults += 1;
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -static void NCStatsNewSegment(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.segments += 1;
 | 
| -  if (vstate->stats.segments > 1) {
 | 
| -    vprint(vstate, (reporter, "error: multiple segments\n"));
 | 
| -    NCStatsSawFailure(vstate);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void NCStatsBadTarget(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.badtarget += 1;
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -static void NCStatsUnsafeIndirect(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.unsafeindirect += 1;
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -static void NCStatsReturn(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.returns += 1;
 | 
| -  NCStatsUnsafeIndirect(vstate);
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -static void NCStatsIllegalInst(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.illegalinst += 1;
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -static void NCStatsBadPrefix(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.badprefix += 1;
 | 
| -  vstate->stats.illegalinst += 1; /* a bad prefix is also an invalid inst */
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -static void NCStatsBadInstLength(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.badinstlength += 1;
 | 
| -  NCStatsSawFailure(vstate);
 | 
| -}
 | 
| -
 | 
| -static void NCStatsInit(struct NCValidatorState *vstate) {
 | 
| -  vstate->stats.instructions = 0;
 | 
| -  vstate->stats.segments = 0;
 | 
| -  vstate->stats.checktarget = 0;
 | 
| -  vstate->stats.targetindirect = 0;
 | 
| -  vstate->stats.badtarget = 0;
 | 
| -  vstate->stats.unsafeindirect = 0;
 | 
| -  vstate->stats.returns = 0;
 | 
| -  vstate->stats.illegalinst = 0;
 | 
| -  vstate->stats.badalignment = 0;
 | 
| -  vstate->stats.internalerrors = 0;
 | 
| -  vstate->stats.badinstlength = 0;
 | 
| -  vstate->stats.badprefix = 0;
 | 
| -  vstate->stats.didstubout = 0;
 | 
| -  vstate->stats.sawfailure = 0;
 | 
| -  InitOpcodeHisto(vstate);
 | 
| -}
 | 
| -
 | 
| -void NCStatsPrint(struct NCValidatorState *vstate) {
 | 
| -  NaClErrorReporter* reporter;
 | 
| -  if (!VERBOSE || (vstate == NULL)) return;
 | 
| -  reporter = vstate->dstate.error_reporter;
 | 
| -  PrintOpcodeHisto(vstate);
 | 
| -  (*reporter->printf)(reporter, "Analysis Summary:\n");
 | 
| -  (*reporter->printf)(reporter, "%d Checked instructions\n",
 | 
| -                      vstate->stats.instructions);
 | 
| -  (*reporter->printf)(reporter, "%d checked jump targets\n",
 | 
| -                      vstate->stats.checktarget);
 | 
| -  (*reporter->printf)(
 | 
| -      reporter, "%d calls/jumps need dynamic checking (%0.2f%%)\n",
 | 
| -      vstate->stats.targetindirect,
 | 
| -      vstate->stats.instructions ?
 | 
| -      100.0 * vstate->stats.targetindirect/vstate->stats.instructions : 0);
 | 
| -  if (vstate->stats.didstubout) {
 | 
| -    (*reporter->printf)(reporter, "Some instructions were replaced with HLTs");
 | 
| -  }
 | 
| -  (*reporter->printf)(reporter, "\nProblems:\n");
 | 
| -  (*reporter->printf)(reporter, "%d illegal instructions\n",
 | 
| -                   vstate->stats.illegalinst);
 | 
| -  (*reporter->printf)(reporter,
 | 
| -                      "%d bad jump targets\n", vstate->stats.badtarget);
 | 
| -  (*reporter->printf)(
 | 
| -      reporter, "%d illegal unprotected indirect jumps (including ret)\n",
 | 
| -      vstate->stats.unsafeindirect);
 | 
| -  (*reporter->printf)(reporter, "%d instruction alignment defects\n",
 | 
| -                      vstate->stats.badalignment);
 | 
| -  (*reporter->printf)(reporter, "%d segmentation errors\n",
 | 
| -                      vstate->stats.segfaults);
 | 
| -  (*reporter->printf)(reporter, "%d bad prefix\n",
 | 
| -                      vstate->stats.badprefix);
 | 
| -  (*reporter->printf)(reporter, "%d bad instruction length\n",
 | 
| -                      vstate->stats.badinstlength);
 | 
| -  (*reporter->printf)(reporter, "%d internal errors\n",
 | 
| -                      vstate->stats.internalerrors);
 | 
| -}
 | 
| -
 | 
| -/***********************************************************************/
 | 
| -/* jump target table                                                   */
 | 
| -const uint8_t nc_iadrmasks[8] = {0x01, 0x02, 0x04, 0x08,
 | 
| -                                 0x10, 0x20, 0x40, 0x80};
 | 
| -
 | 
| -/* forward declarations, needed for registration */
 | 
| -static Bool ValidateInst(const NCDecoderInst *dinst);
 | 
| -static Bool ValidateInstReplacement(NCDecoderStatePair* tthis,
 | 
| -                                    NCDecoderInst *dinst_old,
 | 
| -                                    NCDecoderInst *dinst_new);
 | 
| -static void NCJumpSummarize(struct NCValidatorState* vstate);
 | 
| -
 | 
| -struct NCValidatorState *NCValidateInit(const NaClPcAddress vbase,
 | 
| -                                        const NaClPcAddress codesize,
 | 
| -                                        const int readonly_text,
 | 
| -                                        const NaClCPUFeaturesX86 *features) {
 | 
| -  struct NCValidatorState *vstate = NULL;
 | 
| -  const int bundle_size = 32;
 | 
| -
 | 
| -  dprint(("NCValidateInit(%"NACL_PRIxNaClPcAddressAll
 | 
| -          ", %"NACL_PRIxNaClMemorySizeAll", %08x)\n", vbase, codesize,
 | 
| -          bundle_size));
 | 
| -  do {
 | 
| -    if (features == NULL)
 | 
| -      break;
 | 
| -    if ((vbase & (bundle_size - 1)) != 0)
 | 
| -      break;
 | 
| -    dprint(("ncv_init(%"NACL_PRIxNaClPcAddress", %"NACL_PRIxNaClMemorySize
 | 
| -            ")\n", vbase, codesize));
 | 
| -    vstate = (struct NCValidatorState *)calloc(1, sizeof(*vstate));
 | 
| -    if (vstate == NULL)
 | 
| -      break;
 | 
| -    /* Record default error reporter here, since we don't construct
 | 
| -     * the decoder state until the call to NCValidateSegment. This allows
 | 
| -     * us to update the error reporter in the decoder state properly.
 | 
| -     */
 | 
| -    vstate->dstate.error_reporter = &kNCNullErrorReporter;
 | 
| -    vstate->num_diagnostics = kMaxDiagnostics;
 | 
| -    vstate->iadrbase = vbase;
 | 
| -    vstate->codesize = codesize;
 | 
| -    vstate->bundle_size = bundle_size;
 | 
| -    vstate->bundle_mask = bundle_size - 1;
 | 
| -    vstate->vttable = (uint8_t *)calloc(NCIATOffset(codesize) + 1, 1);
 | 
| -    vstate->kttable = (uint8_t *)calloc(NCIATOffset(codesize) + 1, 1);
 | 
| -    vstate->pattern_nonfirst_insts_table = NULL;
 | 
| -    vstate->summarize_fn = NCJumpSummarize;
 | 
| -    vstate->do_stub_out = 0;
 | 
| -    vstate->readonly_text = readonly_text;
 | 
| -    if (vstate->vttable == NULL || vstate->kttable == NULL)
 | 
| -      break;
 | 
| -    dprint(("  allocated tables\n"));
 | 
| -    NCStatsInit(vstate);
 | 
| -    NaClCopyCPUFeaturesX86(&vstate->cpufeatures, features);
 | 
| -    return vstate;
 | 
| -  } while (0);
 | 
| -  /* Failure. Clean up memory before returning. */
 | 
| -  if (NULL != vstate) {
 | 
| -    if (NULL != vstate->kttable)
 | 
| -      free(vstate->kttable);
 | 
| -    if (NULL != vstate->vttable)
 | 
| -      free(vstate->vttable);
 | 
| -    free(vstate);
 | 
| -  }
 | 
| -  return NULL;
 | 
| -}
 | 
| -
 | 
| -void NCValidateSetStubOutMode(struct NCValidatorState *vstate,
 | 
| -                              int do_stub_out) {
 | 
| -  vstate->do_stub_out = do_stub_out;
 | 
| -  /* We also turn off error diagnostics, under the assumption
 | 
| -   * you don't want them. (Note: if the user wants them,
 | 
| -   * you can run ncval to get them)/
 | 
| -   */
 | 
| -  if (do_stub_out) {
 | 
| -    NCValidateSetNumDiagnostics(vstate, 0);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void NCValidateSetNumDiagnostics(struct NCValidatorState* vstate,
 | 
| -                                 int num_diagnostics) {
 | 
| -  vstate->num_diagnostics = num_diagnostics;
 | 
| -}
 | 
| -
 | 
| -void NCValidateSetErrorReporter(struct NCValidatorState* state,
 | 
| -                                NaClErrorReporter* error_reporter) {
 | 
| -  NCDecoderStateSetErrorReporter(&state->dstate, error_reporter);
 | 
| -}
 | 
| -
 | 
| -static INLINE void RememberInstructionBoundary(const NCDecoderInst *dinst,
 | 
| -                                              struct NCValidatorState *vstate) {
 | 
| -  /* The decoder should never pass us an out-of-bounds instruction. */
 | 
| -  CHECK(dinst->inst_addr < vstate->codesize);
 | 
| -  if (NCGetAdrTable(dinst->inst_addr, vstate->vttable)) {
 | 
| -    vprint(vstate, (reporter,
 | 
| -                    "RememberIP: Saw inst at %"NACL_PRIxNaClPcAddressAll
 | 
| -                    " twice\n", NCPrintableInstructionAddress(dinst)));
 | 
| -    NCStatsInternalError(vstate);
 | 
| -    return;
 | 
| -  }
 | 
| -  NCStatsInst(vstate);
 | 
| -  NCSetAdrTable(dinst->inst_addr, vstate->vttable);
 | 
| -}
 | 
| -
 | 
| -static void RememberJumpTarget(const NCDecoderInst *dinst, int32_t jump_offset,
 | 
| -                               struct NCValidatorState *vstate) {
 | 
| -  NaClPcAddress target = (dinst->inst_addr + dinst->inst.bytes.length
 | 
| -                          + jump_offset);
 | 
| -
 | 
| -  /* For testing only, this mode disables inter-instruction checks. */
 | 
| -  if (NACL_FLAG_unsafe_single_inst32_mode) return;
 | 
| -
 | 
| -  if (target < vstate->codesize) {
 | 
| -    NCSetAdrTable(target, vstate->kttable);
 | 
| -  } else if ((target & vstate->bundle_mask) == 0) {
 | 
| -    /* Allow bundle-aligned jumps. */
 | 
| -  } else if (dinst->unchanged) {
 | 
| -    /* If we are replacing this instruction during dynamic code modification
 | 
| -     * and it has not changed, the jump target must be valid because the
 | 
| -     * instruction has been previously validated.  However, we may be only
 | 
| -     * replacing a subsection of the code segment and therefore may not have
 | 
| -     * information about instruction boundaries outside of the code being
 | 
| -     * replaced. Therefore, we allow unaligned direct jumps outside of the code
 | 
| -     * being validated if and only if the instruction is unchanged.
 | 
| -     * If dynamic code replacement is not being performed, inst->unchanged
 | 
| -     * should always be false.
 | 
| -     */
 | 
| -  } else {
 | 
| -    ValidatePrintInstructionError(dinst, "JUMP TARGET out of range", vstate);
 | 
| -    NCStatsBadTarget(vstate);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -static void ForgetInstructionBoundary(const NCDecoderInst *dinst,
 | 
| -                                     struct NCValidatorState *vstate) {
 | 
| -  /* The decoder should never pass us an out-of-bounds instruction. */
 | 
| -  CHECK(dinst->inst_addr < vstate->codesize);
 | 
| -  NCClearAdrTable(dinst->inst_addr, vstate->vttable);
 | 
| -  if (NULL != vstate->pattern_nonfirst_insts_table) {
 | 
| -    NCSetAdrTable(dinst->inst_addr, vstate->pattern_nonfirst_insts_table);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -int NCValidateFinish(struct NCValidatorState *vstate) {
 | 
| -  if (vstate == NULL) {
 | 
| -    dprint(("validator not initialized. Did you call ncvalidate_init()?\n"));
 | 
| -    /* non-zero indicates failure */
 | 
| -    return 1;
 | 
| -  }
 | 
| -
 | 
| -  /* If we are stubbing out code, the following checks don't provide any
 | 
| -   * usefull information, so quit early.
 | 
| -   */
 | 
| -  if (vstate->do_stub_out) return vstate->stats.sawfailure;
 | 
| -
 | 
| -  /* Double check that the base address matches the alignment constraint. */
 | 
| -  if (vstate->iadrbase & vstate->bundle_mask) {
 | 
| -    /* This should never happen because the alignment of iadrbase is */
 | 
| -    /* checked in NCValidateInit(). */
 | 
| -    ValidatePrintOffsetError(0, "Bad base address alignment", vstate);
 | 
| -    NCStatsBadAlignment(vstate);
 | 
| -  }
 | 
| -
 | 
| -  /* Apply summary analysis to collected data during pass over
 | 
| -   * instructions.
 | 
| -   */
 | 
| -  (*(vstate->summarize_fn))(vstate);
 | 
| -
 | 
| -  /* Now that all the work is done, generate return code. */
 | 
| -  /* Return zero if there are no problems.                */
 | 
| -  return (vstate->stats.sawfailure);
 | 
| -}
 | 
| -
 | 
| -void NCValidateFreeState(struct NCValidatorState **vstate) {
 | 
| -  CHECK(*vstate != NULL);
 | 
| -  free((*vstate)->vttable);
 | 
| -  free((*vstate)->kttable);
 | 
| -  free((*vstate)->pattern_nonfirst_insts_table);
 | 
| -  free(*vstate);
 | 
| -  *vstate = NULL;
 | 
| -}
 | 
| -
 | 
| -/* ValidateSFenceClFlush is called for the sfence/clflush opcode 0f ae /7 */
 | 
| -/* It returns 0 if the current instruction is implemented, and 1 if not.  */
 | 
| -static int ValidateSFenceClFlush(const NCDecoderInst *dinst) {
 | 
| -  NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
 | 
| -  uint8_t mrm = NCInstBytesByteInline(&dinst->inst_bytes, 2);
 | 
| -
 | 
| -  if (modrm_modInline(mrm) == 3) {
 | 
| -    /* this is an sfence */
 | 
| -    if (NaClGetCPUFeatureX86(&vstate->cpufeatures, NaClCPUFeatureX86_FXSR))
 | 
| -      return 0;
 | 
| -    return 1;
 | 
| -  } else {
 | 
| -    /* this is an clflush */
 | 
| -    if (NaClGetCPUFeatureX86(&vstate->cpufeatures, NaClCPUFeatureX86_CLFLUSH))
 | 
| -      return 0;
 | 
| -    return 1;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -static void ValidateCallAlignment(const NCDecoderInst *dinst) {
 | 
| -  NaClPcAddress fallthru = dinst->inst_addr + dinst->inst.bytes.length;
 | 
| -  struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
 | 
| -  if (fallthru & vstate->bundle_mask) {
 | 
| -#if defined(ERROR_ON_CALL_BUNDLE_ALIGNMENT)
 | 
| -    /* NOTE: Previously the validator recorded an error for call instructions
 | 
| -     * that were not aligned against the end of a bundle, as these, while
 | 
| -     * safe, are not correct with the current code generation idioms.
 | 
| -     * This #if defined(ERROR_ON_CALL_BUNDLE_ALIGNMENT) was added to allow
 | 
| -     * experimentation with different call/return idioms.
 | 
| -     */
 | 
| -    ValidatePrintInstructionError(dinst, "Bad call alignment", vstate);
 | 
| -    /* This makes bad call alignment a fatal error. */
 | 
| -    NCStatsBadAlignment(vstate);
 | 
| -#endif
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -static void ValidateJmp8(const NCDecoderInst *dinst) {
 | 
| -  int8_t offset = NCInstBytesByteInline(&dinst->inst_bytes,
 | 
| -                                        dinst->inst.prefixbytes+1);
 | 
| -  struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
 | 
| -  NCStatsCheckTarget(vstate);
 | 
| -  RememberJumpTarget(dinst, offset, vstate);
 | 
| -}
 | 
| -
 | 
| -static void ValidateJmpz(const NCDecoderInst *dinst) {
 | 
| -  NCInstBytesPtr opcode;
 | 
| -  uint8_t opcode0;
 | 
| -  int32_t offset;
 | 
| -  NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
 | 
| -  NCInstBytesPtrInitInc(&opcode, &dinst->inst_bytes,
 | 
| -                        dinst->inst.prefixbytes);
 | 
| -  opcode0 = NCInstBytesByteInline(&opcode, 0);
 | 
| -  NCStatsCheckTarget(vstate);
 | 
| -  if (opcode0 == 0x0f) {
 | 
| -    /* Multbyte opcode. Intruction is of form:
 | 
| -     *    0F80 .. 0F8F: jCC $Jz
 | 
| -     */
 | 
| -    NCInstBytesPtr opcode_2;
 | 
| -    NCInstBytesPtrInitInc(&opcode_2, &opcode, 2);
 | 
| -    offset = NCInstBytesInt32(&opcode_2, dinst->inst.immbytes);
 | 
| -  } else {
 | 
| -    /* Single byte opcode. Must be one of:
 | 
| -     *    E8: call $Jz
 | 
| -     *    E9: jmp $Jx
 | 
| -     */
 | 
| -    NCInstBytesPtr opcode_1;
 | 
| -    NCInstBytesPtrInitInc(&opcode_1, &opcode, 1);
 | 
| -    offset = NCInstBytesInt32(&opcode_1, dinst->inst.immbytes);
 | 
| -    /* as a courtesy, check call alignment correctness */
 | 
| -    if (opcode0 == 0xe8) ValidateCallAlignment(dinst);
 | 
| -  }
 | 
| -  RememberJumpTarget(dinst, offset, vstate);
 | 
| -}
 | 
| -
 | 
| -/*
 | 
| - * The NaCl five-byte safe indirect calling sequence looks like this:
 | 
| - *   83 e0 e0                 and  $0xe0,%eax
 | 
| - *   ff d0                    call *%eax
 | 
| - * The call may be replaced with a ff e0 jmp. Any register may
 | 
| - * be used, not just eax. The validator requires exactly this
 | 
| - * sequence.
 | 
| - * Note: The code above assumes 32-bit alignment. Change e0 as appropriate
 | 
| - * if a different alignment is used.
 | 
| - */
 | 
| -static void ValidateIndirect5(const NCDecoderInst *dinst) {
 | 
| -  NCInstBytesPtr jmpopcode;
 | 
| -  NCInstBytesPtr andopcode;
 | 
| -  uint8_t               mrm;
 | 
| -  uint8_t               targetreg;
 | 
| -  const uint8_t         kReg_ESP = 4;
 | 
| -  NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
 | 
| -
 | 
| -  struct NCDecoderInst *andinst = PreviousInst(dinst, 1);
 | 
| -  if ((andinst == NULL) || (andinst->inst.bytes.length != 3)) {
 | 
| -    NCBadInstructionError(dinst, "Unsafe indirect jump");
 | 
| -    NCStatsUnsafeIndirect(vstate);
 | 
| -    return;
 | 
| -  }
 | 
| -  /* note: no prefixbytes allowed */
 | 
| -  NCInstBytesPtrInitInc(&jmpopcode, &dinst->inst_bytes, 0);
 | 
| -  /* note: no prefixbytes allowed */
 | 
| -  NCInstBytesPtrInitInc(&andopcode, &andinst->inst_bytes, 0);
 | 
| -  mrm = NCInstBytesByteInline(&jmpopcode, 1);
 | 
| -  /* Note that the modrm_rm field holds the
 | 
| -   * target addr the modrm_reg is the opcode.
 | 
| -   */
 | 
| -  targetreg = modrm_rmInline(mrm);
 | 
| -  NCStatsCheckTarget(vstate);
 | 
| -  NCStatsTargetIndirect(vstate);
 | 
| -  do {
 | 
| -    /* no prefix bytes allowed */
 | 
| -    if (dinst->inst.prefixbytes != 0) break;
 | 
| -    if (dinst->inst.prefixbytes != 0) break;
 | 
| -    /* Check all the opcodes. */
 | 
| -    /* In GROUP5, 2 => call, 4 => jmp */
 | 
| -    if (NCInstBytesByteInline(&jmpopcode, 0) != 0xff) break;
 | 
| -    if ((modrm_regInline(mrm) != 2) && (modrm_regInline(mrm) != 4)) break;
 | 
| -    /* Issue 32: disallow unsafe call/jump indirection */
 | 
| -    /* example:    ff 12     call (*edx)               */
 | 
| -    /* Reported by defend.the.world on 11 Dec 2008     */
 | 
| -    if (modrm_modInline(mrm) != 3) break;
 | 
| -    if (targetreg == kReg_ESP) break;
 | 
| -    if (NCInstBytesByteInline(&andopcode, 0) != 0x83) break;
 | 
| -    /* check modrm bytes of or and and instructions */
 | 
| -    if (NCInstBytesByteInline(&andopcode, 1) != (0xe0 | targetreg)) break;
 | 
| -    /* check mask */
 | 
| -    if (NCInstBytesByteInline(&andopcode, 2) !=
 | 
| -        (0x0ff & ~vstate->bundle_mask)) break;
 | 
| -    /* All checks look good. Make the sequence 'atomic.' */
 | 
| -    ForgetInstructionBoundary(dinst, vstate);
 | 
| -    /* as a courtesy, check call alignment correctness */
 | 
| -    if (modrm_regInline(mrm) == 2) ValidateCallAlignment(dinst);
 | 
| -    return;
 | 
| -  } while (0);
 | 
| -  NCBadInstructionError(dinst, "Unsafe indirect jump");
 | 
| -  NCStatsUnsafeIndirect(vstate);
 | 
| -}
 | 
| -
 | 
| -/* Checks if the set of prefixes are allowed for the instruction.
 | 
| - * By default, we only allow prefixes if they have been allowed
 | 
| - * by the bad prefix mask generated inside ncdecode_table.c.
 | 
| - * These masks are defined by the NaClInstType of the instruction.
 | 
| - * See ncdecode_table.c for more details on how these masks are set.
 | 
| - *
 | 
| - * Currently:
 | 
| - * Only 386, 386L, 386R, 386RE instruction allow  Data 16
 | 
| - * (unless used as part of instruction selection in a multibyte instruction).
 | 
| - * Only 386, JMP8, and JMPZ allow segment registers prefixes.
 | 
| - * Only 386L and CMPXCHG8B allow the LOCK prefix.
 | 
| - * Only 386R and 386RE instructions allow the REP prefix.
 | 
| - * Only 386RE instructions allow the REPNE prefix.
 | 
| - *
 | 
| - * Note: The prefixmask does not include the prefix value (if any) used to
 | 
| - * select multiple byte instructions. Such prefixes have been moved to
 | 
| - * opcode_prefixmask, so that the selection (based on that prefix) has
 | 
| - * been recorded.
 | 
| - *
 | 
| - * In general, we do not allow multiple prefixes. Exceptions are as
 | 
| - * follows:
 | 
| - *   1 - Data 16 is allowed on lock instructions, so that 2 byte values
 | 
| - *       can be locked.
 | 
| - *   2 - Multibyte instructions that are selected
 | 
| - *       using prefix values Data 16, REP and REPNE, can only have
 | 
| - *       one of these prefixes (Combinations of these three prefixes
 | 
| - *       are not allowed for such multibyte instructions).
 | 
| - *   3 - Locks are only allowed on instructions with type 386L. The
 | 
| - *       exception is inst cmpxch8b, which also can have a lock.
 | 
| - *   4 - The only two prefix byte combination allowed is Data 16 and Lock.
 | 
| - *   5 - Long nops that are hard coded can contain more than one prefix.
 | 
| - *       See ncdecode.c for details (they don't use ValidatePrefixes).
 | 
| - */
 | 
| -static Bool ValidatePrefixes(const NCDecoderInst *dinst) {
 | 
| -  if (dinst->inst.prefixbytes == 0) return TRUE;
 | 
| -
 | 
| -  if ((dinst->inst.prefixmask &
 | 
| -       BadPrefixMask[dinst->opinfo->insttype]) != 0) {
 | 
| -    return FALSE;
 | 
| -  }
 | 
| -
 | 
| -  /* If a multibyte instruction is using a selection prefix, be
 | 
| -   * sure that there is no conflict with other selection prefixes.
 | 
| -   */
 | 
| -  if ((dinst->inst.opcode_prefixmask != 0) &&
 | 
| -      ((dinst->inst.prefixmask &
 | 
| -        (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) != 0)) {
 | 
| -    return FALSE;
 | 
| -  }
 | 
| -
 | 
| -  /* Only allow a lock if it is a 386L instruction, or the special
 | 
| -   * cmpxchg8b instruction.
 | 
| -   */
 | 
| -  if (dinst->inst.prefixmask & kPrefixLOCK) {
 | 
| -    if ((dinst->opinfo->insttype != NACLi_386L) &&
 | 
| -        (dinst->opinfo->insttype != NACLi_CMPXCHG8B)) {
 | 
| -      return FALSE;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /* Only allow more than one prefix if two prefixes, and they are
 | 
| -   * data 16 and lock.
 | 
| -   */
 | 
| -  if ((dinst->inst.prefixbytes > 1) &&
 | 
| -      !((dinst->inst.prefixbytes == 2) &&
 | 
| -        (dinst->inst.prefixmask == (kPrefixLOCK | kPrefixDATA16)) &&
 | 
| -        /* Be sure data 16 (66) appears before lock (f0) prefix. */
 | 
| -        (dinst->inst.lock_prefix_index == 1))) {
 | 
| -    return FALSE;
 | 
| -  }
 | 
| -
 | 
| -  return TRUE;
 | 
| -}
 | 
| -
 | 
| -static const size_t kMaxValidInstLength = 11;
 | 
| -
 | 
| -/* The modrm mod field is a two-bit value. Values 00, 01, and, 10
 | 
| - * define memory references. Value 11 defines register accesses instead
 | 
| - * of memory.
 | 
| - */
 | 
| -static const int kModRmModFieldDefinesRegisterRef = 0x3;
 | 
| -
 | 
| -static Bool ValidateInst(const NCDecoderInst *dinst) {
 | 
| -  NaClCPUFeaturesX86 *cpufeatures;
 | 
| -  int squashme = 0;
 | 
| -  NCValidatorState* vstate;
 | 
| -  if (dinst == NULL) return TRUE;
 | 
| -  vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
 | 
| -
 | 
| -  OpcodeHisto(NCInstBytesByteInline(&dinst->inst_bytes,
 | 
| -                                    dinst->inst.prefixbytes),
 | 
| -              vstate);
 | 
| -  /* For testing only, this mode disables inter-instruction checks. */
 | 
| -  if (!NACL_FLAG_unsafe_single_inst32_mode) {
 | 
| -    RememberInstructionBoundary(dinst, vstate);
 | 
| -  }
 | 
| -
 | 
| -  cpufeatures = &vstate->cpufeatures;
 | 
| -
 | 
| -  if (!ValidatePrefixes(dinst)) {
 | 
| -    NCBadInstructionError(dinst, "Bad prefix usage");
 | 
| -    NCStatsBadPrefix(vstate);
 | 
| -  }
 | 
| -
 | 
| -  if ((dinst->opinfo->insttype != NACLi_NOP) &&
 | 
| -      ((size_t) (dinst->inst.bytes.length - dinst->inst.prefixbytes)
 | 
| -       > kMaxValidInstLength)) {
 | 
| -    NCBadInstructionError(dinst, "Instruction too long");
 | 
| -    NCStatsBadInstLength(vstate);
 | 
| -  }
 | 
| -
 | 
| -  switch (dinst->opinfo->insttype) {
 | 
| -    case NACLi_NOP:
 | 
| -    case NACLi_386:
 | 
| -    case NACLi_386L:
 | 
| -    case NACLi_386R:
 | 
| -    case NACLi_386RE:
 | 
| -      break;
 | 
| -    case NACLi_LAHF:
 | 
| -      if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_TARGET_SUBARCH == 64)
 | 
| -        squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_LAHF);
 | 
| -      break;
 | 
| -    case NACLi_JMP8:
 | 
| -      ValidateJmp8(dinst);
 | 
| -      break;
 | 
| -    case NACLi_JMPZ:
 | 
| -      ValidateJmpz(dinst);
 | 
| -      break;
 | 
| -    case NACLi_INDIRECT:
 | 
| -      ValidateIndirect5(dinst);
 | 
| -      break;
 | 
| -    case NACLi_X87:
 | 
| -    case NACLi_X87_FSINCOS:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_x87);
 | 
| -      break;
 | 
| -    case NACLi_SFENCE_CLFLUSH:
 | 
| -      squashme = ValidateSFenceClFlush(dinst);
 | 
| -      break;
 | 
| -    case NACLi_CMPXCHG8B:
 | 
| -      /* Only allow if the modrm mod field accesses memory.
 | 
| -       * This stops us from accepting f00f on multiple bytes.
 | 
| -       * http://en.wikipedia.org/wiki/Pentium_F00F_bug
 | 
| -       */
 | 
| -      if (modrm_modInline(dinst->inst.mrm)
 | 
| -          == kModRmModFieldDefinesRegisterRef) {
 | 
| -        NCBadInstructionError(dinst, "Illegal instruction");
 | 
| -        NCStatsIllegalInst(vstate);
 | 
| -      }
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_CX8);
 | 
| -      break;
 | 
| -    case NACLi_CMOV:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_CMOV);
 | 
| -      break;
 | 
| -    case NACLi_FCMOV:
 | 
| -      squashme = !(NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_CMOV) &&
 | 
| -                   NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_x87));
 | 
| -      break;
 | 
| -    case NACLi_RDTSC:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_TSC);
 | 
| -      break;
 | 
| -    case NACLi_MMX:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_MMX);
 | 
| -      break;
 | 
| -    case NACLi_MMXSSE2:
 | 
| -      /* Note: We accept these instructions if either MMX or SSE2 bits */
 | 
| -      /* are set, in case MMX instructions go away someday...          */
 | 
| -      squashme = !(NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_MMX) ||
 | 
| -                   NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE2));
 | 
| -      break;
 | 
| -    case NACLi_SSE:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE);
 | 
| -      break;
 | 
| -    case NACLi_SSE2:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE2);
 | 
| -      break;
 | 
| -    case NACLi_SSE3:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE3);
 | 
| -      break;
 | 
| -    case NACLi_SSE4A:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE4A);
 | 
| -      break;
 | 
| -    case NACLi_SSE41:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE41);
 | 
| -      break;
 | 
| -    case NACLi_SSE42:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE42);
 | 
| -      break;
 | 
| -    case NACLi_MOVBE:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_MOVBE);
 | 
| -      break;
 | 
| -    case NACLi_POPCNT:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_POPCNT);
 | 
| -      break;
 | 
| -    case NACLi_LZCNT:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_LZCNT);
 | 
| -      break;
 | 
| -    case NACLi_SSSE3:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSSE3);
 | 
| -      break;
 | 
| -    case NACLi_3DNOW:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_3DNOW);
 | 
| -      break;
 | 
| -    case NACLi_E3DNOW:
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_E3DNOW);
 | 
| -      break;
 | 
| -    case NACLi_SSE2x:
 | 
| -      /* This case requires CPUID checking code */
 | 
| -      /* Note: DATA16 prefix required. The generated table
 | 
| -       * for group 14 (which the only 2 SSE2x instructions are in),
 | 
| -       * allows instructions with and without a 66 prefix. However,
 | 
| -       * the SSE2x instructions psrldq and pslldq are only allowed
 | 
| -       * with the 66 prefix. Hence, this code has been added to
 | 
| -       * do this check.
 | 
| -       */
 | 
| -      if (!(dinst->inst.opcode_prefixmask & kPrefixDATA16)) {
 | 
| -        NCBadInstructionError(dinst, "Bad prefix usage");
 | 
| -        NCStatsBadPrefix(vstate);
 | 
| -      }
 | 
| -      squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE2);
 | 
| -      break;
 | 
| -
 | 
| -    case NACLi_RETURN:
 | 
| -      NCBadInstructionError(dinst, "ret instruction (not allowed)");
 | 
| -      NCStatsReturn(vstate);
 | 
| -      /* ... and fall through to illegal instruction code */
 | 
| -    case NACLi_EMMX:
 | 
| -      /* EMMX needs to be supported someday but isn't ready yet. */
 | 
| -    case NACLi_INVALID:
 | 
| -    case NACLi_ILLEGAL:
 | 
| -    case NACLi_SYSTEM:
 | 
| -    case NACLi_RDMSR:
 | 
| -    case NACLi_RDTSCP:
 | 
| -    case NACLi_SYSCALL:
 | 
| -    case NACLi_SYSENTER:
 | 
| -    case NACLi_LONGMODE:
 | 
| -    case NACLi_SVM:
 | 
| -    case NACLi_OPINMRM:
 | 
| -    case NACLi_3BYTE:
 | 
| -    case NACLi_CMPXCHG16B: {
 | 
| -        NCBadInstructionError(dinst, "Illegal instruction");
 | 
| -        NCStatsIllegalInst(vstate);
 | 
| -        break;
 | 
| -      }
 | 
| -    case NACLi_UNDEFINED: {
 | 
| -        NCBadInstructionError(dinst, "Undefined instruction");
 | 
| -        NCStatsIllegalInst(vstate);
 | 
| -        NCStatsInternalError(vstate);
 | 
| -        break;
 | 
| -      }
 | 
| -    default:
 | 
| -      NCBadInstructionError(dinst, "Undefined instruction type");
 | 
| -      NCStatsInternalError(vstate);
 | 
| -      break;
 | 
| -  }
 | 
| -  if (squashme) {
 | 
| -    if (vstate->readonly_text) {
 | 
| -      NCBadInstructionError(dinst,
 | 
| -                            "Illegal instruction for fixed-feature CPU mode");
 | 
| -      NCStatsIllegalInst(vstate);
 | 
| -    } else {
 | 
| -      NCStubOutMem(vstate, dinst->dstate->memory.mpc,
 | 
| -                   dinst->dstate->memory.read_length);
 | 
| -    }
 | 
| -  }
 | 
| -  return TRUE;
 | 
| -}
 | 
| -
 | 
| -Bool UnsafePartialValidateInst(const NCDecoderInst *dinst) {
 | 
| -  NCValidatorState *vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
 | 
| -  Bool result = FALSE;
 | 
| -
 | 
| -  NACL_FLAG_unsafe_single_inst32_mode = TRUE;
 | 
| -  NCStatsInit(vstate);
 | 
| -  if (ValidateInst(dinst)) {
 | 
| -    result = vstate->stats.sawfailure == 0;
 | 
| -  };
 | 
| -  NACL_FLAG_unsafe_single_inst32_mode = FALSE;
 | 
| -  return result;
 | 
| -}
 | 
| -
 | 
| -/*
 | 
| - * Validate that two nacljmps are byte-for-byte identical.  Note that
 | 
| - * one of the individual jumps must be validated in isolation with
 | 
| - * ValidateIndirect5() before this is called.
 | 
| - */
 | 
| -static void ValidateIndirect5Replacement(NCDecoderInst *dinst_old,
 | 
| -                                         NCDecoderInst *dinst_new) {
 | 
| -  do {
 | 
| -    /* check that the and-guard is 3 bytes and bit-for-bit identical */
 | 
| -    NCDecoderInst *andinst_old = PreviousInst(dinst_old, 1);
 | 
| -    NCDecoderInst *andinst_new = PreviousInst(dinst_new, 1);
 | 
| -    if ((andinst_old == NULL) || (andinst_old->inst.bytes.length != 3)) break;
 | 
| -    if ((andinst_new == NULL) || (andinst_new->inst.bytes.length != 3)) break;
 | 
| -    if (memcmp(andinst_old->inst.bytes.byte,
 | 
| -               andinst_new->inst.bytes.byte, 3) != 0) break;
 | 
| -
 | 
| -    /* check that the indirect-jmp is 2 bytes and bit-for-bit identical */
 | 
| -    if (dinst_old->inst.bytes.length != 2) break;
 | 
| -    if (dinst_new->inst.bytes.length != 2) break;
 | 
| -    if (memcmp(dinst_old->inst.bytes.byte,
 | 
| -               dinst_new->inst.bytes.byte, 2) != 0) break;
 | 
| -
 | 
| -    return;
 | 
| -  } while (0);
 | 
| -  NCBadInstructionError(dinst_new,
 | 
| -                        "Replacement indirect jump must match original");
 | 
| -  NCStatsUnsafeIndirect(NCVALIDATOR_STATE_DOWNCAST(dinst_new->dstate));
 | 
| -}
 | 
| -
 | 
| -/*
 | 
| - * Check that mstate_new is a valid replacement instruction for mstate_old.
 | 
| - * Note that mstate_old was validated when it was inserted originally.
 | 
| - */
 | 
| -static Bool ValidateInstReplacement(NCDecoderStatePair* tthis,
 | 
| -                                    NCDecoderInst *dinst_old,
 | 
| -                                    NCDecoderInst *dinst_new) {
 | 
| -  dinst_new->unchanged = memcmp(dinst_old->inst.bytes.byte,
 | 
| -                                dinst_new->inst.bytes.byte,
 | 
| -                                dinst_new->inst.bytes.length) == 0;
 | 
| -  ValidateInst(dinst_new);
 | 
| -
 | 
| -  if (dinst_old->opinfo->insttype == NACLi_INDIRECT
 | 
| -    || dinst_new->opinfo->insttype == NACLi_INDIRECT) {
 | 
| -    /* Verify that nacljmps never change */
 | 
| -    ValidateIndirect5Replacement(dinst_old, dinst_new);
 | 
| -  }
 | 
| -  return TRUE;
 | 
| -}
 | 
| -
 | 
| -/* Create the decoder state for the validator state, using the
 | 
| - * given parameters.
 | 
| - */
 | 
| -static void NCValidateDStateInit(NCValidatorState *vstate,
 | 
| -                                 uint8_t *mbase, NaClPcAddress vbase,
 | 
| -                                 NaClMemorySize sz) {
 | 
| -  NCDecoderState* dstate = &vstate->dstate;
 | 
| -  /* Note: Based on the current API, we must grab the error reporter
 | 
| -   * and reinstall it, after the call to NCValidateDStateInit, so that
 | 
| -   * we don't replace it with the default error reporter.
 | 
| -   */
 | 
| -  NaClErrorReporter* reporter = dstate->error_reporter;
 | 
| -  NCDecoderStateConstruct(dstate, mbase, vbase, sz,
 | 
| -                          vstate->inst_buffer, kNCValidatorInstBufferSize);
 | 
| -  dstate->action_fn = ValidateInst;
 | 
| -  dstate->new_segment_fn = (NCDecoderStateMethod) NCStatsNewSegment;
 | 
| -  dstate->segmentation_error_fn = (NCDecoderStateMethod) NCStatsSegFault;
 | 
| -  dstate->internal_error_fn = (NCDecoderStateMethod) NCStatsInternalError;
 | 
| -  NCDecoderStateSetErrorReporter(dstate, reporter);
 | 
| -}
 | 
| -
 | 
| -void NCValidateSegment(uint8_t *mbase, NaClPcAddress vbase, NaClMemorySize sz,
 | 
| -                       struct NCValidatorState *vstate) {
 | 
| -  /* Sanity checks */
 | 
| -  /* TODO(ncbray): remove redundant vbase/size args. */
 | 
| -  if ((vbase & vstate->bundle_mask) != 0) {
 | 
| -    ValidatePrintOffsetError(0, "Bad vbase alignment", vstate);
 | 
| -    NCStatsSegFault(vstate);
 | 
| -    return;
 | 
| -  }
 | 
| -  if (vbase != vstate->iadrbase) {
 | 
| -    ValidatePrintOffsetError(0, "Mismatched vbase addresses", vstate);
 | 
| -    NCStatsSegFault(vstate);
 | 
| -    return;
 | 
| -  }
 | 
| -  if (sz != vstate->codesize) {
 | 
| -    ValidatePrintOffsetError(0, "Mismatched code size", vstate);
 | 
| -    NCStatsSegFault(vstate);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  sz = NCHaltTrimSize(mbase, sz, vstate->bundle_size);
 | 
| -  vstate->codesize = sz;
 | 
| -
 | 
| -  if (sz == 0) {
 | 
| -    ValidatePrintOffsetError(0, "Bad text segment (zero size)", vstate);
 | 
| -    NCStatsSegFault(vstate);
 | 
| -    return;
 | 
| -  }
 | 
| -  NCValidateDStateInit(vstate, mbase, vbase, sz);
 | 
| -  NCDecoderStateDecode(&vstate->dstate);
 | 
| -  NCDecoderStateDestruct(&vstate->dstate);
 | 
| -}
 | 
| -
 | 
| -int NCValidateSegmentPair(uint8_t *mbase_old, uint8_t *mbase_new,
 | 
| -                          NaClPcAddress vbase, size_t sz,
 | 
| -                          const NaClCPUFeaturesX86 *features) {
 | 
| -  /* TODO(karl): Refactor to use inheritance from NCDecoderStatePair? */
 | 
| -  NCDecoderStatePair pair;
 | 
| -  NCValidatorState* new_vstate;
 | 
| -  NCValidatorState* old_vstate;
 | 
| -
 | 
| -  int result = 0;
 | 
| -
 | 
| -  /* Verify that we actually have a segment to walk. */
 | 
| -  if (sz == 0) {
 | 
| -    printf("VALIDATOR: %"NACL_PRIxNaClPcAddress
 | 
| -           ": Bad text segment (zero size)\n", vbase);
 | 
| -    return 0;
 | 
| -  }
 | 
| -
 | 
| -  old_vstate = NCValidateInit(vbase, sz, FALSE, features);
 | 
| -  if (old_vstate != NULL) {
 | 
| -    NCValidateDStateInit(old_vstate, mbase_old, vbase, sz);
 | 
| -    new_vstate = NCValidateInit(vbase, sz, FALSE, features);
 | 
| -    if (new_vstate != NULL) {
 | 
| -      NCValidateDStateInit(new_vstate, mbase_new, vbase, sz);
 | 
| -
 | 
| -      NCDecoderStatePairConstruct(&pair,
 | 
| -                                  &old_vstate->dstate,
 | 
| -                                  &new_vstate->dstate,
 | 
| -                                  NULL);  /* copy_func */
 | 
| -      pair.action_fn = ValidateInstReplacement;
 | 
| -      if (NCDecoderStatePairDecode(&pair)) {
 | 
| -        result = 1;
 | 
| -      } else {
 | 
| -        ValidatePrintOffsetError(0, "Replacement not applied!\n", new_vstate);
 | 
| -      }
 | 
| -      if (NCValidateFinish(new_vstate)) {
 | 
| -        /* Errors occurred during validation. */
 | 
| -        result = 0;
 | 
| -      }
 | 
| -      NCDecoderStatePairDestruct(&pair);
 | 
| -      NCDecoderStateDestruct(&new_vstate->dstate);
 | 
| -      NCValidateFreeState(&new_vstate);
 | 
| -    }
 | 
| -    NCDecoderStateDestruct(&old_vstate->dstate);
 | 
| -    NCValidateFreeState(&old_vstate);
 | 
| -  }
 | 
| -  return result;
 | 
| -}
 | 
| -
 | 
| -/* Walk the collected information on instruction boundaries and jump targets,
 | 
| - * and verify that they are legal.
 | 
| - */
 | 
| -static void NCJumpSummarize(struct NCValidatorState* vstate) {
 | 
| -  uint32_t offset;
 | 
| -
 | 
| -  /* Verify that jumps are to the beginning of instructions, and that the
 | 
| -   * jumped to instruction is not in the middle of a native client pattern.
 | 
| -   */
 | 
| -  dprint(("CheckTargets: %"NACL_PRIxNaClPcAddress"-%"NACL_PRIxNaClPcAddress"\n",
 | 
| -          vstate->iadrbase, vstate->iadrbase+vstate->codesize));
 | 
| -  for (offset = 0; offset < vstate->codesize; offset += 1) {
 | 
| -    if (NCGetAdrTable(offset, vstate->kttable)) {
 | 
| -      NCStatsCheckTarget(vstate);
 | 
| -      if (!NCGetAdrTable(offset, vstate->vttable)) {
 | 
| -        ValidatePrintOffsetError(offset, "Bad jump target", vstate);
 | 
| -        NCStatsBadTarget(vstate);
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /* check basic block boundaries */
 | 
| -  for (offset = 0; offset < vstate->codesize; offset += vstate->bundle_size) {
 | 
| -    if (!NCGetAdrTable(offset, vstate->vttable)) {
 | 
| -      ValidatePrintOffsetError(offset, "Bad basic block alignment", vstate);
 | 
| -      NCStatsBadAlignment(vstate);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| 
 |