Coverage for /Syzygy/refinery/analyzers/memory_analyzer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
85.2%52610.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 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/refinery/analyzers/memory_analyzer.h"
  16    :  
  17    :  #include <dbghelp.h>
  18    :  #include <string>
  19    :  
  20    :  #include "base/memory/scoped_ptr.h"
  21    :  #include "syzygy/core/address_space.h"
  22    :  #include "syzygy/refinery/process_state/process_state_util.h"
  23    :  #include "syzygy/refinery/process_state/refinery.pb.h"
  24    :  
  25    :  namespace refinery {
  26    :  
  27    :  namespace {
  28    :  
  29    :  using MemoryAddressSpace = core::AddressSpace<Address, Size, std::string>;
  30    :  
  31    :  bool RecordMemoryContents(AddressRange new_range,
  32    :                            std::string bytes,
  33  E :                            MemoryAddressSpace* address_space) {
  34  E :    DCHECK(address_space);
  35  E :    DCHECK_EQ(new_range.size(), bytes.size());
  36    :  
  37    :    MemoryAddressSpace::iterator it =
  38  E :        address_space->FindFirstIntersection(new_range);
  39  E :    for (; it != address_space->end() && it->first.Intersects(new_range); ++it) {
  40  E :      const auto& range = it->first;
  41  E :      const std::string& data = it->second;
  42    :      // If this range is fully subsumed by the new range there's nothing
  43    :      // to do. Otherwise we need to slice the data and prepend and/or append
  44    :      // it to the new range and data.
  45  E :      if (range.start() < new_range.start()) {
  46  E :        size_t prepend = new_range.start() - range.start();
  47  E :        bytes.insert(0, data, 0, prepend);
  48  E :        new_range = AddressRange(range.start(), new_range.size() + prepend);
  49    :      }
  50  E :      if (range.end() > new_range.end()) {
  51  E :        size_t append = range.end() - new_range.end();
  52  E :        bytes.append(data, data.size() - append, append);
  53  E :        new_range = AddressRange(new_range.start(), new_range.size() + append);
  54    :      }
  55  E :    }
  56  E :    DCHECK_EQ(new_range.size(), bytes.size());
  57    :  
  58  E :    if (!address_space->SubsumeInsert(new_range, bytes)) {
  59  i :      NOTREACHED() << "SubsumeInsert failed!";
  60  i :      return false;
  61    :    }
  62    :  
  63  E :    return true;
  64  E :  }
  65    :  
  66    :  }  // namespace
  67    :  
  68    :  // static
  69    :  const char MemoryAnalyzer::kMemoryAnalyzerName[] = "MemoryAnalyzer";
  70    :  
  71    :  Analyzer::AnalysisResult MemoryAnalyzer::Analyze(
  72    :      const minidump::Minidump& minidump,
  73  E :      ProcessState* process_state) {
  74  E :    DCHECK(process_state != nullptr);
  75    :  
  76    :    minidump::Minidump::Stream memory_list =
  77  E :        minidump.FindNextStream(nullptr, MemoryListStream);
  78  E :    if (!memory_list.IsValid())
  79  i :      return ANALYSIS_ERROR;
  80    :    // Ensure MemoryListStream is unique.
  81    :    minidump::Minidump::Stream offending_list =
  82  E :        minidump.FindNextStream(&memory_list, MemoryListStream);
  83  E :    if (offending_list.IsValid())
  84  i :      return ANALYSIS_ERROR;
  85    :  
  86  E :    ULONG32 num_ranges = 0;
  87  E :    if (!memory_list.ReadElement(&num_ranges))
  88  i :      return ANALYSIS_ERROR;
  89    :  
  90  E :    BytesLayerPtr bytes_layer;
  91  E :    process_state->FindOrCreateLayer(&bytes_layer);
  92    :  
  93    :    // It seems minidumps sometimes contain overlapping memory ranges. It's
  94    :    // difficult to reason on why this is, and it's difficult to know which byte
  95    :    // value of two or more alternates is "the one". To consolidate this
  96    :    // consistently into the byte layer we choose the byte values from the last
  97    :    // range that supplies a given byte.
  98    :    using MemoryAddressSpace = core::AddressSpace<Address, Size, std::string>;
  99  E :    MemoryAddressSpace memory_temp;
 100  E :    for (size_t i = 0; i < num_ranges; ++i) {
 101  E :      MINIDUMP_MEMORY_DESCRIPTOR descriptor = {};
 102  E :      if (!memory_list.ReadElement(&descriptor))
 103  i :        return ANALYSIS_ERROR;
 104    :  
 105  E :      Address range_addr = descriptor.StartOfMemoryRange;
 106  E :      Size range_size = descriptor.Memory.DataSize;
 107    :      minidump::Minidump::Stream bytes_stream =
 108  E :          minidump.GetStreamFor(descriptor.Memory);
 109    :  
 110  E :      std::string bytes;
 111  E :      if (!bytes_stream.ReadBytes(range_size, &bytes))
 112  i :        return ANALYSIS_ERROR;
 113    :  
 114  E :      AddressRange new_range(range_addr, range_size);
 115  E :      if (!new_range.IsValid())
 116  i :        return ANALYSIS_ERROR;
 117    :  
 118    :      // Record the new range and consolidate it with any overlaps.
 119  E :      if (!RecordMemoryContents(new_range, bytes, &memory_temp))
 120  i :        return ANALYSIS_ERROR;
 121  E :    }
 122    :  
 123    :    // Now transfer the temp address space to the bytes layer.
 124  E :    for (const auto& entry : memory_temp) {
 125    :      // Create the memory record.
 126  E :      AddressRange new_range(entry.first.start(), entry.first.size());
 127  E :      BytesRecordPtr bytes_record;
 128  E :      bytes_layer->CreateRecord(new_range, &bytes_record);
 129  E :      Bytes* bytes_proto = bytes_record->mutable_data();
 130  E :      bytes_proto->mutable_data()->assign(entry.second);
 131  E :    }
 132    :  
 133  E :    return ANALYSIS_COMPLETE;
 134  E :  }
 135    :  
 136    :  }  // namespace refinery

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