Coverage for /Syzygy/instrument/transforms/coverage_transform.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
84.2%64760.C++source

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/instrument/transforms/coverage_transform.h"
  16    :  
  17    :  #include "syzygy/block_graph/basic_block_assembler.h"
  18    :  #include "syzygy/block_graph/block_util.h"
  19    :  #include "syzygy/common/indexed_frequency_data.h"
  20    :  #include "syzygy/core/disassembler_util.h"
  21    :  #include "syzygy/pe/pe_utils.h"
  22    :  
  23    :  namespace instrument {
  24    :  namespace transforms {
  25    :  
  26    :  namespace {
  27    :  
  28    :  using common::IndexedFrequencyData;
  29    :  using common::kBasicBlockCoverageAgentId;
  30    :  using assm::eax;
  31    :  using block_graph::ApplyBasicBlockSubGraphTransform;
  32    :  using block_graph::ApplyBlockGraphTransform;
  33    :  using block_graph::BasicBlock;
  34    :  using block_graph::BasicCodeBlock;
  35    :  using block_graph::BasicBlockAssembler;
  36    :  using block_graph::BasicBlockReference;
  37    :  using block_graph::BlockGraph;
  38    :  using block_graph::Displacement;
  39    :  using block_graph::Immediate;
  40    :  using block_graph::Operand;
  41    :  using block_graph::TransformPolicyInterface;
  42    :  
  43    :  typedef CoverageInstrumentationTransform::RelativeAddressRange
  44    :      RelativeAddressRange;
  45    :  
  46    :  const BlockGraph::Offset kFrequencyDataOffset =
  47    :      offsetof(IndexedFrequencyData, frequency_data);
  48    :  
  49    :  // Compares two relative address ranges to see if they overlap. Assumes they
  50    :  // are already sorted. This is used to validate basic-block ranges.
  51    :  struct RelativeAddressRangesOverlapFunctor {
  52    :    bool operator()(const RelativeAddressRange& r1,
  53  E :                    const RelativeAddressRange& r2) const {
  54  E :      DCHECK_LT(r1.start(), r2.start());
  55    :  
  56  E :      if (r1.end() > r2.start())
  57  i :        return true;
  58    :  
  59  E :      return false;
  60  E :    }
  61    :  };
  62    :  
  63    :  }  // namespace
  64    :  
  65    :  const char CoverageInstrumentationTransform::kTransformName[] =
  66    :      "CoverageInstrumentationTransform";
  67    :  
  68    :  CoverageInstrumentationTransform::CoverageInstrumentationTransform()
  69    :      : add_bb_freq_data_tx_(kBasicBlockCoverageAgentId,
  70    :                             "Basic-Block Frequency Data",
  71    :                             common::kBasicBlockFrequencyDataVersion,
  72    :                             common::IndexedFrequencyData::COVERAGE,
  73  E :                             sizeof(common::IndexedFrequencyData)) {
  74    :    // Initialize the EntryThunkTransform.
  75  E :    entry_thunk_tx_.set_instrument_unsafe_references(false);
  76  E :    entry_thunk_tx_.set_only_instrument_module_entry(true);
  77  E :  }
  78    :  
  79    :  bool CoverageInstrumentationTransform::TransformBasicBlockSubGraph(
  80    :      const TransformPolicyInterface* policy,
  81    :      BlockGraph* block_graph,
  82  E :      BasicBlockSubGraph* basic_block_subgraph) {
  83  E :    DCHECK(policy != NULL);
  84  E :    DCHECK(block_graph != NULL);
  85  E :    DCHECK(basic_block_subgraph != NULL);
  86    :  
  87  E :    BlockGraph::Block* data_block = add_bb_freq_data_tx_.frequency_data_block();
  88  E :    DCHECK(data_block != NULL);
  89  E :    DCHECK_EQ(sizeof(IndexedFrequencyData), data_block->data_size());
  90    :  
  91    :    // Iterate over the basic blocks.
  92    :    BasicBlockSubGraph::BBCollection::iterator it =
  93  E :        basic_block_subgraph->basic_blocks().begin();
  94  E :    for (; it != basic_block_subgraph->basic_blocks().end(); ++it) {
  95    :      // We're only interested in code blocks.
  96  E :      BasicCodeBlock* bb = BasicCodeBlock::Cast(*it);
  97  E :      if (bb == NULL)
  98  E :        continue;
  99    :  
 100    :      // Find the source range associated with this basic-block.
 101  E :      BlockGraph::Block::SourceRange source_range;
 102  E :      if (!GetBasicBlockSourceRange(*bb, &source_range)) {
 103  i :        LOG(ERROR) << "Unable to get source range for basic block '"
 104    :                   << bb->name() << "'";
 105  i :        return false;
 106    :      }
 107    :  
 108    :      // We prepend each basic code block with the following instructions:
 109    :      //   0. push eax
 110    :      //   1. mov eax, dword ptr[data.frequency_data]
 111    :      //   2. mov byte ptr[eax + basic_block_index], 1
 112    :      //   3. pop eax
 113  E :      BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
 114    :  
 115    :      // Prepend the instrumentation instructions.
 116  E :      assm.push(eax);
 117  E :      assm.mov(eax, Operand(Displacement(data_block, kFrequencyDataOffset)));
 118  E :      assm.mov_b(Operand(eax, Displacement(bb_ranges_.size())), Immediate(1));
 119  E :      assm.pop(eax);
 120    :  
 121  E :      bb_ranges_.push_back(source_range);
 122  E :    }
 123    :  
 124  E :    return true;
 125  E :  }
 126    :  
 127    :  bool CoverageInstrumentationTransform::PreBlockGraphIteration(
 128    :      const TransformPolicyInterface* policy,
 129    :      BlockGraph* block_graph,
 130  E :      BlockGraph::Block* header_block) {
 131  E :    DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
 132  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 133  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
 134  E :    DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
 135    :  
 136    :    if (!ApplyBlockGraphTransform(
 137  E :            &add_bb_freq_data_tx_, policy, block_graph, header_block)) {
 138  i :      LOG(ERROR) << "Failed to insert basic-block frequency data.";
 139  i :      return false;
 140    :    }
 141    :  
 142  E :    return true;
 143  E :  }
 144    :  
 145    :  bool CoverageInstrumentationTransform::OnBlock(
 146    :      const TransformPolicyInterface* policy,
 147    :      BlockGraph* block_graph,
 148  E :      BlockGraph::Block* block) {
 149  E :    DCHECK(policy != NULL);
 150  E :    DCHECK(block_graph != NULL);
 151  E :    DCHECK(block != NULL);
 152    :  
 153    :    // We only care about blocks that are safe for basic block decomposition.
 154  E :    if (!policy->BlockIsSafeToBasicBlockDecompose(block))
 155  E :      return true;
 156    :  
 157    :    // Apply our basic block transform.
 158    :    if (!ApplyBasicBlockSubGraphTransform(
 159  E :        this, policy, block_graph, block, NULL)) {
 160  i :      return false;
 161    :    }
 162    :  
 163  E :    return true;
 164  E :  }
 165    :  
 166    :  bool CoverageInstrumentationTransform::PostBlockGraphIteration(
 167    :      const TransformPolicyInterface* policy,
 168    :      BlockGraph* block_graph,
 169  E :      BlockGraph::Block* header_block) {
 170  E :    DCHECK(policy != NULL);
 171  E :    DCHECK(block_graph != NULL);
 172  E :    DCHECK(header_block != NULL);
 173    :  
 174    :    // Get a reference to the frequency data and make that the parameter that
 175    :    // we pass to the entry thunks. We run the thunk transform after the coverage
 176    :    // instrumentation transform as it creates new code blocks that we don't
 177    :    // want to instrument.
 178    :    auto ref_to_freq_data(
 179  E :        Immediate(add_bb_freq_data_tx_.frequency_data_block(), 0));
 180  E :    entry_thunk_tx_.SetEntryThunkParameter(ref_to_freq_data);
 181    :    if (!ApplyBlockGraphTransform(
 182  E :            &entry_thunk_tx_, policy, block_graph, header_block)) {
 183  i :      LOG(ERROR) << "Failed to thunk image entry points.";
 184  i :      return false;
 185    :    }
 186    :  
 187  E :    size_t num_basic_blocks = bb_ranges_.size();
 188  E :    if (num_basic_blocks == 0) {
 189  i :      LOG(WARNING) << "Encountered no basic code blocks during instrumentation.";
 190  i :      return true;
 191    :    }
 192    :  
 193    :    if (!add_bb_freq_data_tx_.ConfigureFrequencyDataBuffer(num_basic_blocks,
 194    :                                                           1,
 195  E :                                                           sizeof(uint8))) {
 196  i :      LOG(ERROR) << "Failed to configure frequency data buffer.";
 197  i :      return false;
 198    :    }
 199    :  
 200    :  #ifndef NDEBUG
 201    :    // If we're in debug mode then sanity check the basic block ranges. When
 202    :    // sorted, they should not overlap.
 203  E :    RelativeAddressRangeVector bb_ranges(bb_ranges_);
 204  E :    std::sort(bb_ranges.begin(), bb_ranges.end());
 205    :    DCHECK(std::adjacent_find(bb_ranges.begin(), bb_ranges.end(),
 206    :                              RelativeAddressRangesOverlapFunctor()) ==
 207  E :        bb_ranges.end());
 208    :  #endif
 209    :  
 210  E :    return true;
 211  E :  }
 212    :  
 213    :  }  // namespace transforms
 214    :  }  // namespace instrument

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