Left: | ||
Right: |
LEFT | RIGHT |
---|---|
(no file at all) | |
1 // Copyright (c) 2015, Google Inc. | |
2 // All rights reserved. | |
Ted Mielczarek
2015/05/04 11:39:41
Thanks for adding tests. I know these are a very c
| |
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 // stackwalker_sh4_unittest.cc: Unit tests for StackwalkerSH4 class. | |
31 | |
32 #include <string.h> | |
33 #include <string> | |
34 #include <vector> | |
35 | |
36 #include "breakpad_googletest_includes.h" | |
37 #include "common/test_assembler.h" | |
38 #include "common/using_std_string.h" | |
39 #include "google_breakpad/common/minidump_format.h" | |
40 #include "google_breakpad/processor/basic_source_line_resolver.h" | |
41 #include "google_breakpad/processor/call_stack.h" | |
42 #include "google_breakpad/processor/code_module.h" | |
43 #include "google_breakpad/processor/source_line_resolver_interface.h" | |
44 #include "google_breakpad/processor/stack_frame_cpu.h" | |
45 #include "processor/stackwalker_unittest_utils.h" | |
46 #include "processor/stackwalker_sh4.h" | |
47 #include "processor/windows_frame_info.h" | |
48 | |
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::StackFrameSH4; | |
56 using google_breakpad::Stackwalker; | |
57 using google_breakpad::StackwalkerSH4; | |
58 using google_breakpad::SystemInfo; | |
59 using google_breakpad::WindowsFrameInfo; | |
60 using google_breakpad::test_assembler::kLittleEndian; | |
61 using google_breakpad::test_assembler::Label; | |
62 using google_breakpad::test_assembler::Section; | |
63 using std::vector; | |
64 using testing::_; | |
65 using testing::AnyNumber; | |
66 using testing::Return; | |
67 using testing::SetArgumentPointee; | |
68 using testing::Test; | |
69 | |
70 class StackwalkerSH4Fixture { | |
Ted Mielczarek
2015/05/04 11:39:41
We should probably move this out into a common hea
| |
71 public: | |
72 StackwalkerSH4Fixture() | |
73 : stack_section(kLittleEndian), | |
74 // Give the two modules reasonable standard locations and names | |
75 // for tests to play with. | |
76 module1(0x400000, 0x10000, "module1", "version1"), | |
77 module2(0x500000, 0x10000, "module2", "version2") { | |
78 // Identify the system as a Linux system. | |
79 system_info.os = "Linux"; | |
80 system_info.os_short = "linux"; | |
81 system_info.os_version = "Observant Opossum"; // Jealous Jellyfish | |
82 system_info.cpu = "sh4"; | |
83 system_info.cpu_info = ""; | |
84 | |
85 // Put distinctive values in the raw CPU context. | |
86 BrandContext(&raw_context); | |
87 | |
88 // Create some modules with some stock debugging information. | |
89 modules.Add(&module1); | |
90 modules.Add(&module2); | |
91 | |
92 // By default, none of the modules have symbol info; call | |
93 // SetModuleSymbols to override this. | |
94 EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) | |
95 .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); | |
96 | |
97 // Avoid GMOCK WARNING "Uninteresting mock function call - returning | |
98 // directly" for FreeSymbolData(). | |
99 EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); | |
100 | |
101 // Reset max_frames_scanned since it's static. | |
102 Stackwalker::set_max_frames_scanned(1024); | |
103 } | |
104 | |
105 // Set the Breakpad symbol information that supplier should return for | |
106 // MODULE to INFO. | |
107 void SetModuleSymbols(MockCodeModule* module, const string& info) { | |
108 size_t buffer_size; | |
109 char* buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); | |
110 EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) | |
111 .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), | |
112 SetArgumentPointee<4>(buffer_size), | |
113 Return(MockSymbolSupplier::FOUND))); | |
114 } | |
115 | |
116 // Populate stack_region with the contents of stack_section. Use | |
117 // stack_section.start() as the region's starting address. | |
118 void RegionFromSection() { | |
119 string contents; | |
120 ASSERT_TRUE(stack_section.GetContents(&contents)); | |
121 stack_region.Init(stack_section.start().Value(), contents); | |
122 } | |
123 | |
124 // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. | |
125 void BrandContext(MDRawContextSH4* raw_context) { | |
126 uint8_t x = 173; | |
127 for (size_t i = 0; i < sizeof(*raw_context); ++i) | |
128 reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17); | |
129 } | |
130 | |
131 SystemInfo system_info; | |
132 MDRawContextSH4 raw_context; | |
133 Section stack_section; | |
134 MockMemoryRegion stack_region; | |
135 MockCodeModule module1; | |
136 MockCodeModule module2; | |
137 MockCodeModules modules; | |
138 MockSymbolSupplier supplier; | |
139 BasicSourceLineResolver resolver; | |
140 CallStack call_stack; | |
141 const vector<StackFrame*>* frames; | |
142 }; | |
143 | |
144 class SanityCheck: public StackwalkerSH4Fixture, public Test { }; | |
145 | |
146 TEST_F(SanityCheck, NoResolver) { | |
147 stack_section.start() = 0x80000000; | |
148 stack_section.D32(0).D32(0x0); | |
149 RegionFromSection(); | |
150 raw_context.pc = 0x400020; | |
151 raw_context.iregs[MD_CONTEXT_SH4_REG_SP] = 0x80000000; | |
152 | |
153 StackFrameSymbolizer frame_symbolizer(NULL, NULL); | |
154 StackwalkerSH4 walker(&system_info, &raw_context, &stack_region, &modules, | |
155 &frame_symbolizer); | |
156 // This should succeed even without a resolver or supplier. | |
157 vector<const CodeModule*> modules_without_symbols; | |
158 vector<const CodeModule*> modules_with_corrupt_symbols; | |
159 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, | |
160 &modules_with_corrupt_symbols)); | |
161 ASSERT_EQ(1U, modules_without_symbols.size()); | |
162 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); | |
163 ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); | |
164 frames = call_stack.frames(); | |
165 ASSERT_EQ(1U, frames->size()); | |
166 StackFrameSH4 *frame = static_cast<StackFrameSH4 *>(frames->at(0)); | |
167 // Check that the values from the original raw context made it | |
168 // through to the context in the stack frame. | |
169 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); | |
170 } | |
171 | |
172 class GetContextFrame: public StackwalkerSH4Fixture, public Test { }; | |
173 | |
174 TEST_F(GetContextFrame, Simple) { | |
175 stack_section.start() = 0x80000000; | |
176 stack_section.D32(0).D32(0x0); | |
177 RegionFromSection(); | |
178 raw_context.pc = 0x400020; | |
179 raw_context.iregs[MD_CONTEXT_SH4_REG_SP] = 0x80000000; | |
180 | |
181 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); | |
182 StackwalkerSH4 walker(&system_info, &raw_context, &stack_region, &modules, | |
183 &frame_symbolizer); | |
184 vector<const CodeModule*> modules_without_symbols; | |
185 vector<const CodeModule*> modules_with_corrupt_symbols; | |
186 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, | |
187 &modules_with_corrupt_symbols)); | |
188 ASSERT_EQ(1U, modules_without_symbols.size()); | |
189 ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); | |
190 frames = call_stack.frames(); | |
191 ASSERT_EQ(1U, frames->size()); | |
192 StackFrameSH4 *frame = static_cast<StackFrameSH4 *>(frames->at(0)); | |
193 // Check that the values from the original raw context made it | |
194 // through to the context in the stack frame. | |
195 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); | |
196 } | |
197 | |
198 // The stackwalker should be able to produce the context frame even | |
199 // without stack memory present. | |
200 TEST_F(GetContextFrame, NoStackMemory) { | |
201 raw_context.pc = 0x400020; | |
202 raw_context.iregs[MD_CONTEXT_SH4_REG_SP] = 0x80000000; | |
203 | |
204 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); | |
205 StackwalkerSH4 walker(&system_info, &raw_context, NULL, &modules, | |
206 &frame_symbolizer); | |
207 vector<const CodeModule*> modules_without_symbols; | |
208 vector<const CodeModule*> modules_with_corrupt_symbols; | |
209 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, | |
210 &modules_with_corrupt_symbols)); | |
211 ASSERT_EQ(1U, modules_without_symbols.size()); | |
212 ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); | |
213 frames = call_stack.frames(); | |
214 ASSERT_EQ(1U, frames->size()); | |
215 StackFrameSH4 *frame = static_cast<StackFrameSH4 *>(frames->at(0)); | |
216 // Check that the values from the original raw context made it | |
217 // through to the context in the stack frame. | |
218 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); | |
219 } | |
220 | |
221 class GetCallerFrame: public StackwalkerSH4Fixture, public Test { }; | |
222 | |
223 TEST_F(GetCallerFrame, ScanWithoutSymbols) { | |
224 // When the stack walker resorts to scanning the stack, | |
225 // only addresses located within loaded modules are | |
226 // considered valid return addresses. | |
227 // Force scanning through three frames to ensure that the | |
228 // stack pointer is set properly in scan-recovered frames. | |
229 stack_section.start() = 0x80000000; | |
230 uint32_t return_address1 = 0x40084c; | |
231 uint32_t return_address2 = 0x400988; | |
232 Label frame1_sp, frame2_sp; | |
233 stack_section | |
234 // frame 0 | |
235 .Append(16, 0) // space | |
236 | |
237 .D32(0x40090000) // junk that's not | |
238 .D32(0x60000000) // a return address | |
239 | |
240 .D32(return_address1) // actual return address | |
241 // frame 1 | |
242 .Mark(&frame1_sp) | |
243 .Append(16, 0) // space | |
244 | |
245 .D32(0xF0000000) // more junk | |
246 .D32(0x0000000D) | |
247 | |
248 .D32(return_address2) // actual return address | |
249 // frame 2 | |
250 .Mark(&frame2_sp) | |
251 .Append(32, 0); // end of stack | |
252 RegionFromSection(); | |
253 | |
254 raw_context.pc = 0x400978; | |
255 raw_context.iregs[MD_CONTEXT_SH4_REG_SP] = stack_section.start().Value(); | |
256 | |
257 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); | |
258 StackwalkerSH4 walker(&system_info, &raw_context, &stack_region, &modules, | |
259 &frame_symbolizer); | |
260 vector<const CodeModule*> modules_without_symbols; | |
261 vector<const CodeModule*> modules_with_corrupt_symbols; | |
262 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, | |
263 &modules_with_corrupt_symbols)); | |
264 ASSERT_EQ(1U, modules_without_symbols.size()); | |
265 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); | |
266 ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); | |
267 frames = call_stack.frames(); | |
268 ASSERT_EQ(3U, frames->size()); | |
269 | |
270 StackFrameSH4 *frame0 = static_cast<StackFrameSH4 *>(frames->at(0)); | |
271 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); | |
272 ASSERT_EQ(StackFrameSH4::CONTEXT_VALID_ALL, frame0->context_validity); | |
273 EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); | |
274 | |
275 StackFrameSH4 *frame1 = static_cast<StackFrameSH4 *>(frames->at(1)); | |
276 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); | |
277 ASSERT_EQ((StackFrameSH4::CONTEXT_VALID_PR | | |
278 StackFrameSH4::CONTEXT_VALID_PC | | |
279 StackFrameSH4::CONTEXT_VALID_SP), | |
280 frame1->context_validity); | |
281 EXPECT_EQ(return_address1, frame1->context.pr); | |
282 EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_SH4_REG_SP]); | |
283 | |
284 StackFrameSH4 *frame2 = static_cast<StackFrameSH4 *>(frames->at(2)); | |
285 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); | |
286 ASSERT_EQ((StackFrameSH4::CONTEXT_VALID_PR | | |
287 StackFrameSH4::CONTEXT_VALID_PC | | |
288 StackFrameSH4::CONTEXT_VALID_SP), | |
289 frame2->context_validity); | |
290 EXPECT_EQ(return_address2, frame2->context.pr); | |
291 EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_SH4_REG_SP]); | |
292 } | |
293 | |
294 TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { | |
295 // During stack scanning, if a potential return address | |
296 // is located within a loaded module that has symbols, | |
297 // it is only considered a valid return address if it | |
298 // lies within a function's bounds. | |
299 stack_section.start() = 0x80000000; | |
300 uint32_t return_address = 0x500200; | |
301 Label frame1_sp; | |
302 | |
303 stack_section | |
304 // frame 0 | |
305 .Append(16, 0) // space | |
306 | |
307 .D32(0x40090000) // junk that's not | |
308 .D32(0x60000000) // a return address | |
309 | |
310 .D32(0x410000) // a couple of plausible return | |
311 .D32(0x510000) // addresses that are not within functions | |
312 | |
313 .D32(return_address) // actual return address | |
314 | |
315 // frame 1 | |
316 .Mark(&frame1_sp) | |
317 .Append(32, 0); // end of stack | |
318 RegionFromSection(); | |
319 | |
320 raw_context.pc = 0x400200; | |
321 raw_context.iregs[MD_CONTEXT_SH4_REG_SP] = stack_section.start().Value(); | |
322 | |
323 SetModuleSymbols(&module1, | |
324 // The youngest frame's function. | |
325 "FUNC 100 400 10 monotreme\n"); | |
326 SetModuleSymbols(&module2, | |
327 // The calling frame's function. | |
328 "FUNC 100 400 10 marsupial\n"); | |
329 | |
330 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); | |
331 StackwalkerSH4 walker(&system_info, &raw_context, &stack_region, &modules, | |
332 &frame_symbolizer); | |
333 vector<const CodeModule*> modules_without_symbols; | |
334 vector<const CodeModule*> modules_with_corrupt_symbols; | |
335 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, | |
336 &modules_with_corrupt_symbols)); | |
337 ASSERT_EQ(0U, modules_without_symbols.size()); | |
338 ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); | |
339 frames = call_stack.frames(); | |
340 ASSERT_EQ(2U, frames->size()); | |
341 | |
342 StackFrameSH4 *frame0 = static_cast<StackFrameSH4 *>(frames->at(0)); | |
343 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); | |
344 ASSERT_EQ(StackFrameSH4::CONTEXT_VALID_ALL, frame0->context_validity); | |
345 EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); | |
346 EXPECT_EQ("monotreme", frame0->function_name); | |
347 EXPECT_EQ(0x400100U, frame0->function_base); | |
348 | |
349 StackFrameSH4 *frame1 = static_cast<StackFrameSH4 *>(frames->at(1)); | |
350 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); | |
351 ASSERT_EQ((StackFrameSH4::CONTEXT_VALID_PC | | |
352 StackFrameSH4::CONTEXT_VALID_PR | | |
353 StackFrameSH4::CONTEXT_VALID_SP), | |
354 frame1->context_validity); | |
355 EXPECT_EQ(return_address, frame1->context.pr); | |
356 EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_SH4_REG_SP]); | |
357 EXPECT_EQ("marsupial", frame1->function_name); | |
358 EXPECT_EQ(0x500100U, frame1->function_base); | |
359 } | |
360 | |
361 | |
362 struct CFIFixture: public StackwalkerSH4Fixture { | |
363 CFIFixture() { | |
364 // Provide a bunch of STACK CFI records; we'll walk to the caller | |
365 // from every point in this series, expecting to find the same set | |
366 // of register values. | |
367 SetModuleSymbols(&module1, | |
368 // The youngest frame's function. | |
369 "FUNC 4000 1000 0 enchiridion\n" | |
370 // Initially, nothing has been pushed on the stack, | |
371 // and the return address is still in the pr register. | |
372 "STACK CFI INIT 4000 1000 .cfa: r15 .ra: pr\n" | |
373 // Push r8 and the pr register. | |
374 "STACK CFI 4001 .cfa: r15 8 + r8: .cfa 8 - ^ .ra: .cfa 4 - ^\n" | |
375 // Save r8..r11 in r0..r3: verify that we populate | |
376 // the youngest frame with all the values we have. | |
377 "STACK CFI 4002 r8: r0 r9: r1 r10: r2 r11: r3\n" | |
378 // Restore r8..r11. Save the non-callee-saves register r1. | |
379 "STACK CFI 4003 .cfa: r15 12 + r1: .cfa 12 - ^" | |
380 " r8: r8 r9: r9 r10: r10 r11: r11\n" | |
381 // Move the .cfa back four bytes, to point at the return | |
382 // address, and restore the sp explicitly. | |
383 "STACK CFI 4005 .cfa: r15 8 + r1: .cfa 8 - ^" | |
384 " r11: .cfa 4 - ^ .ra: .cfa ^ r15: .cfa 4 +\n" | |
385 // Recover the PC explicitly from a new stack slot; | |
386 // provide garbage for the .ra. | |
387 "STACK CFI 4006 .cfa: r15 12 + pr: .cfa 12 - ^\n" | |
388 | |
389 // The calling function. | |
390 "FUNC 5000 1000 10 epictetus\n" | |
391 // Mark it as end of stack. | |
392 "STACK CFI INIT 5000 1000 .cfa: 0 .ra: 0\n" | |
393 | |
394 // A function whose CFI makes the stack pointer | |
395 // go backwards. | |
396 "FUNC 6000 1000 20 palinal\n" | |
397 "STACK CFI INIT 6000 1000 .cfa: r15 4 - ra: pr\n" | |
398 | |
399 // A function with CFI expressions that can't be | |
400 // evaluated. | |
401 "FUNC 7000 1000 20 rhetorical\n" | |
402 "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n"); | |
403 | |
404 // Provide some distinctive values for the caller's registers. | |
405 expected.pr = 0x405510; | |
406 expected.iregs[MD_CONTEXT_SH4_REG_SP] = 0x80000000; | |
407 expected.iregs[8] = 0xb5d55e68; | |
408 expected.iregs[9] = 0xebd134f3; | |
409 expected.iregs[10] = 0xa31e74bc; | |
410 expected.iregs[11] = 0x2dcb16b3; | |
411 | |
412 // Expect CFI to recover all callee-saves registers. Since CFI is the | |
413 // only stack frame construction technique we have, aside from the | |
414 // context frame itself, there's no way for us to have a set of valid | |
415 // registers smaller than this. | |
416 expected_validity = (StackFrameSH4::CONTEXT_VALID_PR | | |
417 StackFrameSH4::CONTEXT_VALID_SP | | |
418 StackFrameSH4::CONTEXT_VALID_R8 | | |
419 StackFrameSH4::CONTEXT_VALID_R9 | | |
420 StackFrameSH4::CONTEXT_VALID_R10| | |
421 StackFrameSH4::CONTEXT_VALID_R11| | |
422 StackFrameSH4::CONTEXT_VALID_R12| | |
423 StackFrameSH4::CONTEXT_VALID_R13| | |
424 StackFrameSH4::CONTEXT_VALID_R14); | |
425 | |
426 // By default, context frames provide all registers, as normal. | |
427 context_frame_validity = StackFrameSH4::CONTEXT_VALID_ALL; | |
428 | |
429 // By default, registers are unchanged. | |
430 raw_context = expected; | |
431 } | |
432 | |
433 // Walk the stack, using stack_section as the contents of the stack | |
434 // and raw_context as the current register values. (Set the stack | |
435 // pointer to the stack's starting address.) Expect two stack | |
436 // frames; in the older frame, expect the callee-saves registers to | |
437 // have values matching those in 'expected'. | |
438 void CheckWalk() { | |
439 RegionFromSection(); | |
440 raw_context.iregs[MD_CONTEXT_SH4_REG_SP] = stack_section.start().Value(); | |
441 | |
442 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); | |
443 StackwalkerSH4 walker(&system_info, &raw_context, &stack_region, | |
444 &modules, &frame_symbolizer); | |
445 vector<const CodeModule*> modules_without_symbols; | |
446 vector<const CodeModule*> modules_with_corrupt_symbols; | |
447 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, | |
448 &modules_with_corrupt_symbols)); | |
449 ASSERT_EQ(0U, modules_without_symbols.size()); | |
450 ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); | |
451 frames = call_stack.frames(); | |
452 ASSERT_EQ(2U, frames->size()); | |
453 | |
454 StackFrameSH4 *frame0 = static_cast<StackFrameSH4 *>(frames->at(0)); | |
455 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); | |
456 ASSERT_EQ(context_frame_validity, frame0->context_validity); | |
457 EXPECT_EQ("enchiridion", frame0->function_name); | |
458 EXPECT_EQ(0x404000U, frame0->function_base); | |
459 | |
460 StackFrameSH4 *frame1 = static_cast<StackFrameSH4 *>(frames->at(1)); | |
461 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); | |
462 ASSERT_EQ(expected_validity, frame1->context_validity); | |
463 if (expected_validity & StackFrameSH4::CONTEXT_VALID_R1) | |
464 EXPECT_EQ(expected.iregs[1], frame1->context.iregs[1]); | |
465 if (expected_validity & StackFrameSH4::CONTEXT_VALID_R4) | |
466 EXPECT_EQ(expected.iregs[4], frame1->context.iregs[4]); | |
467 if (expected_validity & StackFrameSH4::CONTEXT_VALID_R5) | |
468 EXPECT_EQ(expected.iregs[5], frame1->context.iregs[5]); | |
469 if (expected_validity & StackFrameSH4::CONTEXT_VALID_R6) | |
470 EXPECT_EQ(expected.iregs[6], frame1->context.iregs[6]); | |
471 if (expected_validity & StackFrameSH4::CONTEXT_VALID_R7) | |
472 EXPECT_EQ(expected.iregs[7], frame1->context.iregs[7]); | |
473 if (expected_validity & StackFrameSH4::CONTEXT_VALID_R8) | |
474 EXPECT_EQ(expected.iregs[8], frame1->context.iregs[8]); | |
475 if (expected_validity & StackFrameSH4::CONTEXT_VALID_R9) | |
476 EXPECT_EQ(expected.iregs[9], frame1->context.iregs[9]); | |
477 if (expected_validity & StackFrameSH4::CONTEXT_VALID_R10) | |
478 EXPECT_EQ(expected.iregs[10], frame1->context.iregs[10]); | |
479 | |
480 // We would never have gotten a frame in the first place if the SP | |
481 // and PC weren't valid or ->instruction weren't set. | |
482 EXPECT_EQ(expected.iregs[MD_CONTEXT_SH4_REG_SP], | |
483 frame1->context.iregs[MD_CONTEXT_SH4_REG_SP]); | |
484 EXPECT_EQ(expected.pr, | |
485 frame1->context.pr); | |
486 EXPECT_EQ("epictetus", frame1->function_name); | |
487 } | |
488 | |
489 // The values we expect to find for the caller's registers. | |
490 MDRawContextSH4 expected; | |
491 | |
492 // The validity mask for expected. | |
493 int expected_validity; | |
494 | |
495 // The validity mask to impose on the context frame. | |
496 int context_frame_validity; | |
497 }; | |
498 | |
499 class CFI: public CFIFixture, public Test { }; | |
500 | |
501 TEST_F(CFI, At4000) { | |
502 stack_section.start() = expected.iregs[MD_CONTEXT_SH4_REG_SP]; | |
503 raw_context.pc = 0x404000; | |
504 raw_context.pr = 0x405510; | |
505 CheckWalk(); | |
506 } | |
507 | |
508 TEST_F(CFI, At4001) { | |
509 Label frame1_sp = expected.iregs[MD_CONTEXT_SH4_REG_SP]; | |
510 stack_section | |
511 .D32(0xb5d55e68) // saved r8 | |
512 .D32(0x405510) // return address | |
513 .Mark(&frame1_sp); // This effectively sets stack_section.start(). | |
514 raw_context.pc = 0x404001; | |
515 raw_context.iregs[8] = 0x635adc9f; // distinct callee r8 | |
516 CheckWalk(); | |
517 } | |
518 | |
519 TEST_F(CFI, At4002) { | |
520 Label frame1_sp = expected.iregs[MD_CONTEXT_SH4_REG_SP]; | |
521 stack_section | |
522 .D32(0xfb81ff3d) // no longer saved r8 | |
523 .D32(0x405510) // return address | |
524 .Mark(&frame1_sp); // This effectively sets stack_section.start(). | |
525 raw_context.pc = 0x404002; | |
526 raw_context.pr = 0x405010; | |
527 raw_context.iregs[0] = 0xb5d55e68; // saved r8 | |
528 raw_context.iregs[1] = 0xebd134f3; // saved r9 | |
529 raw_context.iregs[2] = 0xa31e74bc; // saved r10 | |
530 raw_context.iregs[3] = 0x2dcb16b3; // saved r11 | |
531 raw_context.iregs[8] = 0xfdd35466; // distinct callee r8 | |
532 raw_context.iregs[9] = 0xf18c946c; // distinct callee r9 | |
533 raw_context.iregs[10] = 0xac2079e8; // distinct callee r10 | |
534 raw_context.iregs[11] = 0xa449829f; // distinct callee r11 | |
535 CheckWalk(); | |
536 } | |
537 | |
538 TEST_F(CFI, At4003) { | |
539 Label frame1_sp = expected.iregs[MD_CONTEXT_SH4_REG_SP]; | |
540 stack_section | |
541 .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves) | |
542 .D32(0xcb78040e) // no longer saved r8 | |
543 .D32(0x405510) // return address | |
544 .Mark(&frame1_sp); // This effectively sets stack_section.start(). | |
545 raw_context.pc = 0x404003; | |
546 raw_context.iregs[1] = 0xfb756319; // distinct callee r1 | |
547 expected.iregs[1] = 0x48c8dd5a; // caller's r1 | |
548 expected_validity |= StackFrameSH4::CONTEXT_VALID_R1; | |
549 CheckWalk(); | |
550 } | |
551 | |
552 // We have no new rule at module offset 0x4004, so the results here should | |
553 // be the same as those at module offset 0x4003. | |
554 TEST_F(CFI, At4004) { | |
555 Label frame1_sp = expected.iregs[MD_CONTEXT_SH4_REG_SP]; | |
556 stack_section | |
557 .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves) | |
558 .D32(0xcb78040e) // no longer saved r8 | |
559 .D32(0x405510) // return address | |
560 .Mark(&frame1_sp); // This effectively sets stack_section.start(). | |
561 raw_context.pc = 0x404004; | |
562 raw_context.iregs[1] = 0xfb756319; // distinct callee r1 | |
563 expected.iregs[1] = 0x48c8dd5a; // caller's r1 | |
564 expected_validity |= StackFrameSH4::CONTEXT_VALID_R1; | |
565 CheckWalk(); | |
566 } | |
567 | |
568 // Here we move the .cfa, but provide an explicit rule to recover the SP, | |
569 // so again there should be no change in the registers recovered. | |
570 TEST_F(CFI, At4005) { | |
571 Label frame1_sp = expected.iregs[MD_CONTEXT_SH4_REG_SP]; | |
572 stack_section | |
573 .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves) | |
574 .D32(0xf013f841) // no longer saved r8 | |
575 .D32(0x405510) // return address | |
576 .Mark(&frame1_sp); // This effectively sets stack_section.start(). | |
577 raw_context.pc = 0x404005; | |
578 raw_context.iregs[1] = 0xfb756319; // distinct callee r1 | |
579 expected.iregs[1] = 0x48c8dd5a; // caller's r1 | |
580 expected_validity |= StackFrameSH4::CONTEXT_VALID_R1; | |
581 CheckWalk(); | |
582 } | |
583 | |
584 // Here we provide an explicit rule for the PC, and have the saved .ra be | |
585 // bogus. | |
586 TEST_F(CFI, At4006) { | |
587 Label frame1_sp = expected.iregs[MD_CONTEXT_SH4_REG_SP]; | |
588 stack_section | |
589 .D32(0x405510) // saved pc | |
590 .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves) | |
591 .D32(0xf013f841) // no longer saved r8 | |
592 .D32(0xf8d15783) // .ra rule recovers this, which is garbage | |
593 .Mark(&frame1_sp); // This effectively sets stack_section.start(). | |
594 raw_context.pc = 0x404006; | |
595 raw_context.iregs[1] = 0xfb756319; // callee's r1, different from caller's | |
596 expected.iregs[1] = 0x48c8dd5a; // caller's r1 | |
597 expected_validity |= StackFrameSH4::CONTEXT_VALID_R1; | |
598 CheckWalk(); | |
599 } | |
600 | |
601 // Check that we reject rules that would cause the stack pointer to | |
602 // move in the wrong direction. | |
603 TEST_F(CFI, RejectBackwards) { | |
604 raw_context.pc = 0x406000; | |
605 raw_context.iregs[MD_CONTEXT_SH4_REG_SP] = 0x80000000; | |
606 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); | |
607 StackwalkerSH4 walker(&system_info, &raw_context, &stack_region, &modules, | |
608 &frame_symbolizer); | |
609 vector<const CodeModule*> modules_without_symbols; | |
610 vector<const CodeModule*> modules_with_corrupt_symbols; | |
611 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, | |
612 &modules_with_corrupt_symbols)); | |
613 ASSERT_EQ(0U, modules_without_symbols.size()); | |
614 ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); | |
615 frames = call_stack.frames(); | |
616 ASSERT_EQ(1U, frames->size()); | |
617 } | |
618 | |
619 // Check that we reject rules whose expressions' evaluation fails. | |
620 TEST_F(CFI, RejectBadExpressions) { | |
621 raw_context.pc = 0x407000; | |
622 raw_context.iregs[MD_CONTEXT_SH4_REG_SP] = 0x80000000; | |
623 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); | |
624 StackwalkerSH4 walker(&system_info, &raw_context, &stack_region, &modules, | |
625 &frame_symbolizer); | |
626 vector<const CodeModule*> modules_without_symbols; | |
627 vector<const CodeModule*> modules_with_corrupt_symbols; | |
628 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, | |
629 &modules_with_corrupt_symbols)); | |
630 ASSERT_EQ(0U, modules_without_symbols.size()); | |
631 ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); | |
632 frames = call_stack.frames(); | |
633 ASSERT_EQ(1U, frames->size()); | |
634 } | |
635 | |
636 | |
LEFT | RIGHT |