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 : // This corresponds to the the type used by ::CaptureStackBackTrace's hash
41 : // for a stack-trace.
42 : typedef ULONG StackId;
43 :
44 E : StackCapture()
45 : : stack_id_(0), num_frames_(0), max_num_frames_(kMaxNumFrames) {
46 E : }
47 :
48 E : explicit StackCapture(size_t max_num_frames)
49 : : stack_id_(0), num_frames_(0), max_num_frames_(0) {
50 E : DCHECK_LT(0u, max_num_frames);
51 E : DCHECK_GE(kMaxNumFrames, max_num_frames);
52 E : max_num_frames_ = max_num_frames;
53 E : }
54 :
55 : // Calculate the size necessary to store a StackCapture with the given
56 : // number of stack frames.
57 : // @param max_num_frames The maximum number of stack frames the object needs
58 : // to be able to hold.
59 : // @returns the size of a StackCapture object with the given number of frames.
60 : static size_t GetSize(size_t max_num_frames);
61 :
62 : // @returns the size of this initialized StackCapture object.
63 E : size_t Size() const { return GetSize(max_num_frames_); }
64 :
65 : // @returns true if this stack trace capture contains valid frame pointers.
66 E : bool IsValid() const { return num_frames_ != 0; }
67 :
68 : // @returns the ID associated with this stack trace.
69 E : StackId stack_id() const { return stack_id_; }
70 :
71 : // @returns the number of valid frame pointers in this stack trace capture.
72 E : size_t num_frames() const { return num_frames_; }
73 :
74 : // @returns the maximum number of valid frame pointers in this stack trace
75 : // capture.
76 E : size_t max_num_frames() const { return max_num_frames_; }
77 :
78 : // @returns a pointer to the captured stack frames, or NULL if no stack
79 : // frames have been captured.
80 E : const void* const* frames() const { return IsValid() ? frames_ : NULL; }
81 :
82 : // Sets the stack ID for a given trace.
83 : // @param The stack ID to set.
84 E : void set_stack_id(StackId stack_id) { stack_id_ = stack_id; }
85 :
86 : // Set the number of bottom frames to skip per stack trace. This is needed to
87 : // be able to improve the stack cache compression in Chrome's unittests where
88 : // the bottom of the stack traces is different for each test case.
89 : // @param bottom_frames_to_skip The number of bottom frames to skip.
90 E : static void set_bottom_frames_to_skip(size_t bottom_frames_to_skip) {
91 E : CHECK_LT(bottom_frames_to_skip, kMaxNumFrames);
92 E : bottom_frames_to_skip_ = bottom_frames_to_skip;
93 E : }
94 :
95 : // Get the number of bottom frames to skip per stack trace.
96 E : static size_t bottom_frames_to_skip() { return bottom_frames_to_skip_; }
97 :
98 : // Initializes a stack trace from an array of frame pointers, a count and
99 : // a StackId (such as returned by ::CaptureStackBackTrace).
100 : // @param stack_id The ID of the stack back trace.
101 : // @param frames an array of frame pointers.
102 : // @param num_frames the number of valid frame pointers in @frames. Note
103 : // that at most kMaxNumFrames frame pointers will be copied to this
104 : // stack trace capture.
105 : void InitFromBuffer(StackId stack_id,
106 : const void* const* frames,
107 : size_t num_frames);
108 :
109 : // Initializes a stack trace using ::CaptureStackBackTrace. This is inlined so
110 : // that it doesn't further pollute the stack trace, but rather makes it
111 : // reflect the actual point of the call.
112 E : __forceinline void InitFromStack() {
113 : num_frames_ = ::CaptureStackBackTrace(
114 E : 0, max_num_frames_, frames_, NULL);
115 E : if (num_frames_ > bottom_frames_to_skip_)
116 E : num_frames_ -= bottom_frames_to_skip_;
117 E : else
118 i : num_frames_ = 1;
119 E : stack_id_ = ComputeStackTraceHash(frames_, num_frames_);
120 E : }
121 :
122 : // The hash comparison functor for use with MSDN's stdext::hash_set.
123 : struct HashCompare {
124 : static const size_t bucket_size = 4;
125 : static const size_t min_buckets = 8;
126 : // Calculates a hash value for the given stack_capture.
127 : size_t operator()(const StackCapture* stack_capture) const;
128 : // Value comparison operator.
129 : bool operator()(const StackCapture* stack_capture1,
130 : const StackCapture* stack_capture2) const;
131 : };
132 :
133 : // Computes the hash of a stack trace using relative addresses of each stack
134 : // frame.
135 : // @returns the relative hash of this stack trace.
136 : StackId ComputeRelativeStackId();
137 :
138 : protected:
139 : // The number of bottom frames to skip on the stack traces.
140 : static size_t bottom_frames_to_skip_;
141 :
142 : // The unique ID of this hash. This is used for storing the hash in the set.
143 : StackId stack_id_;
144 :
145 : // The number of valid frames in this stack trace capture, and the maximum
146 : // number it can represent. We use uint8s here because we're limited to
147 : // kMaxNumFrames by the OS machinery and want this data structure to be as
148 : // compact as possible.
149 : uint8 num_frames_;
150 : uint8 max_num_frames_;
151 :
152 : // The array or frame pointers comprising this stack trace capture.
153 : // This is a runtime dynamic array whose actual length is max_num_frames_, but
154 : // we use the maximum length here so that other users of StackCapture can
155 : // capture full stack traces if they so desire.
156 : // NOTE: This must be the last member of the class.
157 : void* frames_[kMaxNumFrames];
158 :
159 : private:
160 : DISALLOW_COPY_AND_ASSIGN(StackCapture);
161 : };
162 :
163 : } // namespace asan
164 : } // namespace agent
165 :
166 : #endif // SYZYGY_AGENT_ASAN_STACK_CAPTURE_H_
|