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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
90.9%1001100.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  E :      return 0;
  42  i :    bytes -= offsetof(StackCapture, frames_);
  43  i :    bytes /= sizeof(void*);
  44  i :    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_ = std::min<uint8>(num_frames, max_num_frames_);
  80    :  
  81  E :    ::memcpy(frames_, frames, num_frames_ * sizeof(*frames_));
  82    :  
  83  E :    ComputeAbsoluteStackId();
  84  E :  }
  85    :  
  86  E :  void StackCapture::InitFromExistingStack(const StackCapture& stack_capture) {
  87  E :    DCHECK(stack_capture.frames() != NULL);
  88  E :    DCHECK_LT(0U, stack_capture.num_frames());
  89    :  
  90    :    // Determine how many frames we can actually store.
  91  E :    num_frames_ = std::min<uint8>(stack_capture.num_frames(), max_num_frames_);
  92    :  
  93  E :    ::memcpy(frames_, stack_capture.frames(), num_frames_ * sizeof(*frames_));
  94    :  
  95    :    // If the number of frames differs, we recalculate the stack ID.
  96  E :    if (num_frames_ == stack_capture.num_frames())
  97  E :      absolute_stack_id_ = stack_capture.absolute_stack_id();
  98  E :    else
  99  i :      ComputeAbsoluteStackId();
 100  E :  }
 101    :  
 102    :  // Disable optimizations so that this function generates a standard frame, and
 103    :  // don't allow it to be inlined.
 104    :  #pragma optimize("", off)
 105  E :  void __declspec(noinline) StackCapture::InitFromStack() {
 106    :    num_frames_ = agent::common::WalkStack(1, max_num_frames_, frames_,
 107  E :                                           &absolute_stack_id_);
 108    :  
 109  E :    if (bottom_frames_to_skip_) {
 110    :      num_frames_ -=
 111  i :          std::min(static_cast<uint8>(bottom_frames_to_skip_), num_frames_);
 112  i :      ComputeAbsoluteStackId();
 113    :    }
 114  E :  }
 115    :  #pragma optimize("", on)
 116    :  
 117    :  namespace {
 118    :  
 119    :  // An address space for storing false modules. These will be reported via
 120    :  // GetModuleFromAddress, used in ComputeRelativeStackId.
 121    :  using FalseModuleSpace = core::AddressSpace<uintptr_t, uintptr_t, const char*>;
 122  E :  FalseModuleSpace false_module_space;
 123    :  
 124    :  // Returns an untracked handle to the module containing the given address, if
 125    :  // there is one. Returns nullptr if no module is found. If false modules have
 126    :  // been injected via the testing seam, will first check those.
 127  E :  HMODULE GetModuleFromAddress(void* address) {
 128    :    // Try the false module space first.
 129  E :    if (!false_module_space.empty()) {
 130  E :      FalseModuleSpace::Range range(reinterpret_cast<uintptr_t>(address), 1);
 131  E :      auto it = false_module_space.FindContaining(range);
 132  E :      if (it != false_module_space.end())
 133  E :        return reinterpret_cast<HMODULE>(it->first.start());
 134    :    }
 135    :  
 136    :    // Query the OS for any loaded modules that house the given address.
 137  E :    HMODULE instance = nullptr;
 138    :    if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
 139    :                              GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
 140    :                              static_cast<char*>(address),
 141  E :                              &instance)) {
 142    :      // Because of JITted code it is entirely possible to encounter frames
 143    :      // that lie outside of all modules. In this case GetModuleHandlExA will
 144    :      // fail, which actually causes an error in base::GetModuleHandleExA.
 145  i :      return nullptr;
 146    :    }
 147  E :    return instance;
 148  E :  }
 149    :  
 150    :  }  // namespace
 151    :  
 152    :  void StackCapture::AddFalseModule(
 153  E :      const char* name, void* address, size_t length) {
 154    :    FalseModuleSpace::Range range(reinterpret_cast<uintptr_t>(address),
 155  E :                                  static_cast<uintptr_t>(length));
 156  E :    CHECK(false_module_space.Insert(range, name));
 157  E :  }
 158    :  
 159  E :  void StackCapture::ClearFalseModules() {
 160  E :    false_module_space.Clear();
 161  E :  }
 162    :  
 163    :  size_t StackCapture::HashCompare::operator()(
 164  E :      const StackCapture* stack_capture) const {
 165  E :    DCHECK(stack_capture != NULL);
 166    :    // We're assuming that the StackId and size_t have the same size, so let's
 167    :    // make sure that's the case.
 168    :    static_assert(sizeof(StackId) == sizeof(size_t),
 169    :                  "StackId and size_t should have the same size.");
 170  E :    return stack_capture->absolute_stack_id();
 171  E :  }
 172    :  
 173    :  bool StackCapture::HashCompare::operator()(
 174    :      const StackCapture* stack_capture1,
 175  E :      const StackCapture* stack_capture2) const {
 176  E :    DCHECK(stack_capture1 != NULL);
 177  E :    DCHECK(stack_capture2 != NULL);
 178    :    return stack_capture1->absolute_stack_id() ==
 179  E :           stack_capture2->absolute_stack_id();
 180  E :  }
 181    :  
 182  E :  void StackCapture::ComputeAbsoluteStackId() {
 183  E :    absolute_stack_id_ = StartStackId();
 184    :  
 185  E :    for (uint8 i = 0; i < num_frames_; ++i)
 186  E :      absolute_stack_id_ = UpdateStackId(absolute_stack_id_, frames_[i]);
 187    :  
 188  E :    absolute_stack_id_ = FinalizeStackId(absolute_stack_id_, num_frames_);
 189  E :  }
 190    :  
 191  E :  void StackCapture::ComputeRelativeStackId() const {
 192    :    // We want to ignore the frames relative to our module to be able to get the
 193    :    // same trace id even if we update our runtime.
 194  E :    HANDLE asan_handle = reinterpret_cast<HANDLE>(&__ImageBase);
 195  E :    DCHECK(asan_handle != NULL);
 196  E :    DCHECK(!relative_stack_id_);
 197    :  
 198  E :    relative_stack_id_ = StartStackId();
 199  E :    for (size_t i = 0; i < num_frames_; ++i) {
 200    :      // NULL stack frames may be returned from ::CaptureStackBackTrace.
 201    :      // This has been observed on Windows 8.
 202  E :      if (frames_[i] == nullptr)
 203  i :        continue;
 204    :  
 205    :      // Entirely skip frames that lie inside this module. This allows the
 206    :      // relative stack ID to be stable across different versions of the RTL
 207    :      // even if stack depth/layout changes.
 208  E :      HMODULE module = GetModuleFromAddress(frames_[i]);
 209  E :      if (module == asan_handle)
 210  E :        continue;
 211    :  
 212    :      // Consider frames that are dynamically generated, but consider only their
 213    :      // indices, not their addresses.
 214  E :      uintptr_t frame = i;
 215  E :      if (module != nullptr) {
 216    :        // For frames that fall within a module, consider their relative address
 217    :        // in the module.
 218    :        frame = reinterpret_cast<uintptr_t>(frames_[i]) -
 219  E :                reinterpret_cast<uintptr_t>(module);
 220    :      }
 221    :  
 222    :      relative_stack_id_ =
 223  E :          UpdateStackId(relative_stack_id_, reinterpret_cast<void*>(frame));
 224  E :    }
 225    :  
 226  E :    relative_stack_id_ = FinalizeStackId(relative_stack_id_, num_frames_);
 227    :  
 228    :    // We could end up with the value 0, in which case we set it to something
 229    :    // else, as 0 is considered uninitialized.
 230  E :    if (!relative_stack_id_)
 231  i :      relative_stack_id_ = ~relative_stack_id_;
 232  E :  }
 233    :  
 234    :  }  // namespace common
 235    :  }  // namespace agent

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