Coverage for /Syzygy/block_graph/block_util_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1291290.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/block_util.h"
  16    :  
  17    :  #include "gtest/gtest.h"
  18    :  #include "syzygy/block_graph/basic_block_assembler.h"
  19    :  #include "syzygy/block_graph/basic_block_test_util.h"
  20    :  
  21    :  namespace block_graph {
  22    :  
  23    :  namespace {
  24    :  
  25    :  class BlockUtilTest: public testing::Test {
  26    :   public:
  27    :    BlockUtilTest()
  28    :        : bb_(NULL),
  29  E :          start_addr_(0xF00D) {
  30  E :      bb_ = subgraph_.AddBasicCodeBlock("foo");
  31  E :    }
  32    :  
  33  E :    BlockGraph::Size AddInstructions(bool add_source_ranges) {
  34    :      using assm::eax;
  35    :      using assm::ebp;
  36    :      using assm::esp;
  37    :  
  38  E :      BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
  39    :  
  40  E :      assm.push(ebp);
  41  E :      assm.mov(ebp, esp);
  42  E :      assm.mov(eax, Operand(ebp,  Displacement(8)));
  43  E :      assm.pop(ebp);
  44    :      // assm.ret(0);
  45    :  
  46  E :      BasicBlock::Instructions::iterator inst_it(bb_->instructions().begin());
  47  E :      BlockGraph::RelativeAddress next_addr(start_addr_);
  48    :  
  49  E :      BasicBlock::Offset next_offs = 0;
  50  E :      for (; inst_it != bb_->instructions().end(); ++inst_it) {
  51  E :        if (add_source_ranges)
  52    :          inst_it->set_source_range(
  53  E :              Instruction::SourceRange(next_addr, inst_it->size()));
  54    :  
  55  E :        next_addr += inst_it->size();
  56  E :        next_offs += inst_it->size();
  57  E :      }
  58    :  
  59  E :      BasicBlockReference ref(BlockGraph::PC_RELATIVE_REF, 4, bb_);
  60    :      bb_->successors().push_back(
  61  E :          Successor(Successor::kConditionAbove, ref, 5));
  62  E :      next_offs += 5;
  63    :  
  64  E :      if (add_source_ranges)
  65    :        bb_->successors().back().set_source_range(
  66  E :            Successor::SourceRange(next_addr, 5));
  67    :  
  68    :      bb_->successors().push_back(
  69  E :          Successor(Successor::kConditionBelowOrEqual, ref, 0));
  70    :  
  71  E :      return next_offs;
  72  E :    }
  73    :  
  74    :   protected:
  75    :    BlockGraph image_;
  76    :    BlockGraph::RelativeAddress start_addr_;
  77    :    BasicBlockSubGraph subgraph_;
  78    :    BasicCodeBlock* bb_;
  79    :  };
  80    :  
  81    :  }  // namespace
  82    :  
  83  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangeEmptyFails) {
  84  E :    AddInstructions(false);
  85  E :    BlockGraph::Block::SourceRange source_range;
  86  E :    ASSERT_FALSE(GetBasicBlockSourceRange(*bb_, &source_range));
  87  E :    EXPECT_EQ(0, source_range.size());
  88  E :  }
  89    :  
  90  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangeNonContiguousFails) {
  91  E :    AddInstructions(true);
  92    :    // Make the range non-contiguous by pushing the successor out one byte.
  93    :    BlockGraph::Block::SourceRange range =
  94  E :        bb_->successors().front().source_range();
  95    :    bb_->successors().front().set_source_range(
  96  E :        BlockGraph::Block::SourceRange(range.start() + 1, range.size()));
  97    :  
  98  E :    BlockGraph::Block::SourceRange source_range;
  99  E :    ASSERT_FALSE(GetBasicBlockSourceRange(*bb_, &source_range));
 100  E :    EXPECT_EQ(0, source_range.size());
 101  E :  }
 102    :  
 103  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangeSequentialSucceeds) {
 104  E :    BlockGraph::Size instr_len = AddInstructions(true);
 105    :  
 106  E :    BlockGraph::Block::SourceRange source_range;
 107  E :    ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
 108    :    BlockGraph::Block::SourceRange expected_range(
 109  E :        BlockGraph::RelativeAddress(0xF00D), instr_len);
 110  E :    EXPECT_EQ(expected_range, source_range);
 111  E :  }
 112    :  
 113  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangeNonSequentialSucceeds) {
 114  E :    BlockGraph::Size instr_len = AddInstructions(true);
 115    :  
 116    :    // Shuffle the ranges by flipping the first and last ranges.
 117    :    BlockGraph::Block::SourceRange temp =
 118  E :        bb_->successors().front().source_range();
 119    :    bb_->successors().front().set_source_range(
 120  E :        bb_->instructions().front().source_range());
 121  E :    bb_->instructions().front().set_source_range(temp);
 122    :  
 123  E :    BlockGraph::Block::SourceRange source_range;
 124  E :    ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
 125    :    BlockGraph::Block::SourceRange expected_range(
 126  E :        BlockGraph::RelativeAddress(0xF00D), instr_len);
 127  E :    EXPECT_EQ(expected_range, source_range);
 128  E :  }
 129    :  
 130  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangePrependInstructionsSucceeds) {
 131  E :    BlockGraph::Size instr_len = AddInstructions(true);
 132    :  
 133    :    // Prepend some instrumentation-like code.
 134  E :    BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
 135  E :    assm.push(Immediate(0xBADF00D));
 136  E :    assm.call(Immediate(bb_));
 137    :  
 138  E :    BlockGraph::Block::SourceRange source_range;
 139  E :    ASSERT_TRUE(GetBasicBlockSourceRange(*bb_, &source_range));
 140    :    BlockGraph::Block::SourceRange expected_range(
 141  E :        BlockGraph::RelativeAddress(0xF00D), instr_len);
 142  E :    EXPECT_EQ(expected_range, source_range);
 143  E :  }
 144    :  
 145  E :  TEST_F(BlockUtilTest, IsUnsafeReference) {
 146    :    // Some safe blocks.
 147  E :    BlockGraph::Block* s1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s1");
 148  E :    BlockGraph::Block* s2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s2");
 149    :  
 150    :    // Some unsafe blocks.
 151  E :    BlockGraph::Block* u1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "u1");
 152  E :    u1->set_attribute(BlockGraph::HAS_INLINE_ASSEMBLY);
 153  E :    BlockGraph::Block* u2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "u2");
 154  E :    u2->set_attribute(BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
 155    :  
 156    :    // If neither or only one has an unsafe attribute then it's not unsafe.
 157    :    EXPECT_FALSE(IsUnsafeReference(s1, BlockGraph::Reference(
 158    :        BlockGraph::PC_RELATIVE_REF,
 159    :        BlockGraph::Reference::kMaximumSize,
 160  E :        s2, 0, 0)));
 161    :    EXPECT_FALSE(IsUnsafeReference(s1, BlockGraph::Reference(
 162    :        BlockGraph::PC_RELATIVE_REF,
 163    :        BlockGraph::Reference::kMaximumSize,
 164  E :        u1, 0, 0)));
 165    :    EXPECT_FALSE(IsUnsafeReference(u2, BlockGraph::Reference(
 166    :        BlockGraph::PC_RELATIVE_REF,
 167    :        BlockGraph::Reference::kMaximumSize,
 168  E :        s2, 0, 0)));
 169    :  
 170    :    // If the reference points to a non-zero offset then it's unsafe.
 171    :    EXPECT_TRUE(IsUnsafeReference(s1, BlockGraph::Reference(
 172    :        BlockGraph::PC_RELATIVE_REF,
 173    :        BlockGraph::Reference::kMaximumSize,
 174  E :        s2, 4, 4)));
 175    :  
 176    :    // If both the referring and referred blocks have unsafe attributes,
 177    :    // the reference is unsafe.
 178    :    EXPECT_TRUE(IsUnsafeReference(u1, BlockGraph::Reference(
 179    :        BlockGraph::PC_RELATIVE_REF,
 180    :        BlockGraph::Reference::kMaximumSize,
 181  E :        u2, 0, 0)));
 182  E :  }
 183    :  
 184  E :  TEST_F(BlockUtilTest, CheckNoUnexpectedStackFrameManipulation) {
 185    :    // Prepend some instrumentation with a conventional calling convention.
 186  E :    BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
 187  E :    assm.push(assm::ebp);
 188  E :    assm.mov(assm::ebp, assm::esp);
 189  E :    assm.mov(assm::eax, Operand(assm::ebp,  Displacement(8)));
 190  E :    assm.pop(assm::ebp);
 191  E :    assm.ret(0);
 192    :  
 193  E :    EXPECT_FALSE(HasUnexpectedStackFrameManipulation(&subgraph_));
 194  E :  }
 195    :  
 196  E :  TEST_F(BlockUtilTest, CheckInvalidInstructionUnexpectedStackFrameManipulation) {
 197    :    // Prepend some instrumentation with a conventional calling convention.
 198  E :    BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
 199  E :    assm.push(assm::ebp);
 200  E :    assm.mov(assm::ebp, assm::esp);
 201    :    // The instruction LEA is invalid stack frame manipulation.
 202  E :    assm.lea(assm::ebp, Operand(assm::ebp,  Displacement(8)));
 203  E :    assm.pop(assm::ebp);
 204  E :    assm.ret(0);
 205    :  
 206  E :    EXPECT_TRUE(HasUnexpectedStackFrameManipulation(&subgraph_));
 207  E :  }
 208    :  
 209  E :  TEST_F(BlockUtilTest, CheckInvalidRegisterUnexpectedStackFrameManipulation) {
 210    :    // Prepend some instrumentation with a conventional calling convention.
 211  E :    BasicBlockAssembler assm(bb_->instructions().begin(), &bb_->instructions());
 212  E :    assm.push(assm::ebp);
 213    :    // The instruction MOV use an invalid register EAX.
 214  E :    assm.mov(assm::ebp, assm::eax);
 215  E :    assm.lea(assm::ebp, Operand(assm::ebp,  Displacement(8)));
 216  E :    assm.pop(assm::ebp);
 217  E :    assm.ret(0);
 218    :  
 219  E :    EXPECT_TRUE(HasUnexpectedStackFrameManipulation(&subgraph_));
 220  E :  }
 221    :  
 222    :  namespace {
 223    :  
 224    :  // A utility class for using the test data built around the function in
 225    :  // basic_block_assembly_func.asm.
 226    :  class BlockUtilOnTestDataTest : public testing::BasicBlockTest {
 227    :   public:
 228  E :    virtual void SetUp() override {
 229  E :      BasicBlockTest::SetUp();
 230  E :      ASSERT_NO_FATAL_FAILURE(InitBlockGraph());
 231  E :    }
 232    :  };
 233    :  
 234    :  }  // namespace
 235    :  
 236  E :  TEST_F(BlockUtilOnTestDataTest, GetJumpTableSize) {
 237    :    block_graph::BlockGraph::BlockMap::const_iterator block_iter =
 238  E :        block_graph_.blocks().begin();
 239    :  
 240  E :    size_t table_size = 0;
 241  E :    bool table_found = false;
 242    :  
 243    :    // Iterates over the blocks of the block_graph. We expect to find only one
 244    :    // block containing one jump table.
 245  E :    for (; block_iter != block_graph_.blocks().end(); ++block_iter) {
 246  E :      if (block_iter->second.type() != BlockGraph::CODE_BLOCK)
 247  E :        continue;
 248    :  
 249    :      // Iterates over the labels of the block to find the jump tables.
 250    :      BlockGraph::Block::LabelMap::const_iterator iter_label =
 251  E :          block_iter->second.labels().begin();
 252  E :      for (; iter_label != block_iter->second.labels().end(); ++iter_label) {
 253  E :        if (!iter_label->second.has_attributes(BlockGraph::JUMP_TABLE_LABEL))
 254  E :          continue;
 255    :  
 256    :        // There's only one jump table in the test data.
 257  E :        EXPECT_FALSE(table_found);
 258  E :        table_found = true;
 259    :  
 260    :        EXPECT_TRUE(block_graph::GetJumpTableSize(&block_iter->second,
 261    :                                                  iter_label,
 262  E :                                                  &table_size));
 263  E :      }
 264  E :    }
 265  E :    EXPECT_EQ(3U, table_size);
 266  E :  }
 267    :  
 268    :  }  // namespace block_graph

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