Coverage for /Syzygy/core/disassembler_util_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1781780.C++test

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/core/disassembler_util.h"
  16    :  
  17    :  #include "base/basictypes.h"
  18    :  #include "base/logging.h"
  19    :  #include "gmock/gmock.h"
  20    :  #include "gtest/gtest.h"
  21    :  #include "syzygy/assm/unittest_util.h"
  22    :  
  23    :  namespace core {
  24    :  
  25    :  namespace {
  26    :  
  27    :  // Decompose a block of code using distorm wrapper.
  28    :  _DecodeResult DecomposeCode(const uint8* code_data,
  29    :                              size_t length,
  30    :                              _DInst result[],
  31    :                              const unsigned int max_results,
  32  E :                              unsigned int* result_count) {
  33  E :    _CodeInfo code = {};
  34  E :    code.dt = Decode32Bits;
  35  E :    code.features = DF_NONE;
  36  E :    code.codeOffset = 0;
  37  E :    code.codeLen = length;
  38  E :    code.code = code_data;
  39  E :    return DistormDecompose(&code, result, max_results, result_count);
  40  E :  }
  41    :  
  42    :  // Decompose a block of code using distorm directly.
  43    :  _DecodeResult RawDecomposeCode(const uint8* code_data,
  44    :                                 size_t length,
  45    :                                 _DInst result[],
  46    :                                 const unsigned int max_results,
  47  E :                                 unsigned int* result_count) {
  48  E :    _CodeInfo code = {};
  49  E :    code.dt = Decode32Bits;
  50  E :    code.features = DF_NONE;
  51  E :    code.codeOffset = 0;
  52  E :    code.codeLen = length;
  53  E :    code.code = code_data;
  54  E :    return distorm_decompose(&code, result, max_results, result_count);
  55  E :  }
  56    :  
  57  E :  _DInst DecodeBuffer(const uint8* buffer, size_t length) {
  58  E :    _DInst inst = {};
  59  E :    EXPECT_TRUE(DecodeOneInstruction(buffer, length, &inst));
  60  E :    EXPECT_EQ(length, inst.size);
  61  E :    return inst;
  62  E :  }
  63    :  
  64    :  // One of the AVX instructions that is currently not supported by distorm.
  65    :  // vxorps ymm0, ymm0, ymm0
  66    :  const uint8 kVxorps[] = { 0xC5, 0xFC, 0x57, 0xC0 };
  67    :  
  68    :  // Instructions for which distorm indicates a size of 0 for the destination
  69    :  // operand size.
  70    :  // fnstcw m16
  71    :  const uint8 kFnstcw[] = { 0xD9, 0x7D, 0xEA };
  72    :  // fldcw m16
  73    :  const uint8 kFldcw[] = { 0xD9, 0x6D, 0xE4 };
  74    :  
  75    :  // Instructions for which distorm do not activated the write flag.
  76    :  // fst qword ptr [0A374E8h]
  77    :  const uint8 kFst[] = { 0xDD, 0x15, 0xE8, 0x74, 0xA3, 0x00 };
  78    :  // fstp qword ptr [0A374E8h]
  79    :  const uint8 kFstp[] = { 0xDD, 0x1D, 0xE8, 0x74, 0xA3, 0x00 };
  80    :  // fist qword ptr [0A374E8h]
  81    :  const uint8 kFist[] = { 0xDB, 0x15, 0xE0, 0x74, 0xA3, 0x00 };
  82    :  // fistp qword ptr [0A374E8h]
  83    :  const uint8 kFistp[] = { 0xDB, 0x1D, 0xE0, 0x74, 0xA3, 0x00 };
  84    :  
  85    :  // Nop Instruction byte sequences.
  86    :  const uint8 kNop2Mov[] = { 0x8B, 0xFF };
  87    :  const uint8 kNop3Lea[] = { 0x8D, 0x49, 0x00 };
  88    :  // The recommended NOP sequences.
  89    :  using testing::kNop1;
  90    :  using testing::kNop2;
  91    :  using testing::kNop3;
  92    :  using testing::kNop4;
  93    :  using testing::kNop5;
  94    :  using testing::kNop6;
  95    :  using testing::kNop7;
  96    :  using testing::kNop8;
  97    :  using testing::kNop9;
  98    :  using testing::kNop10;
  99    :  using testing::kNop11;
 100    :  
 101    :  // Call instruction.
 102    :  const uint8 kCall[] = { 0xE8, 0xCA, 0xFE, 0xBA, 0xBE };
 103    :  
 104    :  // Control Flow byte sequences (note that the JMP is indirect).
 105    :  const uint8 kJmp[] = { 0xFF, 0x24, 0x8D, 0xCA, 0xFE, 0xBA, 0xBE };
 106    :  const uint8 kRet[] = { 0xC3 };
 107    :  const uint8 kRetN[] = { 0xC2, 0x08, 0x00 };
 108    :  const uint8 kJe[] = { 0x74, 0xCA };
 109    :  const uint8 kSysEnter[] = { 0x0F, 0x34 };
 110    :  const uint8 kSysExit[] = { 0x0F, 0x35 };
 111    :  
 112    :  // Interrupts.
 113    :  const uint8 kInt2[] = { 0xCD, 0x02 };
 114    :  const uint8 kInt3[] = { 0xCC };
 115    :  
 116    :  // Improperly handled 3-byte VEX encoded instructions.
 117    :  const uint8 kVpermq[] = { 0xC4, 0xE3, 0xFD, 0x00, 0xED, 0x44 };
 118    :  const uint8 kVpermd[] = { 0xC4, 0xE2, 0x4D, 0x36, 0xC0 };
 119    :  const uint8 kVbroadcasti128[] = { 0xC4, 0xE2, 0x7D, 0x5A, 0x45, 0xD0 };
 120    :  const uint8 kVinserti128[] = { 0xC4, 0xE3, 0x7D, 0x38, 0x2C, 0x0F, 0x01 };
 121    :  const uint8 kVpbroadcastb[] = { 0xC4, 0xE2, 0x79, 0x78, 0xC0 };
 122    :  const uint8 kVextracti128[] = { 0xC4, 0xE3, 0x7D, 0x39, 0xC8, 0x01};
 123    :  
 124  E :  void TestBadlyDecodedInstruction(const uint8* code, size_t code_length) {
 125  E :    _DInst inst[1] = {};
 126  E :    unsigned int inst_count = 0;
 127    :    _DecodeResult result = RawDecomposeCode(
 128  E :        code, code_length, inst, arraysize(inst), &inst_count);
 129  E :    EXPECT_EQ(DECRES_MEMORYERR, result);
 130  E :    EXPECT_EQ(0u, inst_count);
 131    :  
 132    :    result = DecomposeCode(
 133  E :        code, code_length, inst, arraysize(inst), &inst_count);
 134  E :    EXPECT_EQ(DECRES_SUCCESS, result);
 135  E :    EXPECT_EQ(1u, inst_count);
 136  E :    EXPECT_EQ(code_length, inst[0].size);
 137  E :  }
 138    :  
 139    :  }  // namespace
 140    :  
 141  E :  TEST(DisassemblerUtilTest, DistormWrapperVxorpsPasses) {
 142  E :    _DInst inst = {};
 143  E :    EXPECT_TRUE(DecodeOneInstruction(kVxorps, sizeof(kVxorps), &inst));
 144  E :  }
 145    :  
 146  E :  TEST(DisassemblerUtilTest, InstructionToString) {
 147  E :    _DInst inst = {};
 148  E :    inst = DecodeBuffer(kNop1, sizeof(kNop1));
 149    :  
 150  E :    std::string Nop1Str;
 151  E :    EXPECT_TRUE(InstructionToString(inst, kNop1, sizeof(kNop1), &Nop1Str));
 152  E :    ASSERT_THAT(Nop1Str, testing::HasSubstr("90"));
 153  E :    ASSERT_THAT(Nop1Str, testing::HasSubstr("NOP"));
 154  E :  }
 155    :  
 156  E :  TEST(DisassemblerUtilTest, IsNop) {
 157  E :    EXPECT_FALSE(IsNop(DecodeBuffer(kJmp, sizeof(kJmp))));
 158  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop1, sizeof(kNop1))));
 159  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop2, sizeof(kNop2))));
 160  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop3, sizeof(kNop3))));
 161  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop4, sizeof(kNop4))));
 162  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop5, sizeof(kNop5))));
 163  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop6, sizeof(kNop6))));
 164  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop7, sizeof(kNop7))));
 165  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop8, sizeof(kNop8))));
 166  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop9, sizeof(kNop9))));
 167  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop10, sizeof(kNop10))));
 168  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop11, sizeof(kNop11))));
 169  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop2Mov, sizeof(kNop2Mov))));
 170  E :    EXPECT_TRUE(IsNop(DecodeBuffer(kNop3Lea, sizeof(kNop3Lea))));
 171  E :  }
 172    :  
 173  E :  TEST(DisassemblerUtilTest, IsCall) {
 174  E :    EXPECT_FALSE(IsCall(DecodeBuffer(kJmp, sizeof(kJmp))));
 175  E :    EXPECT_FALSE(IsCall(DecodeBuffer(kNop1, sizeof(kNop1))));
 176  E :    EXPECT_TRUE(IsCall(DecodeBuffer(kCall, sizeof(kCall))));
 177  E :  }
 178    :  
 179  E :  TEST(DisassemblerUtilTest, IsSystemCall) {
 180  E :    EXPECT_FALSE(IsSystemCall(DecodeBuffer(kJmp, sizeof(kJmp))));
 181  E :    EXPECT_FALSE(IsSystemCall(DecodeBuffer(kNop1, sizeof(kNop1))));
 182  E :    EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
 183  E :    EXPECT_TRUE(IsSystemCall(DecodeBuffer(kSysExit, sizeof(kSysExit))));
 184  E :  }
 185    :  
 186  E :  TEST(DisassemblerUtilTest, IsConditionalBranch) {
 187  E :    EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
 188  E :    EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
 189  E :    EXPECT_FALSE(IsConditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
 190  E :    EXPECT_TRUE(IsConditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
 191  E :  }
 192    :  
 193  E :  TEST(DisassemblerUtilTest, IsUnconditionalBranch) {
 194  E :    EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
 195  E :    EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kRet, sizeof(kRet))));
 196  E :    EXPECT_FALSE(IsUnconditionalBranch(DecodeBuffer(kJe, sizeof(kJe))));
 197  E :    EXPECT_TRUE(IsUnconditionalBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
 198  E :  }
 199    :  
 200  E :  TEST(DisassemblerUtilTest, IsBranch) {
 201  E :    EXPECT_FALSE(IsBranch(DecodeBuffer(kNop4, sizeof(kNop4))));
 202  E :    EXPECT_FALSE(IsBranch(DecodeBuffer(kRet, sizeof(kRet))));
 203  E :    EXPECT_TRUE(IsBranch(DecodeBuffer(kJe, sizeof(kJe))));
 204  E :    EXPECT_TRUE(IsBranch(DecodeBuffer(kJmp, sizeof(kJmp))));
 205  E :  }
 206    :  
 207  E :  TEST(DisassemblerUtilTest, HasPcRelativeOperand) {
 208  E :    EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kRetN, sizeof(kRet)), 0));
 209  E :    EXPECT_FALSE(HasPcRelativeOperand(DecodeBuffer(kJmp, sizeof(kJmp)), 0));
 210  E :    EXPECT_TRUE(HasPcRelativeOperand(DecodeBuffer(kJe, sizeof(kJe)), 0));
 211  E :  }
 212    :  
 213  E :  TEST(DisassemblerUtilTest, IsControlFlow) {
 214  E :    EXPECT_FALSE(IsControlFlow(DecodeBuffer(kNop4, sizeof(kNop4))));
 215  E :    EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
 216  E :    EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
 217  E :    EXPECT_TRUE(IsControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
 218  E :    EXPECT_TRUE(IsControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
 219  E :    EXPECT_TRUE(IsControlFlow(DecodeBuffer(kSysEnter, sizeof(kSysEnter))));
 220  E :  }
 221    :  
 222  E :  TEST(DisassemblerUtilTest, IsImplicitControlFlow) {
 223  E :    EXPECT_FALSE(IsImplicitControlFlow(DecodeBuffer(kJe, sizeof(kJe))));
 224  E :    EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRet, sizeof(kRet))));
 225  E :    EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kRetN, sizeof(kRetN))));
 226  E :    EXPECT_TRUE(IsImplicitControlFlow(DecodeBuffer(kJmp, sizeof(kJmp))));
 227  E :  }
 228    :  
 229  E :  TEST(DisassemblerUtilTest, IsInterrupt) {
 230  E :    EXPECT_FALSE(IsInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
 231  E :    EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
 232  E :    EXPECT_TRUE(IsInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
 233  E :  }
 234    :  
 235  E :  TEST(DisassemblerUtilTest, IsDebugInterrupt) {
 236  E :    EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kJe, sizeof(kJe))));
 237  E :    EXPECT_FALSE(IsDebugInterrupt(DecodeBuffer(kInt2, sizeof(kInt2))));
 238  E :    EXPECT_TRUE(IsDebugInterrupt(DecodeBuffer(kInt3, sizeof(kInt3))));
 239  E :  }
 240    :  
 241  E :  TEST(DisassemblerUtilTest, GetRegisterType) {
 242  E :    EXPECT_EQ(R_DL, GetRegisterType(assm::kRegisterDl));
 243  E :    EXPECT_EQ(R_AX, GetRegisterType(assm::kRegisterAx));
 244  E :    EXPECT_EQ(R_EDI, GetRegisterType(assm::kRegisterEdi));
 245    :  
 246  E :    EXPECT_EQ(R_BH, GetRegisterType(assm::bh));
 247  E :    EXPECT_EQ(R_CX, GetRegisterType(assm::cx));
 248  E :    EXPECT_EQ(R_ESP, GetRegisterType(assm::esp));
 249  E :  }
 250    :  
 251  E :  TEST(DisassemblerUtilTest, GetRegisterId) {
 252  E :    EXPECT_EQ(assm::kRegisterAl, GetRegisterId(R_AL));
 253  E :    EXPECT_EQ(assm::kRegisterSp, GetRegisterId(R_SP));
 254  E :    EXPECT_EQ(assm::kRegisterEdi, GetRegisterId(R_EDI));
 255  E :  }
 256    :  
 257  E :  TEST(DisassemblerUtilTest, GetRegister) {
 258  E :    EXPECT_EQ(assm::bh, GetRegister(R_BH));
 259  E :    EXPECT_EQ(assm::cx, GetRegister(R_CX));
 260  E :    EXPECT_EQ(assm::ebp, GetRegister(R_EBP));
 261  E :  }
 262    :  
 263  E :  TEST(DisassemblerUtilTest, DistormDecompose) {
 264  E :    const unsigned int kMaxResults = 16;
 265  E :    unsigned int result_count = 0;
 266    :    _DInst results[kMaxResults];
 267    :    EXPECT_EQ(DECRES_SUCCESS,
 268    :              DecomposeCode(kNop3Lea,
 269    :                            sizeof(kNop3Lea),
 270    :                            results,
 271    :                            kMaxResults,
 272  E :                            &result_count));
 273  E :    EXPECT_EQ(1U, result_count);
 274  E :    EXPECT_EQ(32U, results[0].ops[0].size);
 275  E :  }
 276    :  
 277  E :  TEST(DisassemblerUtilTest, DistormDecomposeFnstcw) {
 278  E :    const unsigned int kMaxResults = 16;
 279  E :    unsigned int result_count = 0;
 280    :    _DInst results[kMaxResults];
 281    :    EXPECT_EQ(DECRES_SUCCESS,
 282    :              DecomposeCode(kFnstcw,
 283    :                            sizeof(kFnstcw),
 284    :                            results,
 285    :                            kMaxResults,
 286  E :                            &result_count));
 287  E :    EXPECT_EQ(1U, result_count);
 288  E :    EXPECT_EQ(16U, results[0].ops[0].size);
 289  E :  }
 290    :  
 291  E :  TEST(DisassemblerUtilTest, DistormDecomposeFldcw) {
 292  E :    const unsigned int kMaxResults = 16;
 293  E :    unsigned int result_count = 0;
 294    :    _DInst results[kMaxResults];
 295    :    EXPECT_EQ(DECRES_SUCCESS,
 296    :              DecomposeCode(kFldcw,
 297    :                            sizeof(kFldcw),
 298    :                            results,
 299    :                            kMaxResults,
 300  E :                            &result_count));
 301  E :    EXPECT_EQ(1U, result_count);
 302  E :    EXPECT_EQ(16U, results[0].ops[0].size);
 303  E :  }
 304    :  
 305    :  // If one of these test starts failing then Distorm now properly handles the
 306    :  // AVX2 instructions. Please remove the workaround in disassembler_util.cc.
 307    :  
 308  E :  TEST(DisassemblerUtilTest, TestBadlyDecodedVpermq) {
 309    :    EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
 310  E :        kVpermq, sizeof(kVpermq)));
 311  E :  }
 312    :  
 313  E :  TEST(DisassemblerUtilTest, TestBadlyDecodedVpermd) {
 314    :    EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
 315  E :        kVpermd, sizeof(kVpermd)));
 316  E :  }
 317    :  
 318  E :  TEST(DisassemblerUtilTest, TestBadlyDecodedVbroadcasti128) {
 319    :    EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
 320  E :        kVbroadcasti128, sizeof(kVbroadcasti128)));
 321  E :  }
 322    :  
 323  E :  TEST(DisassemblerUtilTest, TestBadlyDecodedVinserti128) {
 324    :    EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
 325  E :        kVinserti128, sizeof(kVinserti128)));
 326  E :  }
 327    :  
 328  E :  TEST(DisassemblerUtilTest, TestBadlyDecodedVpbroadcastb) {
 329    :    EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
 330  E :        kVpbroadcastb, sizeof(kVpbroadcastb)));
 331  E :  }
 332    :  
 333  E :  TEST(DisassemblerUtilTest, TestBadlyDecodedVextracti128) {
 334    :    EXPECT_NO_FATAL_FAILURE(TestBadlyDecodedInstruction(
 335  E :        kVextracti128, sizeof(kVextracti128)));
 336  E :  }
 337    :  
 338    :  }  // namespace core

Coverage information generated Thu Jan 14 17:40:38 2016.