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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
80.6%831030.C++source

Line-by-line coverage:

   1    :  // Copyright 2013 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    :  // Implements the JumpTableCaseCountTransform class.
  16    :  
  17    :  #include "syzygy/instrument/transforms/jump_table_count_transform.h"
  18    :  
  19    :  #include <limits>
  20    :  
  21    :  #include "base/logging.h"
  22    :  #include "base/strings/string_util.h"
  23    :  #include "base/strings/stringprintf.h"
  24    :  #include "syzygy/block_graph/block_builder.h"
  25    :  #include "syzygy/block_graph/block_util.h"
  26    :  #include "syzygy/common/defs.h"
  27    :  #include "syzygy/common/indexed_frequency_data.h"
  28    :  #include "syzygy/instrument/transforms/entry_thunk_transform.h"
  29    :  #include "syzygy/pe/pe_utils.h"
  30    :  #include "syzygy/pe/transforms/pe_add_imports_transform.h"
  31    :  
  32    :  namespace instrument {
  33    :  namespace transforms {
  34    :  
  35    :  namespace {
  36    :  
  37    :  using block_graph::BasicBlock;
  38    :  using block_graph::BasicBlockSubGraph;
  39    :  using block_graph::BasicCodeBlock;
  40    :  using block_graph::BasicDataBlock;
  41    :  using block_graph::BasicBlockAssembler;
  42    :  using block_graph::BasicBlockReference;
  43    :  using block_graph::BlockBuilder;
  44    :  using block_graph::BlockGraph;
  45    :  using block_graph::Displacement;
  46    :  using block_graph::Immediate;
  47    :  using block_graph::Instruction;
  48    :  using block_graph::Operand;
  49    :  using block_graph::TransformPolicyInterface;
  50    :  using pe::transforms::PEAddImportsTransform;
  51    :  using pe::transforms::ImportedModule;
  52    :  
  53    :  const char kDefaultModuleName[] = "basic_block_entry_client.dll";
  54    :  const char kJumpTableCaseCounter[] = "_increment_indexed_freq_data";
  55    :  const char kThunkSuffix[] = "_jump_table_thunk";
  56    :  
  57    :  // Sets up the jump table counter hook import.
  58    :  // @param policy The policy object restricting how the transform is applied.
  59    :  // @param block_graph The block-graph to populate.
  60    :  // @param header_block The header block from block_graph.
  61    :  // @param module_name The name of the module implementing the hooks.
  62    :  // @param jump_table_case_counter will refer to the imported hook function.
  63    :  // @returns true on success, false otherwise.
  64    :  bool SetupCounterHook(const TransformPolicyInterface* policy,
  65    :                        BlockGraph* block_graph,
  66    :                        BlockGraph::Block* header_block,
  67    :                        const std::string& module_name,
  68  E :                        BlockGraph::Reference* jump_table_case_counter) {
  69  E :    DCHECK(block_graph != NULL);
  70  E :    DCHECK(header_block != NULL);
  71  E :    DCHECK(jump_table_case_counter != NULL);
  72    :  
  73    :    // Setup the import module.
  74  E :    ImportedModule module(module_name);
  75    :    size_t index_case_counter = module.AddSymbol(
  76    :        kJumpTableCaseCounter,
  77  E :        ImportedModule::kAlwaysImport);
  78    :  
  79    :    // Setup the add-imports transform.
  80  E :    PEAddImportsTransform add_imports;
  81  E :    add_imports.AddModule(&module);
  82    :  
  83    :    // Add the imports to the block-graph.
  84    :    if (!ApplyBlockGraphTransform(
  85  E :            &add_imports, policy, block_graph, header_block)) {
  86  i :      LOG(ERROR) << "Unable to add import entry for jump table hook functions.";
  87  i :      return false;
  88    :    }
  89    :  
  90    :    // Get a reference to the hook function.
  91  E :    if (!module.GetSymbolReference(index_case_counter, jump_table_case_counter)) {
  92  i :      LOG(ERROR) << "Unable to get jump table hooks.";
  93  i :      return false;
  94    :    }
  95  E :    DCHECK(jump_table_case_counter->IsValid());
  96    :  
  97  E :    return true;
  98  E :  }
  99    :  
 100    :  }  // namespace
 101    :  
 102    :  const char JumpTableCaseCountTransform::kTransformName[] =
 103    :      "JumpTableCountTransform";
 104    :  
 105    :  JumpTableCaseCountTransform::JumpTableCaseCountTransform()
 106    :      : add_frequency_data_(common::kJumpTableCountAgentId,
 107    :                            "Jump Table Frequency Data",
 108    :                            common::kJumpTableFrequencyDataVersion,
 109    :                            common::IndexedFrequencyData::JUMP_TABLE,
 110    :                            sizeof(common::IndexedFrequencyData)),
 111    :        instrument_dll_name_(kDefaultModuleName),
 112  E :        jump_table_case_count_(0) {
 113  E :  }
 114    :  
 115    :  bool JumpTableCaseCountTransform::PreBlockGraphIteration(
 116    :      const TransformPolicyInterface* policy,
 117    :      BlockGraph* block_graph,
 118  E :      BlockGraph::Block* header_block) {
 119  E :    DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
 120  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 121  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
 122  E :    DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
 123    :  
 124    :    // Setup the jump table counter entry hook.
 125    :    if (!SetupCounterHook(policy,
 126    :                          block_graph,
 127    :                          header_block,
 128    :                          instrument_dll_name_,
 129  E :                          &jump_table_case_counter_hook_ref_)) {
 130  i :      return false;
 131    :    }
 132    :  
 133    :    // Add the static jump table count frequency data.
 134    :    if (!ApplyBlockGraphTransform(&add_frequency_data_,
 135    :                                  policy,
 136    :                                  block_graph,
 137  E :                                  header_block)) {
 138  i :      LOG(ERROR) << "Failed to insert jump table count frequency data.";
 139  i :      return false;
 140    :    }
 141    :  
 142    :    // Find or create the section we put our thunks in.
 143    :    thunk_section_ = block_graph->FindOrAddSection(common::kThunkSectionName,
 144  E :                                                   pe::kCodeCharacteristics);
 145  E :    DCHECK(thunk_section_ != NULL);
 146    :  
 147  E :    return true;
 148  E :  }
 149    :  
 150    :  bool JumpTableCaseCountTransform::OnBlock(
 151    :      const TransformPolicyInterface* policy,
 152    :      BlockGraph* block_graph,
 153  E :      BlockGraph::Block* block) {
 154  E :    DCHECK(policy != NULL);
 155  E :    DCHECK(block_graph != NULL);
 156  E :    DCHECK(block != NULL);
 157    :  
 158  E :    if (block->type() != BlockGraph::CODE_BLOCK)
 159  E :      return true;
 160    :  
 161    :    // Iterate over the labels of the block to find the jump tables.
 162  E :    for (BlockGraph::Block::LabelMap::const_iterator iter_label(
 163    :             block->labels().begin());
 164  E :        iter_label != block->labels().end();
 165  E :        ++iter_label) {
 166  E :      if (!iter_label->second.has_attributes(BlockGraph::JUMP_TABLE_LABEL))
 167  E :        continue;
 168    :  
 169  E :      size_t table_size = 0;
 170  E :      if (!block_graph::GetJumpTableSize(block, iter_label, &table_size))
 171  i :        return false;
 172    :  
 173    :      jump_table_infos_.push_back(
 174  E :          std::make_pair(block->addr() + iter_label->first, table_size));
 175    :  
 176    :      BlockGraph::Block::ReferenceMap::const_iterator iter_ref =
 177  E :          block->references().find(iter_label->first);
 178    :  
 179    :      // Iterate over the references and thunk them.
 180  E :      for (size_t i = 0; i < table_size; ++i) {
 181  E :        DCHECK(iter_ref != block->references().end());
 182    :  
 183    :        BlockGraph::Block* thunk_block = CreateOneThunk(block_graph,
 184  E :                                                        iter_ref->second);
 185  E :        if (thunk_block == NULL) {
 186  i :          jump_table_infos_.pop_back();
 187  i :          return false;
 188    :        }
 189    :  
 190    :        BlockGraph::Reference thunk_ref(BlockGraph::ABSOLUTE_REF,
 191    :                                        sizeof(iter_ref->second.size()),
 192  E :                                        thunk_block, 0, 0);
 193  E :        block->SetReference(iter_ref->first, thunk_ref);
 194  E :        ++iter_ref;
 195  E :      }
 196  E :    }
 197    :  
 198  E :    return true;
 199  E :  }
 200    :  
 201    :  bool JumpTableCaseCountTransform::PostBlockGraphIteration(
 202    :      const TransformPolicyInterface* policy,
 203    :      BlockGraph* block_graph,
 204  E :      BlockGraph::Block* header_block) {
 205  E :    DCHECK(policy != NULL);
 206  E :    DCHECK(block_graph != NULL);
 207  E :    DCHECK(header_block != NULL);
 208    :  
 209  E :    if (jump_table_case_count_ == 0) {
 210  i :      LOG(INFO) << "Encountered no jump tables during instrumentation.";
 211  i :      return true;
 212    :    }
 213    :  
 214    :    if (!add_frequency_data_.ConfigureFrequencyDataBuffer(jump_table_case_count_,
 215    :                                                          1,
 216  E :                                                          sizeof(uint32))) {
 217  i :      LOG(ERROR) << "Failed to configure frequency data buffer.";
 218  i :      return false;
 219    :    }
 220    :  
 221    :    // Add the module entry thunks.
 222  E :    EntryThunkTransform add_thunks;
 223  E :    add_thunks.set_only_instrument_module_entry(true);
 224  E :    add_thunks.set_instrument_dll_name(instrument_dll_name_);
 225    :  
 226  E :    auto module_data(Immediate(add_frequency_data_.frequency_data_block(), 0));
 227  E :    if (!add_thunks.SetEntryThunkParameter(module_data)) {
 228  i :      LOG(ERROR) << "Failed to configure the entry thunks with the module_data "
 229    :                 << "parameter.";
 230  i :      return false;
 231    :    }
 232    :  
 233    :    if (!ApplyBlockGraphTransform(
 234  E :            &add_thunks, policy, block_graph, header_block)) {
 235  i :      LOG(ERROR) << "Unable to thunk module entry points.";
 236  i :      return false;
 237    :    }
 238    :  
 239  E :    return true;
 240  E :  }
 241    :  
 242    :  BlockGraph::Block* JumpTableCaseCountTransform::CreateOneThunk(
 243    :      BlockGraph* block_graph,
 244  E :      const BlockGraph::Reference& destination) {
 245    :    // Construct the name for the new thunk.
 246  E :    std::string thunk_name(destination.referenced()->name() + kThunkSuffix);
 247    :  
 248    :    auto jump_table_case_counter_hook(
 249    :        Operand(Displacement(jump_table_case_counter_hook_ref_.referenced(),
 250  E :                             jump_table_case_counter_hook_ref_.offset())));
 251    :  
 252    :    // Construct the thunk basic block.
 253  E :    BasicBlockSubGraph bbsg;
 254    :    BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
 255    :        thunk_name,
 256    :        NULL,
 257    :        BlockGraph::CODE_BLOCK,
 258    :        thunk_section_->id(),
 259    :        1,
 260  E :        0);
 261  E :    BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(thunk_name);
 262  E :    block_desc->basic_block_order.push_back(bb);
 263    :  
 264  E :    BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
 265  E :    DCHECK_LT(jump_table_case_count_, std::numeric_limits<size_t>::max());
 266  E :    assm.push(Immediate(jump_table_case_count_++, assm::kSize32Bit));
 267  E :    assm.call(jump_table_case_counter_hook);
 268  E :    assm.jmp(Immediate(destination.referenced(), destination.offset()));
 269    :  
 270    :    // Condense into a block.
 271  E :    BlockBuilder block_builder(block_graph);
 272  E :    if (!block_builder.Merge(&bbsg)) {
 273  i :      LOG(ERROR) << "Failed to build thunk block.";
 274  i :      return NULL;
 275    :    }
 276    :  
 277    :    // Exactly one new block should have been created.
 278  E :    DCHECK_EQ(1u, block_builder.new_blocks().size());
 279  E :    return block_builder.new_blocks().front();
 280  E :  }
 281    :  
 282    :  }  // namespace transforms
 283    :  }  // namespace instrument

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