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