Coverage for /Syzygy/agent/common/stack_capture.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
92.1%931010.C++source

Line-by-line coverage:

   1    :  // Copyright 2013 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/agent/common/stack_capture.h"
  16    :  
  17    :  #include <algorithm>
  18    :  
  19    :  #include "base/logging.h"
  20    :  #include "syzygy/agent/common/stack_walker_x86.h"
  21    :  #include "syzygy/core/address_space.h"
  22    :  
  23    :  // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
  24    :  extern "C" IMAGE_DOS_HEADER __ImageBase;
  25    :  
  26    :  namespace agent {
  27    :  namespace common {
  28    :  
  29    :  // The number of bottom frames to skip per stack trace.
  30    :  size_t StackCapture::bottom_frames_to_skip_ =
  31  E :      ::common::kDefaultBottomFramesToSkip;
  32    :  
  33  E :  size_t StackCapture::GetSize(size_t max_num_frames) {
  34  E :    DCHECK_LT(0u, max_num_frames);
  35  E :    max_num_frames = std::min(max_num_frames, kMaxNumFrames);
  36  E :    return offsetof(StackCapture, frames_) + max_num_frames * sizeof(void*);
  37  E :  }
  38    :  
  39  E :  size_t StackCapture::GetMaxNumFrames(size_t bytes) {
  40  E :    if (bytes < offsetof(StackCapture, frames_))
  41  i :      return 0;
  42  E :    bytes -= offsetof(StackCapture, frames_);
  43  E :    bytes /= sizeof(void*);
  44  E :    return bytes;
  45  E :  }
  46    :  
  47  E :  void StackCapture::AddRef() {
  48  E :    if (RefCountIsSaturated())
  49  i :      return;
  50  E :    DCHECK_GT(kMaxRefCount, ref_count_);
  51  E :    ++ref_count_;
  52  E :  }
  53    :  
  54  E :  void StackCapture::RemoveRef() {
  55  E :    DCHECK_LT(0u, ref_count_);
  56  E :    if (RefCountIsSaturated())
  57  E :      return;
  58  E :    --ref_count_;
  59  E :  }
  60    :  
  61  E :  StackId StackCapture::relative_stack_id() const {
  62    :    // Note that by design 0 is a not a valid stack ID.
  63  E :    if (!relative_stack_id_)
  64  E :      ComputeRelativeStackId();
  65  E :    return relative_stack_id_;
  66  E :  }
  67    :  
  68    :  // static
  69  E :  void StackCapture::Init() {
  70  E :    bottom_frames_to_skip_ = ::common::kDefaultBottomFramesToSkip;
  71  E :  }
  72    :  
  73    :  void StackCapture::InitFromBuffer(const void* const* frames,
  74  E :                                    size_t num_frames) {
  75  E :    DCHECK(frames != NULL);
  76  E :    DCHECK_LT(0U, num_frames);
  77    :  
  78    :    // Determine how many frames we can actually store.
  79  E :    num_frames_ =
  80    :        std::min<uint8_t>(static_cast<uint8_t>(num_frames), max_num_frames_);
  81    :  
  82  E :    ::memcpy(frames_, frames, num_frames_ * sizeof(*frames_));
  83    :  
  84  E :    ComputeAbsoluteStackId();
  85  E :  }
  86    :  
  87  E :  void StackCapture::InitFromExistingStack(const StackCapture& stack_capture) {
  88  E :    DCHECK(stack_capture.frames() != NULL);
  89  E :    DCHECK_LT(0U, stack_capture.num_frames());
  90    :  
  91    :    // Determine how many frames we can actually store.
  92  E :    num_frames_ = std::min<uint8_t>(
  93    :        static_cast<uint8_t>(stack_capture.num_frames()), max_num_frames_);
  94    :  
  95  E :    ::memcpy(frames_, stack_capture.frames(), num_frames_ * sizeof(*frames_));
  96    :  
  97    :    // If the number of frames differs, we recalculate the stack ID.
  98  E :    if (num_frames_ == stack_capture.num_frames())
  99  E :      absolute_stack_id_ = stack_capture.absolute_stack_id();
 100  E :    else
 101  i :      ComputeAbsoluteStackId();
 102  E :  }
 103    :  
 104    :  // Disable optimizations so that this function generates a standard frame, and
 105    :  // don't allow it to be inlined.
 106    :  #pragma optimize("", off)
 107  E :  void __declspec(noinline) StackCapture::InitFromStack() {
 108  E :    num_frames_ = static_cast<uint8_t>(agent::common::WalkStack(
 109    :        1, max_num_frames_, frames_, &absolute_stack_id_));
 110    :  
 111  E :    if (bottom_frames_to_skip_) {
 112  i :      num_frames_ -=
 113    :          std::min(static_cast<uint8_t>(bottom_frames_to_skip_), num_frames_);
 114  i :      ComputeAbsoluteStackId();
 115    :    }
 116  E :  }
 117    :  #pragma optimize("", on)
 118    :  
 119    :  namespace {
 120    :  
 121    :  // An address space for storing false modules. These will be reported via
 122    :  // GetModuleFromAddress, used in ComputeRelativeStackId.
 123    :  using FalseModuleSpace = core::AddressSpace<uintptr_t, uintptr_t, const char*>;
 124  E :  FalseModuleSpace false_module_space;
 125    :  
 126    :  // Returns an untracked handle to the module containing the given address, if
 127    :  // there is one. Returns nullptr if no module is found. If false modules have
 128    :  // been injected via the testing seam, will first check those.
 129  E :  HMODULE GetModuleFromAddress(void* address) {
 130    :    // Try the false module space first.
 131  E :    if (!false_module_space.empty()) {
 132  E :      FalseModuleSpace::Range range(reinterpret_cast<uintptr_t>(address), 1);
 133  E :      auto it = false_module_space.FindContaining(range);
 134  E :      if (it != false_module_space.end())
 135  E :        return reinterpret_cast<HMODULE>(it->first.start());
 136    :    }
 137    :  
 138    :    // Query the OS for any loaded modules that house the given address.
 139  E :    HMODULE instance = nullptr;
 140  E :    if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
 141    :                              GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
 142    :                              static_cast<char*>(address),
 143    :                              &instance)) {
 144    :      // Because of JITted code it is entirely possible to encounter frames
 145    :      // that lie outside of all modules. In this case GetModuleHandlExA will
 146    :      // fail, which actually causes an error in base::GetModuleHandleExA.
 147  i :      return nullptr;
 148    :    }
 149  E :    return instance;
 150  E :  }
 151    :  
 152    :  }  // namespace
 153    :  
 154    :  void StackCapture::AddFalseModule(
 155  E :      const char* name, void* address, size_t length) {
 156  E :    FalseModuleSpace::Range range(reinterpret_cast<uintptr_t>(address),
 157    :                                  static_cast<uintptr_t>(length));
 158  E :    CHECK(false_module_space.Insert(range, name));
 159  E :  }
 160    :  
 161  E :  void StackCapture::ClearFalseModules() {
 162  E :    false_module_space.Clear();
 163  E :  }
 164    :  
 165  E :  void StackCapture::ComputeAbsoluteStackId() {
 166  E :    absolute_stack_id_ = StartStackId();
 167    :  
 168  E :    for (uint8_t i = 0; i < num_frames_; ++i)
 169  E :      absolute_stack_id_ = UpdateStackId(absolute_stack_id_, frames_[i]);
 170    :  
 171  E :    absolute_stack_id_ = FinalizeStackId(absolute_stack_id_, num_frames_);
 172  E :  }
 173    :  
 174  E :  void StackCapture::ComputeRelativeStackId() const {
 175    :    // We want to ignore the frames relative to our module to be able to get the
 176    :    // same trace id even if we update our runtime.
 177  E :    HANDLE asan_handle = reinterpret_cast<HANDLE>(&__ImageBase);
 178  E :    DCHECK(asan_handle != NULL);
 179  E :    DCHECK(!relative_stack_id_);
 180    :  
 181  E :    relative_stack_id_ = StartStackId();
 182  E :    for (size_t i = 0; i < num_frames_; ++i) {
 183    :      // NULL stack frames may be returned from ::CaptureStackBackTrace.
 184    :      // This has been observed on Windows 8.
 185  E :      if (frames_[i] == nullptr)
 186  i :        continue;
 187    :  
 188    :      // Entirely skip frames that lie inside this module. This allows the
 189    :      // relative stack ID to be stable across different versions of the RTL
 190    :      // even if stack depth/layout changes.
 191  E :      HMODULE module = GetModuleFromAddress(frames_[i]);
 192  E :      if (module == asan_handle)
 193  E :        continue;
 194    :  
 195    :      // Consider frames that are dynamically generated, but consider only their
 196    :      // indices, not their addresses.
 197  E :      uintptr_t frame = i;
 198  E :      if (module != nullptr) {
 199    :        // For frames that fall within a module, consider their relative address
 200    :        // in the module.
 201  E :        frame = reinterpret_cast<uintptr_t>(frames_[i]) -
 202    :                reinterpret_cast<uintptr_t>(module);
 203    :      }
 204    :  
 205  E :      relative_stack_id_ =
 206    :          UpdateStackId(relative_stack_id_, reinterpret_cast<void*>(frame));
 207  E :    }
 208    :  
 209  E :    relative_stack_id_ = FinalizeStackId(relative_stack_id_, num_frames_);
 210    :  
 211    :    // We could end up with the value 0, in which case we set it to something
 212    :    // else, as 0 is considered uninitialized.
 213  E :    if (!relative_stack_id_)
 214  i :      relative_stack_id_ = ~relative_stack_id_;
 215  E :  }
 216    :  
 217    :  }  // namespace common
 218    :  }  // namespace agent

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