Coverage for /Syzygy/block_graph/basic_block_assembler_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
99.6%2272280.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/block_graph/basic_block_assembler.h"
  16    :  
  17    :  #include "gtest/gtest.h"
  18    :  
  19    :  namespace block_graph {
  20    :  
  21    :  namespace {
  22    :  
  23    :  class BasicBlockAssemblerTest : public testing::Test {
  24    :   public:
  25    :    typedef BlockGraph::RelativeAddress RelativeAddress;
  26    :    typedef BlockGraph::Block::SourceRange SourceRange;
  27    :  
  28    :    BasicBlockAssemblerTest();
  29    :  
  30  E :    void SetUp() OVERRIDE {
  31  E :    }
  32    :  
  33  E :    void TearDown() OVERRIDE {
  34  E :    }
  35    :  
  36    :   protected:
  37    :    struct Ref {
  38    :      size_t offset;
  39    :      BasicBlockReference::ReferredType type;
  40    :      const void* reference;
  41    :    };
  42    :  
  43    :    template <size_t N>
  44  E :    void AssertRefs(const Ref(& refs)[N]) {
  45  E :      ASSERT_EQ(1, instructions_.size());
  46  E :      const Instruction& instr = instructions_.front();
  47    :  
  48  E :      for (size_t i = 0; i < N; ++i) {
  49    :        BasicBlock::BasicBlockReferenceMap::const_iterator it =
  50  E :            instr.references().find(refs[i].offset);
  51  E :        ASSERT_NE(instr.references().end(), it);
  52  E :        ASSERT_EQ(refs[i].type, it->second.referred_type());
  53  E :        switch (refs[i].type) {
  54    :          case BasicBlockReference::REFERRED_TYPE_BLOCK:
  55  E :            ASSERT_EQ(refs[i].reference, it->second.block());
  56  E :            break;
  57    :          case BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK:
  58  E :            ASSERT_EQ(refs[i].reference, it->second.basic_block());
  59  E :            break;
  60    :          default:
  61  i :            ASSERT_TRUE(false);
  62    :        }
  63    :  
  64  E :        ASSERT_EQ(refs[i].type, it->second.referred_type());
  65  E :      }
  66    :  
  67  E :      instructions_.clear();
  68  E :    }
  69    :  
  70  E :    void AssertNoRefs() {
  71  E :      ASSERT_EQ(1, instructions_.size());
  72  E :      ASSERT_EQ(0, instructions_.front().references().size());
  73  E :      instructions_.clear();
  74  E :    }
  75    :  
  76    :    BlockGraph::Block test_block_;
  77    :    BasicCodeBlock test_bb_;
  78    :    BasicBlock::Instructions instructions_;
  79    :    BasicBlockAssembler asm_;
  80    :  };
  81    :  
  82    :  #define ASSERT_REFS(...) \
  83    :    do { \
  84    :      const Ref refs[] = { __VA_ARGS__ }; \
  85    :      ASSERT_NO_FATAL_FAILURE(AssertRefs(refs)); \
  86    :    } while (0)
  87    :  
  88    :  #define ASSERT_NO_REFS() ASSERT_NO_FATAL_FAILURE(AssertNoRefs())
  89    :  
  90    :  BasicBlockAssemblerTest::BasicBlockAssemblerTest()
  91    :      : test_block_(99, BlockGraph::CODE_BLOCK, 10, "test block"),
  92    :        test_bb_("foo"),
  93  E :        asm_(instructions_.end(), &instructions_) {
  94  E :  }
  95    :  
  96    :  void TestValue(const Value& value,
  97    :                 uint32 expected_value,
  98  E :                 core::ValueSize expected_size) {
  99  E :    EXPECT_EQ(expected_size, value.size());
 100  E :    EXPECT_EQ(expected_value, value.value());
 101    :    EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
 102  E :              value.reference().referred_type());
 103    :  
 104  E :    Value value_copy(value);
 105  E :    EXPECT_EQ(expected_size, value_copy.size());
 106  E :    EXPECT_EQ(expected_value, value_copy.value());
 107    :    EXPECT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
 108  E :              value_copy.reference().referred_type());
 109    :  
 110  E :    EXPECT_TRUE(value == value_copy);
 111    :  
 112  E :    Value value_diff(expected_value - 1);
 113  E :    EXPECT_FALSE(value == value_diff);
 114  E :  }
 115    :  
 116  E :  void Test8BitValue(uint32 input_value, uint32 expected_value) {
 117  E :    TestValue(Value(input_value), expected_value, core::kSize8Bit);
 118    :    TestValue(
 119  E :        Value(input_value, core::kSize8Bit), expected_value, core::kSize8Bit);
 120  E :  }
 121    :  
 122  E :  void Test32BitValue(uint32 input_value, uint32 expected_value) {
 123  E :    TestValue(Value(input_value), expected_value, core::kSize32Bit);
 124    :    TestValue(
 125  E :        Value(input_value, core::kSize32Bit), expected_value, core::kSize32Bit);
 126  E :  }
 127    :  
 128    :  }  // namespace
 129    :  
 130    :  typedef BasicBlockAssemblerTest ValueTest;
 131    :  
 132  E :  void TestValueCopy(const Value& input) {
 133    :    // Make sure copy-constructing the value works.
 134  E :    Value copy(input);
 135    :  
 136  E :    ASSERT_EQ(input.value(), copy.value());
 137  E :    ASSERT_EQ(input.size(), copy.size());
 138    :    ASSERT_EQ(input.reference().referred_type(),
 139  E :              copy.reference().referred_type());
 140  E :    ASSERT_EQ(input.reference().block(), copy.reference().block());
 141  E :    ASSERT_EQ(input.reference().basic_block(), copy.reference().basic_block());
 142  E :    ASSERT_EQ(input.reference().offset(), copy.reference().offset());
 143  E :    ASSERT_EQ(input.reference().base(), copy.reference().base());
 144    :  
 145    :    // Make sure assignment operator works.
 146  E :    Value copy2;
 147  E :    copy2 = input;
 148  E :    ASSERT_EQ(input.value(), copy2.value());
 149  E :    ASSERT_EQ(input.size(), copy2.size());
 150    :    ASSERT_EQ(input.reference().referred_type(),
 151  E :              copy2.reference().referred_type());
 152  E :    ASSERT_EQ(input.reference().block(), copy2.reference().block());
 153  E :    ASSERT_EQ(input.reference().basic_block(), copy2.reference().basic_block());
 154  E :    ASSERT_EQ(input.reference().offset(), copy2.reference().offset());
 155  E :    ASSERT_EQ(input.reference().base(), copy2.reference().base());
 156  E :  }
 157    :  
 158  E :  TEST_F(ValueTest, Construction) {
 159    :    {
 160  E :      Value value_empty;
 161  E :      ASSERT_EQ(0, value_empty.value());
 162  E :      ASSERT_EQ(core::kSizeNone, value_empty.size());
 163    :      ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_UNKNOWN,
 164  E :                value_empty.reference().referred_type());
 165    :  
 166  E :      TestValueCopy(value_empty);
 167  E :    }
 168    :  
 169  E :    Test8BitValue(0, 0);
 170  E :    Test8BitValue(127, 127);
 171    :  
 172  E :    Test8BitValue(-128, 0xFFFFFF80);
 173  E :    Test8BitValue(0, 0);
 174  E :    Test8BitValue(127, 0x0000007F);
 175    :  
 176  E :    Test32BitValue(128, 0x00000080);
 177  E :    Test32BitValue(0xCAFEBABE, 0xCAFEBABE);
 178    :  
 179  E :    Test32BitValue(-129, 0xFFFFFF7F);
 180  E :    Test32BitValue(128, 0x000000080);
 181  E :    Test32BitValue(0xBABE, 0xBABE);
 182    :  
 183    :    {
 184  E :      const BlockGraph::Offset kOffs = 10;
 185  E :      Value value_block_ref(&test_block_, kOffs);
 186    :  
 187  E :      ASSERT_EQ(0, value_block_ref.value());
 188  E :      ASSERT_EQ(core::kSize32Bit, value_block_ref.size());
 189    :      ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BLOCK,
 190  E :                value_block_ref.reference().referred_type());
 191  E :      ASSERT_EQ(&test_block_, value_block_ref.reference().block());
 192  E :      ASSERT_EQ(kOffs, value_block_ref.reference().offset());
 193  E :      ASSERT_EQ(0, value_block_ref.reference().base());
 194    :  
 195  E :      TestValueCopy(value_block_ref);
 196  E :    }
 197    :  
 198    :    {
 199  E :      Value value_bb_ref(&test_bb_);
 200    :  
 201  E :      ASSERT_EQ(0, value_bb_ref.value());
 202  E :      ASSERT_EQ(core::kSize32Bit, value_bb_ref.size());
 203    :      ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK,
 204  E :                value_bb_ref.reference().referred_type());
 205  E :      ASSERT_EQ(&test_bb_, value_bb_ref.reference().basic_block());
 206  E :      ASSERT_EQ(0, value_bb_ref.reference().offset());
 207  E :      ASSERT_EQ(0, value_bb_ref.reference().base());
 208    :  
 209  E :      TestValueCopy(value_bb_ref);
 210  E :    }
 211    :  
 212    :    {
 213    :      // Explicitly specified size and reference info.
 214  E :      BasicBlockReference ref(BlockGraph::PC_RELATIVE_REF, 1, &test_block_, 1, 2);
 215  E :      Value value_expl_ref(0xBE, core::kSize8Bit, ref);
 216    :  
 217  E :      ASSERT_EQ(0xBE, value_expl_ref.value());
 218  E :      ASSERT_EQ(core::kSize8Bit, value_expl_ref.size());
 219    :      ASSERT_EQ(BasicBlockReference::REFERRED_TYPE_BLOCK,
 220  E :                value_expl_ref.reference().referred_type());
 221  E :      ASSERT_EQ(&test_block_, value_expl_ref.reference().block());
 222  E :      ASSERT_EQ(1, value_expl_ref.reference().offset());
 223  E :      ASSERT_EQ(2, value_expl_ref.reference().base());
 224    :  
 225  E :      TestValueCopy(value_expl_ref);
 226  E :    }
 227  E :  }
 228    :  
 229    :  typedef BasicBlockAssemblerTest OperandTest;
 230    :  
 231  E :  void TestOperandCopy(const Operand& input) {
 232  E :    Operand copy(input);
 233    :  
 234  E :    ASSERT_EQ(input.base(), copy.base());
 235  E :    ASSERT_EQ(input.index(), copy.index());
 236  E :    ASSERT_EQ(input.scale(), copy.scale());
 237  E :    ASSERT_EQ(input.displacement().value(), copy.displacement().value());
 238  E :    ASSERT_EQ(input.displacement().size(), copy.displacement().size());
 239  E :    ASSERT_EQ(input.displacement().reference(), copy.displacement().reference());
 240    :  
 241  E :    Operand copy2(core::eax);
 242    :  
 243  E :    copy2 = input;
 244  E :    ASSERT_EQ(input.base(), copy2.base());
 245  E :    ASSERT_EQ(input.index(), copy2.index());
 246  E :    ASSERT_EQ(input.scale(), copy2.scale());
 247  E :    ASSERT_EQ(input.displacement().value(), copy2.displacement().value());
 248  E :    ASSERT_EQ(input.displacement().size(), copy2.displacement().size());
 249  E :    ASSERT_EQ(input.displacement().reference(), copy2.displacement().reference());
 250  E :  }
 251    :  
 252  E :  TEST_F(OperandTest, Construction) {
 253    :    // A register-indirect.
 254  E :    TestOperandCopy(Operand(core::eax));
 255    :  
 256    :    // Register-indirect with displacement.
 257  E :    TestOperandCopy(Operand(core::eax, Displacement(100)));
 258  E :    TestOperandCopy(Operand(core::eax, Displacement(&test_block_, 2)));
 259  E :    TestOperandCopy(Operand(core::eax, Displacement(&test_bb_)));
 260    :  
 261    :    // Displacement-only mode.
 262  E :    TestOperandCopy(Operand(Displacement(100)));
 263  E :    TestOperandCopy(Operand(Displacement(&test_block_, 2)));
 264  E :    TestOperandCopy(Operand(Displacement(&test_bb_)));
 265    :  
 266    :    TestOperandCopy(Operand(core::eax,
 267    :                            core::ebp,
 268    :                            core::kTimes2,
 269  E :                            Displacement(100)));
 270    :    TestOperandCopy(Operand(core::eax,
 271    :                            core::ebp,
 272    :                            core::kTimes2,
 273  E :                            Displacement(&test_block_, 2)));
 274    :    TestOperandCopy(Operand(core::eax,
 275    :                            core::ebp,
 276    :                            core::kTimes2,
 277  E :                            Displacement(&test_bb_)));
 278    :  
 279    :    // The [base + index * scale] mode - no displ.
 280  E :    TestOperandCopy(Operand(core::eax, core::ebp, core::kTimes2));
 281    :  
 282    :    // The [index * scale + displ32] mode - no base.
 283    :    TestOperandCopy(Operand(core::ebp,
 284    :                            core::kTimes2,
 285  E :                            Displacement(100)));
 286    :    TestOperandCopy(Operand(core::ebp,
 287    :                            core::kTimes2,
 288  E :                            Displacement(&test_block_, 2)));
 289    :    TestOperandCopy(Operand(core::ebp,
 290    :                            core::kTimes2,
 291  E :                            Displacement(&test_bb_)));
 292  E :  }
 293    :  
 294  E :  TEST_F(BasicBlockAssemblerTest, call) {
 295  E :    asm_.call(Immediate(0xCAFEBABE));
 296  E :    ASSERT_NO_REFS();
 297    :  
 298  E :    asm_.call(Immediate(&test_block_, 0));
 299  E :    ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
 300    :  
 301  E :    asm_.call(Operand(Displacement(&test_bb_)));
 302  E :    ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
 303  E :  }
 304    :  
 305  E :  TEST_F(BasicBlockAssemblerTest, jmp) {
 306  E :    asm_.jmp(Immediate(0xCAFEBABE));
 307  E :    ASSERT_NO_REFS();
 308    :  
 309  E :    asm_.jmp(Immediate(&test_block_, 0));
 310  E :    ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
 311    :  
 312  E :    asm_.jmp(Operand(Displacement(&test_bb_)));
 313  E :    ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
 314  E :  }
 315    :  
 316  E :  TEST_F(BasicBlockAssemblerTest, mov_b) {
 317    :    // mov [base + index * scale + displ], immediate
 318    :    asm_.mov(Operand(core::eax, core::ebx, core::kTimes4,
 319    :                     Displacement(&test_block_, 0)),
 320  E :             Immediate(10));
 321  E :    ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
 322  E :  }
 323    :  
 324  E :  TEST_F(BasicBlockAssemblerTest, mov) {
 325    :    // Simple register-register move.
 326  E :    asm_.mov(core::eax, core::ebx);
 327  E :    ASSERT_NO_REFS();
 328    :  
 329    :    // Simple immediate-register move.
 330  E :    asm_.mov(core::eax, Immediate(10));
 331  E :    ASSERT_NO_REFS();
 332    :  
 333    :    // Immediate-with reference to register.
 334  E :    asm_.mov(core::eax, Immediate(&test_block_, 0));
 335  E :    ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
 336    :  
 337    :    // Torture test; mov [displ], immediate,
 338    :    // both src and dst contain references.
 339  E :    asm_.mov(Operand(Displacement(&test_block_, 0)), Immediate(&test_bb_));
 340    :    ASSERT_REFS(2, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_,
 341  E :                6, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
 342    :  
 343    :    // Torture test; mov [base + index * scale + displ], immediate,
 344    :    // both src and dst contain references.
 345    :    asm_.mov(Operand(core::eax, core::ebx, core::kTimes4,
 346    :                     Displacement(&test_block_, 0)),
 347  E :             Immediate(&test_bb_));
 348    :    ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_,
 349  E :                7, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
 350  E :  }
 351    :  
 352  E :  TEST_F(BasicBlockAssemblerTest, lea) {
 353  E :    asm_.lea(core::eax, Operand(core::eax));
 354  E :    ASSERT_NO_REFS();
 355    :  
 356    :    asm_.lea(core::eax,
 357    :             Operand(core::eax, core::ebx, core::kTimes4,
 358  E :                     Displacement(&test_bb_)));
 359  E :    ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
 360  E :  }
 361    :  
 362  E :  TEST_F(BasicBlockAssemblerTest, push) {
 363  E :    asm_.push(core::esp);
 364  E :    ASSERT_NO_REFS();
 365    :  
 366  E :    asm_.push(Immediate(&test_block_, 0));
 367  E :    ASSERT_REFS(1, BasicBlockReference::REFERRED_TYPE_BLOCK, &test_block_);
 368    :  
 369    :    asm_.push(Operand(core::eax, core::ebx, core::kTimes4,
 370  E :                      Displacement(&test_bb_)));
 371  E :    ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
 372  E :  }
 373    :  
 374  E :  TEST_F(BasicBlockAssemblerTest, pop) {
 375  E :    asm_.pop(core::ebp);
 376  E :    ASSERT_NO_REFS();
 377    :  
 378    :    asm_.pop(Operand(core::eax, core::ebx, core::kTimes4,
 379  E :                      Displacement(&test_bb_)));
 380  E :    ASSERT_REFS(3, BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK, &test_bb_);
 381  E :  }
 382    :  
 383  E :  TEST_F(BasicBlockAssemblerTest, ret) {
 384  E :    asm_.ret();
 385  E :    ASSERT_NO_REFS();
 386    :  
 387  E :    asm_.ret(4);
 388  E :    ASSERT_NO_REFS();
 389  E :  }
 390    :  
 391  E :  TEST_F(BasicBlockAssemblerTest, UndefinedSourceRange) {
 392  E :    ASSERT_EQ(asm_.source_range(), SourceRange());
 393  E :    asm_.call(Immediate(0xCAFEBABE));
 394  E :    ASSERT_EQ(instructions_.back().source_range(), SourceRange());
 395  E :  }
 396    :  
 397  E :  TEST_F(BasicBlockAssemblerTest, SetSourceRange) {
 398  E :    SourceRange range(RelativeAddress(10), 10);
 399  E :    asm_.set_source_range(range);
 400  E :    asm_.call(Immediate(0xCAFEBABE));
 401  E :    ASSERT_EQ(instructions_.back().source_range(), range);
 402  E :  }
 403    :  
 404  E :  TEST_F(BasicBlockAssemblerTest, SetMultipleSourceRange) {
 405  E :    SourceRange range1(RelativeAddress(10), 10);
 406  E :    SourceRange range2(RelativeAddress(20), 20);
 407    :  
 408  E :    asm_.set_source_range(range1);
 409  E :    asm_.call(Immediate(0xCAFEBABE));
 410  E :    ASSERT_EQ(instructions_.back().source_range(), range1);
 411    :  
 412  E :    asm_.set_source_range(range2);
 413  E :    asm_.pop(core::ebp);
 414  E :    ASSERT_EQ(instructions_.back().source_range(), range2);
 415    :  
 416  E :    asm_.ret(4);
 417  E :    ASSERT_EQ(instructions_.back().source_range(), range2);
 418  E :  }
 419    :  
 420    :  }  // namespace basic_block

Coverage information generated Thu Mar 14 11:53:36 2013.