Coverage for /Syzygy/playback/playback.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
75.6%991310.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/playback/playback.h"
  16    :  
  17    :  #include "syzygy/core/address.h"
  18    :  #include "syzygy/pdb/omap.h"
  19    :  #include "syzygy/pe/find.h"
  20    :  #include "syzygy/pe/metadata.h"
  21    :  #include "syzygy/pe/pe_file.h"
  22    :  
  23    :  namespace playback {
  24    :  
  25    :  using trace::parser::Parser;
  26    :  
  27    :  Playback::Playback(const base::FilePath& module_path,
  28    :                     const base::FilePath& instrumented_path,
  29    :                     const TraceFileList& trace_files)
  30    :      : module_path_(module_path),
  31    :        instrumented_path_(instrumented_path),
  32    :        trace_files_(trace_files),
  33    :        pe_file_(NULL),
  34    :        image_(NULL),
  35  E :        parser_(NULL) {
  36  E :  }
  37    :  
  38  E :  Playback::~Playback() {
  39  E :    pe_file_ = NULL;
  40  E :    image_ = NULL;
  41  E :    parser_ = NULL;
  42  E :  }
  43    :  
  44  E :  bool Playback::Init(PEFile* pe_file, ImageLayout* image, Parser* parser) {
  45    :    // Fail if the function was already initialized,
  46    :    // or if the parameters aren't.
  47  E :    DCHECK(pe_file != NULL);
  48  E :    DCHECK(image != NULL);
  49  E :    DCHECK(parser != NULL);
  50    :  
  51  E :    DCHECK(pe_file_ == NULL);
  52  E :    DCHECK(image_ == NULL);
  53  E :    DCHECK(parser_ == NULL);
  54    :  
  55  E :    pe_file_ = pe_file;
  56  E :    image_ = image;
  57  E :    parser_ = parser;
  58    :  
  59    :    // Load and decompose the module.
  60  E :    if (!LoadModuleInformation())
  61  E :      return false;
  62  E :    if (!InitializeParser())
  63  E :      return false;
  64  E :    if (!LoadInstrumentedOmap())
  65  i :      return false;
  66  E :    if (!DecomposeImage())
  67  i :      return false;
  68    :  
  69  E :    return true;
  70  E :  }
  71    :  
  72  E :  bool Playback::LoadModuleInformation() {
  73  E :    DCHECK(pe_file_ != NULL);
  74  E :    DCHECK(image_ != NULL);
  75    :  
  76    :    // Validate the instrumented module, and extract the signature of the original
  77    :    // module it was built from.
  78  E :    pe::PEFile::Signature orig_signature;
  79  E :    if (!ValidateInstrumentedModuleAndParseSignature(&orig_signature))
  80  i :      return false;
  81    :  
  82    :    // If the input DLL path is empty, use the inferred one from the
  83    :    // instrumented module.
  84  E :    if (module_path_.empty()) {
  85  i :      LOG(INFO) << "Inferring input DLL path from instrumented module: "
  86    :                << orig_signature.path;
  87  i :      module_path_ = base::FilePath(orig_signature.path);
  88    :    }
  89    :  
  90    :    // Try to read the input DLL.
  91  E :    LOG(INFO) << "Reading input DLL.";
  92  E :    if (!pe_file_->Init(module_path_)) {
  93  i :      LOG(ERROR) << "Unable to read input image: " << module_path_.value();
  94  i :      return false;
  95    :    }
  96  E :    pe::PEFile::Signature input_signature;
  97  E :    pe_file_->GetSignature(&input_signature);
  98    :  
  99    :    // Validate that the input DLL signature matches the original signature
 100    :    // extracted from the instrumented module.
 101  E :    if (!orig_signature.IsConsistent(input_signature)) {
 102  E :      LOG(ERROR) << "Instrumented module metadata does not match input module.";
 103  E :      return false;
 104    :    }
 105    :  
 106  E :    return true;
 107  E :  }
 108    :  
 109  E :  bool Playback::InitializeParser() {
 110    :    // Open the log files. We do this before running the decomposer as if these
 111    :    // fail we'll have wasted a lot of time!
 112    :  
 113  E :    for (TraceFileIter i = trace_files_.begin(); i < trace_files_.end(); ++i) {
 114  E :      const base::FilePath& trace_path = *i;
 115  E :      LOG(INFO) << "Opening '" << trace_path.BaseName().value() << "'.";
 116  E :      if (!parser_->OpenTraceFile(trace_path)) {
 117  E :        LOG(ERROR) << "Unable to open trace log: " << trace_path.value();
 118  E :        return false;
 119    :      }
 120  E :    }
 121    :  
 122  E :    return true;
 123  E :  }
 124    :  
 125  E :  bool Playback::LoadInstrumentedOmap() {
 126    :    // Find the PDB file for the instrumented module.
 127  E :    base::FilePath instrumented_pdb;
 128    :    if (!pe::FindPdbForModule(instrumented_path_, &instrumented_pdb) ||
 129  E :        instrumented_pdb.empty()) {
 130  i :      LOG(ERROR) << "Unable to find PDB for instrumented image \""
 131    :                 << instrumented_path_.value() << "\".";
 132  i :      return false;
 133    :    }
 134  E :    LOG(INFO) << "Found PDB for instrumented module: \""
 135    :              << instrumented_pdb.value() << "\".";
 136    :  
 137    :    // Load the OMAPTO table from the instrumented PDB. This will allow us to map
 138    :    // call-trace event addresses to addresses in the original image.
 139  E :    if (!pdb::ReadOmapsFromPdbFile(instrumented_pdb, &omap_to_, &omap_from_)) {
 140  i :      LOG(ERROR) << "Failed to read OMAPTO vector from PDB \""
 141    :                 << instrumented_pdb.value() << "\".";
 142  i :      return false;
 143    :    }
 144  E :    LOG(INFO) << "Read OMAP data from instrumented module PDB.";
 145    :  
 146  E :    return true;
 147  E :  }
 148    :  
 149  E :  bool Playback::DecomposeImage() {
 150  E :    DCHECK(pe_file_ != NULL);
 151  E :    DCHECK(image_ != NULL);
 152    :  
 153  E :    BlockGraph* block_graph = image_->blocks.graph();
 154  E :    ImageLayout image(block_graph);
 155    :  
 156    :    // Decompose the DLL to be reordered. This will let us map call-trace events
 157    :    // to actual Blocks.
 158  E :    LOG(INFO) << "Decomposing input image: " << module_path_.value();
 159  E :    Decomposer decomposer(*pe_file_);
 160  E :    if (!decomposer.Decompose(&image)) {
 161  i :      LOG(ERROR) << "Unable to decompose input image: " << module_path_.value();
 162  i :      return false;
 163    :    }
 164    :  
 165    :    // Make a copy of the image layout without padding blocks, which are
 166    :    // completely unnecessary in a playback.
 167  E :    LOG(INFO) << "Removing padding blocks.";
 168  E :    if (!pe::CopyImageLayoutWithoutPadding(image, image_)) {
 169  i :      LOG(ERROR) << "Failed to remove padding blocks.";
 170  i :      return false;
 171    :    }
 172    :  
 173  E :    return true;
 174  E :  }
 175    :  
 176    :  bool Playback::ValidateInstrumentedModuleAndParseSignature(
 177  E :    pe::PEFile::Signature* orig_signature) {
 178  E :    DCHECK(orig_signature != NULL);
 179    :  
 180  E :    pe::PEFile pe_file;
 181  E :    if (!pe_file.Init(instrumented_path_)) {
 182  i :      LOG(ERROR) << "Unable to parse instrumented module: "
 183    :                 << instrumented_path_.value();
 184  i :      return false;
 185    :    }
 186  E :    pe_file.GetSignature(&instr_signature_);
 187    :  
 188    :    // Load the metadata from the PE file. Validate the toolchain version and
 189    :    // return the original module signature.
 190  E :    pe::Metadata metadata;
 191  E :    if (!metadata.LoadFromPE(pe_file))
 192  i :      return false;
 193  E :    *orig_signature = metadata.module_signature();
 194    :  
 195  E :    if (!common::kSyzygyVersion.IsCompatible(metadata.toolchain_version())) {
 196  i :      LOG(ERROR) << "Module was instrumented with an incompatible version of "
 197    :                 << "the toolchain: " << instrumented_path_.value();
 198  i :      return false;
 199    :    }
 200    :  
 201  E :    return true;
 202  E :  }
 203    :  
 204    :  bool Playback::MatchesInstrumentedModuleSignature(
 205  E :      const ModuleInformation& module_info) const {
 206    :    // On Windows XP gathered traces, only the module size is non-zero.
 207  E :    if (module_info.image_checksum == 0 && module_info.time_date_stamp == 0) {
 208    :      // If the size matches, then check that the names fit.
 209  i :      if (instr_signature_.module_size != module_info.module_size)
 210  i :        return false;
 211    :  
 212  i :      base::FilePath base_name = instrumented_path_.BaseName();
 213    :      return (module_info.image_file_name.rfind(base_name.value()) !=
 214  i :          std::wstring::npos);
 215  i :    } else {
 216    :      // On Vista and greater, we can check the full module signature.
 217    :      return (instr_signature_.module_checksum == module_info.image_checksum &&
 218    :          instr_signature_.module_size == module_info.module_size &&
 219  E :          instr_signature_.module_time_date_stamp == module_info.time_date_stamp);
 220    :    }
 221  E :  }
 222    :  
 223    :  const Playback::BlockGraph::Block* Playback::FindFunctionBlock(
 224  E :      DWORD process_id, FuncAddr function) {
 225  E :    DCHECK(parser_ != NULL);
 226  E :    DCHECK(image_ != NULL);
 227    :  
 228    :    AbsoluteAddress64 abs_address =
 229  E :        reinterpret_cast<AbsoluteAddress64>(function);
 230    :  
 231    :    // Resolve the module in which the called function resides.
 232    :    const ModuleInformation* module_info =
 233  E :        parser_->GetModuleInformation(process_id, abs_address);
 234    :  
 235    :    // We should be able to resolve the instrumented module.
 236  E :    if (module_info == NULL) {
 237  i :      LOG(ERROR) << "Failed to resolve module for entry event (pid="
 238    :                 << process_id << ", addr=0x" << function << ").";
 239  i :      return NULL;
 240    :    }
 241    :  
 242    :    // Ignore events not belonging to the instrumented module of interest.
 243  E :    if (!MatchesInstrumentedModuleSignature(*module_info)) {
 244  i :      return NULL;
 245    :    }
 246    :  
 247    :    // Convert the address to an RVA. We can only instrument 32-bit DLLs, so we're
 248    :    // sure that the following address conversion is safe.
 249    :    core::RelativeAddress rva(
 250  E :        static_cast<uint32>(abs_address - module_info->base_address));
 251    :  
 252    :    // Convert the address from one in the instrumented module to one in the
 253    :    // original module using the OMAP data.
 254  E :    rva = pdb::TranslateAddressViaOmap(omap_to(), rva);
 255    :  
 256    :    // Get the block that this function call refers to.
 257  E :    const BlockGraph::Block* block = image_->blocks.GetBlockByAddress(rva);
 258  E :    if (block == NULL) {
 259  i :      LOG(ERROR) << "Unable to map " << rva << " to a block.";
 260  i :      return NULL;
 261    :    }
 262  E :    if (block->type() != BlockGraph::CODE_BLOCK) {
 263  i :      LOG(ERROR) << rva << " maps to a non-code block (" << block->name()
 264    :                 << " in " << module_info->image_file_name << ").";
 265  i :      return NULL;
 266    :    }
 267    :  
 268  E :    return block;
 269  E :  }
 270    :  
 271    :  }  // namespace playback

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