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
|