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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
83.6%61730.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/block_util.h"
  22    :  #include "syzygy/pe/pe_utils.h"
  23    :  
  24    :  namespace instrument {
  25    :  namespace transforms {
  26    :  
  27    :  namespace {
  28    :  
  29    :  using common::IndexedFrequencyData;
  30    :  using common::kBasicBlockCoverageAgentId;
  31    :  using core::eax;
  32    :  using block_graph::ApplyBasicBlockSubGraphTransform;
  33    :  using block_graph::ApplyBlockGraphTransform;
  34    :  using block_graph::BasicBlock;
  35    :  using block_graph::BasicCodeBlock;
  36    :  using block_graph::BasicBlockAssembler;
  37    :  using block_graph::BasicBlockReference;
  38    :  using block_graph::BlockGraph;
  39    :  using block_graph::Displacement;
  40    :  using block_graph::Immediate;
  41    :  using block_graph::Operand;
  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  E :                             common::kBasicBlockFrequencyDataVersion) {
  72    :    // Initialize the EntryThunkTransform.
  73  E :    entry_thunk_tx_.set_instrument_unsafe_references(false);
  74  E :    entry_thunk_tx_.set_only_instrument_module_entry(true);
  75  E :  }
  76    :  
  77    :  bool CoverageInstrumentationTransform::TransformBasicBlockSubGraph(
  78    :      BlockGraph* block_graph,
  79  E :      BasicBlockSubGraph* basic_block_subgraph) {
  80  E :    DCHECK(block_graph != NULL);
  81  E :    DCHECK(basic_block_subgraph != NULL);
  82    :  
  83  E :    BlockGraph::Block* data_block = add_bb_freq_data_tx_.frequency_data_block();
  84  E :    DCHECK(data_block != NULL);
  85  E :    DCHECK_EQ(sizeof(IndexedFrequencyData), data_block->data_size());
  86    :  
  87    :    // Iterate over the basic blocks.
  88    :    BasicBlockSubGraph::BBCollection::iterator it =
  89  E :        basic_block_subgraph->basic_blocks().begin();
  90  E :    for (; it != basic_block_subgraph->basic_blocks().end(); ++it) {
  91    :      // We're only interested in code blocks.
  92  E :      BasicCodeBlock* bb = BasicCodeBlock::Cast(*it);
  93  E :      if (bb == NULL)
  94  E :        continue;
  95    :  
  96    :      // Find the source range associated with this basic-block.
  97  E :      BlockGraph::Block::SourceRange source_range;
  98  E :      if (!GetBasicBlockSourceRange(*bb, &source_range)) {
  99  i :        LOG(ERROR) << "Unable to get source range for basic block '"
 100    :                   << bb->name() << "'";
 101  i :        return false;
 102    :      }
 103    :  
 104    :      // We prepend each basic code block with the following instructions:
 105    :      //   0. push eax
 106    :      //   1. mov eax, dword ptr[data.frequency_data]
 107    :      //   2. mov byte ptr[eax + basic_block_index], 1
 108    :      //   3. pop eax
 109  E :      BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
 110    :  
 111    :      // Prepend the instrumentation instructions.
 112  E :      assm.push(eax);
 113  E :      assm.mov(eax, Operand(Displacement(data_block, kFrequencyDataOffset)));
 114  E :      assm.mov_b(Operand(eax, Displacement(bb_ranges_.size())), Immediate(1));
 115  E :      assm.pop(eax);
 116    :  
 117  E :      bb_ranges_.push_back(source_range);
 118  E :    }
 119    :  
 120  E :    return true;
 121  E :  }
 122    :  
 123    :  bool CoverageInstrumentationTransform::PreBlockGraphIteration(
 124  E :      BlockGraph* block_graph, BlockGraph::Block* header_block) {
 125  E :    DCHECK(block_graph != NULL);
 126  E :    DCHECK(header_block != NULL);
 127    :  
 128    :    if (!ApplyBlockGraphTransform(
 129  E :            &add_bb_freq_data_tx_, block_graph, header_block)) {
 130  i :      LOG(ERROR) << "Failed to insert basic-block frequency data.";
 131  i :      return false;
 132    :    }
 133    :  
 134  E :    return true;
 135  E :  }
 136    :  
 137    :  bool CoverageInstrumentationTransform::OnBlock(
 138  E :      BlockGraph* block_graph, BlockGraph::Block* block) {
 139  E :    DCHECK(block_graph != NULL);
 140  E :    DCHECK(block != NULL);
 141    :  
 142    :    // We only care about code blocks.
 143  E :    if (block->type() != BlockGraph::CODE_BLOCK)
 144  E :      return true;
 145    :  
 146    :    // We only care about blocks that are safe for basic block decomposition.
 147  E :    if (!pe::CodeBlockIsBasicBlockDecomposable(block))
 148  E :      return true;
 149    :  
 150    :    // Apply our basic block transform.
 151  E :    if (!ApplyBasicBlockSubGraphTransform(this, block_graph, block, NULL)) {
 152  i :      return false;
 153    :    }
 154    :  
 155  E :    return true;
 156  E :  }
 157    :  
 158    :  bool CoverageInstrumentationTransform::PostBlockGraphIteration(
 159  E :      BlockGraph* block_graph, BlockGraph::Block* header_block) {
 160  E :    DCHECK(block_graph != NULL);
 161  E :    DCHECK(header_block != NULL);
 162    :  
 163    :    // Get a reference to the frequency data and make that the parameter that
 164    :    // we pass to the entry thunks. We run the thunk transform after the coverage
 165    :    // instrumentation transform as it creates new code blocks that we don't
 166    :    // want to instrument.
 167    :    block_graph::Immediate ref_to_freq_data(
 168  E :        add_bb_freq_data_tx_.frequency_data_block(), 0);
 169  E :    entry_thunk_tx_.SetEntryThunkParameter(ref_to_freq_data);
 170    :    if (!ApplyBlockGraphTransform(
 171  E :            &entry_thunk_tx_, block_graph, header_block)) {
 172  i :      LOG(ERROR) << "Failed to thunk image entry points.";
 173  i :      return false;
 174    :    }
 175    :  
 176  E :    size_t num_basic_blocks = bb_ranges_.size();
 177  E :    if (num_basic_blocks == 0) {
 178  i :      LOG(WARNING) << "Encountered no basic code blocks during instrumentation.";
 179  i :      return true;
 180    :    }
 181    :  
 182    :    if (!add_bb_freq_data_tx_.ConfigureFrequencyDataBuffer(num_basic_blocks,
 183  E :                                                           sizeof(uint8))) {
 184  i :      LOG(ERROR) << "Failed to configure frequency data buffer.";
 185  i :      return false;
 186    :    }
 187    :  
 188    :  #ifndef NDEBUG
 189    :    // If we're in debug mode then sanity check the basic block ranges. When
 190    :    // sorted, they should not overlap.
 191  E :    RelativeAddressRangeVector bb_ranges(bb_ranges_);
 192  E :    std::sort(bb_ranges.begin(), bb_ranges.end());
 193    :    DCHECK(std::adjacent_find(bb_ranges.begin(), bb_ranges.end(),
 194    :                              RelativeAddressRangesOverlapFunctor()) ==
 195  E :        bb_ranges.end());
 196    :  #endif
 197    :  
 198  E :    return true;
 199  E :  }
 200    :  
 201    :  }  // namespace transforms
 202    :  }  // namespace instrument

Coverage information generated Tue Jun 25 13:56:24 2013.