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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%00110.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/stack_frame_analyzer.h"
  16    :  
  17    :  #include <vector>
  18    :  
  19    :  #include "base/bind.h"
  20    :  #include "base/strings/stringprintf.h"
  21    :  #include "base/win/scoped_comptr.h"
  22    :  #include "syzygy/common/com_utils.h"
  23    :  #include "syzygy/pe/dia_util.h"
  24    :  #include "syzygy/refinery/analyzers/stack_frame_analyzer_impl.h"
  25    :  #include "syzygy/refinery/process_state/layer_data.h"
  26    :  #include "syzygy/refinery/process_state/process_state.h"
  27    :  #include "syzygy/refinery/process_state/process_state_util.h"
  28    :  #include "syzygy/refinery/types/type_repository.h"
  29    :  
  30  m :  namespace refinery {
  31    :  
  32  m :  namespace {
  33    :  
  34  m :  bool GetInnerMostScopeForVA(IDiaSession* session,
  35  m :                              Address va,
  36  m :                              base::win::ScopedComPtr<IDiaSymbol>* scope) {
  37  m :    DCHECK(session);
  38  m :    DCHECK(scope);
  39    :  
  40    :    // Attempt to get a block.
  41  m :    HRESULT hr = session->findSymbolByVA(va, SymTagBlock, scope->Receive());
  42  m :    if (hr != S_OK) {
  43    :      // No SymTagBlock. Attempt to get a SymTagFunction.
  44  m :      hr = session->findSymbolByVA(va, SymTagFunction, scope->Receive());
  45  m :      if (hr != S_OK) {
  46  m :        LOG(ERROR) << base::StringPrintf(
  47  m :                          "Failed to find block or function for VA (%08llx): ",
  48  m :                          va) << common::LogHr(hr);
  49  m :        return false;
  50  m :      }
  51  m :    }
  52    :  
  53  m :    return true;
  54  m :  }
  55    :  
  56  m :  }  // namespace
  57    :  
  58    :  // static
  59  m :  const char StackFrameAnalyzer::kStackFrameAnalyzerName[] = "StackFrameAnalyzer";
  60    :  
  61  m :  StackFrameAnalyzer::StackFrameAnalyzer(
  62  m :      scoped_refptr<DiaSymbolProvider> dia_symbol_provider,
  63  m :      scoped_refptr<SymbolProvider> symbol_provider)
  64  m :      : dia_symbol_provider_(dia_symbol_provider),
  65  m :        symbol_provider_(symbol_provider) {
  66  m :    DCHECK(dia_symbol_provider.get() != nullptr);
  67  m :    DCHECK(symbol_provider.get() != nullptr);
  68  m :  }
  69    :  
  70  m :  Analyzer::AnalysisResult StackFrameAnalyzer::Analyze(
  71  m :      const minidump::Minidump& minidump,
  72  m :      ProcessState* process_state) {
  73  m :    DCHECK(process_state != nullptr);
  74    :  
  75    :    // Ensure the stack frame layer has already been populated.
  76  m :    StackFrameLayerPtr frame_layer;
  77  m :    if (!process_state->FindLayer(&frame_layer)) {
  78  m :      LOG(ERROR) << "StackFrameAnalyzer: no stack frame layer.";
  79  m :      return ANALYSIS_ERROR;
  80  m :    }
  81    :  
  82    :    // Process each stack frame.
  83  m :    for (StackFrameRecordPtr frame_record : *frame_layer) {
  84    :      // TODO(manzagop): figure out the proper return value and handling for
  85    :      // AnalyzeFrame. We won't always be able to analyze frame (eg no symbols)
  86    :      // and that's acceptable.
  87  m :      AnalyzeFrame(frame_record, process_state);
  88  m :    }
  89    :  
  90  m :    return ANALYSIS_COMPLETE;
  91  m :  }
  92    :  
  93  m :  bool StackFrameAnalyzer::AnalyzeFrame(StackFrameRecordPtr frame_record,
  94  m :                                        ProcessState* process_state) {
  95  m :    DCHECK(frame_record.get() != nullptr);
  96  m :    DCHECK(process_state != nullptr);
  97    :  
  98  m :    const StackFrame& frame_proto = frame_record->data();
  99  m :    Address instruction_pointer =
 100  m :        static_cast<Address>(frame_proto.register_info().eip());
 101    :  
 102    :    // Retrieve symbol information.
 103  m :    if (!SetSymbolInformation(instruction_pointer, process_state)) {
 104  m :      LOG(INFO) << "Unable to get symbol information for frame. Skipping.";
 105  m :      return true;  // Not an error.
 106  m :    }
 107  m :    ModuleLayerAccessor accessor(process_state);
 108  m :    ModuleId module_id = accessor.GetModuleId(instruction_pointer);
 109  m :    if (module_id == kNoModuleId) {
 110  m :      LOG(INFO) << "No module corresponding to instruction pointer.";
 111  m :      return false;
 112  m :    }
 113    :  
 114    :    // Get the innermost scope, be it a block or the function itself.
 115    :    // TODO(manzagop): Identical code folding means there may be more than one
 116    :    // symbol for a given address. Look into this.
 117  m :    base::win::ScopedComPtr<IDiaSymbol> scope;
 118  m :    if (!GetInnerMostScopeForVA(dia_session_.get(), instruction_pointer, &scope))
 119  m :      return false;
 120    :  
 121    :    // Walk up the scopes, processing scope's data.
 122  m :    StackFrameDataAnalyzer data_analyzer(frame_record, typename_index_, module_id,
 123  m :                                         process_state);
 124  m :    while (true) {
 125    :      // Process each SymTagData child in the block / function.
 126    :      // TODO(manzagop): the data visitor will stop visiting at the first error.
 127    :      // Figure out how to surface issues without preventing processing (eg
 128    :      // with a callback).
 129  m :      pe::ChildVisitor data_visitor(scope.get(), SymTagData);
 130  m :      if (!data_visitor.VisitChildren(
 131  m :              base::Bind(&StackFrameDataAnalyzer::Analyze,
 132  m :                         base::Unretained(&data_analyzer)))) {
 133  m :        LOG(ERROR) << "Error while analyzing scope. Continuing to next scope.";
 134  m :        return false;
 135  m :      }
 136    :  
 137    :      // Stop processing when function has been processed.
 138  m :      enum SymTagEnum sym_tag_scope = SymTagNull;
 139  m :      if (!pe::GetSymTag(scope.get(), &sym_tag_scope))
 140  m :        return false;
 141  m :      if (sym_tag_scope == SymTagFunction)
 142  m :        break;
 143    :  
 144    :      // Move up to lexical parent.
 145  m :      base::win::ScopedComPtr<IDiaSymbol> lexical_parent;
 146  m :      if (!pe::GetSymLexicalParent(scope.get(), &lexical_parent))
 147  m :        return false;  // We should be able to get to a function.
 148  m :      scope = lexical_parent;
 149  m :    }
 150    :  
 151  m :    return true;
 152  m :  }
 153    :  
 154  m :  bool StackFrameAnalyzer::SetSymbolInformation(Address instruction_pointer,
 155  m :                                                ProcessState* process_state) {
 156  m :    DCHECK(process_state != nullptr);
 157    :  
 158  m :    dia_session_.Release();
 159  m :    typename_index_ = nullptr;
 160    :  
 161    :    // Get the module's signature.
 162  m :    ModuleLayerAccessor accessor(process_state);
 163  m :    pe::PEFile::Signature signature;
 164  m :    if (!accessor.GetModuleSignature(instruction_pointer, &signature))
 165  m :      return false;
 166    :  
 167    :    // Get the typename index for the module.
 168  m :    if (!symbol_provider_->FindOrCreateTypeNameIndex(signature,
 169  m :                                                     &typename_index_)) {
 170  m :      return false;
 171  m :    }
 172    :  
 173    :    // Get dia session for the module and set its address.
 174  m :    base::win::ScopedComPtr<IDiaSession> session_tmp;
 175  m :    if (!dia_symbol_provider_->FindOrCreateDiaSession(signature, &session_tmp))
 176  m :      return false;
 177  m :    HRESULT hr = session_tmp->put_loadAddress(signature.base_address.value());
 178  m :    if (FAILED(hr)) {
 179  m :      LOG(ERROR) << "Unable to set session's load address: " << common::LogHr(hr);
 180  m :      return false;
 181  m :    }
 182  m :    dia_session_ = session_tmp;
 183    :  
 184  m :    return true;
 185  m :  }
 186    :  
 187  m :  }  // namespace refinery

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