|
1 // Copyright (c) 2010, Google Inc. |
|
2 // All rights reserved. |
|
3 // |
|
4 // Redistribution and use in source and binary forms, with or without |
|
5 // modification, are permitted provided that the following conditions are |
|
6 // met: |
|
7 // |
|
8 // * Redistributions of source code must retain the above copyright |
|
9 // notice, this list of conditions and the following disclaimer. |
|
10 // * Redistributions in binary form must reproduce the above |
|
11 // copyright notice, this list of conditions and the following disclaimer |
|
12 // in the documentation and/or other materials provided with the |
|
13 // distribution. |
|
14 // * Neither the name of Google Inc. nor the names of its |
|
15 // contributors may be used to endorse or promote products derived from |
|
16 // this software without specific prior written permission. |
|
17 // |
|
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
29 |
|
30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
|
31 |
|
32 // stackwalker_x86_unittest.cc: Unit tests for StackwalkerX86 class. |
|
33 |
|
34 #include <string> |
|
35 #include <vector> |
|
36 |
|
37 #include "breakpad_googletest_includes.h" |
|
38 #include "common/test_assembler.h" |
|
39 #include "common/using_std_string.h" |
|
40 #include "google_breakpad/common/minidump_format.h" |
|
41 #include "google_breakpad/processor/basic_source_line_resolver.h" |
|
42 #include "google_breakpad/processor/call_stack.h" |
|
43 #include "google_breakpad/processor/code_module.h" |
|
44 #include "google_breakpad/processor/source_line_resolver_interface.h" |
|
45 #include "google_breakpad/processor/stack_frame_cpu.h" |
|
46 #include "processor/stackwalker_unittest_utils.h" |
|
47 #include "processor/stackwalker_x86.h" |
|
48 #include "processor/windows_frame_info.h" |
|
49 |
|
50 using google_breakpad::BasicSourceLineResolver; |
|
51 using google_breakpad::CallStack; |
|
52 using google_breakpad::CodeModule; |
|
53 using google_breakpad::StackFrameSymbolizer; |
|
54 using google_breakpad::StackFrame; |
|
55 using google_breakpad::StackFrameX86; |
|
56 using google_breakpad::StackwalkerX86; |
|
57 using google_breakpad::SystemInfo; |
|
58 using google_breakpad::WindowsFrameInfo; |
|
59 using google_breakpad::test_assembler::kLittleEndian; |
|
60 using google_breakpad::test_assembler::Label; |
|
61 using google_breakpad::test_assembler::Section; |
|
62 using std::vector; |
|
63 using testing::_; |
|
64 using testing::Return; |
|
65 using testing::SetArgumentPointee; |
|
66 using testing::Test; |
|
67 |
|
68 class StackwalkerX86Fixture { |
|
69 public: |
|
70 StackwalkerX86Fixture() |
|
71 : stack_section(kLittleEndian), |
|
72 // Give the two modules reasonable standard locations and names |
|
73 // for tests to play with. |
|
74 module1(0x40000000, 0x10000, "module1", "version1"), |
|
75 module2(0x50000000, 0x10000, "module2", "version2"), |
|
76 module3(0x771d0000, 0x180000, "module3", "version3"), |
|
77 module4(0x75f90000, 0x46000, "module4", "version4"), |
|
78 module5(0x75730000, 0x110000, "module5", "version5"), |
|
79 module6(0x647f0000, 0x1ba8000, "module6", "version6") { |
|
80 // Identify the system as a Linux system. |
|
81 system_info.os = "Linux"; |
|
82 system_info.os_short = "linux"; |
|
83 system_info.os_version = "Salacious Skink"; |
|
84 system_info.cpu = "x86"; |
|
85 system_info.cpu_info = ""; |
|
86 |
|
87 // Put distinctive values in the raw CPU context. |
|
88 BrandContext(&raw_context); |
|
89 |
|
90 // Create some modules with some stock debugging information. |
|
91 modules.Add(&module1); |
|
92 modules.Add(&module2); |
|
93 modules.Add(&module3); |
|
94 modules.Add(&module4); |
|
95 modules.Add(&module5); |
|
96 modules.Add(&module6); |
|
97 |
|
98 // By default, none of the modules have symbol info; call |
|
99 // SetModuleSymbols to override this. |
|
100 EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _)) |
|
101 .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); |
|
102 } |
|
103 |
|
104 // Set the Breakpad symbol information that supplier should return for |
|
105 // MODULE to INFO. |
|
106 void SetModuleSymbols(MockCodeModule *module, const string &info) { |
|
107 char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info); |
|
108 EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _)) |
|
109 .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), |
|
110 Return(MockSymbolSupplier::FOUND))); |
|
111 } |
|
112 |
|
113 // Populate stack_region with the contents of stack_section. Use |
|
114 // stack_section.start() as the region's starting address. |
|
115 void RegionFromSection() { |
|
116 string contents; |
|
117 ASSERT_TRUE(stack_section.GetContents(&contents)); |
|
118 stack_region.Init(stack_section.start().Value(), contents); |
|
119 } |
|
120 |
|
121 // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. |
|
122 void BrandContext(MDRawContextX86 *raw_context) { |
|
123 uint8_t x = 173; |
|
124 for (size_t i = 0; i < sizeof(*raw_context); i++) |
|
125 reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17); |
|
126 } |
|
127 |
|
128 SystemInfo system_info; |
|
129 MDRawContextX86 raw_context; |
|
130 Section stack_section; |
|
131 MockMemoryRegion stack_region; |
|
132 MockCodeModule module1; |
|
133 MockCodeModule module2; |
|
134 MockCodeModule module3; |
|
135 MockCodeModule module4; |
|
136 MockCodeModule module5; |
|
137 MockCodeModule module6; |
|
138 MockCodeModules modules; |
|
139 MockSymbolSupplier supplier; |
|
140 BasicSourceLineResolver resolver; |
|
141 CallStack call_stack; |
|
142 const vector<StackFrame *> *frames; |
|
143 }; |
|
144 |
|
145 class SanityCheck: public StackwalkerX86Fixture, public Test { }; |
|
146 |
|
147 TEST_F(SanityCheck, NoResolver) { |
|
148 stack_section.start() = 0x80000000; |
|
149 stack_section.D32(0).D32(0); // end-of-stack marker |
|
150 RegionFromSection(); |
|
151 raw_context.eip = 0x40000200; |
|
152 raw_context.ebp = 0x80000000; |
|
153 |
|
154 StackFrameSymbolizer frame_symbolizer(NULL, NULL); |
|
155 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
156 &frame_symbolizer); |
|
157 // This should succeed, even without a resolver or supplier. |
|
158 vector<const CodeModule*> modules_without_symbols; |
|
159 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
160 ASSERT_EQ(1U, modules_without_symbols.size()); |
|
161 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); |
|
162 frames = call_stack.frames(); |
|
163 StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0)); |
|
164 // Check that the values from the original raw context made it |
|
165 // through to the context in the stack frame. |
|
166 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); |
|
167 } |
|
168 |
|
169 class GetContextFrame: public StackwalkerX86Fixture, public Test { }; |
|
170 |
|
171 TEST_F(GetContextFrame, Simple) { |
|
172 stack_section.start() = 0x80000000; |
|
173 stack_section.D32(0).D32(0); // end-of-stack marker |
|
174 RegionFromSection(); |
|
175 raw_context.eip = 0x40000200; |
|
176 raw_context.ebp = 0x80000000; |
|
177 |
|
178 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
179 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
180 &frame_symbolizer); |
|
181 vector<const CodeModule*> modules_without_symbols; |
|
182 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
183 ASSERT_EQ(1U, modules_without_symbols.size()); |
|
184 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); |
|
185 frames = call_stack.frames(); |
|
186 StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0)); |
|
187 // Check that the values from the original raw context made it |
|
188 // through to the context in the stack frame. |
|
189 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); |
|
190 } |
|
191 |
|
192 // The stackwalker should be able to produce the context frame even |
|
193 // without stack memory present. |
|
194 TEST_F(GetContextFrame, NoStackMemory) { |
|
195 raw_context.eip = 0x40000200; |
|
196 raw_context.ebp = 0x80000000; |
|
197 |
|
198 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
199 StackwalkerX86 walker(&system_info, &raw_context, NULL, &modules, |
|
200 &frame_symbolizer); |
|
201 vector<const CodeModule*> modules_without_symbols; |
|
202 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
203 ASSERT_EQ(1U, modules_without_symbols.size()); |
|
204 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); |
|
205 frames = call_stack.frames(); |
|
206 StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0)); |
|
207 // Check that the values from the original raw context made it |
|
208 // through to the context in the stack frame. |
|
209 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); |
|
210 } |
|
211 |
|
212 class GetCallerFrame: public StackwalkerX86Fixture, public Test { }; |
|
213 |
|
214 // Walk a traditional frame. A traditional frame saves the caller's |
|
215 // %ebp just below the return address, and has its own %ebp pointing |
|
216 // at the saved %ebp. |
|
217 TEST_F(GetCallerFrame, Traditional) { |
|
218 stack_section.start() = 0x80000000; |
|
219 Label frame0_ebp, frame1_ebp; |
|
220 stack_section |
|
221 .Append(12, 0) // frame 0: space |
|
222 .Mark(&frame0_ebp) // frame 0 %ebp points here |
|
223 .D32(frame1_ebp) // frame 0: saved %ebp |
|
224 .D32(0x40008679) // frame 0: return address |
|
225 .Append(8, 0) // frame 1: space |
|
226 .Mark(&frame1_ebp) // frame 1 %ebp points here |
|
227 .D32(0) // frame 1: saved %ebp (stack end) |
|
228 .D32(0); // frame 1: return address (stack end) |
|
229 RegionFromSection(); |
|
230 raw_context.eip = 0x4000c7a5; |
|
231 raw_context.esp = stack_section.start().Value(); |
|
232 raw_context.ebp = frame0_ebp.Value(); |
|
233 |
|
234 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
235 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
236 &frame_symbolizer); |
|
237 vector<const CodeModule*> modules_without_symbols; |
|
238 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
239 ASSERT_EQ(1U, modules_without_symbols.size()); |
|
240 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); |
|
241 frames = call_stack.frames(); |
|
242 ASSERT_EQ(2U, frames->size()); |
|
243 |
|
244 { // To avoid reusing locals by mistake |
|
245 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
246 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
247 EXPECT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
248 EXPECT_EQ(0x4000c7a5U, frame0->instruction); |
|
249 EXPECT_EQ(0x4000c7a5U, frame0->context.eip); |
|
250 EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); |
|
251 EXPECT_EQ(NULL, frame0->windows_frame_info); |
|
252 } |
|
253 |
|
254 { // To avoid reusing locals by mistake |
|
255 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
256 EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); |
|
257 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
258 | StackFrameX86::CONTEXT_VALID_ESP |
|
259 | StackFrameX86::CONTEXT_VALID_EBP), |
|
260 frame1->context_validity); |
|
261 EXPECT_EQ(0x40008679U, frame1->instruction + 1); |
|
262 EXPECT_EQ(0x40008679U, frame1->context.eip); |
|
263 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); |
|
264 EXPECT_EQ(NULL, frame1->windows_frame_info); |
|
265 } |
|
266 } |
|
267 |
|
268 // Walk a traditional frame, but use a bogus %ebp value, forcing a scan |
|
269 // of the stack for something that looks like a return address. |
|
270 TEST_F(GetCallerFrame, TraditionalScan) { |
|
271 stack_section.start() = 0x80000000; |
|
272 Label frame1_ebp; |
|
273 stack_section |
|
274 // frame 0 |
|
275 .D32(0xf065dc76) // locals area: |
|
276 .D32(0x46ee2167) // garbage that doesn't look like |
|
277 .D32(0xbab023ec) // a return address |
|
278 .D32(frame1_ebp) // saved %ebp (%ebp fails to point here, forcing scan) |
|
279 .D32(0x4000129d) // return address |
|
280 // frame 1 |
|
281 .Append(8, 0) // space |
|
282 .Mark(&frame1_ebp) // %ebp points here |
|
283 .D32(0) // saved %ebp (stack end) |
|
284 .D32(0); // return address (stack end) |
|
285 |
|
286 RegionFromSection(); |
|
287 raw_context.eip = 0x4000f49d; |
|
288 raw_context.esp = stack_section.start().Value(); |
|
289 // Make the frame pointer bogus, to make the stackwalker scan the stack |
|
290 // for something that looks like a return address. |
|
291 raw_context.ebp = 0xd43eed6e; |
|
292 |
|
293 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
294 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
295 &frame_symbolizer); |
|
296 vector<const CodeModule*> modules_without_symbols; |
|
297 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
298 ASSERT_EQ(1U, modules_without_symbols.size()); |
|
299 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); |
|
300 frames = call_stack.frames(); |
|
301 ASSERT_EQ(2U, frames->size()); |
|
302 |
|
303 { // To avoid reusing locals by mistake |
|
304 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
305 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
306 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
307 EXPECT_EQ(0x4000f49dU, frame0->instruction); |
|
308 EXPECT_EQ(0x4000f49dU, frame0->context.eip); |
|
309 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); |
|
310 EXPECT_EQ(0xd43eed6eU, frame0->context.ebp); |
|
311 EXPECT_EQ(NULL, frame0->windows_frame_info); |
|
312 } |
|
313 |
|
314 { // To avoid reusing locals by mistake |
|
315 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
316 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); |
|
317 // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the |
|
318 // walker does not actually fetch the EBP after a scan (forcing the |
|
319 // next frame to be scanned as well). But let's grandfather the existing |
|
320 // behavior in for now. |
|
321 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
322 | StackFrameX86::CONTEXT_VALID_ESP |
|
323 | StackFrameX86::CONTEXT_VALID_EBP), |
|
324 frame1->context_validity); |
|
325 EXPECT_EQ(0x4000129dU, frame1->instruction + 1); |
|
326 EXPECT_EQ(0x4000129dU, frame1->context.eip); |
|
327 EXPECT_EQ(0x80000014U, frame1->context.esp); |
|
328 EXPECT_EQ(0xd43eed6eU, frame1->context.ebp); |
|
329 EXPECT_EQ(NULL, frame1->windows_frame_info); |
|
330 } |
|
331 } |
|
332 |
|
333 // Force scanning for a return address a long way down the stack |
|
334 TEST_F(GetCallerFrame, TraditionalScanLongWay) { |
|
335 stack_section.start() = 0x80000000; |
|
336 Label frame1_ebp; |
|
337 stack_section |
|
338 // frame 0 |
|
339 .D32(0xf065dc76) // locals area: |
|
340 .D32(0x46ee2167) // garbage that doesn't look like |
|
341 .D32(0xbab023ec) // a return address |
|
342 .Append(20 * 4, 0) // a bunch of space |
|
343 .D32(frame1_ebp) // saved %ebp (%ebp fails to point here, forcing scan) |
|
344 .D32(0x4000129d) // return address |
|
345 // frame 1 |
|
346 .Append(8, 0) // space |
|
347 .Mark(&frame1_ebp) // %ebp points here |
|
348 .D32(0) // saved %ebp (stack end) |
|
349 .D32(0); // return address (stack end) |
|
350 |
|
351 RegionFromSection(); |
|
352 raw_context.eip = 0x4000f49d; |
|
353 raw_context.esp = stack_section.start().Value(); |
|
354 // Make the frame pointer bogus, to make the stackwalker scan the stack |
|
355 // for something that looks like a return address. |
|
356 raw_context.ebp = 0xd43eed6e; |
|
357 |
|
358 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
359 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
360 &frame_symbolizer); |
|
361 vector<const CodeModule*> modules_without_symbols; |
|
362 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
363 ASSERT_EQ(1U, modules_without_symbols.size()); |
|
364 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); |
|
365 frames = call_stack.frames(); |
|
366 ASSERT_EQ(2U, frames->size()); |
|
367 |
|
368 { // To avoid reusing locals by mistake |
|
369 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
370 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
371 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
372 EXPECT_EQ(0x4000f49dU, frame0->instruction); |
|
373 EXPECT_EQ(0x4000f49dU, frame0->context.eip); |
|
374 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); |
|
375 EXPECT_EQ(0xd43eed6eU, frame0->context.ebp); |
|
376 EXPECT_EQ(NULL, frame0->windows_frame_info); |
|
377 } |
|
378 |
|
379 { // To avoid reusing locals by mistake |
|
380 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
381 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); |
|
382 // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the |
|
383 // walker does not actually fetch the EBP after a scan (forcing the |
|
384 // next frame to be scanned as well). But let's grandfather the existing |
|
385 // behavior in for now. |
|
386 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
387 | StackFrameX86::CONTEXT_VALID_ESP |
|
388 | StackFrameX86::CONTEXT_VALID_EBP), |
|
389 frame1->context_validity); |
|
390 EXPECT_EQ(0x4000129dU, frame1->instruction + 1); |
|
391 EXPECT_EQ(0x4000129dU, frame1->context.eip); |
|
392 EXPECT_EQ(0x80000064U, frame1->context.esp); |
|
393 EXPECT_EQ(0xd43eed6eU, frame1->context.ebp); |
|
394 EXPECT_EQ(NULL, frame1->windows_frame_info); |
|
395 } |
|
396 } |
|
397 |
|
398 // Use Windows frame data (a "STACK WIN 4" record, from a |
|
399 // FrameTypeFrameData DIA record) to walk a stack frame. |
|
400 TEST_F(GetCallerFrame, WindowsFrameData) { |
|
401 SetModuleSymbols(&module1, |
|
402 "STACK WIN 4 aa85 176 0 0 4 10 4 0 1" |
|
403 " $T2 $esp .cbSavedRegs + =" |
|
404 " $T0 .raSearchStart =" |
|
405 " $eip $T0 ^ =" |
|
406 " $esp $T0 4 + =" |
|
407 " $ebx $T2 4 - ^ =" |
|
408 " $edi $T2 8 - ^ =" |
|
409 " $esi $T2 12 - ^ =" |
|
410 " $ebp $T2 16 - ^ =\n"); |
|
411 Label frame1_esp, frame1_ebp; |
|
412 stack_section.start() = 0x80000000; |
|
413 stack_section |
|
414 // frame 0 |
|
415 .D32(frame1_ebp) // saved regs: %ebp |
|
416 .D32(0xa7120d1a) // %esi |
|
417 .D32(0x630891be) // %edi |
|
418 .D32(0x9068a878) // %ebx |
|
419 .D32(0xa08ea45f) // locals: unused |
|
420 .D32(0x40001350) // return address |
|
421 // frame 1 |
|
422 .Mark(&frame1_esp) |
|
423 .Append(12, 0) // empty space |
|
424 .Mark(&frame1_ebp) |
|
425 .D32(0) // saved %ebp (stack end) |
|
426 .D32(0); // saved %eip (stack end) |
|
427 |
|
428 RegionFromSection(); |
|
429 raw_context.eip = 0x4000aa85; |
|
430 raw_context.esp = stack_section.start().Value(); |
|
431 raw_context.ebp = 0xf052c1de; // should not be needed to walk frame |
|
432 |
|
433 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
434 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
435 &frame_symbolizer); |
|
436 vector<const CodeModule*> modules_without_symbols; |
|
437 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
438 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
439 frames = call_stack.frames(); |
|
440 ASSERT_EQ(2U, frames->size()); |
|
441 |
|
442 { // To avoid reusing locals by mistake |
|
443 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
444 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
445 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
446 EXPECT_EQ(0x4000aa85U, frame0->instruction); |
|
447 EXPECT_EQ(0x4000aa85U, frame0->context.eip); |
|
448 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); |
|
449 EXPECT_EQ(0xf052c1deU, frame0->context.ebp); |
|
450 EXPECT_TRUE(frame0->windows_frame_info != NULL); |
|
451 } |
|
452 |
|
453 { // To avoid reusing locals by mistake |
|
454 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
455 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); |
|
456 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
457 | StackFrameX86::CONTEXT_VALID_ESP |
|
458 | StackFrameX86::CONTEXT_VALID_EBP |
|
459 | StackFrameX86::CONTEXT_VALID_EBX |
|
460 | StackFrameX86::CONTEXT_VALID_ESI |
|
461 | StackFrameX86::CONTEXT_VALID_EDI), |
|
462 frame1->context_validity); |
|
463 EXPECT_EQ(0x40001350U, frame1->instruction + 1); |
|
464 EXPECT_EQ(0x40001350U, frame1->context.eip); |
|
465 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); |
|
466 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); |
|
467 EXPECT_EQ(0x9068a878U, frame1->context.ebx); |
|
468 EXPECT_EQ(0xa7120d1aU, frame1->context.esi); |
|
469 EXPECT_EQ(0x630891beU, frame1->context.edi); |
|
470 EXPECT_EQ(NULL, frame1->windows_frame_info); |
|
471 } |
|
472 } |
|
473 |
|
474 // Use Windows frame data (a "STACK WIN 4" record, from a |
|
475 // FrameTypeFrameData DIA record) to walk a stack frame where the stack |
|
476 // is aligned and we must search |
|
477 TEST_F(GetCallerFrame, WindowsFrameDataAligned) { |
|
478 SetModuleSymbols(&module1, |
|
479 "STACK WIN 4 aa85 176 0 0 4 4 8 0 1" |
|
480 " $T1 .raSearch =" |
|
481 " $T0 $T1 4 - 8 @ =" |
|
482 " $ebp $T1 4 - ^ =" |
|
483 " $eip $T1 ^ =" |
|
484 " $esp $T1 4 + ="); |
|
485 Label frame1_esp, frame1_ebp; |
|
486 stack_section.start() = 0x80000000; |
|
487 stack_section |
|
488 // frame 0 |
|
489 .D32(0x0ffa0ffa) // unused saved register |
|
490 .D32(0xdeaddead) // locals |
|
491 .D32(0xbeefbeef) |
|
492 .D32(0) // 8-byte alignment |
|
493 .D32(frame1_ebp) |
|
494 .D32(0x5000129d) // return address |
|
495 // frame 1 |
|
496 .Mark(&frame1_esp) |
|
497 .D32(0x1) // parameter |
|
498 .Mark(&frame1_ebp) |
|
499 .D32(0) // saved %ebp (stack end) |
|
500 .D32(0); // saved %eip (stack end) |
|
501 |
|
502 RegionFromSection(); |
|
503 raw_context.eip = 0x4000aa85; |
|
504 raw_context.esp = stack_section.start().Value(); |
|
505 raw_context.ebp = 0xf052c1de; // should not be needed to walk frame |
|
506 |
|
507 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
508 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
509 &frame_symbolizer); |
|
510 vector<const CodeModule*> modules_without_symbols; |
|
511 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
512 ASSERT_EQ(1U, modules_without_symbols.size()); |
|
513 ASSERT_EQ("module2", modules_without_symbols[0]->debug_file()); |
|
514 frames = call_stack.frames(); |
|
515 ASSERT_EQ(2U, frames->size()); |
|
516 |
|
517 { // To avoid reusing locals by mistake |
|
518 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
519 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
520 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
521 EXPECT_EQ(0x4000aa85U, frame0->instruction); |
|
522 EXPECT_EQ(0x4000aa85U, frame0->context.eip); |
|
523 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); |
|
524 EXPECT_EQ(0xf052c1deU, frame0->context.ebp); |
|
525 EXPECT_TRUE(frame0->windows_frame_info != NULL); |
|
526 } |
|
527 |
|
528 { // To avoid reusing locals by mistake |
|
529 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
530 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); |
|
531 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
532 | StackFrameX86::CONTEXT_VALID_ESP |
|
533 | StackFrameX86::CONTEXT_VALID_EBP), |
|
534 frame1->context_validity); |
|
535 EXPECT_EQ(0x5000129dU, frame1->instruction + 1); |
|
536 EXPECT_EQ(0x5000129dU, frame1->context.eip); |
|
537 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); |
|
538 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); |
|
539 EXPECT_EQ(NULL, frame1->windows_frame_info); |
|
540 } |
|
541 } |
|
542 |
|
543 // Use Windows frame data (a "STACK WIN 4" record, from a |
|
544 // FrameTypeFrameData DIA record) to walk a frame, and depend on the |
|
545 // parameter size from the callee as well. |
|
546 TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) { |
|
547 SetModuleSymbols(&module1, "FUNC 1000 100 c module1::wheedle\n"); |
|
548 SetModuleSymbols(&module2, |
|
549 // Note bogus parameter size in FUNC record; the stack walker |
|
550 // should prefer the STACK WIN record, and see '4' below. |
|
551 "FUNC aa85 176 beef module2::whine\n" |
|
552 "STACK WIN 4 aa85 176 0 0 4 10 4 0 1" |
|
553 " $T2 $esp .cbLocals + .cbSavedRegs + =" |
|
554 " $T0 .raSearchStart =" |
|
555 " $eip $T0 ^ =" |
|
556 " $esp $T0 4 + =" |
|
557 " $ebp $T0 20 - ^ =" |
|
558 " $ebx $T0 8 - ^ =\n"); |
|
559 Label frame0_esp, frame0_ebp; |
|
560 Label frame1_esp; |
|
561 Label frame2_esp, frame2_ebp; |
|
562 stack_section.start() = 0x80000000; |
|
563 stack_section |
|
564 // frame 0, in module1::wheedle. Traditional frame. |
|
565 .Mark(&frame0_esp) |
|
566 .Append(16, 0) // frame space |
|
567 .Mark(&frame0_ebp) |
|
568 .D32(0x6fa902e0) // saved %ebp. Not a frame pointer. |
|
569 .D32(0x5000aa95) // return address, in module2::whine |
|
570 // frame 1, in module2::whine. FrameData frame. |
|
571 .Mark(&frame1_esp) |
|
572 .D32(0xbaa0cb7a) // argument 3 passed to module1::wheedle |
|
573 .D32(0xbdc92f9f) // argument 2 |
|
574 .D32(0x0b1d8442) // argument 1 |
|
575 .D32(frame2_ebp) // saved %ebp |
|
576 .D32(0xb1b90a15) // unused |
|
577 .D32(0xf18e072d) // unused |
|
578 .D32(0x2558c7f3) // saved %ebx |
|
579 .D32(0x0365e25e) // unused |
|
580 .D32(0x2a179e38) // return address; $T0 points here |
|
581 // frame 2, in no module |
|
582 .Mark(&frame2_esp) |
|
583 .Append(12, 0) // empty space |
|
584 .Mark(&frame2_ebp) |
|
585 .D32(0) // saved %ebp (stack end) |
|
586 .D32(0); // saved %eip (stack end) |
|
587 |
|
588 RegionFromSection(); |
|
589 raw_context.eip = 0x40001004; // in module1::wheedle |
|
590 raw_context.esp = stack_section.start().Value(); |
|
591 raw_context.ebp = frame0_ebp.Value(); |
|
592 |
|
593 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
594 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
595 &frame_symbolizer); |
|
596 vector<const CodeModule*> modules_without_symbols; |
|
597 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
598 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
599 frames = call_stack.frames(); |
|
600 ASSERT_EQ(3U, frames->size()); |
|
601 |
|
602 { // To avoid reusing locals by mistake |
|
603 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
604 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
605 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
606 EXPECT_EQ(0x40001004U, frame0->instruction); |
|
607 EXPECT_EQ(0x40001004U, frame0->context.eip); |
|
608 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); |
|
609 EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); |
|
610 EXPECT_EQ(&module1, frame0->module); |
|
611 EXPECT_EQ("module1::wheedle", frame0->function_name); |
|
612 EXPECT_EQ(0x40001000U, frame0->function_base); |
|
613 // The FUNC record for module1::wheedle should have produced a |
|
614 // WindowsFrameInfo structure with only the parameter size valid. |
|
615 ASSERT_TRUE(frame0->windows_frame_info != NULL); |
|
616 EXPECT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE, |
|
617 frame0->windows_frame_info->valid); |
|
618 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_UNKNOWN, |
|
619 frame0->windows_frame_info->type_); |
|
620 EXPECT_EQ(12U, frame0->windows_frame_info->parameter_size); |
|
621 } |
|
622 |
|
623 { // To avoid reusing locals by mistake |
|
624 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
625 EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); |
|
626 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
627 | StackFrameX86::CONTEXT_VALID_ESP |
|
628 | StackFrameX86::CONTEXT_VALID_EBP), |
|
629 frame1->context_validity); |
|
630 EXPECT_EQ(0x5000aa95U, frame1->instruction + 1); |
|
631 EXPECT_EQ(0x5000aa95U, frame1->context.eip); |
|
632 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); |
|
633 EXPECT_EQ(0x6fa902e0U, frame1->context.ebp); |
|
634 EXPECT_EQ(&module2, frame1->module); |
|
635 EXPECT_EQ("module2::whine", frame1->function_name); |
|
636 EXPECT_EQ(0x5000aa85U, frame1->function_base); |
|
637 ASSERT_TRUE(frame1->windows_frame_info != NULL); |
|
638 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); |
|
639 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, |
|
640 frame1->windows_frame_info->type_); |
|
641 // This should not see the 0xbeef parameter size from the FUNC |
|
642 // record, but should instead see the STACK WIN record. |
|
643 EXPECT_EQ(4U, frame1->windows_frame_info->parameter_size); |
|
644 } |
|
645 |
|
646 { // To avoid reusing locals by mistake |
|
647 StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2)); |
|
648 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); |
|
649 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
650 | StackFrameX86::CONTEXT_VALID_ESP |
|
651 | StackFrameX86::CONTEXT_VALID_EBP |
|
652 | StackFrameX86::CONTEXT_VALID_EBX), |
|
653 frame2->context_validity); |
|
654 EXPECT_EQ(0x2a179e38U, frame2->instruction + 1); |
|
655 EXPECT_EQ(0x2a179e38U, frame2->context.eip); |
|
656 EXPECT_EQ(frame2_esp.Value(), frame2->context.esp); |
|
657 EXPECT_EQ(frame2_ebp.Value(), frame2->context.ebp); |
|
658 EXPECT_EQ(0x2558c7f3U, frame2->context.ebx); |
|
659 EXPECT_EQ(NULL, frame2->module); |
|
660 EXPECT_EQ(NULL, frame2->windows_frame_info); |
|
661 } |
|
662 } |
|
663 |
|
664 // Use Windows frame data (a "STACK WIN 4" record, from a |
|
665 // FrameTypeFrameData DIA record) to walk a stack frame, where the |
|
666 // expression fails to yield both an $eip and an $ebp value, and the stack |
|
667 // walker must scan. |
|
668 TEST_F(GetCallerFrame, WindowsFrameDataScan) { |
|
669 SetModuleSymbols(&module1, |
|
670 "STACK WIN 4 c8c 111 0 0 4 10 4 0 1 bad program string\n"); |
|
671 // Mark frame 1's PC as the end of the stack. |
|
672 SetModuleSymbols(&module2, |
|
673 "FUNC 7c38 accf 0 module2::function\n" |
|
674 "STACK WIN 4 7c38 accf 0 0 4 10 4 0 1 $eip 0 = $ebp 0 =\n"); |
|
675 Label frame1_esp; |
|
676 stack_section.start() = 0x80000000; |
|
677 stack_section |
|
678 // frame 0 |
|
679 .Append(16, 0x2a) // unused, garbage |
|
680 .D32(0x50007ce9) // return address |
|
681 // frame 1 |
|
682 .Mark(&frame1_esp) |
|
683 .Append(8, 0); // empty space |
|
684 |
|
685 RegionFromSection(); |
|
686 raw_context.eip = 0x40000c9c; |
|
687 raw_context.esp = stack_section.start().Value(); |
|
688 raw_context.ebp = 0x2ae314cd; // should not be needed to walk frame |
|
689 |
|
690 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
691 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
692 &frame_symbolizer); |
|
693 vector<const CodeModule*> modules_without_symbols; |
|
694 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
695 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
696 frames = call_stack.frames(); |
|
697 ASSERT_EQ(2U, frames->size()); |
|
698 |
|
699 { // To avoid reusing locals by mistake |
|
700 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
701 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
702 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
703 EXPECT_EQ(0x40000c9cU, frame0->instruction); |
|
704 EXPECT_EQ(0x40000c9cU, frame0->context.eip); |
|
705 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); |
|
706 EXPECT_EQ(0x2ae314cdU, frame0->context.ebp); |
|
707 EXPECT_TRUE(frame0->windows_frame_info != NULL); |
|
708 } |
|
709 |
|
710 { // To avoid reusing locals by mistake |
|
711 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
712 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); |
|
713 // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the walker |
|
714 // does not actually fetch the EBP after a scan (forcing the next frame |
|
715 // to be scanned as well). But let's grandfather the existing behavior in |
|
716 // for now. |
|
717 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
718 | StackFrameX86::CONTEXT_VALID_ESP |
|
719 | StackFrameX86::CONTEXT_VALID_EBP), |
|
720 frame1->context_validity); |
|
721 EXPECT_EQ(0x50007ce9U, frame1->instruction + 1); |
|
722 EXPECT_EQ(0x50007ce9U, frame1->context.eip); |
|
723 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); |
|
724 EXPECT_TRUE(frame1->windows_frame_info != NULL); |
|
725 } |
|
726 } |
|
727 |
|
728 // Use Windows frame data (a "STACK WIN 4" record, from a |
|
729 // FrameTypeFrameData DIA record) to walk a stack frame, where the |
|
730 // expression yields an $eip that falls outside of any module, and the |
|
731 // stack walker must scan. |
|
732 TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) { |
|
733 SetModuleSymbols(&module1, |
|
734 "STACK WIN 4 6e6 e7 0 0 0 8 4 0 1" |
|
735 // A traditional frame, actually. |
|
736 " $eip $ebp 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =\n"); |
|
737 // Mark frame 1's PC as the end of the stack. |
|
738 SetModuleSymbols(&module2, |
|
739 "FUNC cfdb 8406 0 module2::function\n" |
|
740 "STACK WIN 4 cfdb 8406 0 0 0 0 0 0 1 $eip 0 = $ebp 0 =\n"); |
|
741 stack_section.start() = 0x80000000; |
|
742 |
|
743 // In this stack, the context's %ebp is pointing at the wrong place, so |
|
744 // the stack walker needs to scan to find the return address, and then |
|
745 // scan again to find the caller's saved %ebp. |
|
746 Label frame0_ebp, frame1_ebp, frame1_esp; |
|
747 stack_section |
|
748 // frame 0 |
|
749 .Append(8, 0x2a) // garbage |
|
750 .Mark(&frame0_ebp) // frame 0 %ebp points here, but should point |
|
751 // at *** below |
|
752 // The STACK WIN record says that the following two values are |
|
753 // frame 1's saved %ebp and return address, but the %ebp is wrong; |
|
754 // they're garbage. The stack walker will scan for the right values. |
|
755 .D32(0x3d937b2b) // alleged to be frame 1's saved %ebp |
|
756 .D32(0x17847f5b) // alleged to be frame 1's return address |
|
757 .D32(frame1_ebp) // frame 1's real saved %ebp; scan will find |
|
758 .D32(0x2b2b2b2b) // first word of realigned register save area |
|
759 // *** frame 0 %ebp ought to be pointing here |
|
760 .D32(0x2c2c2c2c) // realigned locals area |
|
761 .D32(0x5000d000) // frame 1's real saved %eip; scan will find |
|
762 // Frame 1, in module2::function. The STACK WIN record describes |
|
763 // this as the oldest frame, without referring to its contents, so |
|
764 // we needn't to provide any actual data here. |
|
765 .Mark(&frame1_esp) |
|
766 .Mark(&frame1_ebp) // frame 1 %ebp points here |
|
767 // A dummy value for frame 1's %ebp to point at. The scan recognizes the |
|
768 // saved %ebp because it points to a valid word in the stack memory region. |
|
769 .D32(0x2d2d2d2d); |
|
770 |
|
771 RegionFromSection(); |
|
772 raw_context.eip = 0x40000700; |
|
773 raw_context.esp = stack_section.start().Value(); |
|
774 raw_context.ebp = frame0_ebp.Value(); |
|
775 |
|
776 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
777 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
778 &frame_symbolizer); |
|
779 vector<const CodeModule*> modules_without_symbols; |
|
780 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
781 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
782 frames = call_stack.frames(); |
|
783 ASSERT_EQ(2U, frames->size()); |
|
784 |
|
785 { // To avoid reusing locals by mistake |
|
786 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
787 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
788 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
789 EXPECT_EQ(0x40000700U, frame0->instruction); |
|
790 EXPECT_EQ(0x40000700U, frame0->context.eip); |
|
791 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); |
|
792 EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); |
|
793 EXPECT_TRUE(frame0->windows_frame_info != NULL); |
|
794 } |
|
795 |
|
796 { // To avoid reusing locals by mistake |
|
797 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
798 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust); |
|
799 // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the |
|
800 // walker does not actually fetch the EBP after a scan (forcing the |
|
801 // next frame to be scanned as well). But let's grandfather the existing |
|
802 // behavior in for now. |
|
803 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
804 | StackFrameX86::CONTEXT_VALID_ESP |
|
805 | StackFrameX86::CONTEXT_VALID_EBP), |
|
806 frame1->context_validity); |
|
807 EXPECT_EQ(0x5000d000U, frame1->instruction + 1); |
|
808 EXPECT_EQ(0x5000d000U, frame1->context.eip); |
|
809 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); |
|
810 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); |
|
811 EXPECT_TRUE(frame1->windows_frame_info != NULL); |
|
812 } |
|
813 } |
|
814 |
|
815 // Use Windows FrameTypeFPO data to walk a stack frame for a function that |
|
816 // does not modify %ebp from the value it had in the caller. |
|
817 TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) { |
|
818 SetModuleSymbols(&module1, |
|
819 // Note bogus parameter size in FUNC record; the walker |
|
820 // should prefer the STACK WIN record, and see the '8' below. |
|
821 "FUNC e8a8 100 feeb module1::discombobulated\n" |
|
822 "STACK WIN 0 e8a8 100 0 0 8 4 10 0 0 0\n"); |
|
823 Label frame0_esp; |
|
824 Label frame1_esp, frame1_ebp; |
|
825 stack_section.start() = 0x80000000; |
|
826 stack_section |
|
827 // frame 0, in module1::wheedle. FrameTypeFPO (STACK WIN 0) frame. |
|
828 .Mark(&frame0_esp) |
|
829 // no outgoing parameters; this is the youngest frame. |
|
830 .D32(0x7c521352) // four bytes of saved registers |
|
831 .Append(0x10, 0x42) // local area |
|
832 .D32(0x40009b5b) // return address, in module1, no function |
|
833 // frame 1, in module1, no function. |
|
834 .Mark(&frame1_esp) |
|
835 .D32(0xf60ea7fc) // junk |
|
836 .Mark(&frame1_ebp) |
|
837 .D32(0) // saved %ebp (stack end) |
|
838 .D32(0); // saved %eip (stack end) |
|
839 |
|
840 RegionFromSection(); |
|
841 raw_context.eip = 0x4000e8b8; // in module1::whine |
|
842 raw_context.esp = stack_section.start().Value(); |
|
843 // Frame pointer unchanged from caller. |
|
844 raw_context.ebp = frame1_ebp.Value(); |
|
845 |
|
846 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
847 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
848 &frame_symbolizer); |
|
849 vector<const CodeModule*> modules_without_symbols; |
|
850 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
851 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
852 frames = call_stack.frames(); |
|
853 ASSERT_EQ(2U, frames->size()); |
|
854 |
|
855 { // To avoid reusing locals by mistake |
|
856 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
857 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
858 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
859 EXPECT_EQ(0x4000e8b8U, frame0->instruction); |
|
860 EXPECT_EQ(0x4000e8b8U, frame0->context.eip); |
|
861 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); |
|
862 EXPECT_EQ(frame1_ebp.Value(), frame0->context.ebp); // unchanged from caller |
|
863 EXPECT_EQ(&module1, frame0->module); |
|
864 EXPECT_EQ("module1::discombobulated", frame0->function_name); |
|
865 EXPECT_EQ(0x4000e8a8U, frame0->function_base); |
|
866 // The STACK WIN record for module1::discombobulated should have |
|
867 // produced a fully populated WindowsFrameInfo structure. |
|
868 ASSERT_TRUE(frame0->windows_frame_info != NULL); |
|
869 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); |
|
870 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, |
|
871 frame0->windows_frame_info->type_); |
|
872 EXPECT_EQ(0x10U, frame0->windows_frame_info->local_size); |
|
873 } |
|
874 |
|
875 { // To avoid reusing locals by mistake |
|
876 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
877 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); |
|
878 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
879 | StackFrameX86::CONTEXT_VALID_ESP |
|
880 | StackFrameX86::CONTEXT_VALID_EBP), |
|
881 frame1->context_validity); |
|
882 EXPECT_EQ(0x40009b5bU, frame1->instruction + 1); |
|
883 EXPECT_EQ(0x40009b5bU, frame1->context.eip); |
|
884 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); |
|
885 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); |
|
886 EXPECT_EQ(&module1, frame1->module); |
|
887 EXPECT_EQ("", frame1->function_name); |
|
888 EXPECT_EQ(NULL, frame1->windows_frame_info); |
|
889 } |
|
890 } |
|
891 |
|
892 // Use Windows FrameTypeFPO data to walk a stack frame for a function |
|
893 // that uses %ebp for its own purposes, saving the value it had in the |
|
894 // caller in the standard place in the saved register area. |
|
895 TEST_F(GetCallerFrame, WindowsFPOUsedEBP) { |
|
896 SetModuleSymbols(&module1, |
|
897 // Note bogus parameter size in FUNC record; the walker |
|
898 // should prefer the STACK WIN record, and see the '8' below. |
|
899 "FUNC 9aa8 e6 abbe module1::RaisedByTheAliens\n" |
|
900 "STACK WIN 0 9aa8 e6 a 0 10 8 4 0 0 1\n"); |
|
901 Label frame0_esp; |
|
902 Label frame1_esp, frame1_ebp; |
|
903 stack_section.start() = 0x80000000; |
|
904 stack_section |
|
905 // frame 0, in module1::wheedle. FrameTypeFPO (STACK WIN 0) frame. |
|
906 .Mark(&frame0_esp) |
|
907 // no outgoing parameters; this is the youngest frame. |
|
908 .D32(frame1_ebp) // saved register area: saved %ebp |
|
909 .D32(0xb68bd5f9) // saved register area: something else |
|
910 .D32(0xd25d05fc) // local area |
|
911 .D32(0x4000debe) // return address, in module1, no function |
|
912 // frame 1, in module1, no function. |
|
913 .Mark(&frame1_esp) |
|
914 .D32(0xf0c9a974) // junk |
|
915 .Mark(&frame1_ebp) |
|
916 .D32(0) // saved %ebp (stack end) |
|
917 .D32(0); // saved %eip (stack end) |
|
918 |
|
919 RegionFromSection(); |
|
920 raw_context.eip = 0x40009ab8; // in module1::RaisedByTheAliens |
|
921 raw_context.esp = stack_section.start().Value(); |
|
922 // RaisedByTheAliens uses %ebp for its own mysterious purposes. |
|
923 raw_context.ebp = 0xecbdd1a5; |
|
924 |
|
925 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
926 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
927 &frame_symbolizer); |
|
928 vector<const CodeModule*> modules_without_symbols; |
|
929 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
930 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
931 frames = call_stack.frames(); |
|
932 ASSERT_EQ(2U, frames->size()); |
|
933 |
|
934 { // To avoid reusing locals by mistake |
|
935 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
936 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
937 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
938 EXPECT_EQ(0x40009ab8U, frame0->instruction); |
|
939 EXPECT_EQ(0x40009ab8U, frame0->context.eip); |
|
940 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); |
|
941 EXPECT_EQ(0xecbdd1a5, frame0->context.ebp); |
|
942 EXPECT_EQ(&module1, frame0->module); |
|
943 EXPECT_EQ("module1::RaisedByTheAliens", frame0->function_name); |
|
944 EXPECT_EQ(0x40009aa8U, frame0->function_base); |
|
945 // The STACK WIN record for module1::RaisedByTheAliens should have |
|
946 // produced a fully populated WindowsFrameInfo structure. |
|
947 ASSERT_TRUE(frame0->windows_frame_info != NULL); |
|
948 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); |
|
949 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, |
|
950 frame0->windows_frame_info->type_); |
|
951 EXPECT_EQ("", frame0->windows_frame_info->program_string); |
|
952 EXPECT_TRUE(frame0->windows_frame_info->allocates_base_pointer); |
|
953 } |
|
954 |
|
955 { // To avoid reusing locals by mistake |
|
956 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
957 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); |
|
958 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
959 | StackFrameX86::CONTEXT_VALID_ESP |
|
960 | StackFrameX86::CONTEXT_VALID_EBP), |
|
961 frame1->context_validity); |
|
962 EXPECT_EQ(0x4000debeU, frame1->instruction + 1); |
|
963 EXPECT_EQ(0x4000debeU, frame1->context.eip); |
|
964 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); |
|
965 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); |
|
966 EXPECT_EQ(&module1, frame1->module); |
|
967 EXPECT_EQ("", frame1->function_name); |
|
968 EXPECT_EQ(NULL, frame1->windows_frame_info); |
|
969 } |
|
970 } |
|
971 |
|
972 // This is a regression unit test which covers a bug which has to do with |
|
973 // FPO-optimized Windows system call stubs in the context frame. There is |
|
974 // a more recent Windows system call dispatch mechanism which differs from |
|
975 // the one which is being tested here. The newer system call dispatch |
|
976 // mechanism creates an extra context frame (KiFastSystemCallRet). |
|
977 TEST_F(GetCallerFrame, WindowsFPOSystemCall) { |
|
978 SetModuleSymbols(&module3, // ntdll.dll |
|
979 "PUBLIC 1f8ac c ZwWaitForSingleObject\n" |
|
980 "STACK WIN 0 1f8ac 1b 0 0 c 0 0 0 0 0\n"); |
|
981 SetModuleSymbols(&module4, // kernelbase.dll |
|
982 "PUBLIC 109f9 c WaitForSingleObjectEx\n" |
|
983 "PUBLIC 36590 0 _except_handler4\n" |
|
984 "STACK WIN 4 109f9 df c 0 c c 48 0 1 $T0 $ebp = $eip " |
|
985 "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L " |
|
986 "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n" |
|
987 "STACK WIN 4 36590 154 17 0 10 0 14 0 1 $T0 $ebp = $eip " |
|
988 "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 " |
|
989 ".cbSavedRegs - = $P $T0 8 + .cbParams + =\n"); |
|
990 SetModuleSymbols(&module5, // kernel32.dll |
|
991 "PUBLIC 11136 8 WaitForSingleObject\n" |
|
992 "PUBLIC 11151 c WaitForSingleObjectExImplementation\n" |
|
993 "STACK WIN 4 11136 16 5 0 8 0 0 0 1 $T0 $ebp = $eip " |
|
994 "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L " |
|
995 "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n" |
|
996 "STACK WIN 4 11151 7a 5 0 c 0 0 0 1 $T0 $ebp = $eip " |
|
997 "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L " |
|
998 "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n"); |
|
999 SetModuleSymbols(&module6, // chrome.dll |
|
1000 "FILE 7038 some_file_name.h\n" |
|
1001 "FILE 839776 some_file_name.cc\n" |
|
1002 "FUNC 217fda 17 4 function_217fda\n" |
|
1003 "217fda 4 102 839776\n" |
|
1004 "FUNC 217ff1 a 4 function_217ff1\n" |
|
1005 "217ff1 0 594 7038\n" |
|
1006 "217ff1 a 596 7038\n" |
|
1007 "STACK WIN 0 217ff1 a 0 0 4 0 0 0 0 0\n"); |
|
1008 |
|
1009 Label frame0_esp, frame1_esp; |
|
1010 Label frame1_ebp, frame2_ebp, frame3_ebp; |
|
1011 stack_section.start() = 0x002ff290; |
|
1012 stack_section |
|
1013 .Mark(&frame0_esp) |
|
1014 .D32(0x771ef8c1) // EIP in frame 0 (system call) |
|
1015 .D32(0x75fa0a91) // return address of frame 0 |
|
1016 .Mark(&frame1_esp) |
|
1017 .D32(0x000017b0) // args to child |
|
1018 .D32(0x00000000) |
|
1019 .D32(0x002ff2d8) |
|
1020 .D32(0x88014a2e) |
|
1021 .D32(0x002ff364) |
|
1022 .D32(0x000017b0) |
|
1023 .D32(0x00000000) |
|
1024 .D32(0x00000024) |
|
1025 .D32(0x00000001) |
|
1026 .D32(0x00000000) |
|
1027 .D32(0x00000000) |
|
1028 .D32(0x00000000) |
|
1029 .D32(0x00000000) |
|
1030 .D32(0x00000000) |
|
1031 .D32(0x00000000) |
|
1032 .D32(0x00000000) |
|
1033 .D32(0x9e3b9800) |
|
1034 .D32(0xfffffff7) |
|
1035 .D32(0x00000000) |
|
1036 .D32(0x002ff2a4) |
|
1037 .D32(0x64a07ff1) // random value to be confused with a return address |
|
1038 .D32(0x002ff8dc) |
|
1039 .D32(0x75fc6590) // random value to be confused with a return address |
|
1040 .D32(0xfdd2c6ea) |
|
1041 .D32(0x00000000) |
|
1042 .Mark(&frame1_ebp) |
|
1043 .D32(frame2_ebp) // Child EBP |
|
1044 .D32(0x75741194) // return address of frame 1 |
|
1045 .D32(0x000017b0) // args to child |
|
1046 .D32(0x0036ee80) |
|
1047 .D32(0x00000000) |
|
1048 .D32(0x65bc7d14) |
|
1049 .Mark(&frame2_ebp) |
|
1050 .D32(frame3_ebp) // Child EBP |
|
1051 .D32(0x75741148) // return address of frame 2 |
|
1052 .D32(0x000017b0) // args to child |
|
1053 .D32(0x0036ee80) |
|
1054 .D32(0x00000000) |
|
1055 .Mark(&frame3_ebp) |
|
1056 .D32(0) // saved %ebp (stack end) |
|
1057 .D32(0); // saved %eip (stack end) |
|
1058 |
|
1059 RegionFromSection(); |
|
1060 raw_context.eip = 0x771ef8c1; // in ntdll::ZwWaitForSingleObject |
|
1061 raw_context.esp = stack_section.start().Value(); |
|
1062 ASSERT_TRUE(raw_context.esp == frame0_esp.Value()); |
|
1063 raw_context.ebp = frame1_ebp.Value(); |
|
1064 |
|
1065 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
1066 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
1067 &frame_symbolizer); |
|
1068 vector<const CodeModule*> modules_without_symbols; |
|
1069 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
1070 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
1071 frames = call_stack.frames(); |
|
1072 |
|
1073 ASSERT_EQ(4U, frames->size()); |
|
1074 |
|
1075 { // To avoid reusing locals by mistake |
|
1076 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
1077 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
1078 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
1079 EXPECT_EQ(0x771ef8c1U, frame0->instruction); |
|
1080 EXPECT_EQ(0x771ef8c1U, frame0->context.eip); |
|
1081 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); |
|
1082 EXPECT_EQ(frame1_ebp.Value(), frame0->context.ebp); |
|
1083 EXPECT_EQ(&module3, frame0->module); |
|
1084 EXPECT_EQ("ZwWaitForSingleObject", frame0->function_name); |
|
1085 // The STACK WIN record for module3!ZwWaitForSingleObject should have |
|
1086 // produced a fully populated WindowsFrameInfo structure. |
|
1087 ASSERT_TRUE(frame0->windows_frame_info != NULL); |
|
1088 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); |
|
1089 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, |
|
1090 frame0->windows_frame_info->type_); |
|
1091 EXPECT_EQ("", frame0->windows_frame_info->program_string); |
|
1092 EXPECT_FALSE(frame0->windows_frame_info->allocates_base_pointer); |
|
1093 } |
|
1094 |
|
1095 { // To avoid reusing locals by mistake |
|
1096 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
1097 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); |
|
1098 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
|
1099 | StackFrameX86::CONTEXT_VALID_ESP |
|
1100 | StackFrameX86::CONTEXT_VALID_EBP), |
|
1101 frame1->context_validity); |
|
1102 EXPECT_EQ(0x75fa0a91U, frame1->instruction + 1); |
|
1103 EXPECT_EQ(0x75fa0a91U, frame1->context.eip); |
|
1104 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); |
|
1105 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); |
|
1106 EXPECT_EQ(&module4, frame1->module); |
|
1107 EXPECT_EQ("WaitForSingleObjectEx", frame1->function_name); |
|
1108 // The STACK WIN record for module4!WaitForSingleObjectEx should have |
|
1109 // produced a fully populated WindowsFrameInfo structure. |
|
1110 ASSERT_TRUE(frame1->windows_frame_info != NULL); |
|
1111 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); |
|
1112 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, |
|
1113 frame1->windows_frame_info->type_); |
|
1114 EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L " |
|
1115 "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", |
|
1116 frame1->windows_frame_info->program_string); |
|
1117 EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer); |
|
1118 } |
|
1119 } |
|
1120 |
|
1121 // Scan the stack for a better return address and potentially skip frames |
|
1122 // when the calculated return address is not in a known module. |
|
1123 // Note, that the span of this scan is somewhat arbitrarily limited to 30 |
|
1124 // search words (pointers): |
|
1125 // const int kRASearchWords = 30; |
|
1126 // This means that frames can be skipped only when their size is relatively |
|
1127 // small: smaller than kRASearchWords * sizeof(InstructionType) |
|
1128 TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) { |
|
1129 MockCodeModule msvcrt_dll(0x77be0000, 0x58000, "msvcrt.dll", "version1"); |
|
1130 SetModuleSymbols(&msvcrt_dll, // msvcrt.dll |
|
1131 "PUBLIC 38180 0 wcsstr\n" |
|
1132 "STACK WIN 4 38180 61 10 0 8 0 0 0 1 $T0 $ebp = $eip $T0 " |
|
1133 "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs " |
|
1134 "- = $P $T0 4 + .cbParams + =\n"); |
|
1135 |
|
1136 MockCodeModule kernel32_dll(0x7c800000, 0x103000, "kernel32.dll", "version1"); |
|
1137 SetModuleSymbols(&kernel32_dll, // kernel32.dll |
|
1138 "PUBLIC efda 8 FindNextFileW\n" |
|
1139 "STACK WIN 4 efda 1bb c 0 8 8 3c 0 1 $T0 $ebp = $eip $T0 " |
|
1140 "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs " |
|
1141 "- = $P $T0 4 + .cbParams + =\n"); |
|
1142 |
|
1143 MockCodeModule chrome_dll(0x1c30000, 0x28C8000, "chrome.dll", "version1"); |
|
1144 SetModuleSymbols(&chrome_dll, // chrome.dll |
|
1145 "FUNC e3cff 4af 0 file_util::FileEnumerator::Next()\n" |
|
1146 "e3cff 1a 711 2505\n" |
|
1147 "STACK WIN 4 e3cff 4af 20 0 4 c 94 0 1 $T1 .raSearch = " |
|
1148 "$T0 $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp " |
|
1149 "$T1 4 + = $20 $T0 152 - ^ = $23 $T0 156 - ^ = $24 " |
|
1150 "$T0 160 - ^ =\n"); |
|
1151 |
|
1152 // Create some modules with some stock debugging information. |
|
1153 MockCodeModules local_modules; |
|
1154 local_modules.Add(&msvcrt_dll); |
|
1155 local_modules.Add(&kernel32_dll); |
|
1156 local_modules.Add(&chrome_dll); |
|
1157 |
|
1158 Label frame0_esp; |
|
1159 Label frame0_ebp; |
|
1160 Label frame1_ebp; |
|
1161 Label frame2_ebp; |
|
1162 Label frame3_ebp; |
|
1163 |
|
1164 stack_section.start() = 0x0932f2d0; |
|
1165 stack_section |
|
1166 .Mark(&frame0_esp) |
|
1167 .D32(0x0764e000) |
|
1168 .D32(0x0764e068) |
|
1169 .Mark(&frame0_ebp) |
|
1170 .D32(frame1_ebp) // Child EBP |
|
1171 .D32(0x001767a0) // return address of frame 0 |
|
1172 // Not in known module |
|
1173 .D32(0x0764e0c6) |
|
1174 .D32(0x001bb1b8) |
|
1175 .D32(0x0764e068) |
|
1176 .D32(0x00000003) |
|
1177 .D32(0x0764e068) |
|
1178 .D32(0x00000003) |
|
1179 .D32(0x07578828) |
|
1180 .D32(0x0764e000) |
|
1181 .D32(0x00000000) |
|
1182 .D32(0x001c0010) |
|
1183 .D32(0x0764e0c6) |
|
1184 .Mark(&frame1_ebp) |
|
1185 .D32(frame2_ebp) // Child EBP |
|
1186 .D32(0x7c80f10f) // return address of frame 1 |
|
1187 // inside kernel32!FindNextFileW |
|
1188 .D32(0x000008f8) |
|
1189 .D32(0x00000000) |
|
1190 .D32(0x00000000) |
|
1191 .D32(0x00000000) |
|
1192 .D32(0x0932f34c) |
|
1193 .D32(0x0764e000) |
|
1194 .D32(0x00001000) |
|
1195 .D32(0x00000000) |
|
1196 .D32(0x00000001) |
|
1197 .D32(0x00000000) |
|
1198 .D32(0x00000000) |
|
1199 .D32(0x0932f6a8) |
|
1200 .D32(0x00000000) |
|
1201 .D32(0x0932f6d8) |
|
1202 .D32(0x00000000) |
|
1203 .D32(0x000000d6) |
|
1204 .D32(0x0764e000) |
|
1205 .D32(0x7ff9a000) |
|
1206 .D32(0x0932f3fc) |
|
1207 .D32(0x00000001) |
|
1208 .D32(0x00000001) |
|
1209 .D32(0x07578828) |
|
1210 .D32(0x0000002e) |
|
1211 .D32(0x0932f340) |
|
1212 .D32(0x0932eef4) |
|
1213 .D32(0x0932ffdc) |
|
1214 .D32(0x7c839ad8) |
|
1215 .D32(0x7c80f0d8) |
|
1216 .D32(0x00000000) |
|
1217 .Mark(&frame2_ebp) |
|
1218 .D32(frame3_ebp) // Child EBP |
|
1219 .D32(0x01d13f91) // return address of frame 2 |
|
1220 // inside chrome_dll!file_util::FileEnumerator::Next |
|
1221 .D32(0x07578828) |
|
1222 .D32(0x0932f6ac) |
|
1223 .D32(0x0932f9c4) |
|
1224 .D32(0x0932f9b4) |
|
1225 .D32(0x00000000) |
|
1226 .D32(0x00000003) |
|
1227 .D32(0x0932f978) |
|
1228 .D32(0x01094330) |
|
1229 .D32(0x00000000) |
|
1230 .D32(0x00000001) |
|
1231 .D32(0x01094330) |
|
1232 .D32(0x00000000) |
|
1233 .D32(0x00000000) |
|
1234 .D32(0x07f30000) |
|
1235 .D32(0x01c3ba17) |
|
1236 .D32(0x08bab840) |
|
1237 .D32(0x07f31580) |
|
1238 .D32(0x00000000) |
|
1239 .D32(0x00000007) |
|
1240 .D32(0x0932f940) |
|
1241 .D32(0x0000002e) |
|
1242 .D32(0x0932f40c) |
|
1243 .D32(0x01d13b53) |
|
1244 .D32(0x0932f958) |
|
1245 .D32(0x00000001) |
|
1246 .D32(0x00000007) |
|
1247 .D32(0x0932f940) |
|
1248 .D32(0x0000002e) |
|
1249 .D32(0x00000000) |
|
1250 .D32(0x0932f6ac) |
|
1251 .D32(0x01e13ef0) |
|
1252 .D32(0x00000001) |
|
1253 .D32(0x00000007) |
|
1254 .D32(0x0932f958) |
|
1255 .D32(0x08bab840) |
|
1256 .D32(0x0932f9b4) |
|
1257 .D32(0x00000000) |
|
1258 .D32(0x0932f9b4) |
|
1259 .D32(0x000000a7) |
|
1260 .D32(0x000000a7) |
|
1261 .D32(0x0932f998) |
|
1262 .D32(0x579627a2) |
|
1263 .Mark(&frame3_ebp) |
|
1264 .D32(0) // saved %ebp (stack end) |
|
1265 .D32(0); // saved %eip (stack end) |
|
1266 |
|
1267 RegionFromSection(); |
|
1268 raw_context.eip = 0x77c181cd; // inside msvcrt!wcsstr |
|
1269 raw_context.esp = frame0_esp.Value(); |
|
1270 raw_context.ebp = frame0_ebp.Value(); |
|
1271 // sanity |
|
1272 ASSERT_TRUE(raw_context.esp == stack_section.start().Value()); |
|
1273 ASSERT_TRUE(raw_context.ebp == stack_section.start().Value() + 8); |
|
1274 |
|
1275 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
1276 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, |
|
1277 &local_modules, &frame_symbolizer); |
|
1278 vector<const CodeModule*> modules_without_symbols; |
|
1279 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
1280 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
1281 frames = call_stack.frames(); |
|
1282 |
|
1283 ASSERT_EQ(3U, frames->size()); |
|
1284 |
|
1285 { // To avoid reusing locals by mistake |
|
1286 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
1287 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
1288 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
1289 EXPECT_EQ(0x77c181cdU, frame0->instruction); |
|
1290 EXPECT_EQ(0x77c181cdU, frame0->context.eip); |
|
1291 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); |
|
1292 EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); |
|
1293 EXPECT_EQ(&msvcrt_dll, frame0->module); |
|
1294 EXPECT_EQ("wcsstr", frame0->function_name); |
|
1295 ASSERT_TRUE(frame0->windows_frame_info != NULL); |
|
1296 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); |
|
1297 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, |
|
1298 frame0->windows_frame_info->type_); |
|
1299 EXPECT_EQ("$T0 $ebp = $eip $T0 " |
|
1300 "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs " |
|
1301 "- = $P $T0 4 + .cbParams + =", |
|
1302 frame0->windows_frame_info->program_string); |
|
1303 // It has program string, so allocates_base_pointer is not expected |
|
1304 EXPECT_FALSE(frame0->windows_frame_info->allocates_base_pointer); |
|
1305 } |
|
1306 |
|
1307 { // To avoid reusing locals by mistake |
|
1308 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
1309 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust); |
|
1310 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | |
|
1311 StackFrameX86::CONTEXT_VALID_ESP | |
|
1312 StackFrameX86::CONTEXT_VALID_EBP), |
|
1313 frame1->context_validity); |
|
1314 EXPECT_EQ(0x7c80f10fU, frame1->instruction + 1); |
|
1315 EXPECT_EQ(0x7c80f10fU, frame1->context.eip); |
|
1316 // frame 1 was skipped, so intead of frame1_ebp compare with frame2_ebp. |
|
1317 EXPECT_EQ(frame2_ebp.Value(), frame1->context.ebp); |
|
1318 EXPECT_EQ(&kernel32_dll, frame1->module); |
|
1319 EXPECT_EQ("FindNextFileW", frame1->function_name); |
|
1320 ASSERT_TRUE(frame1->windows_frame_info != NULL); |
|
1321 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); |
|
1322 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, |
|
1323 frame1->windows_frame_info->type_); |
|
1324 EXPECT_EQ("$T0 $ebp = $eip $T0 " |
|
1325 "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs " |
|
1326 "- = $P $T0 4 + .cbParams + =", |
|
1327 frame1->windows_frame_info->program_string); |
|
1328 EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer); |
|
1329 } |
|
1330 |
|
1331 { // To avoid reusing locals by mistake |
|
1332 StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2)); |
|
1333 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); |
|
1334 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | |
|
1335 StackFrameX86::CONTEXT_VALID_ESP | |
|
1336 StackFrameX86::CONTEXT_VALID_EBP), |
|
1337 frame2->context_validity); |
|
1338 EXPECT_EQ(0x01d13f91U, frame2->instruction + 1); |
|
1339 EXPECT_EQ(0x01d13f91U, frame2->context.eip); |
|
1340 // frame 1 was skipped, so intead of frame2_ebp compare with frame3_ebp. |
|
1341 EXPECT_EQ(frame3_ebp.Value(), frame2->context.ebp); |
|
1342 EXPECT_EQ(&chrome_dll, frame2->module); |
|
1343 EXPECT_EQ("file_util::FileEnumerator::Next()", frame2->function_name); |
|
1344 ASSERT_TRUE(frame2->windows_frame_info != NULL); |
|
1345 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame2->windows_frame_info->valid); |
|
1346 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, |
|
1347 frame2->windows_frame_info->type_); |
|
1348 EXPECT_EQ("$T1 .raSearch = " |
|
1349 "$T0 $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp " |
|
1350 "$T1 4 + = $20 $T0 152 - ^ = $23 $T0 156 - ^ = $24 " |
|
1351 "$T0 160 - ^ =", |
|
1352 frame2->windows_frame_info->program_string); |
|
1353 EXPECT_FALSE(frame2->windows_frame_info->allocates_base_pointer); |
|
1354 } |
|
1355 } |
|
1356 |
|
1357 struct CFIFixture: public StackwalkerX86Fixture { |
|
1358 CFIFixture() { |
|
1359 // Provide a bunch of STACK CFI records; individual tests walk to the |
|
1360 // caller from every point in this series, expecting to find the same |
|
1361 // set of register values. |
|
1362 SetModuleSymbols(&module1, |
|
1363 // The youngest frame's function. |
|
1364 "FUNC 4000 1000 10 enchiridion\n" |
|
1365 // Initially, just a return address. |
|
1366 "STACK CFI INIT 4000 100 .cfa: $esp 4 + .ra: .cfa 4 - ^\n" |
|
1367 // Push %ebx. |
|
1368 "STACK CFI 4001 .cfa: $esp 8 + $ebx: .cfa 8 - ^\n" |
|
1369 // Move %esi into %ebx. Weird, but permitted. |
|
1370 "STACK CFI 4002 $esi: $ebx\n" |
|
1371 // Allocate frame space, and save %edi. |
|
1372 "STACK CFI 4003 .cfa: $esp 20 + $edi: .cfa 16 - ^\n" |
|
1373 // Put the return address in %edi. |
|
1374 "STACK CFI 4005 .ra: $edi\n" |
|
1375 // Save %ebp, and use it as a frame pointer. |
|
1376 "STACK CFI 4006 .cfa: $ebp 8 + $ebp: .cfa 12 - ^\n" |
|
1377 |
|
1378 // The calling function. |
|
1379 "FUNC 5000 1000 10 epictetus\n" |
|
1380 // Mark it as end of stack. |
|
1381 "STACK CFI INIT 5000 1000 .cfa: $esp .ra 0\n"); |
|
1382 |
|
1383 // Provide some distinctive values for the caller's registers. |
|
1384 expected.esp = 0x80000000; |
|
1385 expected.eip = 0x40005510; |
|
1386 expected.ebp = 0xc0d4aab9; |
|
1387 expected.ebx = 0x60f20ce6; |
|
1388 expected.esi = 0x53d1379d; |
|
1389 expected.edi = 0xafbae234; |
|
1390 |
|
1391 // By default, registers are unchanged. |
|
1392 raw_context = expected; |
|
1393 } |
|
1394 |
|
1395 // Walk the stack, using stack_section as the contents of the stack |
|
1396 // and raw_context as the current register values. (Set |
|
1397 // raw_context.esp to the stack's starting address.) Expect two |
|
1398 // stack frames; in the older frame, expect the callee-saves |
|
1399 // registers to have values matching those in 'expected'. |
|
1400 void CheckWalk() { |
|
1401 RegionFromSection(); |
|
1402 raw_context.esp = stack_section.start().Value(); |
|
1403 |
|
1404 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); |
|
1405 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, |
|
1406 &frame_symbolizer); |
|
1407 vector<const CodeModule*> modules_without_symbols; |
|
1408 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); |
|
1409 ASSERT_EQ(0U, modules_without_symbols.size()); |
|
1410 frames = call_stack.frames(); |
|
1411 ASSERT_EQ(2U, frames->size()); |
|
1412 |
|
1413 { // To avoid reusing locals by mistake |
|
1414 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); |
|
1415 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); |
|
1416 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); |
|
1417 EXPECT_EQ("enchiridion", frame0->function_name); |
|
1418 EXPECT_EQ(0x40004000U, frame0->function_base); |
|
1419 ASSERT_TRUE(frame0->windows_frame_info != NULL); |
|
1420 ASSERT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE, |
|
1421 frame0->windows_frame_info->valid); |
|
1422 ASSERT_TRUE(frame0->cfi_frame_info != NULL); |
|
1423 } |
|
1424 |
|
1425 { // To avoid reusing locals by mistake |
|
1426 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); |
|
1427 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); |
|
1428 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | |
|
1429 StackFrameX86::CONTEXT_VALID_ESP | |
|
1430 StackFrameX86::CONTEXT_VALID_EBP | |
|
1431 StackFrameX86::CONTEXT_VALID_EBX | |
|
1432 StackFrameX86::CONTEXT_VALID_ESI | |
|
1433 StackFrameX86::CONTEXT_VALID_EDI), |
|
1434 frame1->context_validity); |
|
1435 EXPECT_EQ(expected.eip, frame1->context.eip); |
|
1436 EXPECT_EQ(expected.esp, frame1->context.esp); |
|
1437 EXPECT_EQ(expected.ebp, frame1->context.ebp); |
|
1438 EXPECT_EQ(expected.ebx, frame1->context.ebx); |
|
1439 EXPECT_EQ(expected.esi, frame1->context.esi); |
|
1440 EXPECT_EQ(expected.edi, frame1->context.edi); |
|
1441 EXPECT_EQ("epictetus", frame1->function_name); |
|
1442 } |
|
1443 } |
|
1444 |
|
1445 // The values the stack walker should find for the caller's registers. |
|
1446 MDRawContextX86 expected; |
|
1447 }; |
|
1448 |
|
1449 class CFI: public CFIFixture, public Test { }; |
|
1450 |
|
1451 TEST_F(CFI, At4000) { |
|
1452 Label frame1_esp = expected.esp; |
|
1453 stack_section |
|
1454 .D32(0x40005510) // return address |
|
1455 .Mark(&frame1_esp); // This effectively sets stack_section.start(). |
|
1456 raw_context.eip = 0x40004000; |
|
1457 CheckWalk(); |
|
1458 } |
|
1459 |
|
1460 TEST_F(CFI, At4001) { |
|
1461 Label frame1_esp = expected.esp; |
|
1462 stack_section |
|
1463 .D32(0x60f20ce6) // saved %ebx |
|
1464 .D32(0x40005510) // return address |
|
1465 .Mark(&frame1_esp); // This effectively sets stack_section.start(). |
|
1466 raw_context.eip = 0x40004001; |
|
1467 raw_context.ebx = 0x91aa9a8b; // callee's %ebx value |
|
1468 CheckWalk(); |
|
1469 } |
|
1470 |
|
1471 TEST_F(CFI, At4002) { |
|
1472 Label frame1_esp = expected.esp; |
|
1473 stack_section |
|
1474 .D32(0x60f20ce6) // saved %ebx |
|
1475 .D32(0x40005510) // return address |
|
1476 .Mark(&frame1_esp); // This effectively sets stack_section.start(). |
|
1477 raw_context.eip = 0x40004002; |
|
1478 raw_context.ebx = 0x53d1379d; // saved %esi |
|
1479 raw_context.esi = 0xa5c790ed; // callee's %esi value |
|
1480 CheckWalk(); |
|
1481 } |
|
1482 |
|
1483 TEST_F(CFI, At4003) { |
|
1484 Label frame1_esp = expected.esp; |
|
1485 stack_section |
|
1486 .D32(0x56ec3db7) // garbage |
|
1487 .D32(0xafbae234) // saved %edi |
|
1488 .D32(0x53d67131) // garbage |
|
1489 .D32(0x60f20ce6) // saved %ebx |
|
1490 .D32(0x40005510) // return address |
|
1491 .Mark(&frame1_esp); // This effectively sets stack_section.start(). |
|
1492 raw_context.eip = 0x40004003; |
|
1493 raw_context.ebx = 0x53d1379d; // saved %esi |
|
1494 raw_context.esi = 0xa97f229d; // callee's %esi |
|
1495 raw_context.edi = 0xb05cc997; // callee's %edi |
|
1496 CheckWalk(); |
|
1497 } |
|
1498 |
|
1499 // The results here should be the same as those at module offset |
|
1500 // 0x4003. |
|
1501 TEST_F(CFI, At4004) { |
|
1502 Label frame1_esp = expected.esp; |
|
1503 stack_section |
|
1504 .D32(0xe29782c2) // garbage |
|
1505 .D32(0xafbae234) // saved %edi |
|
1506 .D32(0x5ba29ce9) // garbage |
|
1507 .D32(0x60f20ce6) // saved %ebx |
|
1508 .D32(0x40005510) // return address |
|
1509 .Mark(&frame1_esp); // This effectively sets stack_section.start(). |
|
1510 raw_context.eip = 0x40004004; |
|
1511 raw_context.ebx = 0x53d1379d; // saved %esi |
|
1512 raw_context.esi = 0x0fb7dc4e; // callee's %esi |
|
1513 raw_context.edi = 0x993b4280; // callee's %edi |
|
1514 CheckWalk(); |
|
1515 } |
|
1516 |
|
1517 TEST_F(CFI, At4005) { |
|
1518 Label frame1_esp = expected.esp; |
|
1519 stack_section |
|
1520 .D32(0xe29782c2) // garbage |
|
1521 .D32(0xafbae234) // saved %edi |
|
1522 .D32(0x5ba29ce9) // garbage |
|
1523 .D32(0x60f20ce6) // saved %ebx |
|
1524 .D32(0x8036cc02) // garbage |
|
1525 .Mark(&frame1_esp); // This effectively sets stack_section.start(). |
|
1526 raw_context.eip = 0x40004005; |
|
1527 raw_context.ebx = 0x53d1379d; // saved %esi |
|
1528 raw_context.esi = 0x0fb7dc4e; // callee's %esi |
|
1529 raw_context.edi = 0x40005510; // return address |
|
1530 CheckWalk(); |
|
1531 } |
|
1532 |
|
1533 TEST_F(CFI, At4006) { |
|
1534 Label frame0_ebp; |
|
1535 Label frame1_esp = expected.esp; |
|
1536 stack_section |
|
1537 .D32(0xdcdd25cd) // garbage |
|
1538 .D32(0xafbae234) // saved %edi |
|
1539 .D32(0xc0d4aab9) // saved %ebp |
|
1540 .Mark(&frame0_ebp) // frame pointer points here |
|
1541 .D32(0x60f20ce6) // saved %ebx |
|
1542 .D32(0x8036cc02) // garbage |
|
1543 .Mark(&frame1_esp); // This effectively sets stack_section.start(). |
|
1544 raw_context.eip = 0x40004006; |
|
1545 raw_context.ebp = frame0_ebp.Value(); |
|
1546 raw_context.ebx = 0x53d1379d; // saved %esi |
|
1547 raw_context.esi = 0x743833c9; // callee's %esi |
|
1548 raw_context.edi = 0x40005510; // return address |
|
1549 CheckWalk(); |
|
1550 } |
|
1551 |