1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64_unittest.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,605 @@ 1.4 +// Copyright (c) 2010, Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> 1.34 + 1.35 +// stackwalker_amd64_unittest.cc: Unit tests for StackwalkerAMD64 class. 1.36 + 1.37 +#include <string.h> 1.38 +#include <string> 1.39 +#include <vector> 1.40 + 1.41 +#include "breakpad_googletest_includes.h" 1.42 +#include "common/test_assembler.h" 1.43 +#include "common/using_std_string.h" 1.44 +#include "google_breakpad/common/minidump_format.h" 1.45 +#include "google_breakpad/processor/basic_source_line_resolver.h" 1.46 +#include "google_breakpad/processor/call_stack.h" 1.47 +#include "google_breakpad/processor/code_module.h" 1.48 +#include "google_breakpad/processor/source_line_resolver_interface.h" 1.49 +#include "google_breakpad/processor/stack_frame_cpu.h" 1.50 +#include "processor/stackwalker_unittest_utils.h" 1.51 +#include "processor/stackwalker_amd64.h" 1.52 + 1.53 +using google_breakpad::BasicSourceLineResolver; 1.54 +using google_breakpad::CallStack; 1.55 +using google_breakpad::CodeModule; 1.56 +using google_breakpad::StackFrameSymbolizer; 1.57 +using google_breakpad::StackFrame; 1.58 +using google_breakpad::StackFrameAMD64; 1.59 +using google_breakpad::StackwalkerAMD64; 1.60 +using google_breakpad::SystemInfo; 1.61 +using google_breakpad::test_assembler::kLittleEndian; 1.62 +using google_breakpad::test_assembler::Label; 1.63 +using google_breakpad::test_assembler::Section; 1.64 +using std::vector; 1.65 +using testing::_; 1.66 +using testing::Return; 1.67 +using testing::SetArgumentPointee; 1.68 +using testing::Test; 1.69 + 1.70 +class StackwalkerAMD64Fixture { 1.71 + public: 1.72 + StackwalkerAMD64Fixture() 1.73 + : stack_section(kLittleEndian), 1.74 + // Give the two modules reasonable standard locations and names 1.75 + // for tests to play with. 1.76 + module1(0x40000000c0000000ULL, 0x10000, "module1", "version1"), 1.77 + module2(0x50000000b0000000ULL, 0x10000, "module2", "version2") { 1.78 + // Identify the system as a Linux system. 1.79 + system_info.os = "Linux"; 1.80 + system_info.os_short = "linux"; 1.81 + system_info.os_version = "Horrendous Hippo"; 1.82 + system_info.cpu = "x86"; 1.83 + system_info.cpu_info = ""; 1.84 + 1.85 + // Put distinctive values in the raw CPU context. 1.86 + BrandContext(&raw_context); 1.87 + 1.88 + // Create some modules with some stock debugging information. 1.89 + modules.Add(&module1); 1.90 + modules.Add(&module2); 1.91 + 1.92 + // By default, none of the modules have symbol info; call 1.93 + // SetModuleSymbols to override this. 1.94 + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _)) 1.95 + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); 1.96 + } 1.97 + 1.98 + // Set the Breakpad symbol information that supplier should return for 1.99 + // MODULE to INFO. 1.100 + void SetModuleSymbols(MockCodeModule *module, const string &info) { 1.101 + char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info); 1.102 + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _)) 1.103 + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), 1.104 + Return(MockSymbolSupplier::FOUND))); 1.105 + } 1.106 + 1.107 + // Populate stack_region with the contents of stack_section. Use 1.108 + // stack_section.start() as the region's starting address. 1.109 + void RegionFromSection() { 1.110 + string contents; 1.111 + ASSERT_TRUE(stack_section.GetContents(&contents)); 1.112 + stack_region.Init(stack_section.start().Value(), contents); 1.113 + } 1.114 + 1.115 + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. 1.116 + void BrandContext(MDRawContextAMD64 *raw_context) { 1.117 + uint8_t x = 173; 1.118 + for (size_t i = 0; i < sizeof(*raw_context); i++) 1.119 + reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17); 1.120 + } 1.121 + 1.122 + SystemInfo system_info; 1.123 + MDRawContextAMD64 raw_context; 1.124 + Section stack_section; 1.125 + MockMemoryRegion stack_region; 1.126 + MockCodeModule module1; 1.127 + MockCodeModule module2; 1.128 + MockCodeModules modules; 1.129 + MockSymbolSupplier supplier; 1.130 + BasicSourceLineResolver resolver; 1.131 + CallStack call_stack; 1.132 + const vector<StackFrame *> *frames; 1.133 +}; 1.134 + 1.135 +class GetContextFrame: public StackwalkerAMD64Fixture, public Test { }; 1.136 + 1.137 +class SanityCheck: public StackwalkerAMD64Fixture, public Test { }; 1.138 + 1.139 +TEST_F(SanityCheck, NoResolver) { 1.140 + // There should be no references to the stack in this walk: we don't 1.141 + // provide any call frame information, so trying to reconstruct the 1.142 + // context frame's caller should fail. So there's no need for us to 1.143 + // provide stack contents. 1.144 + raw_context.rip = 0x40000000c0000200ULL; 1.145 + raw_context.rbp = 0x8000000080000000ULL; 1.146 + 1.147 + StackFrameSymbolizer frame_symbolizer(NULL, NULL); 1.148 + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, 1.149 + &frame_symbolizer); 1.150 + // This should succeed even without a resolver or supplier. 1.151 + vector<const CodeModule*> modules_without_symbols; 1.152 + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); 1.153 + ASSERT_EQ(1U, modules_without_symbols.size()); 1.154 + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); 1.155 + frames = call_stack.frames(); 1.156 + ASSERT_GE(1U, frames->size()); 1.157 + StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0)); 1.158 + // Check that the values from the original raw context made it 1.159 + // through to the context in the stack frame. 1.160 + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); 1.161 +} 1.162 + 1.163 +TEST_F(GetContextFrame, Simple) { 1.164 + // There should be no references to the stack in this walk: we don't 1.165 + // provide any call frame information, so trying to reconstruct the 1.166 + // context frame's caller should fail. So there's no need for us to 1.167 + // provide stack contents. 1.168 + raw_context.rip = 0x40000000c0000200ULL; 1.169 + raw_context.rbp = 0x8000000080000000ULL; 1.170 + 1.171 + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); 1.172 + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, 1.173 + &frame_symbolizer); 1.174 + vector<const CodeModule*> modules_without_symbols; 1.175 + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); 1.176 + ASSERT_EQ(1U, modules_without_symbols.size()); 1.177 + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); 1.178 + frames = call_stack.frames(); 1.179 + ASSERT_GE(1U, frames->size()); 1.180 + StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0)); 1.181 + // Check that the values from the original raw context made it 1.182 + // through to the context in the stack frame. 1.183 + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); 1.184 +} 1.185 + 1.186 +// The stackwalker should be able to produce the context frame even 1.187 +// without stack memory present. 1.188 +TEST_F(GetContextFrame, NoStackMemory) { 1.189 + raw_context.rip = 0x40000000c0000200ULL; 1.190 + raw_context.rbp = 0x8000000080000000ULL; 1.191 + 1.192 + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); 1.193 + StackwalkerAMD64 walker(&system_info, &raw_context, NULL, &modules, 1.194 + &frame_symbolizer); 1.195 + vector<const CodeModule*> modules_without_symbols; 1.196 + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); 1.197 + ASSERT_EQ(1U, modules_without_symbols.size()); 1.198 + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); 1.199 + frames = call_stack.frames(); 1.200 + ASSERT_GE(1U, frames->size()); 1.201 + StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0)); 1.202 + // Check that the values from the original raw context made it 1.203 + // through to the context in the stack frame. 1.204 + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); 1.205 +} 1.206 + 1.207 +class GetCallerFrame: public StackwalkerAMD64Fixture, public Test { }; 1.208 + 1.209 +TEST_F(GetCallerFrame, ScanWithoutSymbols) { 1.210 + // When the stack walker resorts to scanning the stack, 1.211 + // only addresses located within loaded modules are 1.212 + // considered valid return addresses. 1.213 + // Force scanning through three frames to ensure that the 1.214 + // stack pointer is set properly in scan-recovered frames. 1.215 + stack_section.start() = 0x8000000080000000ULL; 1.216 + uint64_t return_address1 = 0x50000000b0000100ULL; 1.217 + uint64_t return_address2 = 0x50000000b0000900ULL; 1.218 + Label frame1_sp, frame2_sp, frame1_rbp; 1.219 + stack_section 1.220 + // frame 0 1.221 + .Append(16, 0) // space 1.222 + 1.223 + .D64(0x40000000b0000000ULL) // junk that's not 1.224 + .D64(0x50000000d0000000ULL) // a return address 1.225 + 1.226 + .D64(return_address1) // actual return address 1.227 + // frame 1 1.228 + .Mark(&frame1_sp) 1.229 + .Append(16, 0) // space 1.230 + 1.231 + .D64(0x40000000b0000000ULL) // more junk 1.232 + .D64(0x50000000d0000000ULL) 1.233 + 1.234 + .Mark(&frame1_rbp) 1.235 + .D64(stack_section.start()) // This is in the right place to be 1.236 + // a saved rbp, but it's bogus, so 1.237 + // we shouldn't report it. 1.238 + 1.239 + .D64(return_address2) // actual return address 1.240 + // frame 2 1.241 + .Mark(&frame2_sp) 1.242 + .Append(32, 0); // end of stack 1.243 + 1.244 + RegionFromSection(); 1.245 + 1.246 + raw_context.rip = 0x40000000c0000200ULL; 1.247 + raw_context.rbp = frame1_rbp.Value(); 1.248 + raw_context.rsp = stack_section.start().Value(); 1.249 + 1.250 + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); 1.251 + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, 1.252 + &frame_symbolizer); 1.253 + vector<const CodeModule*> modules_without_symbols; 1.254 + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); 1.255 + ASSERT_EQ(2U, modules_without_symbols.size()); 1.256 + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); 1.257 + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); 1.258 + frames = call_stack.frames(); 1.259 + ASSERT_EQ(3U, frames->size()); 1.260 + 1.261 + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); 1.262 + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); 1.263 + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); 1.264 + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); 1.265 + 1.266 + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); 1.267 + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); 1.268 + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | 1.269 + StackFrameAMD64::CONTEXT_VALID_RSP | 1.270 + StackFrameAMD64::CONTEXT_VALID_RBP), 1.271 + frame1->context_validity); 1.272 + EXPECT_EQ(return_address1, frame1->context.rip); 1.273 + EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); 1.274 + EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp); 1.275 + 1.276 + StackFrameAMD64 *frame2 = static_cast<StackFrameAMD64 *>(frames->at(2)); 1.277 + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); 1.278 + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | 1.279 + StackFrameAMD64::CONTEXT_VALID_RSP), 1.280 + frame2->context_validity); 1.281 + EXPECT_EQ(return_address2, frame2->context.rip); 1.282 + EXPECT_EQ(frame2_sp.Value(), frame2->context.rsp); 1.283 +} 1.284 + 1.285 +TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { 1.286 + // During stack scanning, if a potential return address 1.287 + // is located within a loaded module that has symbols, 1.288 + // it is only considered a valid return address if it 1.289 + // lies within a function's bounds. 1.290 + stack_section.start() = 0x8000000080000000ULL; 1.291 + uint64_t return_address = 0x50000000b0000110ULL; 1.292 + Label frame1_sp, frame1_rbp; 1.293 + 1.294 + stack_section 1.295 + // frame 0 1.296 + .Append(16, 0) // space 1.297 + 1.298 + .D64(0x40000000b0000000ULL) // junk that's not 1.299 + .D64(0x50000000b0000000ULL) // a return address 1.300 + 1.301 + .D64(0x40000000c0001000ULL) // a couple of plausible addresses 1.302 + .D64(0x50000000b000aaaaULL) // that are not within functions 1.303 + 1.304 + .D64(return_address) // actual return address 1.305 + // frame 1 1.306 + .Mark(&frame1_sp) 1.307 + .Append(32, 0) // end of stack 1.308 + .Mark(&frame1_rbp); 1.309 + RegionFromSection(); 1.310 + 1.311 + raw_context.rip = 0x40000000c0000200ULL; 1.312 + raw_context.rbp = frame1_rbp.Value(); 1.313 + raw_context.rsp = stack_section.start().Value(); 1.314 + 1.315 + SetModuleSymbols(&module1, 1.316 + // The youngest frame's function. 1.317 + "FUNC 100 400 10 platypus\n"); 1.318 + SetModuleSymbols(&module2, 1.319 + // The calling frame's function. 1.320 + "FUNC 100 400 10 echidna\n"); 1.321 + 1.322 + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); 1.323 + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, 1.324 + &frame_symbolizer); 1.325 + vector<const CodeModule*> modules_without_symbols; 1.326 + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); 1.327 + ASSERT_EQ(0U, modules_without_symbols.size()); 1.328 + frames = call_stack.frames(); 1.329 + ASSERT_EQ(2U, frames->size()); 1.330 + 1.331 + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); 1.332 + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); 1.333 + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); 1.334 + EXPECT_EQ("platypus", frame0->function_name); 1.335 + EXPECT_EQ(0x40000000c0000100ULL, frame0->function_base); 1.336 + 1.337 + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); 1.338 + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); 1.339 + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | 1.340 + StackFrameAMD64::CONTEXT_VALID_RSP | 1.341 + StackFrameAMD64::CONTEXT_VALID_RBP), 1.342 + frame1->context_validity); 1.343 + EXPECT_EQ(return_address, frame1->context.rip); 1.344 + EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); 1.345 + EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp); 1.346 + EXPECT_EQ("echidna", frame1->function_name); 1.347 + EXPECT_EQ(0x50000000b0000100ULL, frame1->function_base); 1.348 +} 1.349 + 1.350 +TEST_F(GetCallerFrame, CallerPushedRBP) { 1.351 + // Functions typically push their %rbp upon entry and set %rbp pointing 1.352 + // there. If stackwalking finds a plausible address for the next frame's 1.353 + // %rbp directly below the return address, assume that it is indeed the 1.354 + // next frame's %rbp. 1.355 + stack_section.start() = 0x8000000080000000ULL; 1.356 + uint64_t return_address = 0x50000000b0000110ULL; 1.357 + Label frame0_rbp, frame1_sp, frame1_rbp; 1.358 + 1.359 + stack_section 1.360 + // frame 0 1.361 + .Append(16, 0) // space 1.362 + 1.363 + .D64(0x40000000b0000000ULL) // junk that's not 1.364 + .D64(0x50000000b0000000ULL) // a return address 1.365 + 1.366 + .D64(0x40000000c0001000ULL) // a couple of plausible addresses 1.367 + .D64(0x50000000b000aaaaULL) // that are not within functions 1.368 + 1.369 + .Mark(&frame0_rbp) 1.370 + .D64(frame1_rbp) // caller-pushed %rbp 1.371 + .D64(return_address) // actual return address 1.372 + // frame 1 1.373 + .Mark(&frame1_sp) 1.374 + .Append(32, 0) // body of frame1 1.375 + .Mark(&frame1_rbp); // end of stack 1.376 + RegionFromSection(); 1.377 + 1.378 + raw_context.rip = 0x40000000c0000200ULL; 1.379 + raw_context.rbp = frame0_rbp.Value(); 1.380 + raw_context.rsp = stack_section.start().Value(); 1.381 + 1.382 + SetModuleSymbols(&module1, 1.383 + // The youngest frame's function. 1.384 + "FUNC 100 400 10 sasquatch\n"); 1.385 + SetModuleSymbols(&module2, 1.386 + // The calling frame's function. 1.387 + "FUNC 100 400 10 yeti\n"); 1.388 + 1.389 + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); 1.390 + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, 1.391 + &frame_symbolizer); 1.392 + vector<const CodeModule*> modules_without_symbols; 1.393 + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); 1.394 + ASSERT_EQ(0U, modules_without_symbols.size()); 1.395 + frames = call_stack.frames(); 1.396 + ASSERT_EQ(2U, frames->size()); 1.397 + 1.398 + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); 1.399 + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); 1.400 + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); 1.401 + EXPECT_EQ(frame0_rbp.Value(), frame0->context.rbp); 1.402 + EXPECT_EQ("sasquatch", frame0->function_name); 1.403 + EXPECT_EQ(0x40000000c0000100ULL, frame0->function_base); 1.404 + 1.405 + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); 1.406 + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); 1.407 + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | 1.408 + StackFrameAMD64::CONTEXT_VALID_RSP | 1.409 + StackFrameAMD64::CONTEXT_VALID_RBP), 1.410 + frame1->context_validity); 1.411 + EXPECT_EQ(return_address, frame1->context.rip); 1.412 + EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); 1.413 + EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp); 1.414 + EXPECT_EQ("yeti", frame1->function_name); 1.415 + EXPECT_EQ(0x50000000b0000100ULL, frame1->function_base); 1.416 +} 1.417 + 1.418 +struct CFIFixture: public StackwalkerAMD64Fixture { 1.419 + CFIFixture() { 1.420 + // Provide a bunch of STACK CFI records; we'll walk to the caller 1.421 + // from every point in this series, expecting to find the same set 1.422 + // of register values. 1.423 + SetModuleSymbols(&module1, 1.424 + // The youngest frame's function. 1.425 + "FUNC 4000 1000 10 enchiridion\n" 1.426 + // Initially, just a return address. 1.427 + "STACK CFI INIT 4000 100 .cfa: $rsp 8 + .ra: .cfa 8 - ^\n" 1.428 + // Push %rbx. 1.429 + "STACK CFI 4001 .cfa: $rsp 16 + $rbx: .cfa 16 - ^\n" 1.430 + // Save %r12 in %rbx. Weird, but permitted. 1.431 + "STACK CFI 4002 $r12: $rbx\n" 1.432 + // Allocate frame space, and save %r13. 1.433 + "STACK CFI 4003 .cfa: $rsp 40 + $r13: .cfa 32 - ^\n" 1.434 + // Put the return address in %r13. 1.435 + "STACK CFI 4005 .ra: $r13\n" 1.436 + // Save %rbp, and use it as a frame pointer. 1.437 + "STACK CFI 4006 .cfa: $rbp 16 + $rbp: .cfa 24 - ^\n" 1.438 + 1.439 + // The calling function. 1.440 + "FUNC 5000 1000 10 epictetus\n" 1.441 + // Mark it as end of stack. 1.442 + "STACK CFI INIT 5000 1000 .cfa: $rsp .ra 0\n"); 1.443 + 1.444 + // Provide some distinctive values for the caller's registers. 1.445 + expected.rsp = 0x8000000080000000ULL; 1.446 + expected.rip = 0x40000000c0005510ULL; 1.447 + expected.rbp = 0x68995b1de4700266ULL; 1.448 + expected.rbx = 0x5a5beeb38de23be8ULL; 1.449 + expected.r12 = 0xed1b02e8cc0fc79cULL; 1.450 + expected.r13 = 0x1d20ad8acacbe930ULL; 1.451 + expected.r14 = 0xe94cffc2f7adaa28ULL; 1.452 + expected.r15 = 0xb638d17d8da413b5ULL; 1.453 + 1.454 + // By default, registers are unchanged. 1.455 + raw_context = expected; 1.456 + } 1.457 + 1.458 + // Walk the stack, using stack_section as the contents of the stack 1.459 + // and raw_context as the current register values. (Set 1.460 + // raw_context.rsp to the stack's starting address.) Expect two 1.461 + // stack frames; in the older frame, expect the callee-saves 1.462 + // registers to have values matching those in 'expected'. 1.463 + void CheckWalk() { 1.464 + RegionFromSection(); 1.465 + raw_context.rsp = stack_section.start().Value(); 1.466 + 1.467 + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); 1.468 + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, 1.469 + &frame_symbolizer); 1.470 + vector<const CodeModule*> modules_without_symbols; 1.471 + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols)); 1.472 + ASSERT_EQ(0U, modules_without_symbols.size()); 1.473 + frames = call_stack.frames(); 1.474 + ASSERT_EQ(2U, frames->size()); 1.475 + 1.476 + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); 1.477 + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); 1.478 + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); 1.479 + EXPECT_EQ("enchiridion", frame0->function_name); 1.480 + EXPECT_EQ(0x40000000c0004000ULL, frame0->function_base); 1.481 + 1.482 + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); 1.483 + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); 1.484 + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | 1.485 + StackFrameAMD64::CONTEXT_VALID_RSP | 1.486 + StackFrameAMD64::CONTEXT_VALID_RBP | 1.487 + StackFrameAMD64::CONTEXT_VALID_RBX | 1.488 + StackFrameAMD64::CONTEXT_VALID_R12 | 1.489 + StackFrameAMD64::CONTEXT_VALID_R13 | 1.490 + StackFrameAMD64::CONTEXT_VALID_R14 | 1.491 + StackFrameAMD64::CONTEXT_VALID_R15), 1.492 + frame1->context_validity); 1.493 + EXPECT_EQ(expected.rip, frame1->context.rip); 1.494 + EXPECT_EQ(expected.rsp, frame1->context.rsp); 1.495 + EXPECT_EQ(expected.rbp, frame1->context.rbp); 1.496 + EXPECT_EQ(expected.rbx, frame1->context.rbx); 1.497 + EXPECT_EQ(expected.r12, frame1->context.r12); 1.498 + EXPECT_EQ(expected.r13, frame1->context.r13); 1.499 + EXPECT_EQ(expected.r14, frame1->context.r14); 1.500 + EXPECT_EQ(expected.r15, frame1->context.r15); 1.501 + EXPECT_EQ("epictetus", frame1->function_name); 1.502 + } 1.503 + 1.504 + // The values we expect to find for the caller's registers. 1.505 + MDRawContextAMD64 expected; 1.506 +}; 1.507 + 1.508 +class CFI: public CFIFixture, public Test { }; 1.509 + 1.510 +TEST_F(CFI, At4000) { 1.511 + Label frame1_rsp = expected.rsp; 1.512 + stack_section 1.513 + .D64(0x40000000c0005510ULL) // return address 1.514 + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). 1.515 + raw_context.rip = 0x40000000c0004000ULL; 1.516 + CheckWalk(); 1.517 +} 1.518 + 1.519 +TEST_F(CFI, At4001) { 1.520 + Label frame1_rsp = expected.rsp; 1.521 + stack_section 1.522 + .D64(0x5a5beeb38de23be8ULL) // saved %rbx 1.523 + .D64(0x40000000c0005510ULL) // return address 1.524 + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). 1.525 + raw_context.rip = 0x40000000c0004001ULL; 1.526 + raw_context.rbx = 0xbe0487d2f9eafe29ULL; // callee's (distinct) %rbx value 1.527 + CheckWalk(); 1.528 +} 1.529 + 1.530 +TEST_F(CFI, At4002) { 1.531 + Label frame1_rsp = expected.rsp; 1.532 + stack_section 1.533 + .D64(0x5a5beeb38de23be8ULL) // saved %rbx 1.534 + .D64(0x40000000c0005510ULL) // return address 1.535 + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). 1.536 + raw_context.rip = 0x40000000c0004002ULL; 1.537 + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 1.538 + raw_context.r12 = 0xb0118de918a4bceaULL; // callee's (distinct) %r12 value 1.539 + CheckWalk(); 1.540 +} 1.541 + 1.542 +TEST_F(CFI, At4003) { 1.543 + Label frame1_rsp = expected.rsp; 1.544 + stack_section 1.545 + .D64(0x0e023828dffd4d81ULL) // garbage 1.546 + .D64(0x1d20ad8acacbe930ULL) // saved %r13 1.547 + .D64(0x319e68b49e3ace0fULL) // garbage 1.548 + .D64(0x5a5beeb38de23be8ULL) // saved %rbx 1.549 + .D64(0x40000000c0005510ULL) // return address 1.550 + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). 1.551 + raw_context.rip = 0x40000000c0004003ULL; 1.552 + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 1.553 + raw_context.r12 = 0x89d04fa804c87a43ULL; // callee's (distinct) %r12 1.554 + raw_context.r13 = 0x5118e02cbdb24b03ULL; // callee's (distinct) %r13 1.555 + CheckWalk(); 1.556 +} 1.557 + 1.558 +// The results here should be the same as those at module offset 0x4003. 1.559 +TEST_F(CFI, At4004) { 1.560 + Label frame1_rsp = expected.rsp; 1.561 + stack_section 1.562 + .D64(0x0e023828dffd4d81ULL) // garbage 1.563 + .D64(0x1d20ad8acacbe930ULL) // saved %r13 1.564 + .D64(0x319e68b49e3ace0fULL) // garbage 1.565 + .D64(0x5a5beeb38de23be8ULL) // saved %rbx 1.566 + .D64(0x40000000c0005510ULL) // return address 1.567 + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). 1.568 + raw_context.rip = 0x40000000c0004004ULL; 1.569 + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 1.570 + raw_context.r12 = 0x89d04fa804c87a43ULL; // callee's (distinct) %r12 1.571 + raw_context.r13 = 0x5118e02cbdb24b03ULL; // callee's (distinct) %r13 1.572 + CheckWalk(); 1.573 +} 1.574 + 1.575 +TEST_F(CFI, At4005) { 1.576 + Label frame1_rsp = expected.rsp; 1.577 + stack_section 1.578 + .D64(0x4b516dd035745953ULL) // garbage 1.579 + .D64(0x1d20ad8acacbe930ULL) // saved %r13 1.580 + .D64(0xa6d445e16ae3d872ULL) // garbage 1.581 + .D64(0x5a5beeb38de23be8ULL) // saved %rbx 1.582 + .D64(0xaa95fa054aedfbaeULL) // garbage 1.583 + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). 1.584 + raw_context.rip = 0x40000000c0004005ULL; 1.585 + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 1.586 + raw_context.r12 = 0x46b1b8868891b34aULL; // callee's %r12 1.587 + raw_context.r13 = 0x40000000c0005510ULL; // return address 1.588 + CheckWalk(); 1.589 +} 1.590 + 1.591 +TEST_F(CFI, At4006) { 1.592 + Label frame0_rbp; 1.593 + Label frame1_rsp = expected.rsp; 1.594 + stack_section 1.595 + .D64(0x043c6dfceb91aa34ULL) // garbage 1.596 + .D64(0x1d20ad8acacbe930ULL) // saved %r13 1.597 + .D64(0x68995b1de4700266ULL) // saved %rbp 1.598 + .Mark(&frame0_rbp) // frame pointer points here 1.599 + .D64(0x5a5beeb38de23be8ULL) // saved %rbx 1.600 + .D64(0xf015ee516ad89eabULL) // garbage 1.601 + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). 1.602 + raw_context.rip = 0x40000000c0004006ULL; 1.603 + raw_context.rbp = frame0_rbp.Value(); 1.604 + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 1.605 + raw_context.r12 = 0x26e007b341acfebdULL; // callee's %r12 1.606 + raw_context.r13 = 0x40000000c0005510ULL; // return address 1.607 + CheckWalk(); 1.608 +}