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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%00145.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_t> checked_value =
  38  m :        base::CheckedNumeric<uint32_t>::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() : child_frame_context_(nullptr) {
  53  m :  }
  54    :  
  55  m :  Analyzer::AnalysisResult StackAnalyzer::Analyze(
  56  m :      const minidump::Minidump& minidump,
  57  m :      const ProcessAnalysis& process_analysis) {
  58  m :    DCHECK(process_analysis.process_state() != nullptr);
  59  m :    DCHECK(process_analysis.dia_symbol_provider() != nullptr);
  60    :  
  61    :    // Create stack walker and helper.
  62  m :    if (!pe::CreateDiaObject(stack_walker_.Receive(),
  63  m :                             CLSID_DiaStackWalker)) {
  64  m :        return ANALYSIS_ERROR;
  65  m :      }
  66  m :    stack_walk_helper_ =
  67  m :        new StackWalkHelper(process_analysis.dia_symbol_provider());
  68    :  
  69    :    // Get the stack layer - it must already have been populated.
  70  m :    StackLayerPtr stack_layer;
  71  m :    if (!process_analysis.process_state()->FindLayer(&stack_layer)) {
  72  m :      LOG(ERROR) << "Missing stack layer.";
  73  m :      return ANALYSIS_ERROR;
  74  m :    }
  75    :  
  76    :    // Process each thread's stack.
  77  m :    Analyzer::AnalysisResult result = ANALYSIS_COMPLETE;
  78  m :    for (StackRecordPtr stack_record : *stack_layer) {
  79    :      // Attempt to stack walk. Note that the stack walk derailing is not an
  80    :      // analysis error.
  81  m :      Analyzer::AnalysisResult stack_result =
  82  m :          StackWalk(stack_record, process_analysis);
  83  m :      if (stack_result == ANALYSIS_ERROR)
  84  m :        return ANALYSIS_ERROR;
  85  m :      if (stack_result == ANALYSIS_ITERATE)
  86  m :        result = ANALYSIS_ITERATE;
  87  m :    }
  88    :  
  89  m :    return result;
  90  m :  }
  91    :  
  92  m :  Analyzer::AnalysisResult StackAnalyzer::StackWalk(
  93  m :      StackRecordPtr stack_record,
  94  m :      const ProcessAnalysis& process_analysis) {
  95  m :    stack_walk_helper_->SetState(stack_record, process_analysis.process_state());
  96  m :    child_frame_context_ = nullptr;
  97    :  
  98    :    // Create the frame enumerator.
  99  m :    base::win::ScopedComPtr<IDiaEnumStackFrames> frame_enumerator;
 100    :    // TODO(manzagop): this is for x86 platforms. Switch to getEnumFrames2.
 101  m :    HRESULT hr = stack_walker_->getEnumFrames(
 102  m :        static_cast<IDiaStackWalkHelper*>(stack_walk_helper_.get()),
 103  m :        frame_enumerator.Receive());
 104  m :    if (hr != S_OK) {
 105  m :      LOG(ERROR) << "Failed to get frame enumerator: " << common::LogHr(hr)
 106  m :                 << ".";
 107  m :      return ANALYSIS_ERROR;
 108  m :    }
 109  m :    frame_enumerator->Reset();
 110    :  
 111    :    // Walk the stack frames.
 112    :    // TODO(manzagop): changes for non-X86 platforms (eg registers).
 113  m :    while (true) {
 114  m :      base::win::ScopedComPtr<IDiaStackFrame> stack_frame;
 115  m :      DWORD retrieved_cnt = 0;
 116  m :      hr = frame_enumerator->Next(1, stack_frame.Receive(), &retrieved_cnt);
 117  m :      if (!SUCCEEDED(hr)) {
 118    :        // Stack walking derailed. Not an an analyzer error per se.
 119  m :        LOG(ERROR) << "Failed to get stack frame: " << common::LogHr(hr) << ".";
 120  m :        return ANALYSIS_COMPLETE;
 121  m :      }
 122  m :      if (hr == S_FALSE || retrieved_cnt != 1)
 123  m :        break;  // No frame.
 124    :  
 125  m :      if (!InsertStackFrameRecord(stack_frame.get(), process_analysis))
 126  m :        return ANALYSIS_ERROR;
 127    :  
 128    :      // WinDBG seems to use a null return address as a termination criterion.
 129  m :      ULONGLONG frame_return_addr = 0ULL;
 130  m :      hr = stack_frame->get_returnAddress(&frame_return_addr);
 131  m :      if (hr != S_OK) {
 132  m :        LOG(ERROR) << "Failed to get frame's return address: "
 133  m :                   << common::LogHr(hr) << ".";
 134  m :        return ANALYSIS_ERROR;
 135  m :      }
 136  m :      if (frame_return_addr == 0ULL) {
 137  m :        stack_record->mutable_data()->set_stack_walk_success(true);
 138  m :        break;
 139  m :      }
 140  m :    }
 141    :  
 142  m :    return ANALYSIS_COMPLETE;
 143  m :  }
 144    :  
 145    :  // TODO(manzagop): revise when support expands beyond x86.
 146  m :  bool StackAnalyzer::InsertStackFrameRecord(
 147  m :      IDiaStackFrame* stack_frame,
 148  m :      const ProcessAnalysis& process_analysis) {
 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  m :    if (frame_full_size.ValueOrDie() == 0U)
 187  m :      return true;  // Skip empty frame.
 188    :  
 189    :    // Create the stack frame record.
 190  m :    AddressRange range(static_cast<Address>(frame_top),
 191  m :                       static_cast<Size>(frame_full_size.ValueOrDie()));
 192  m :    if (!range.IsValid()) {
 193  m :      LOG(ERROR) << "Invalid frame range.";
 194  m :      return false;
 195  m :    }
 196    :  
 197  m :    StackFrameLayerPtr frame_layer;
 198  m :    process_analysis.process_state()->FindOrCreateLayer(&frame_layer);
 199    :  
 200  m :    StackFrameRecordPtr frame_record;
 201  m :    frame_layer->CreateRecord(range, &frame_record);
 202  m :    StackFrame* frame_proto = frame_record->mutable_data();
 203    :  
 204    :    // Populate the stack frame record.
 205    :  
 206    :    // Register context.
 207    :    // TODO(manzagop): flesh out the register context.
 208  m :    RegisterInformation* context = frame_proto->mutable_register_info();
 209  m :    uint32_t eip = 0U;
 210  m :    if (!GetRegisterValue(stack_frame, CV_REG_EIP, &eip))
 211  m :      return false;
 212  m :    context->set_eip(eip);
 213  m :    uint32_t allreg_vframe = 0U;
 214  m :    if (GetRegisterValue(stack_frame, CV_ALLREG_VFRAME, &allreg_vframe)) {
 215    :      // Register doesn't seem to always be available. Not considered an error.
 216  m :      context->set_allreg_vframe(allreg_vframe);
 217  m :      if (child_context)
 218  m :        child_context->set_parent_allreg_vframe(allreg_vframe);
 219  m :    }
 220    :  
 221  m :    frame_proto->set_frame_size_bytes(frame_size);
 222  m :    frame_proto->set_locals_base(locals_base);
 223    :  
 224  m :    child_frame_context_ = context;
 225  m :    return true;
 226  m :  }
 227    :  
 228  m :  }  // namespace refinery

Coverage information generated Fri Jul 29 11:00:21 2016.