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