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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%00142.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_analyzer.h"
  16    :  
  17    :  #include "base/numerics/safe_math.h"
  18    :  #include "base/strings/stringprintf.h"
  19    :  #include "syzygy/common/com_utils.h"
  20    :  #include "syzygy/pe/dia_util.h"
  21    :  #include "syzygy/refinery/analyzers/stack_analyzer_impl.h"
  22    :  #include "syzygy/refinery/process_state/refinery.pb.h"
  23    :  
  24  m :  namespace refinery {
  25    :  
  26  m :  namespace {
  27    :  
  28  m :  bool GetRegisterValue(IDiaStackFrame* frame,
  29  m :                        CV_HREG_e register_index,
  30  m :                        uint32_t* register_value) {
  31  m :    DCHECK(frame); DCHECK(register_value);
  32    :  
  33  m :    uint64_t value = 0ULL;
  34  m :    if (!pe::GetRegisterValue(frame, register_index, &value)) {
  35  m :      return false;
  36  m :    }
  37  m :    base::CheckedNumeric<uint32> checked_value =
  38  m :        base::CheckedNumeric<uint32>::cast(value);
  39  m :    if (!checked_value.IsValid()) {
  40  m :      LOG(ERROR) << "register value is not a 32 bit value.";
  41  m :      return false;
  42  m :    }
  43  m :    *register_value = checked_value.ValueOrDie();
  44  m :    return true;
  45  m :  }
  46    :  
  47  m :  }  // namespace
  48    :  
  49    :  // static
  50  m :  const char StackAnalyzer::kStackAnalyzerName[] = "StackAnalyzer";
  51    :  
  52  m :  StackAnalyzer::StackAnalyzer(scoped_refptr<DiaSymbolProvider> symbol_provider)
  53  m :      : symbol_provider_(symbol_provider), child_frame_context_(nullptr) {
  54  m :    DCHECK(symbol_provider.get() != nullptr);
  55  m :  }
  56    :  
  57  m :  Analyzer::AnalysisResult StackAnalyzer::Analyze(
  58  m :      const minidump::Minidump& minidump,
  59  m :      ProcessState* process_state) {
  60  m :    DCHECK(process_state != nullptr);
  61    :  
  62    :    // Create stack walker and helper.
  63  m :    HRESULT hr = stack_walker_.CreateInstance(CLSID_DiaStackWalker);
  64  m :    if (hr != S_OK) {
  65  m :      LOG(ERROR) << "Failed to create DiaStackWalker: " << common::LogHr(hr)
  66  m :                 << ".";
  67  m :      return ANALYSIS_ERROR;
  68  m :    }
  69  m :    stack_walk_helper_ = new StackWalkHelper(symbol_provider_);
  70    :  
  71    :    // Get the stack layer - it must already have been populated.
  72  m :    StackLayerPtr stack_layer;
  73  m :    if (!process_state->FindLayer(&stack_layer)) {
  74  m :      LOG(ERROR) << "Missing stack layer.";
  75  m :      return ANALYSIS_ERROR;
  76  m :    }
  77    :  
  78    :    // Process each thread's stack.
  79  m :    Analyzer::AnalysisResult result = ANALYSIS_COMPLETE;
  80  m :    for (StackRecordPtr stack_record : *stack_layer) {
  81    :      // Attempt to stack walk. Note that the stack walk derailing is not an
  82    :      // analysis error.
  83  m :      Analyzer::AnalysisResult stack_result =
  84  m :          StackWalk(stack_record, process_state);
  85  m :      if (stack_result == ANALYSIS_ERROR)
  86  m :        return ANALYSIS_ERROR;
  87  m :      if (stack_result == ANALYSIS_ITERATE)
  88  m :        result = ANALYSIS_ITERATE;
  89  m :    }
  90    :  
  91  m :    return result;
  92  m :  }
  93    :  
  94  m :  Analyzer::AnalysisResult StackAnalyzer::StackWalk(StackRecordPtr stack_record,
  95  m :                                                    ProcessState* process_state) {
  96  m :    stack_walk_helper_->SetState(stack_record, process_state);
  97  m :    child_frame_context_ = nullptr;
  98    :  
  99    :    // Create the frame enumerator.
 100  m :    base::win::ScopedComPtr<IDiaEnumStackFrames> frame_enumerator;
 101    :    // TODO(manzagop): this is for x86 platforms. Switch to getEnumFrames2.
 102  m :    HRESULT hr = stack_walker_->getEnumFrames(
 103  m :        static_cast<IDiaStackWalkHelper*>(stack_walk_helper_.get()),
 104  m :        frame_enumerator.Receive());
 105  m :    if (hr != S_OK) {
 106  m :      LOG(ERROR) << "Failed to get frame enumerator: " << common::LogHr(hr)
 107  m :                 << ".";
 108  m :      return ANALYSIS_ERROR;
 109  m :    }
 110  m :    frame_enumerator->Reset();
 111    :  
 112    :    // Walk the stack frames.
 113    :    // TODO(manzagop): changes for non-X86 platforms (eg registers).
 114  m :    while (true) {
 115  m :      base::win::ScopedComPtr<IDiaStackFrame> stack_frame;
 116  m :      DWORD retrieved_cnt = 0;
 117  m :      hr = frame_enumerator->Next(1, stack_frame.Receive(), &retrieved_cnt);
 118  m :      if (!SUCCEEDED(hr)) {
 119    :        // Stack walking derailed. Not an an analyzer error per se.
 120  m :        LOG(ERROR) << "Failed to get stack frame: " << common::LogHr(hr) << ".";
 121  m :        return ANALYSIS_COMPLETE;
 122  m :      }
 123  m :      if (hr == S_FALSE || retrieved_cnt != 1)
 124  m :        break;  // No frame.
 125    :  
 126  m :      if (!InsertStackFrameRecord(stack_frame.get(), process_state))
 127  m :        return ANALYSIS_ERROR;
 128    :  
 129    :      // WinDBG seems to use a null return address as a termination criterion.
 130  m :      ULONGLONG frame_return_addr = 0ULL;
 131  m :      hr = stack_frame->get_returnAddress(&frame_return_addr);
 132  m :      if (hr != S_OK) {
 133  m :        LOG(ERROR) << "Failed to get frame's return address: "
 134  m :                   << common::LogHr(hr) << ".";
 135  m :        return ANALYSIS_ERROR;
 136  m :      }
 137  m :      if (frame_return_addr == 0ULL) {
 138  m :        stack_record->mutable_data()->set_stack_walk_success(true);
 139  m :        break;
 140  m :      }
 141  m :    }
 142    :  
 143  m :    return ANALYSIS_COMPLETE;
 144  m :  }
 145    :  
 146    :  // TODO(manzagop): revise when support expands beyond x86.
 147  m :  bool StackAnalyzer::InsertStackFrameRecord(IDiaStackFrame* stack_frame,
 148  m :                                             ProcessState* process_state) {
 149  m :    RegisterInformation* child_context = child_frame_context_;
 150  m :    child_frame_context_ = nullptr;
 151    :  
 152    :    // Get the frame's base.
 153  m :    uint64_t frame_base = 0ULL;
 154  m :    if (!pe::GetFrameBase(stack_frame, &frame_base))
 155  m :      return false;
 156    :  
 157    :    // Get frame's top.
 158  m :    uint64_t frame_top = 0ULL;
 159  m :    if (!pe::GetRegisterValue(stack_frame, CV_REG_ESP, &frame_top))
 160  m :      return false;
 161    :  
 162    :    // Get the frame's size. Note: this differs from the difference between
 163    :    // top of frame and base in that it excludes callee parameter size.
 164  m :    uint32_t frame_size = 0U;
 165  m :    if (!pe::GetSize(stack_frame, &frame_size))
 166  m :      return false;
 167    :  
 168    :    // Get base address of locals.
 169  m :    uint64_t locals_base = 0ULL;
 170  m :    if (!pe::GetLocalsBase(stack_frame, &locals_base))
 171  m :      return false;
 172    :  
 173    :    // TODO(manzagop): get register values and some notion about their validity.
 174    :  
 175    :    // Populate the stack frame layer.
 176    :  
 177    :    // Compute the frame's full size.
 178  m :    DCHECK_LE(frame_top, frame_base);
 179  m :    base::CheckedNumeric<Size> frame_full_size =
 180  m :        base::CheckedNumeric<Size>::cast(frame_base - frame_top);
 181  m :    if (!frame_full_size.IsValid()) {
 182  m :      LOG(ERROR) << "Frame full size doesn't fit a 32bit integer.";
 183  m :      return false;
 184  m :    }
 185    :  
 186    :    // Create the stack frame record.
 187  m :    AddressRange range(static_cast<Address>(frame_top),
 188  m :                       static_cast<Size>(frame_full_size.ValueOrDie()));
 189  m :    if (!range.IsValid()) {
 190  m :      LOG(ERROR) << "Invalid frame range.";
 191  m :      return false;
 192  m :    }
 193    :  
 194  m :    StackFrameLayerPtr frame_layer;
 195  m :    process_state->FindOrCreateLayer(&frame_layer);
 196    :  
 197  m :    StackFrameRecordPtr frame_record;
 198  m :    frame_layer->CreateRecord(range, &frame_record);
 199  m :    StackFrame* frame_proto = frame_record->mutable_data();
 200    :  
 201    :    // Populate the stack frame record.
 202    :  
 203    :    // Register context.
 204    :    // TODO(manzagop): flesh out the register context.
 205  m :    RegisterInformation* context = frame_proto->mutable_register_info();
 206  m :    uint32_t eip = 0U;
 207  m :    if (!GetRegisterValue(stack_frame, CV_REG_EIP, &eip))
 208  m :      return false;
 209  m :    context->set_eip(eip);
 210  m :    uint32_t allreg_vframe = 0U;
 211  m :    if (GetRegisterValue(stack_frame, CV_ALLREG_VFRAME, &allreg_vframe)) {
 212    :      // Register doesn't seem to always be available. Not considered an error.
 213  m :      context->set_allreg_vframe(allreg_vframe);
 214  m :      child_context->set_parent_allreg_vframe(allreg_vframe);
 215  m :    }
 216    :  
 217  m :    frame_proto->set_frame_size_bytes(frame_size);
 218  m :    frame_proto->set_locals_base(locals_base);
 219    :  
 220  m :    child_frame_context_ = context;
 221  m :    return true;
 222  m :  }
 223    :  
 224  m :  }  // namespace refinery

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