/*
 * 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.
 */

// Unit tests for code in nc_inst_state.cc (and nc_inst_state_statics.c).

#ifndef NACL_TRUSTED_BUT_NOT_TCB
#error("This file is not meant for use in the TCB")
#endif

// To turn on debugging of instruction decoding, change value of
// DEBUGGING to 1.
#define DEBUGGING 0

#include "gtest/gtest.h"
#include "native_client/src/include/nacl_macros.h"
#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state.h"
#include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h"

// Include static functions, so that we can test.
extern "C" {
#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_statics.c"
};

namespace {

// Size of buffer to use to contain bytes of an instruction.
static const size_t kBufferSize = 24;

// Test harness for routines in nc_inst_state.c and nc_inst_state_statics.c.
class NcInstStateTests : public ::testing::Test {
 protected:
  NcInstStateTests();
  void SetUp();
  void TearDown();

  // Plant the given byte as the next input byte in the input buffer.
  // Uses plant_index to determine the current end of the input buffer.
  void Plant(uint8_t byte);

  // Reset test state to a cleared input buffer, and (re)initialize
  // the instruction state.
  void Reset();

  // Routine to add dummy calls so that compilation errors are not defined
  // for static routines we have not tested.
  void dummy();

  // Reinitializes instruction state.
  void ResetState();

  // Resets the instruction pattern, and its flags to a default initial
  // state.
  void ResetInstPattern();

  // Fills the input buffer with unlikely bytes, and initializes
  // the reader to the beginning of the input buffer.
  void ResetInput();

  // Fills the input buffer with unlikely bytes, and set the plant
  // index to the beginning of the input buffer.
  void ResetInputBuffer();

  // Verify that we have consumed the given number of prefix bytes, with
  // the given number of rex prefixes, and that the prefix mask is set
  // to the given mask.
  //
  // Parameters are:
  //   num_bytes - Number of prefix bytes read.
  //   num_rex   - Number of prefix bytes that were rex prefixes.
  //   mask      - prefix mask that should have been generated.
  void VerifyConsumedPrefixBytes(uint8_t num_bytes, uint8_t num_rex,
                                 uint32_t mask);

  // Run tests that verify that the call to NaClConsume0F38XXNaClInstBytes
  // behaved as expected. Assumes the call was made through a call
  // to NaClConsumeInstBytes.
  void VerifyConsume0F38XXInstructions();

  // Run tests that verify that the call to NaClConsume0F3AXXNaClInstBytes
  // behaved as expected. Assumes the call was made through a call
  // to NaClConsumeInstBytes.
  void VerifyConsume0F3AXXInstructions();

  // Run tests that verify that the call to NaClConsume0FXXNaClInstBytes
  // behaved as expected.  Assumes the call was made through a call
  // to NaClConsumeInstBytes.
  void VerifyConsume0FXXInstructions();

  // Run tests that verify that the call to NaClConsumeX87NaClInstBytes
  // behaved as expected.  Assumes the call was made through a call
  // to NaClConsumeInstBytes.
  void VerifyConsumeX87Instructions();

  // Run tests that verify that the call to NaClConsumeInstBytes consumed
  // a single byte.
  void VerifyConsumeOneByteInstructions();

  // The instruction state to test.
  struct NaClInstState* _state;
  // The instruction iterator to use.
  struct NaClInstIter* _iter;
  // The memory segment to test.
  struct NaClSegment _segment;
  // The memory buffer in the memory segment.
  uint8_t _buffer[kBufferSize];
  // The instruction pattern to match against.
  struct NaClInst _inst_pattern;
  // The index of where the next planted byte should
  // be added to the input buffer.
  size_t _plant_index;
};

// Helper function to convert Bool to bool. This function is defined
// to get around a visual studio warning for 64-bits, which causes
// our trybots to fail (in our build system, compiler warnings are converted
// to compiler errors).
static inline bool Bool2bool(Bool b) {
  return b ? true : false;
}

NcInstStateTests::NcInstStateTests() {
  ResetInputBuffer();
  NaClSegmentInitialize(_buffer, 0, kBufferSize, &_segment);
}

void NcInstStateTests::SetUp() {
  _iter = NaClInstIterCreate(kNaClDecoderTables, &_segment);
  _state = NaClInstIterGetUndecodedState(_iter);
  ResetInput();
  ResetState();
}

void NcInstStateTests::TearDown() {
  NaClInstIterDestroy(_iter);
}

void NcInstStateTests::Reset() {
  ResetInput();
  ResetState();
}

void NcInstStateTests::ResetState() {
  NaClInstStateInit(_iter, _state);
  ResetInstPattern();
}

void NcInstStateTests::ResetInstPattern() {
  _inst_pattern.flags = NACL_EMPTY_IFLAGS;
  _state->inst = &_inst_pattern;
}

void NcInstStateTests::ResetInputBuffer() {
  // Fill input buffer with unlikely byte codes.
  for (size_t i = 0; i < kBufferSize; ++i) {
    _buffer[i] = 'X';
  }
  // Mark start point for planting data into
  // the input buffer.
  _plant_index = 0;
}

void NcInstStateTests::ResetInput() {
  ResetInputBuffer();
  NCInstBytesReset(&_state->bytes);
}

void NcInstStateTests::Plant(uint8_t byte) {
  // TODO(Karl): Why do we get a compile time error if we use ASSERT.
  ASSERT_LT(_plant_index, kBufferSize) <<
      "Planted too many bytes, buffer overflow!";
  _buffer[_plant_index++] = byte;
  // Need to reset memory so that peek byte is set.
  NCRemainingMemoryReset(_state->bytes.memory);
}

void NcInstStateTests::VerifyConsumedPrefixBytes(
    uint8_t num_bytes, uint8_t num_rex, uint32_t mask) {
  EXPECT_EQ(num_bytes, _state->bytes.length);
  EXPECT_EQ(num_bytes, _state->num_prefix_bytes);
  EXPECT_EQ(mask, _state->prefix_mask);
  EXPECT_EQ(num_rex, _state->num_rex_prefixes);
}

void NcInstStateTests::VerifyConsume0F38XXInstructions() {
  NaClInstPrefixDescriptor desc;
  uint32_t prefix_mask = _state->prefix_mask;
  // Note: This code assumes that the prefix mask may have
  // other flags set before this routine is called. Hence,
  // we must be careful when updating and checking the
  // mask.

  // Test for all possible XX.
  for (int i = 0; i < NCDTABLESIZE; ++i) {
    // Test successfully matching 0f38XX
    _state->prefix_mask = prefix_mask;
    Plant(0x0f);
    Plant(0x38);
    Plant(i);
    NaClConsumeInstBytes(_state, &desc);
    if (NaClHasBit(_state->prefix_mask, kPrefixREP)) {
      EXPECT_EQ(NaClInstPrefixEnumSize, desc.matched_prefix);
    } else if (NaClHasBit(_state->prefix_mask, kPrefixREPNE)) {
      EXPECT_EQ(PrefixF20F38, desc.matched_prefix);
    } else if (NaClHasBit(_state->prefix_mask, kPrefixDATA16)) {
      EXPECT_EQ(Prefix660F38, desc.matched_prefix);
    } else {
      EXPECT_EQ(Prefix0F38, desc.matched_prefix);
    }
    EXPECT_EQ((uint8_t) i, desc.opcode_byte);
    EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
    ResetInput();
    ResetState();
  }

  // Now verify if that there isn't an XX byte, things short curcuit correctly.
  _state->prefix_mask = prefix_mask;
  Plant(0x0f);
  Plant(0x38);
  _state->length_limit = 2;
  NaClConsumeInstBytes(_state, &desc);
  EXPECT_EQ(NaClInstPrefixEnumSize, desc.matched_prefix);
  EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
  ResetInput();
  ResetState();
}

void NcInstStateTests::VerifyConsume0F3AXXInstructions() {
  NaClInstPrefixDescriptor desc;
  uint32_t prefix_mask = _state->prefix_mask;
  // Note: This code assumes that the prefix mask may have
  // other flags set before this routine is called. Hence,
  // we must be careful when updating and checking the
  // mask.

  // Test for all possible XX.
  for (int i = 0; i < NCDTABLESIZE; ++i) {
    // Test successfully matching 0F3AXX
    _state->prefix_mask = prefix_mask;
    Plant(0x0f);
    Plant(0x3a);
    Plant(i);
    NaClConsumeInstBytes(_state, &desc);
    if (NaClHasBit(_state->prefix_mask, kPrefixREP) ||
        NaClHasBit(_state->prefix_mask, kPrefixREPNE)) {
      EXPECT_EQ(NaClInstPrefixEnumSize, desc.matched_prefix);
    } else if (NaClHasBit(_state->prefix_mask, kPrefixDATA16)) {
      EXPECT_EQ(Prefix660F3A, desc.matched_prefix);
    } else {
      EXPECT_EQ(Prefix0F3A, desc.matched_prefix);
    }
    EXPECT_EQ((uint8_t) i, desc.opcode_byte);
    EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
    ResetInput();
    ResetState();
  }

  // Now verify if that there isn't an XX byte, things short curcuit correctly.
  _state->prefix_mask = prefix_mask;
  Plant(0x0f);
  Plant(0x3a);
  _state->length_limit = 2;
  NaClConsumeInstBytes(_state, &desc);
  EXPECT_EQ(NaClInstPrefixEnumSize, desc.matched_prefix);
  EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
  ResetInput();
  ResetState();
}

void NcInstStateTests::VerifyConsume0FXXInstructions() {
  NaClInstPrefixDescriptor desc;
  uint32_t prefix_mask = _state->prefix_mask;
  // Note: This code assumes that the prefix mask may have
  // other flags set before this routine is called. Hence,
  // we must be careful when updating and checking the
  // mask.

  // Test for all possible XX.
  for (int i = 0; i < NCDTABLESIZE; ++i) {
    if (i == 0x38 || i == 0x3a) continue;  // exclude special lookup cases.
    // Test successfully matching 0fXX
    _state->prefix_mask = prefix_mask;
    Plant(0x0f);
    Plant(i);
    NaClConsumeInstBytes(_state, &desc);
    if (NaClHasBit(_state->prefix_mask, kPrefixREP)) {
      if (NaClHasBit(_state->prefix_mask, kPrefixREPNE)) {
        EXPECT_EQ(NaClInstPrefixEnumSize, desc.matched_prefix);
      } else {
        EXPECT_EQ(PrefixF30F, desc.matched_prefix);
      }
    } else if (NaClHasBit(_state->prefix_mask, kPrefixREPNE)) {
      EXPECT_EQ(PrefixF20F, desc.matched_prefix);
    } else if (NaClHasBit(_state->prefix_mask, kPrefixDATA16)) {
      EXPECT_EQ(Prefix660F, desc.matched_prefix);
    } else {
      EXPECT_EQ(Prefix0F, desc.matched_prefix);
    }
    EXPECT_EQ((uint8_t) i, desc.opcode_byte);
    EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
    ResetInput();
    ResetState();
  }

  // Now verify if that there isn't an XX byte, things short curcuit correctly.
  _state->prefix_mask = prefix_mask;
  Plant(0x0f);
  _state->length_limit = 1;
  NaClConsumeInstBytes(_state, &desc);
  EXPECT_EQ(NaClInstPrefixEnumSize, desc.matched_prefix);
  EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
  ResetInput();
  ResetState();
}

void NcInstStateTests::VerifyConsumeX87Instructions() {
  NaClInstPrefixDescriptor desc;
  uint32_t prefix_mask = _state->prefix_mask;
  // Note: This code assumes that the prefix mask may have
  // other flags set before this routine is called. Hence,
  // we must be careful when updating and checking the
  // mask.

  // Try for all possible x87 initial bytes.
  for (uint8_t byte1 = 0xD8; byte1 <= 0xDF; ++byte1) {
    // Test for all possible XX.
    for (int i = 0; i < NCDTABLESIZE; ++i) {
      // Test successfully matching byte1 XX
      _state->prefix_mask = prefix_mask;
      Plant(byte1);
      Plant(i);
      NaClConsumeInstBytes(_state, &desc);
      NaClInstPrefix prefix = (NaClInstPrefix) (PrefixD8 + (byte1 - 0xD8));
      EXPECT_EQ(prefix, desc.matched_prefix);
      EXPECT_EQ((uint8_t) i, desc.opcode_byte);
      EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
      ResetInput();
      ResetState();
    }

    // Now verify if that there isn't an XX byte, things short curcuit
    // correctly. For this context, it should return matching a single
    // byte instruction with no prefix.
    _state->prefix_mask = prefix_mask;
    Plant(byte1);
    _state->length_limit = 1;
    NaClConsumeInstBytes(_state, &desc);
    EXPECT_EQ(NoPrefix, desc.matched_prefix);
    EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
    ResetInput();
    ResetState();
  }
}

void NcInstStateTests::VerifyConsumeOneByteInstructions() {
  NaClInstPrefixDescriptor desc;
  uint32_t prefix_mask = _state->prefix_mask;
  // Note: This code assumes that the prefix mask may have
  // other flags set before this routine is called. Hence,
  // we must be careful when updating and checking the
  // mask.

  // Test for all possible XX.
  for (int i = 0; i < NCDTABLESIZE; ++i) {
    // exclude special lookup cases.
    if (i == 0x0f || (i >= 0xD8 && i <= 0xDF)) continue;
    // Test successfully XX
    _state->prefix_mask = prefix_mask;
    Plant(i);
    NaClConsumeInstBytes(_state, &desc);
    EXPECT_EQ(NoPrefix, desc.matched_prefix);
    EXPECT_EQ((uint8_t) i, desc.opcode_byte);
    EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
    ResetInput();
    ResetState();
  }

  // Now verify if that there isn't an XX byte, things short curcuit correctly.
  _state->prefix_mask = prefix_mask;
  _state->length_limit = 0;
  NaClConsumeInstBytes(_state, &desc);
  EXPECT_EQ(NaClInstPrefixEnumSize, desc.matched_prefix);
  EXPECT_EQ((uint8_t) 0, desc.next_length_adjustment);
  ResetInput();
  ResetState();
}

void NcInstStateTests::dummy() {
  NaClInstPrefixDescriptor prefix_desc;
  prefix_desc.opcode_byte = 0x0;
  prefix_desc.next_length_adjustment = 0;
  prefix_desc.matched_prefix = NoPrefix;
  NaClConsumeAndCheckOperandSize(_state);
  NaClConsumeAndCheckAddressSize(_state);
  NaClConsumeModRm(_state);
  NaClConsumeSib(_state);
  NaClConsumeDispBytes(_state);
  NaClConsumeImmediateBytes(_state);
  NaClValidatePrefixFlags(_state);
  NaClClearInstState(_state, 0);
  NaClGetNextInstCandidates(_state, &prefix_desc, NULL);
  NaClConsumeHardCodedNop(_state);
}

// Test function NaClExtactOpSize, which returns the expected
// number of bytes to represent operands.
TEST_F(NcInstStateTests, TestExtractOpSize) {
  // Test 32 amd 64 bit assumptions.

  // Test explicit size restrictors. Note: Only b should make a difference
  // in matching the pattern, since v, w, and o are used as excluders rather
  // than for matching (i.e. don't match unless operand size should be
  // 1).
  _inst_pattern.flags = NACL_IFLAG(OperandSize_b);
  EXPECT_EQ(1, NaClExtractOpSize(_state)) << "bytes are of size 1\n";
  _inst_pattern.flags = NACL_IFLAG(OperandSize_w);
  EXPECT_EQ(4, NaClExtractOpSize(_state));
  _inst_pattern.flags = NACL_IFLAG(OperandSize_v);
  EXPECT_EQ(4, NaClExtractOpSize(_state));
  _inst_pattern.flags = NACL_IFLAG(OperandSize_o);
  EXPECT_EQ(4, NaClExtractOpSize(_state));
  ResetState();

  // See if we interpret the Data16 prefix correctly.
  _state->prefix_mask = kPrefixDATA16;
  EXPECT_EQ(2, NaClExtractOpSize(_state));
  _inst_pattern.flags = NACL_IFLAG(SizeIgnoresData16);
  EXPECT_EQ(4, NaClExtractOpSize(_state));
  ResetState();

  // Test strictly 64-bit assumptions.
  if (NACL_TARGET_SUBARCH == 64) {
    // Check that we return a size 64 if the REX.W bit is set.
    for (uint8_t rex = NaClRexMin; rex <= NaClRexMax; ++rex) {
      _state->rexprefix = rex;
      if (NaClRexW(rex)) {
        EXPECT_EQ(8, NaClExtractOpSize(_state));
      } else {
        EXPECT_EQ(4, NaClExtractOpSize(_state));
      }
    }
    ResetState();

    // If we force the size to 64, it returns size 64.
    _inst_pattern.flags = NACL_IFLAG(OperandSizeForce64);
    EXPECT_EQ(8, NaClExtractOpSize(_state));
    ResetState();

    // Now repeat the tests, but with the default size set to 64 bits,
    // which replaces the default size of 4 with 8.

    // Test explicit size restrictors. Note: Only b should make a difference
    // in matching the pattern, since v, w, and o are used as excluders rather
    // than for matching (i.e. don't match unless operand size matches).
    _inst_pattern.flags =
        NACL_IFLAG(OperandSize_b) | NACL_IFLAG(OperandSizeDefaultIs64);
    EXPECT_EQ(1, NaClExtractOpSize(_state)) << "bytes are of size 1\n";
    _inst_pattern.flags =
        NACL_IFLAG(OperandSize_w) | NACL_IFLAG(OperandSizeDefaultIs64);
    EXPECT_EQ(8, NaClExtractOpSize(_state));
    _inst_pattern.flags =
        NACL_IFLAG(OperandSize_v) | NACL_IFLAG(OperandSizeDefaultIs64);
    EXPECT_EQ(8, NaClExtractOpSize(_state));
    _inst_pattern.flags =
        NACL_IFLAG(OperandSize_o) | NACL_IFLAG(OperandSizeDefaultIs64);
    EXPECT_EQ(8, NaClExtractOpSize(_state));
    ResetState();

    // See if we interpret the Data16 prefix correctly.
    _state->prefix_mask = kPrefixDATA16;
    _inst_pattern.flags = NACL_IFLAG(OperandSizeDefaultIs64);
    EXPECT_EQ(2, NaClExtractOpSize(_state));
    _inst_pattern.flags =
        NACL_IFLAG(SizeIgnoresData16) | NACL_IFLAG(OperandSizeDefaultIs64);
    EXPECT_EQ(8, NaClExtractOpSize(_state));
    ResetState();

    // Check that we return a size 64 independent of the REX.W bit.
    _inst_pattern.flags = NACL_IFLAG(OperandSizeDefaultIs64);
    for (uint8_t rex = NaClRexMin; rex <= NaClRexMax; ++rex) {
      _state->rexprefix = rex;
      EXPECT_EQ(8, NaClExtractOpSize(_state));
    }
  }
}

// Test function NaClExtractAddressSize, which returns the expected
// number of bits in operands corresponding to addresses.
TEST_F(NcInstStateTests, TestExtractAddressSize) {
  // Depending on whether we are in 32/64 bit mode, there are two
  // different address sizes.
  int small_address;
  int large_address;
  if (NACL_TARGET_SUBARCH == 64) {
    small_address = 32;
    large_address = 64;
  } else {
    small_address = 16;
    large_address = 32;
  }
  EXPECT_EQ(large_address, NaClExtractAddressSize(_state));
  _state->prefix_mask = kPrefixADDR16;
  EXPECT_EQ(small_address, NaClExtractAddressSize(_state));
}

extern "C" {
  // Define acceptable prefixes, and the corresponding flag that
  // should be set (except for rex prefixes).
  static const struct  prefix_pairs {
    uint8_t byte;
    uint32_t mask;
  } prefix_values[] = {
    {kValueSEGCS, kPrefixSEGCS},
    {kValueSEGSS, kPrefixSEGSS},
    {kValueSEGFS, kPrefixSEGFS},
    {kValueSEGGS, kPrefixSEGGS},
    {kValueDATA16, kPrefixDATA16},
    {kValueADDR16, kPrefixADDR16},
    {kValueREPNE, kPrefixREPNE},
    {kValueREP, kPrefixREP},
    {kValueLOCK, kPrefixLOCK},
    {kValueSEGES, kPrefixSEGES},
    {kValueSEGDS, kPrefixSEGDS}
  };
};

// Test function NaClConsumePrefixBytes to verify it only recognizes
// valid prefix values.
TEST_F(NcInstStateTests, ConsumesKnownPrefixBytes) {
  for (int byte = 0; byte < NCDTABLESIZE; ++byte) {
    bool byte_categorized = false;
    Plant(byte);
    EXPECT_TRUE(Bool2bool(NaClConsumePrefixBytes(_state)));
    if (NACL_TARGET_SUBARCH == 64 &&
        byte >= NaClRexMin && byte <= NaClRexMax) {
      VerifyConsumedPrefixBytes(1, 1, kPrefixREX);
      byte_categorized = true;
    } else {
      for (size_t j = 0; j < NACL_ARRAY_SIZE(prefix_values); ++j) {
        if (byte == prefix_values[j].byte) {
          VerifyConsumedPrefixBytes(1, 0, prefix_values[j].mask);
          byte_categorized = true;
        }
      }
    }
    if (!byte_categorized) {
      VerifyConsumedPrefixBytes(0, 0, 0);
    }
    ResetInput();
    ResetState();
  }
}

// Test function NaClConsumePrefixBytes to verify it can recognize
// pairs of non-rex prefix bytes.
TEST_F(NcInstStateTests, ConsumeNonRexPrefixBytePairs) {
  // First try some pairs within non-rex prefix bytes.
  for (size_t i = 0; i < NACL_ARRAY_SIZE(prefix_values) - 1; ++i) {
    Plant(prefix_values[i].byte);
    Plant(prefix_values[i+1].byte);
    EXPECT_TRUE(Bool2bool(NaClConsumePrefixBytes(_state)));
    VerifyConsumedPrefixBytes(2, 0,
                              prefix_values[i].mask | prefix_values[i+1].mask);
    ResetInput();
    ResetState();
  }
}

// Test Function NaClConsumePrefixBytes to verify it can recognize
// a Rex prefix followed by a non-rex prefix.
TEST_F(NcInstStateTests, ConsumeRexThenNonRexPrefixPairs) {
  if (NACL_TARGET_SUBARCH == 64) {
    // Try some pairs where one is rex.
    for (size_t i = 0; i < NACL_ARRAY_SIZE(prefix_values); ++i) {
      for (uint8_t rex = NaClRexMin; rex <= NaClRexMax; ++rex) {
        Plant(rex);
        Plant(prefix_values[i].byte);
        EXPECT_TRUE(Bool2bool(NaClConsumePrefixBytes(_state)));
        VerifyConsumedPrefixBytes(2, 1, prefix_values[i].mask | kPrefixREX);
        ResetInput();
        ResetState();
      }
    }
  }
}

// Test Function NaClConsumePrefixBytes to verify it can recognize
// a non-rex prefix, followed by a rex prefix.
TEST_F(NcInstStateTests, ConsumeNonRexThenRexPrefixPairs) {
  if (NACL_TARGET_SUBARCH == 64) {
    // Try some pairs where one is rex.
    for (size_t i = 0; i < NACL_ARRAY_SIZE(prefix_values); ++i) {
      for (uint8_t rex = NaClRexMin; rex <= NaClRexMax; ++rex) {
        Plant(prefix_values[i].byte);
        Plant(rex);
        EXPECT_TRUE(Bool2bool(NaClConsumePrefixBytes(_state)));
        VerifyConsumedPrefixBytes(2, 1, prefix_values[i].mask | kPrefixREX);
        ResetInput();
        ResetState();
      }
    }
  }
}

// Test function NaClConsumePrefixBytes on multiple rex prefixes.
TEST_F(NcInstStateTests, ConsumeMultipleRexPrefixes) {
  if (NACL_TARGET_SUBARCH == 64) {
    for (uint8_t rex1 = NaClRexMin; rex1 <= NaClRexMax; ++rex1) {
      for (uint8_t rex2 = NaClRexMin; rex2 <= NaClRexMax; ++rex2) {
        Plant(rex1);
        Plant(rex2);
        EXPECT_TRUE(Bool2bool(NaClConsumePrefixBytes(_state)));
        VerifyConsumedPrefixBytes(2, 2, kPrefixREX);
        ResetInput();
        ResetState();
      }
    }
  }
}

// Test function NaClConsumePrefixBytes to see if we allow multiple
// copies of the same (non-rex) prefix.
TEST_F(NcInstStateTests, ConsumeDuplicatePrefixes) {
  // Try with non rex prefixes.
  for (size_t i = 0; i < NACL_ARRAY_SIZE(prefix_values); ++i) {
    Plant(prefix_values[i].byte);
    Plant(prefix_values[i].byte);
    EXPECT_TRUE(Bool2bool(NaClConsumePrefixBytes(_state)));
    VerifyConsumedPrefixBytes(2, 0, prefix_values[i].mask);
    ResetInput();
    ResetState();
  }
}

// Test if we can recognize 14 prefix bytes.
TEST_F(NcInstStateTests, Consume14PrefixBytes) {
  for (int i = 0; i < 14; ++i) {
    Plant(kValueDATA16);
  }
  EXPECT_TRUE(Bool2bool(NaClConsumePrefixBytes(_state)));
  VerifyConsumedPrefixBytes(14, 0, kPrefixDATA16);
}

// Test that we can't accept 15 prefix bytes.
TEST_F(NcInstStateTests, Consume15PrefixBytes) {
  for (int i = 0; i < 15; ++i) {
    Plant(kValueDATA16);
  }
  EXPECT_TRUE(Bool2bool(NaClConsumePrefixBytes(_state)));
  EXPECT_EQ((uint8_t) 14, _state->bytes.length);
}

// Defines the set of prefix bytes that effect multibyte instructions
// (i.e. REP, REPNE,  and DATA16), and all possible combinations of
// these prefixes.
static const uint32_t kMultibytePrefixes[] = {
  0,
  kPrefixREP,
  kPrefixREP | kPrefixREPNE,
  kPrefixREP | kPrefixREPNE | kPrefixDATA16,
  kPrefixREPNE,
  kPrefixREPNE | kPrefixDATA16,
  kPrefixDATA16
};

// Test function NaClConsume0F38XXNaClInstBytes, as called through
// function NaClConsumeInstBytes.
TEST_F(NcInstStateTests, ConsumeOF38XXInstructions) {
  // First try effects of just multibyte prefixes.
  for (size_t i = 0; i < NACL_ARRAY_SIZE(kMultibytePrefixes); ++i) {
    _state->prefix_mask = kMultibytePrefixes[i];
    VerifyConsume0F38XXInstructions();

    // Verify that adding a rex prefix don't effect anything.
    _state->prefix_mask = kMultibytePrefixes[i] | kPrefixREX;
    VerifyConsume0F38XXInstructions();

    // Now try adding other possible prefixes to see if they break anything.
    for (size_t j = 0; j < NACL_ARRAY_SIZE(prefix_values); ++j) {
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask;
      VerifyConsume0F38XXInstructions();

      // Verify that adding a rex prefix don't effect anything.
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask
          | kPrefixREX;
      VerifyConsume0F38XXInstructions();
    }
  }
}

// Test function NaClConsume0F3AXXNaClInstBytes, as called through
// function NaClConsumeInstBytes.
TEST_F(NcInstStateTests, ConsumeOF3AXXInstructions) {
  // First try effects of just multibyte prefixes.
  for (size_t i = 0; i < NACL_ARRAY_SIZE(kMultibytePrefixes); ++i) {
    _state->prefix_mask = kMultibytePrefixes[i];
    VerifyConsume0F3AXXInstructions();

    // Verify that adding a rex prefix don't effect anything.
    _state->prefix_mask = kMultibytePrefixes[i] | kPrefixREX;
    VerifyConsume0F3AXXInstructions();

    // Now try adding other possible prefixes to see if they break anything.
    for (size_t j = 0; j < NACL_ARRAY_SIZE(prefix_values); ++j) {
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask;
      VerifyConsume0F3AXXInstructions();

      // Verify that adding a rex prefix don't effect anything.
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask
          | kPrefixREX;
      VerifyConsume0F3AXXInstructions();
    }
  }
}

// Test function NaClConsume0FXXNaClInstBytes, as called through
// function NaClConsumeInstBytes.
TEST_F(NcInstStateTests, ConsumeOFXXInstructions) {
  // First try effects of just multibyte prefixes.
  for (size_t i = 0; i < NACL_ARRAY_SIZE(kMultibytePrefixes); ++i) {
    _state->prefix_mask = kMultibytePrefixes[i];
    VerifyConsume0FXXInstructions();

    // Verify that adding a rex prefix don't effect anything.
    _state->prefix_mask = kMultibytePrefixes[i] | kPrefixREX;
    VerifyConsume0FXXInstructions();

    // Now try adding other possible prefixes to see if they break anything.
    for (size_t j = 0; j < NACL_ARRAY_SIZE(prefix_values); ++j) {
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask;
      VerifyConsume0FXXInstructions();

      // Verify that adding a rex prefix don't effect anything.
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask
          | kPrefixREX;
      VerifyConsume0FXXInstructions();
    }
  }
}

// Test function NaClConsumeX87NaClInstBytes, as called through
// function NaClConsumeInstBytes.
TEST_F(NcInstStateTests, ConsumeX87Instructions) {
  // First try effects of just multibyte prefixes.
  for (size_t i = 0; i < NACL_ARRAY_SIZE(kMultibytePrefixes); ++i) {
    _state->prefix_mask = kMultibytePrefixes[i];
    VerifyConsumeX87Instructions();

    // Verify that adding a rex prefix don't effect anything.
    _state->prefix_mask = kMultibytePrefixes[i] | kPrefixREX;
    VerifyConsumeX87Instructions();

    // Now try adding other possible prefixes to see if they break anything.
    for (size_t j = 0; j < NACL_ARRAY_SIZE(prefix_values); ++j) {
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask;
      VerifyConsumeX87Instructions();

      // Verify that adding a rex prefix don't effect anything.
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask
          | kPrefixREX;
      VerifyConsumeX87Instructions();
    }
  }
}

// Test function NaClConsumeInstBytes for one byte instruction values.
TEST_F(NcInstStateTests, ConsumeOneByteInstructions) {
  // First try effects of just multibyte prefixes.
  for (size_t i = 0; i < NACL_ARRAY_SIZE(kMultibytePrefixes); ++i) {
    _state->prefix_mask = kMultibytePrefixes[i];
    VerifyConsumeOneByteInstructions();

    // Verify that adding a rex prefix don't effect anything.
    _state->prefix_mask = kMultibytePrefixes[i] | kPrefixREX;
    VerifyConsumeOneByteInstructions();

    // Now try adding other possible prefixes to see if they break anything.
    for (size_t j = 0; j < NACL_ARRAY_SIZE(prefix_values); ++j) {
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask;
      VerifyConsumeOneByteInstructions();

      // Verify that adding a rex prefix don't effect anything.
      _state->prefix_mask = kMultibytePrefixes[i] | prefix_values[i].mask
          | kPrefixREX;
      VerifyConsumeOneByteInstructions();
    }
  }
}

};  // anonymous namespace

int main(int argc, char *argv[]) {
  NaClLogModuleInit();
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
