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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
94.1%80850.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc.
   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/typed_block.h"
  19    :  #include "syzygy/common/basic_block_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::BasicBlockFrequencyData;
  30    :  using core::eax;
  31    :  using block_graph::BasicBlock;
  32    :  using block_graph::BasicBlockAssembler;
  33    :  using block_graph::BasicBlockReference;
  34    :  using block_graph::BlockGraph;
  35    :  using block_graph::Displacement;
  36    :  using block_graph::Immediate;
  37    :  using block_graph::Operand;
  38    :  
  39    :  typedef block_graph::TypedBlock<BasicBlockFrequencyData> CoverageDataBlock;
  40    :  
  41    :  bool AddCoverageDataSection(BlockGraph* block_graph,
  42  E :                              BlockGraph::Block** coverage_data_block) {
  43  E :    DCHECK(block_graph != NULL);
  44  E :    DCHECK(coverage_data_block != NULL);
  45    :  
  46    :    BlockGraph::Section* coverage_section = block_graph->FindSection(
  47  E :        common::kBasicBlockFrequencySectionName);
  48  E :    if (coverage_section != NULL) {
  49  E :      LOG(ERROR) << "Block-graph already contains a code coverage data section ("
  50    :                 << common::kBasicBlockFrequencySectionName << ").";
  51  E :      return false;
  52    :    }
  53    :  
  54    :    coverage_section = block_graph->AddSection(
  55    :        common::kBasicBlockFrequencySectionName,
  56  E :        common::kBasicBlockFrequencySectionCharacteristics);
  57  E :    DCHECK(coverage_section != NULL);
  58    :  
  59    :    BlockGraph::Block* block =
  60    :        block_graph->AddBlock(BlockGraph::DATA_BLOCK,
  61    :                              sizeof(BasicBlockFrequencyData),
  62  E :                              "Coverage data");
  63  E :    DCHECK(block != NULL);
  64  E :    block->set_section(coverage_section->id());
  65    :  
  66  E :    BasicBlockFrequencyData coverage_data = {};
  67  E :    coverage_data.agent_id = common::kBasicBlockCoverageAgentId;
  68  E :    coverage_data.version = common::kBasicBlockFrequencyDataVersion;
  69  E :    coverage_data.tls_index = TLS_OUT_OF_INDEXES;
  70    :  
  71  E :    block->CopyData(sizeof(coverage_data), &coverage_data);
  72  E :    *coverage_data_block = block;
  73    :  
  74  E :    return true;
  75  E :  }
  76    :  
  77    :  }  // namespace
  78    :  
  79    :  const char CoverageInstrumentationTransform::kTransformName[] =
  80    :      "CoverageInstrumentationTransform";
  81    :  
  82    :  CoverageInstrumentationTransform::CoverageInstrumentationTransform()
  83  E :      : coverage_data_block_(NULL) {
  84  E :  }
  85    :  
  86    :  bool CoverageInstrumentationTransform::TransformBasicBlockSubGraph(
  87    :      BlockGraph* block_graph,
  88  E :      BasicBlockSubGraph* basic_block_subgraph) {
  89  E :    DCHECK(block_graph != NULL);
  90  E :    DCHECK(basic_block_subgraph != NULL);
  91    :  
  92    :    // Iterate over the basic blocks.
  93    :    BasicBlockSubGraph::BBCollection::iterator it =
  94  E :        basic_block_subgraph->basic_blocks().begin();
  95  E :    for (; it != basic_block_subgraph->basic_blocks().end(); ++it) {
  96  E :      BasicBlockSubGraph::BasicBlock& bb = it->second;
  97    :  
  98    :      // We're only interested in code blocks.
  99  E :      if (bb.type() != BasicBlock::BASIC_CODE_BLOCK)
 100  E :        continue;
 101    :  
 102    :      // Find the source range associated with this basic-block.
 103    :      // TODO(chrisha): Make this a utility function on BasicBlock and eventually
 104    :      //     move all of the data into instructions and successors.
 105    :      const BlockGraph::Block::SourceRanges::RangePair* range_pair =
 106    :          basic_block_subgraph->original_block()->source_ranges().FindRangePair(
 107  E :              BlockGraph::Block::SourceRanges::SourceRange(bb.offset(), 1));
 108    :  
 109    :      // If there's no source data, something has gone terribly wrong. In fact, it
 110    :      // likely means that we've stacked transforms and new instructions have
 111    :      // been prepended to this BB. We don't support this yet.
 112  E :      DCHECK(range_pair != NULL);
 113    :  
 114    :      // We prepend each basic code block with the following instructions:
 115    :      //   0. push eax
 116    :      //   1. mov eax, dword ptr[basic_block_seen_array]
 117    :      //   2. mov byte ptr[eax + basic_block_index], 1
 118    :      //   3. pop eax
 119    :      BasicBlockAssembler assm(bb.instructions().begin(),
 120  E :                               &bb.instructions());
 121    :      // Prepend the instrumentation instructions.
 122  E :      assm.push(eax);
 123    :      static const BlockGraph::Offset kDstOffset =
 124    :          offsetof(BasicBlockFrequencyData, frequency_data);
 125  E :      assm.mov(eax, Operand(Displacement(coverage_data_block_, kDstOffset)));
 126  E :      assm.mov_b(Operand(eax, Displacement(bb_ranges_.size())), Immediate(1));
 127  E :      assm.pop(eax);
 128    :  
 129    :      // Get the RVA of the BB by translating its offset. We also get its size
 130    :      // from the source range. This assumes that the BB is an original
 131    :      // untransformed BB.
 132  E :      const BlockGraph::Block::DataRange& data_range = range_pair->first;
 133  E :      const BlockGraph::Block::SourceRange& src_range = range_pair->second;
 134    :      core::RelativeAddress bb_addr = src_range.start() +
 135  E :          (bb.offset() - data_range.start());
 136  E :      size_t bb_size = src_range.size();
 137  E :      bb_ranges_.push_back(RelativeAddressRange(bb_addr, bb_size));
 138  E :    }
 139    :  
 140  E :    return true;
 141  E :  }
 142    :  
 143    :  bool CoverageInstrumentationTransform::PreBlockGraphIteration(
 144  E :      BlockGraph* block_graph, BlockGraph::Block* header_block) {
 145  E :    DCHECK(block_graph != NULL);
 146  E :    DCHECK(header_block != NULL);
 147    :  
 148  E :    if (!AddCoverageDataSection(block_graph, &coverage_data_block_))
 149  E :      return false;
 150  E :    DCHECK(coverage_data_block_ != NULL);
 151    :  
 152  E :    return true;
 153  E :  }
 154    :  
 155    :  bool CoverageInstrumentationTransform::OnBlock(
 156  E :      BlockGraph* block_graph, BlockGraph::Block* block) {
 157  E :    DCHECK(block_graph != NULL);
 158  E :    DCHECK(block != NULL);
 159    :  
 160    :    // We only care about code blocks.
 161  E :    if (block->type() != BlockGraph::CODE_BLOCK)
 162  E :      return true;
 163    :  
 164    :    // We only care about blocks that are safe for basic block decomposition.
 165  E :    if (!pe::CodeBlockIsBasicBlockDecomposable(block))
 166  E :      return true;
 167    :  
 168    :    // Apply our basic block transform.
 169    :    if (!block_graph::ApplyBasicBlockSubGraphTransform(
 170  E :        this, block_graph, block, NULL)) {
 171  i :      return false;
 172    :    }
 173    :  
 174  E :    return true;
 175  E :  }
 176    :  
 177    :  bool CoverageInstrumentationTransform::PostBlockGraphIteration(
 178  E :      BlockGraph* block_graph, BlockGraph::Block* header_block) {
 179  E :    DCHECK(block_graph != NULL);
 180  E :    DCHECK(header_block != NULL);
 181    :  
 182  E :    if (bb_ranges_.size() == 0) {
 183  i :      LOG(WARNING) << "Encountered no basic code blocks during instrumentation.";
 184  i :      return true;
 185    :    }
 186    :  
 187    :    // Set the final basic block count. This is used by the runtime library to
 188    :    // know how big an array to allocate for the statistics.
 189  E :    CoverageDataBlock coverage_data;
 190  E :    DCHECK(coverage_data_block_ != NULL);
 191  E :    CHECK(coverage_data.Init(0, coverage_data_block_));
 192  E :    coverage_data->num_basic_blocks = bb_ranges_.size();
 193  E :    coverage_data->frequency_size = 1U;
 194    :  
 195    :    // Get/create a read/write .rdata section.
 196    :    BlockGraph::Section* rdata_section = block_graph->FindOrAddSection(
 197  E :        pe::kReadWriteDataSectionName, pe::kReadWriteDataCharacteristics);
 198  E :    if (rdata_section == NULL) {
 199  i :      LOG(ERROR) << "Unable to find or create section \""
 200    :                 << pe::kReadWriteDataSectionName << "\".";
 201  i :      return false;
 202    :    }
 203    :  
 204    :    // Create an empty block that is sufficient to hold all of the coverage
 205    :    // results. We will initially point basic_block_seen_array at this so that
 206    :    // even if the call-trace service is down the program can run without
 207    :    // crashing. We put this in .rdata so that .bbfreq contains only a single
 208    :    // block.
 209    :    BlockGraph::Block* bb_seen_array_block =
 210    :        block_graph->AddBlock(BlockGraph::DATA_BLOCK,
 211    :                              bb_ranges_.size(),
 212  E :                              "Basic Blocks Seen Array");
 213  E :    DCHECK(bb_seen_array_block != NULL);
 214  E :    bb_seen_array_block->set_section(rdata_section->id());
 215    :  
 216    :    // Hook it up to the coverage_data array pointer.
 217    :    coverage_data_block_->SetReference(
 218    :        coverage_data.OffsetOf(coverage_data->frequency_data),
 219    :        BlockGraph::Reference(
 220    :            BlockGraph::ABSOLUTE_REF,
 221    :            sizeof(coverage_data->frequency_data),
 222    :            bb_seen_array_block,
 223    :            0,
 224  E :            0));
 225    :  
 226  E :    return true;
 227  E :  }
 228    :  
 229    :  }  // namespace transforms
 230    :  }  // namespace instrument

Coverage information generated Thu Sep 06 11:30:46 2012.