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

Coverage information generated Thu Jul 04 09:34:53 2013.