OLD | NEW |
| (Empty) |
1 // Copyright 2015 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_walker_x86.h" | |
16 | |
17 #include <windows.h> | |
18 | |
19 #include "gtest/gtest.h" | |
20 #include "syzygy/testing/metrics.h" | |
21 | |
22 namespace agent { | |
23 namespace common { | |
24 | |
25 namespace { | |
26 | |
27 class StackWalkerX86Test : public testing::Test { | |
28 public: | |
29 StackWalkerX86Test() | |
30 : dummy_ebp_(nullptr), dummy_esp_(nullptr), dummy_ret_(0u) { | |
31 ::memset(frames_, 0, sizeof(frames_)); | |
32 ::memset(frames2_, 0, sizeof(frames2_)); | |
33 ::memset(dummy_stack_, 0, sizeof(dummy_stack_)); | |
34 } | |
35 | |
36 static const uintptr_t kBaseRet = 0x1000000u; | |
37 | |
38 void Push(uintptr_t value) { | |
39 --dummy_esp_; | |
40 ASSERT_LE(dummy_stack_, dummy_esp_); | |
41 *dummy_esp_ = value; | |
42 } | |
43 | |
44 void PushEbp() { | |
45 Push(reinterpret_cast<uintptr_t>(dummy_ebp_)); | |
46 dummy_ebp_ = dummy_esp_; | |
47 } | |
48 | |
49 void PopEbp() { | |
50 dummy_ebp_ = reinterpret_cast<uintptr_t*>(*dummy_esp_); | |
51 ++dummy_esp_; | |
52 ASSERT_LE(dummy_esp_, dummy_stack_ + arraysize(dummy_stack_)); | |
53 } | |
54 | |
55 void PushRet() { | |
56 Push(dummy_ret_); | |
57 ++dummy_ret_; | |
58 } | |
59 | |
60 void ResetStack() { | |
61 ::memset(dummy_stack_, 0, sizeof(dummy_stack_)); | |
62 dummy_ebp_ = dummy_stack_ + arraysize(dummy_stack_); | |
63 dummy_esp_ = dummy_stack_ + arraysize(dummy_stack_); | |
64 dummy_ret_ = kBaseRet; | |
65 | |
66 // Push a return address, so that the very topmost thing on the | |
67 // stack is a return. | |
68 PushRet(); | |
69 } | |
70 | |
71 void SetUp() override { | |
72 ResetStack(); | |
73 } | |
74 | |
75 void BuildValidFrame(size_t locals) { | |
76 PushEbp(); | |
77 for (size_t i = 0; i < locals; ++i) | |
78 Push(::rand()); | |
79 PushRet(); | |
80 } | |
81 | |
82 void BuildInvalidFrameTooSmall() { | |
83 // Only push an EBP. This will be too close to the EBP of the next valid | |
84 // stack frame. | |
85 PushEbp(); | |
86 } | |
87 | |
88 void BuildInvalidFrameNonIncreasingBasePointer() { | |
89 Push(*dummy_ebp_ - 4 * sizeof(uintptr_t)); | |
90 dummy_ebp_ = dummy_esp_; | |
91 PushRet(); | |
92 } | |
93 | |
94 void BuildInvalidFrameUnalignedBasePointer() { | |
95 Push(*dummy_ebp_ - 1); | |
96 dummy_ebp_ = dummy_esp_; | |
97 PushRet(); | |
98 } | |
99 | |
100 void BuildInvalidFrameInvalidReturnAddress() { | |
101 PushEbp(); | |
102 Push(0); // Output a null return address. | |
103 ++dummy_ret_; | |
104 } | |
105 | |
106 void BuildInvalidFrameInvalidBasePointer() { | |
107 Push(reinterpret_cast<uintptr_t>(dummy_stack_ + arraysize(dummy_stack_))); | |
108 dummy_ebp_ = dummy_esp_; | |
109 PushRet(); | |
110 } | |
111 | |
112 void BuildInvalidFrameOverflowingBasePointer() { | |
113 // This base pointer will overflow to 0 when incremented. | |
114 Push(0xFFFFFFFC); | |
115 dummy_ebp_ = dummy_esp_; | |
116 PushRet(); | |
117 } | |
118 | |
119 void ExpectSuccessfulWalk(size_t num_frames, | |
120 size_t frames_to_skip) { | |
121 // Push a dummy EBP on the stack, which simulates the stack frame of the | |
122 // function actually calling WalkStack. | |
123 PushEbp(); | |
124 StackId stack_id; | |
125 EXPECT_EQ(num_frames, | |
126 WalkStackImpl(dummy_ebp_, dummy_esp_, | |
127 dummy_stack_ + arraysize(dummy_stack_), | |
128 frames_to_skip, kMaxFrames, frames_, &stack_id)); | |
129 for (size_t i = 0; i < num_frames; ++i) { | |
130 EXPECT_EQ(reinterpret_cast<void*>(dummy_ret_ - i - 1 - frames_to_skip), | |
131 frames_[i]); | |
132 } | |
133 | |
134 PopEbp(); | |
135 } | |
136 | |
137 static const size_t kMaxFrames = 100; | |
138 void* frames_[kMaxFrames]; | |
139 void* frames2_[kMaxFrames]; | |
140 | |
141 uintptr_t dummy_stack_[1024]; | |
142 uintptr_t* dummy_ebp_; | |
143 uintptr_t* dummy_esp_; | |
144 uintptr_t dummy_ret_; | |
145 }; | |
146 | |
147 } // namespace | |
148 | |
149 TEST_F(StackWalkerX86Test, ValidWalk) { | |
150 BuildValidFrame(0); | |
151 ExpectSuccessfulWalk(2, 0); | |
152 BuildValidFrame(2); | |
153 ExpectSuccessfulWalk(3, 0); | |
154 BuildValidFrame(1); | |
155 ExpectSuccessfulWalk(4, 0); | |
156 ExpectSuccessfulWalk(3, 1); | |
157 ExpectSuccessfulWalk(2, 2); | |
158 } | |
159 | |
160 TEST_F(StackWalkerX86Test, WalkStopsWhenFrameTooSmall) { | |
161 BuildValidFrame(0); | |
162 ExpectSuccessfulWalk(2, 0); | |
163 | |
164 BuildInvalidFrameTooSmall(); | |
165 BuildValidFrame(1); | |
166 ExpectSuccessfulWalk(1, 0); | |
167 | |
168 BuildValidFrame(2); | |
169 ExpectSuccessfulWalk(2, 0); | |
170 | |
171 BuildValidFrame(1); | |
172 ExpectSuccessfulWalk(3, 0); | |
173 ExpectSuccessfulWalk(2, 1); | |
174 } | |
175 | |
176 TEST_F(StackWalkerX86Test, WalkStopsAtNonIncreasingBasePointer) { | |
177 BuildValidFrame(0); | |
178 ExpectSuccessfulWalk(2, 0); | |
179 | |
180 BuildInvalidFrameNonIncreasingBasePointer(); | |
181 ExpectSuccessfulWalk(2, 0); | |
182 | |
183 BuildValidFrame(2); | |
184 ExpectSuccessfulWalk(3, 0); | |
185 | |
186 BuildValidFrame(1); | |
187 ExpectSuccessfulWalk(4, 0); | |
188 ExpectSuccessfulWalk(3, 1); | |
189 } | |
190 | |
191 TEST_F(StackWalkerX86Test, WalkStopsAtUnalignedBasePointer) { | |
192 BuildValidFrame(0); | |
193 ExpectSuccessfulWalk(2, 0); | |
194 | |
195 BuildInvalidFrameUnalignedBasePointer(); | |
196 ExpectSuccessfulWalk(2, 0); | |
197 | |
198 BuildValidFrame(2); | |
199 ExpectSuccessfulWalk(3, 0); | |
200 | |
201 BuildValidFrame(1); | |
202 ExpectSuccessfulWalk(4, 0); | |
203 ExpectSuccessfulWalk(3, 1); | |
204 } | |
205 | |
206 TEST_F(StackWalkerX86Test, WalkStopsAtInvalidReturnAddress) { | |
207 BuildValidFrame(0); | |
208 ExpectSuccessfulWalk(2, 0); | |
209 | |
210 BuildInvalidFrameInvalidReturnAddress(); | |
211 ExpectSuccessfulWalk(0, 0); | |
212 | |
213 BuildValidFrame(2); | |
214 ExpectSuccessfulWalk(1, 0); | |
215 | |
216 BuildValidFrame(1); | |
217 ExpectSuccessfulWalk(2, 0); | |
218 } | |
219 | |
220 TEST_F(StackWalkerX86Test, WalkStopsAtInvalidBasePointer) { | |
221 BuildValidFrame(0); | |
222 ExpectSuccessfulWalk(2, 0); | |
223 | |
224 BuildInvalidFrameInvalidBasePointer(); | |
225 ExpectSuccessfulWalk(2, 0); | |
226 | |
227 BuildValidFrame(2); | |
228 ExpectSuccessfulWalk(3, 0); | |
229 | |
230 BuildValidFrame(1); | |
231 ExpectSuccessfulWalk(4, 0); | |
232 ExpectSuccessfulWalk(3, 1); | |
233 } | |
234 | |
235 TEST_F(StackWalkerX86Test, WalkStopAtOverflowingBasePointer) { | |
236 BuildValidFrame(0); | |
237 ExpectSuccessfulWalk(2, 0); | |
238 | |
239 BuildInvalidFrameOverflowingBasePointer(); | |
240 ExpectSuccessfulWalk(2, 0); | |
241 | |
242 BuildValidFrame(2); | |
243 ExpectSuccessfulWalk(3, 0); | |
244 | |
245 BuildValidFrame(1); | |
246 ExpectSuccessfulWalk(4, 0); | |
247 ExpectSuccessfulWalk(3, 1); | |
248 } | |
249 | |
250 TEST_F(StackWalkerX86Test, CompareToCaptureStackBackTrace) { | |
251 // Use the OS stack walker to get the number of frames. Skip the top frame | |
252 // (in this function) as WalkStack and CaptureStackBackTrace won't have the | |
253 // same return address. | |
254 size_t num_frames = | |
255 ::CaptureStackBackTrace(1, kMaxFrames, frames_, nullptr); | |
256 | |
257 while (num_frames > 0) { | |
258 StackId stack_id; | |
259 size_t num_frames2 = WalkStack(1, num_frames, frames_, &stack_id); | |
260 size_t exp_frames2 = | |
261 ::CaptureStackBackTrace(1, num_frames, frames2_, nullptr); | |
262 EXPECT_EQ(num_frames, num_frames2); | |
263 EXPECT_EQ(exp_frames2, num_frames2); | |
264 EXPECT_EQ(0, ::memcmp(frames_, frames2_, num_frames * sizeof(*frames_))); | |
265 | |
266 --num_frames; | |
267 } | |
268 } | |
269 | |
270 } // namespace common | |
271 } // namespace agent | |
OLD | NEW |