Coverage for /Syzygy/block_graph/basic_block_assembler_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
99.5%1851860.C++test

Line-by-line coverage:

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

Coverage information generated Thu Sep 06 11:30:46 2012.