Coverage for /Syzygy/agent/asan/stack_capture.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
96.6%28290.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    :  // Declares a utility class for getting and storing quick and dirty stack
  16    :  // captures.
  17    :  
  18    :  #ifndef SYZYGY_AGENT_ASAN_STACK_CAPTURE_H_
  19    :  #define SYZYGY_AGENT_ASAN_STACK_CAPTURE_H_
  20    :  
  21    :  #include <windows.h>
  22    :  
  23    :  #include "base/logging.h"
  24    :  
  25    :  namespace agent {
  26    :  namespace asan {
  27    :  
  28    :  // Computes the hash of a given stack trace. The hash function is simply an add
  29    :  // of all the stack trace pointers.
  30    :  uint32 ComputeStackTraceHash(void** stack_trace, uint8 stack_depth);
  31    :  
  32    :  // A simple class for holding a stack trace capture.
  33    :  class StackCapture {
  34    :   public:
  35    :    // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
  36    :    // The maximum number of frames which CaptureStackBackTrace can be asked
  37    :    // to traverse must be less than 63, so set it to 62.
  38    :    static const size_t kMaxNumFrames = 62;
  39    :  
  40    :    // The type used for reference counting. We use saturation arithmetic, so it
  41    :    // will top out at kMaxRefCount.
  42    :    typedef uint16 RefCount;
  43    :    static const RefCount kMaxRefCount = -1;
  44    :  
  45    :    // This corresponds to the the type used by ::CaptureStackBackTrace's hash
  46    :    // for a stack-trace.
  47    :    typedef ULONG StackId;
  48    :  
  49    :    StackCapture()
  50    :        : ref_count_(0), stack_id_(0), num_frames_(0),
  51  E :          max_num_frames_(kMaxNumFrames) {
  52  E :    }
  53    :  
  54  E :    explicit StackCapture(size_t max_num_frames)
  55    :        : ref_count_(0), stack_id_(0), num_frames_(0), max_num_frames_(0) {
  56  E :      DCHECK_LT(0u, max_num_frames);
  57  E :      DCHECK_GE(kMaxNumFrames, max_num_frames);
  58  E :      max_num_frames_ = max_num_frames;
  59  E :    }
  60    :  
  61    :    // Static initialisation of StackCapture context.
  62    :    static void Init();
  63    :  
  64    :    // Calculate the size necessary to store a StackCapture with the given
  65    :    // number of stack frames.
  66    :    // @param max_num_frames The maximum number of stack frames the object needs
  67    :    //     to be able to hold.
  68    :    // @returns the size of a StackCapture object with the given number of frames.
  69    :    static size_t GetSize(size_t max_num_frames);
  70    :  
  71    :    // Calculate the max number of frames that can be fit into a memory region of
  72    :    // the given size.
  73    :    // @param bytes The number of bytes to be used.
  74    :    // @returns the maxmimum number of frames that will fit in the provided number
  75    :    //     of bytes.
  76    :    static size_t GetMaxNumFrames(size_t bytes);
  77    :  
  78    :    // @returns the size of this initialized StackCapture object.
  79  E :    size_t Size() const { return GetSize(max_num_frames_); }
  80    :  
  81    :    // @returns true if this stack trace capture contains valid frame pointers.
  82  E :    bool IsValid() const { return num_frames_ != 0; }
  83    :  
  84    :    // Increments the reference count of this stack capture.
  85    :    void AddRef();
  86    :  
  87    :    // Decrements the reference count of this stack capture.
  88    :    void RemoveRef();
  89    :  
  90    :    // @returns true if the reference count is saturated, false otherwise. A
  91    :    //     saturated reference count means that further calls to AddRef and
  92    :    //     RemoveRef will be nops, and HasNoRefs will always return false.
  93  E :    bool RefCountIsSaturated() const { return ref_count_ == kMaxRefCount; }
  94    :  
  95    :    // @returns true if this stack capture is not referenced, false otherwise.
  96  E :    bool HasNoRefs() const { return ref_count_ == 0; }
  97    :  
  98    :    // @returns the ID associated with this stack trace.
  99  E :    StackId stack_id() const { return stack_id_; }
 100    :  
 101    :    // @returns the number of valid frame pointers in this stack trace capture.
 102  E :    size_t num_frames() const { return num_frames_; }
 103    :  
 104    :    // @returns the maximum number of valid frame pointers in this stack trace
 105    :    //     capture.
 106  E :    size_t max_num_frames() const { return max_num_frames_; }
 107    :  
 108    :    // @returns a pointer to the captured stack frames, or NULL if no stack
 109    :    //     frames have been captured.
 110  E :    const void* const* frames() const { return IsValid() ? frames_ : NULL; }
 111    :  
 112    :    // Sets the stack ID for a given trace.
 113    :    // @param The stack ID to set.
 114  E :    void set_stack_id(StackId stack_id) { stack_id_ = stack_id; }
 115    :  
 116    :    // Set the number of bottom frames to skip per stack trace. This is needed to
 117    :    // be able to improve the stack cache compression in Chrome's unittests where
 118    :    // the bottom of the stack traces is different for each test case.
 119    :    // @param bottom_frames_to_skip The number of bottom frames to skip.
 120  E :    static void set_bottom_frames_to_skip(size_t bottom_frames_to_skip) {
 121  E :      CHECK_LT(bottom_frames_to_skip, kMaxNumFrames);
 122  E :      bottom_frames_to_skip_ = bottom_frames_to_skip;
 123  E :    }
 124    :  
 125    :    // Get the number of bottom frames to skip per stack trace.
 126  E :    static size_t bottom_frames_to_skip() { return bottom_frames_to_skip_; }
 127    :  
 128    :    // Initializes a stack trace from an array of frame pointers, a count and
 129    :    // a StackId (such as returned by ::CaptureStackBackTrace).
 130    :    // @param stack_id The ID of the stack back trace.
 131    :    // @param frames an array of frame pointers.
 132    :    // @param num_frames the number of valid frame pointers in @frames. Note
 133    :    //     that at most kMaxNumFrames frame pointers will be copied to this
 134    :    //     stack trace capture.
 135    :    void InitFromBuffer(StackId stack_id,
 136    :                        const void* const* frames,
 137    :                        size_t num_frames);
 138    :  
 139    :    // Initializes a stack trace using ::CaptureStackBackTrace. This is inlined so
 140    :    // that it doesn't further pollute the stack trace, but rather makes it
 141    :    // reflect the actual point of the call.
 142  E :    __forceinline void InitFromStack() {
 143    :      num_frames_ = ::CaptureStackBackTrace(
 144  E :          0, max_num_frames_, frames_, NULL);
 145  E :      if (num_frames_ > bottom_frames_to_skip_)
 146  E :        num_frames_ -= bottom_frames_to_skip_;
 147  E :      else
 148  i :        num_frames_ = 1;
 149  E :      stack_id_ = ComputeStackTraceHash(frames_, num_frames_);
 150  E :    }
 151    :  
 152    :    // The hash comparison functor for use with MSDN's stdext::hash_set.
 153    :    struct HashCompare {
 154    :      static const size_t bucket_size = 4;
 155    :      static const size_t min_buckets = 8;
 156    :      // Calculates a hash value for the given stack_capture.
 157    :      size_t operator()(const StackCapture* stack_capture) const;
 158    :      // Value comparison operator.
 159    :      bool operator()(const StackCapture* stack_capture1,
 160    :                      const StackCapture* stack_capture2) const;
 161    :    };
 162    :  
 163    :    // Computes the hash of a stack trace using relative addresses of each stack
 164    :    // frame.
 165    :    // @returns the relative hash of this stack trace.
 166    :    StackId ComputeRelativeStackId();
 167    :  
 168    :   protected:
 169    :    // Don't skip any frames by default.
 170    :    static const size_t kDefaultBottomFramesToSkip_ = 0;
 171    :  
 172    :    // The number of bottom frames to skip on the stack traces.
 173    :    static size_t bottom_frames_to_skip_;
 174    :  
 175    :    // The unique ID of this hash. This is used for storing the hash in the set.
 176    :    StackId stack_id_;
 177    :  
 178    :    // The number of valid frames in this stack trace capture, and the maximum
 179    :    // number it can represent. We use uint8s here because we're limited to
 180    :    // kMaxNumFrames by the OS machinery and want this data structure to be as
 181    :    // compact as possible.
 182    :    uint8 num_frames_;
 183    :    uint8 max_num_frames_;
 184    :  
 185    :    // The reference count for this stack capture. We use saturation arithmetic
 186    :    // and something that is referenced 2^16 - 1 times will stay at that reference
 187    :    // count and never be removed from the stack cache.
 188    :    RefCount ref_count_;
 189    :  
 190    :    // The array or frame pointers comprising this stack trace capture.
 191    :    // This is a runtime dynamic array whose actual length is max_num_frames_, but
 192    :    // we use the maximum length here so that other users of StackCapture can
 193    :    // capture full stack traces if they so desire.
 194    :    // NOTE: This must be the last member of the class.
 195    :    void* frames_[kMaxNumFrames];
 196    :  
 197    :   private:
 198    :    DISALLOW_COPY_AND_ASSIGN(StackCapture);
 199    :  };
 200    :  
 201    :  }  // namespace asan
 202    :  }  // namespace agent
 203    :  
 204    :  #endif  // SYZYGY_AGENT_ASAN_STACK_CAPTURE_H_

Coverage information generated Thu Jul 04 09:34:53 2013.