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
|