Coverage for /Syzygy/block_graph/block_util_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1081080.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    :  
  20    :  namespace block_graph {
  21    :  
  22    :  namespace {
  23    :  
  24    :  class BlockUtilTest: public testing::Test {
  25    :   public:
  26    :    BlockUtilTest()
  27    :        : bb_("foo"),
  28  E :          start_addr_(0xF00D) {
  29  E :    }
  30    :  
  31  E :    void TestAttributes(BlockGraph::BlockAttributes attributes, bool expected) {
  32  E :      BlockGraph::Block* code = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "c");
  33  E :      code->set_attributes(attributes);
  34  E :      ASSERT_EQ(expected, CodeBlockAttributesAreBasicBlockSafe(code));
  35  E :    }
  36    :  
  37  E :    BlockGraph::Size AddInstructions(bool add_source_ranges) {
  38    :      using core::eax;
  39    :      using core::ebp;
  40    :      using core::esp;
  41    :  
  42  E :      BasicBlockAssembler assm(bb_.instructions().begin(), &bb_.instructions());
  43    :  
  44  E :      assm.push(ebp);
  45  E :      assm.mov(ebp, esp);
  46  E :      assm.mov(eax, Operand(ebp,  Displacement(8)));
  47  E :      assm.pop(ebp);
  48    :      // assm.ret(0);
  49    :  
  50  E :      BasicBlock::Instructions::iterator inst_it(bb_.instructions().begin());
  51  E :      BlockGraph::RelativeAddress next_addr(start_addr_);
  52    :  
  53  E :      BasicBlock::Offset next_offs = 0;
  54  E :      for (; inst_it != bb_.instructions().end(); ++inst_it) {
  55  E :        if (add_source_ranges)
  56    :          inst_it->set_source_range(
  57  E :              Instruction::SourceRange(next_addr, inst_it->size()));
  58    :  
  59  E :        next_addr += inst_it->size();
  60  E :        next_offs += inst_it->size();
  61  E :      }
  62    :  
  63  E :      BasicBlockReference ref(BlockGraph::PC_RELATIVE_REF, 4, &bb_);
  64    :      bb_.successors().push_back(
  65  E :          Successor(Successor::kConditionAbove, ref, 5));
  66  E :      next_offs += 5;
  67    :  
  68  E :      if (add_source_ranges)
  69    :        bb_.successors().back().set_source_range(
  70  E :            Successor::SourceRange(next_addr, 5));
  71    :  
  72    :      bb_.successors().push_back(
  73  E :          Successor(Successor::kConditionBelowOrEqual, ref, 0));
  74    :  
  75  E :      return next_offs;
  76  E :    }
  77    :  
  78    :   protected:
  79    :    BlockGraph image_;
  80    :    BlockGraph::RelativeAddress start_addr_;
  81    :    BasicCodeBlock bb_;
  82    :  };
  83    :  
  84    :  }  // namespace
  85    :  
  86  E :  TEST_F(BlockUtilTest, CodeBlockAttributesAreBasicBlockSafeGapBlock) {
  87  E :    ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::GAP_BLOCK, false));
  88  E :  }
  89    :  
  90  E :  TEST_F(BlockUtilTest, CodeBlockAttributesAreBasicBlockSafePaddingBlock) {
  91  E :    ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::PADDING_BLOCK, false));
  92  E :  }
  93    :  
  94  E :  TEST_F(BlockUtilTest, CodeBlockAttributesAreBasicBlockSafeHasInlineAssembly) {
  95    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::HAS_INLINE_ASSEMBLY,
  96  E :                                           false));
  97  E :  }
  98    :  
  99  E :  TEST_F(BlockUtilTest, CodeBlockAttributesAreBasicBlockSafeUnsupportedCompiler) {
 100    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 101  E :        BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER, false));
 102  E :  }
 103    :  
 104  E :  TEST_F(BlockUtilTest, CodeBlockAttributesAreBasicBlockSafeErroredDisassembly) {
 105    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::ERRORED_DISASSEMBLY,
 106  E :                                           false));
 107  E :  }
 108    :  
 109  E :  TEST_F(BlockUtilTest, CodeBlockAttributesAreBasicBlockSafeExceptionHandling) {
 110    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::HAS_EXCEPTION_HANDLING,
 111  E :                                           false));
 112  E :  }
 113    :  
 114  E :  TEST_F(BlockUtilTest, CodeBlockAttributesAreBasicBlockSafeDisassembledPastEnd) {
 115    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(BlockGraph::DISASSEMBLED_PAST_END,
 116  E :                                           false));
 117  E :  }
 118    :  
 119  E :  TEST_F(BlockUtilTest, CodeBlockAttributesAreBasicBlockSafeBuiltBySyzygy) {
 120    :    ASSERT_NO_FATAL_FAILURE(TestAttributes(
 121  E :        BlockGraph::HAS_INLINE_ASSEMBLY | BlockGraph::BUILT_BY_SYZYGY, true));
 122  E :  }
 123    :  
 124  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangeEmptyFails) {
 125  E :    BlockGraph::Size instr_len = AddInstructions(false);
 126    :  
 127  E :    BlockGraph::Block::SourceRange source_range;
 128  E :    ASSERT_FALSE(GetBasicBlockSourceRange(bb_, &source_range));
 129  E :    EXPECT_EQ(0, source_range.size());
 130  E :  }
 131    :  
 132  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangeNonContiguousFails) {
 133  E :    BlockGraph::Size instr_len = AddInstructions(true);
 134    :  
 135    :    // Make the range non-contiguous by pushing the successor out one byte.
 136    :    BlockGraph::Block::SourceRange range =
 137  E :        bb_.successors().front().source_range();
 138    :    bb_.successors().front().set_source_range(
 139  E :        BlockGraph::Block::SourceRange(range.start() + 1, range.size()));
 140    :  
 141  E :    BlockGraph::Block::SourceRange source_range;
 142  E :    ASSERT_FALSE(GetBasicBlockSourceRange(bb_, &source_range));
 143  E :    EXPECT_EQ(0, source_range.size());
 144  E :  }
 145    :  
 146  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangeSequentialSucceeds) {
 147  E :    BlockGraph::Size instr_len = AddInstructions(true);
 148    :  
 149  E :    BlockGraph::Block::SourceRange source_range;
 150  E :    ASSERT_TRUE(GetBasicBlockSourceRange(bb_, &source_range));
 151    :    BlockGraph::Block::SourceRange expected_range(
 152  E :        BlockGraph::RelativeAddress(0xF00D), instr_len);
 153  E :    EXPECT_EQ(expected_range, source_range);
 154  E :  }
 155    :  
 156  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangeNonSequentialSucceeds) {
 157  E :    BlockGraph::Size instr_len = AddInstructions(true);
 158    :  
 159    :    // Shuffle the ranges by flipping the first and last ranges.
 160  E :    BlockGraph::Block::SourceRange temp = bb_.successors().front().source_range();
 161    :    bb_.successors().front().set_source_range(
 162  E :        bb_.instructions().front().source_range());
 163  E :    bb_.instructions().front().set_source_range(temp);
 164    :  
 165  E :    BlockGraph::Block::SourceRange source_range;
 166  E :    ASSERT_TRUE(GetBasicBlockSourceRange(bb_, &source_range));
 167    :    BlockGraph::Block::SourceRange expected_range(
 168  E :        BlockGraph::RelativeAddress(0xF00D), instr_len);
 169  E :    EXPECT_EQ(expected_range, source_range);
 170  E :  }
 171    :  
 172  E :  TEST_F(BlockUtilTest, GetBasicBlockSourceRangePrependInstructionsSucceeds) {
 173  E :    BlockGraph::Size instr_len = AddInstructions(true);
 174    :  
 175    :    // Prepend some instrumentation-like code.
 176  E :    BasicBlockAssembler assm(bb_.instructions().begin(), &bb_.instructions());
 177  E :    assm.push(Immediate(0xBADF00D));
 178  E :    assm.call(Displacement(&bb_));
 179    :  
 180  E :    BlockGraph::Block::SourceRange source_range;
 181  E :    ASSERT_TRUE(GetBasicBlockSourceRange(bb_, &source_range));
 182    :    BlockGraph::Block::SourceRange expected_range(
 183  E :        BlockGraph::RelativeAddress(0xF00D), instr_len);
 184  E :    EXPECT_EQ(expected_range, source_range);
 185  E :  }
 186    :  
 187  E :  TEST_F(BlockUtilTest, IsUnsafeReference) {
 188    :    // Some safe blocks.
 189  E :    BlockGraph::Block* s1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s1");
 190  E :    BlockGraph::Block* s2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "s2");
 191    :  
 192    :    // Some unsafe blocks.
 193  E :    BlockGraph::Block* u1 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "u1");
 194  E :    u1->set_attribute(BlockGraph::HAS_INLINE_ASSEMBLY);
 195  E :    BlockGraph::Block* u2 = image_.AddBlock(BlockGraph::CODE_BLOCK, 40, "u2");
 196  E :    u2->set_attribute(BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
 197    :  
 198    :    // If neither or only one has an unsafe attribute then it's not unsafe.
 199    :    EXPECT_FALSE(IsUnsafeReference(s1, BlockGraph::Reference(
 200    :        BlockGraph::PC_RELATIVE_REF,
 201    :        BlockGraph::Reference::kMaximumSize,
 202  E :        s2, 0, 0)));
 203    :    EXPECT_FALSE(IsUnsafeReference(s1, BlockGraph::Reference(
 204    :        BlockGraph::PC_RELATIVE_REF,
 205    :        BlockGraph::Reference::kMaximumSize,
 206  E :        u1, 0, 0)));
 207    :    EXPECT_FALSE(IsUnsafeReference(u2, BlockGraph::Reference(
 208    :        BlockGraph::PC_RELATIVE_REF,
 209    :        BlockGraph::Reference::kMaximumSize,
 210  E :        s2, 0, 0)));
 211    :  
 212    :    // If the reference points to a non-zero offset then it's unsafe.
 213    :    EXPECT_TRUE(IsUnsafeReference(s1, BlockGraph::Reference(
 214    :        BlockGraph::PC_RELATIVE_REF,
 215    :        BlockGraph::Reference::kMaximumSize,
 216  E :        s2, 4, 4)));
 217    :  
 218    :    // If both the referring and referred blocks have unsafe attributes,
 219    :    // the reference is unsafe.
 220    :    EXPECT_TRUE(IsUnsafeReference(u1, BlockGraph::Reference(
 221    :        BlockGraph::PC_RELATIVE_REF,
 222    :        BlockGraph::Reference::kMaximumSize,
 223  E :        u2, 0, 0)));
 224  E :  }
 225    :  
 226    :  }  // namespace block_graph

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