toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm_unittest.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2010, Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 31
michael@0 32 // stackwalker_arm_unittest.cc: Unit tests for StackwalkerARM class.
michael@0 33
michael@0 34 #include <string.h>
michael@0 35 #include <string>
michael@0 36 #include <vector>
michael@0 37
michael@0 38 #include "breakpad_googletest_includes.h"
michael@0 39 #include "common/test_assembler.h"
michael@0 40 #include "common/using_std_string.h"
michael@0 41 #include "google_breakpad/common/minidump_format.h"
michael@0 42 #include "google_breakpad/processor/basic_source_line_resolver.h"
michael@0 43 #include "google_breakpad/processor/call_stack.h"
michael@0 44 #include "google_breakpad/processor/code_module.h"
michael@0 45 #include "google_breakpad/processor/source_line_resolver_interface.h"
michael@0 46 #include "google_breakpad/processor/stack_frame_cpu.h"
michael@0 47 #include "processor/stackwalker_unittest_utils.h"
michael@0 48 #include "processor/stackwalker_arm.h"
michael@0 49 #include "processor/windows_frame_info.h"
michael@0 50
michael@0 51 using google_breakpad::BasicSourceLineResolver;
michael@0 52 using google_breakpad::CallStack;
michael@0 53 using google_breakpad::CodeModule;
michael@0 54 using google_breakpad::StackFrameSymbolizer;
michael@0 55 using google_breakpad::StackFrame;
michael@0 56 using google_breakpad::StackFrameARM;
michael@0 57 using google_breakpad::StackwalkerARM;
michael@0 58 using google_breakpad::SystemInfo;
michael@0 59 using google_breakpad::WindowsFrameInfo;
michael@0 60 using google_breakpad::test_assembler::kLittleEndian;
michael@0 61 using google_breakpad::test_assembler::Label;
michael@0 62 using google_breakpad::test_assembler::Section;
michael@0 63 using std::vector;
michael@0 64 using testing::_;
michael@0 65 using testing::Return;
michael@0 66 using testing::SetArgumentPointee;
michael@0 67 using testing::Test;
michael@0 68
michael@0 69 class StackwalkerARMFixture {
michael@0 70 public:
michael@0 71 StackwalkerARMFixture()
michael@0 72 : stack_section(kLittleEndian),
michael@0 73 // Give the two modules reasonable standard locations and names
michael@0 74 // for tests to play with.
michael@0 75 module1(0x40000000, 0x10000, "module1", "version1"),
michael@0 76 module2(0x50000000, 0x10000, "module2", "version2") {
michael@0 77 // Identify the system as a Linux system.
michael@0 78 system_info.os = "Linux";
michael@0 79 system_info.os_short = "linux";
michael@0 80 system_info.os_version = "Lugubrious Labrador";
michael@0 81 system_info.cpu = "arm";
michael@0 82 system_info.cpu_info = "";
michael@0 83
michael@0 84 // Put distinctive values in the raw CPU context.
michael@0 85 BrandContext(&raw_context);
michael@0 86
michael@0 87 // Create some modules with some stock debugging information.
michael@0 88 modules.Add(&module1);
michael@0 89 modules.Add(&module2);
michael@0 90
michael@0 91 // By default, none of the modules have symbol info; call
michael@0 92 // SetModuleSymbols to override this.
michael@0 93 EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
michael@0 94 .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
michael@0 95 }
michael@0 96
michael@0 97 // Set the Breakpad symbol information that supplier should return for
michael@0 98 // MODULE to INFO.
michael@0 99 void SetModuleSymbols(MockCodeModule *module, const string &info) {
michael@0 100 char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info);
michael@0 101 EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
michael@0 102 .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
michael@0 103 Return(MockSymbolSupplier::FOUND)));
michael@0 104 }
michael@0 105
michael@0 106 // Populate stack_region with the contents of stack_section. Use
michael@0 107 // stack_section.start() as the region's starting address.
michael@0 108 void RegionFromSection() {
michael@0 109 string contents;
michael@0 110 ASSERT_TRUE(stack_section.GetContents(&contents));
michael@0 111 stack_region.Init(stack_section.start().Value(), contents);
michael@0 112 }
michael@0 113
michael@0 114 // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking.
michael@0 115 void BrandContext(MDRawContextARM *raw_context) {
michael@0 116 uint8_t x = 173;
michael@0 117 for (size_t i = 0; i < sizeof(*raw_context); i++)
michael@0 118 reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17);
michael@0 119 }
michael@0 120
michael@0 121 SystemInfo system_info;
michael@0 122 MDRawContextARM raw_context;
michael@0 123 Section stack_section;
michael@0 124 MockMemoryRegion stack_region;
michael@0 125 MockCodeModule module1;
michael@0 126 MockCodeModule module2;
michael@0 127 MockCodeModules modules;
michael@0 128 MockSymbolSupplier supplier;
michael@0 129 BasicSourceLineResolver resolver;
michael@0 130 CallStack call_stack;
michael@0 131 const vector<StackFrame *> *frames;
michael@0 132 };
michael@0 133
michael@0 134 class SanityCheck: public StackwalkerARMFixture, public Test { };
michael@0 135
michael@0 136 TEST_F(SanityCheck, NoResolver) {
michael@0 137 // Since we have no call frame information, and all unwinding
michael@0 138 // requires call frame information, the stack walk will end after
michael@0 139 // the first frame.
michael@0 140 StackFrameSymbolizer frame_symbolizer(NULL, NULL);
michael@0 141 StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
michael@0 142 &frame_symbolizer);
michael@0 143 // This should succeed even without a resolver or supplier.
michael@0 144 vector<const CodeModule*> modules_without_symbols;
michael@0 145 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 146 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 147 frames = call_stack.frames();
michael@0 148 ASSERT_EQ(1U, frames->size());
michael@0 149 StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
michael@0 150 // Check that the values from the original raw context made it
michael@0 151 // through to the context in the stack frame.
michael@0 152 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
michael@0 153 }
michael@0 154
michael@0 155 class GetContextFrame: public StackwalkerARMFixture, public Test { };
michael@0 156
michael@0 157 TEST_F(GetContextFrame, Simple) {
michael@0 158 // Since we have no call frame information, and all unwinding
michael@0 159 // requires call frame information, the stack walk will end after
michael@0 160 // the first frame.
michael@0 161 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 162 StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
michael@0 163 &frame_symbolizer);
michael@0 164 vector<const CodeModule*> modules_without_symbols;
michael@0 165 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 166 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 167 frames = call_stack.frames();
michael@0 168 ASSERT_EQ(1U, frames->size());
michael@0 169 StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
michael@0 170 // Check that the values from the original raw context made it
michael@0 171 // through to the context in the stack frame.
michael@0 172 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
michael@0 173 }
michael@0 174
michael@0 175 // The stackwalker should be able to produce the context frame even
michael@0 176 // without stack memory present.
michael@0 177 TEST_F(GetContextFrame, NoStackMemory) {
michael@0 178 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 179 StackwalkerARM walker(&system_info, &raw_context, -1, NULL, &modules,
michael@0 180 &frame_symbolizer);
michael@0 181 vector<const CodeModule*> modules_without_symbols;
michael@0 182 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 183 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 184 frames = call_stack.frames();
michael@0 185 ASSERT_EQ(1U, frames->size());
michael@0 186 StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
michael@0 187 // Check that the values from the original raw context made it
michael@0 188 // through to the context in the stack frame.
michael@0 189 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
michael@0 190 }
michael@0 191
michael@0 192 class GetCallerFrame: public StackwalkerARMFixture, public Test { };
michael@0 193
michael@0 194 TEST_F(GetCallerFrame, ScanWithoutSymbols) {
michael@0 195 // When the stack walker resorts to scanning the stack,
michael@0 196 // only addresses located within loaded modules are
michael@0 197 // considered valid return addresses.
michael@0 198 // Force scanning through three frames to ensure that the
michael@0 199 // stack pointer is set properly in scan-recovered frames.
michael@0 200 stack_section.start() = 0x80000000;
michael@0 201 uint32_t return_address1 = 0x50000100;
michael@0 202 uint32_t return_address2 = 0x50000900;
michael@0 203 Label frame1_sp, frame2_sp;
michael@0 204 stack_section
michael@0 205 // frame 0
michael@0 206 .Append(16, 0) // space
michael@0 207
michael@0 208 .D32(0x40090000) // junk that's not
michael@0 209 .D32(0x60000000) // a return address
michael@0 210
michael@0 211 .D32(return_address1) // actual return address
michael@0 212 // frame 1
michael@0 213 .Mark(&frame1_sp)
michael@0 214 .Append(16, 0) // space
michael@0 215
michael@0 216 .D32(0xF0000000) // more junk
michael@0 217 .D32(0x0000000D)
michael@0 218
michael@0 219 .D32(return_address2) // actual return address
michael@0 220 // frame 2
michael@0 221 .Mark(&frame2_sp)
michael@0 222 .Append(32, 0); // end of stack
michael@0 223 RegionFromSection();
michael@0 224
michael@0 225 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510;
michael@0 226 raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value();
michael@0 227
michael@0 228 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 229 StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
michael@0 230 &frame_symbolizer);
michael@0 231 vector<const CodeModule*> modules_without_symbols;
michael@0 232 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 233 ASSERT_EQ(2U, modules_without_symbols.size());
michael@0 234 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 235 ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
michael@0 236 frames = call_stack.frames();
michael@0 237 ASSERT_EQ(3U, frames->size());
michael@0 238
michael@0 239 StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
michael@0 240 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 241 ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 242 EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
michael@0 243
michael@0 244 StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
michael@0 245 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
michael@0 246 ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
michael@0 247 StackFrameARM::CONTEXT_VALID_SP),
michael@0 248 frame1->context_validity);
michael@0 249 EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 250 EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 251
michael@0 252 StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2));
michael@0 253 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust);
michael@0 254 ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
michael@0 255 StackFrameARM::CONTEXT_VALID_SP),
michael@0 256 frame2->context_validity);
michael@0 257 EXPECT_EQ(return_address2, frame2->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 258 EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 259 }
michael@0 260
michael@0 261 TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
michael@0 262 // During stack scanning, if a potential return address
michael@0 263 // is located within a loaded module that has symbols,
michael@0 264 // it is only considered a valid return address if it
michael@0 265 // lies within a function's bounds.
michael@0 266 stack_section.start() = 0x80000000;
michael@0 267 uint32_t return_address = 0x50000200;
michael@0 268 Label frame1_sp;
michael@0 269
michael@0 270 stack_section
michael@0 271 // frame 0
michael@0 272 .Append(16, 0) // space
michael@0 273
michael@0 274 .D32(0x40090000) // junk that's not
michael@0 275 .D32(0x60000000) // a return address
michael@0 276
michael@0 277 .D32(0x40001000) // a couple of plausible addresses
michael@0 278 .D32(0x5000F000) // that are not within functions
michael@0 279
michael@0 280 .D32(return_address) // actual return address
michael@0 281 // frame 1
michael@0 282 .Mark(&frame1_sp)
michael@0 283 .Append(32, 0); // end of stack
michael@0 284 RegionFromSection();
michael@0 285
michael@0 286 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40000200;
michael@0 287 raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value();
michael@0 288
michael@0 289 SetModuleSymbols(&module1,
michael@0 290 // The youngest frame's function.
michael@0 291 "FUNC 100 400 10 monotreme\n");
michael@0 292 SetModuleSymbols(&module2,
michael@0 293 // The calling frame's function.
michael@0 294 "FUNC 100 400 10 marsupial\n");
michael@0 295
michael@0 296 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 297 StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
michael@0 298 &frame_symbolizer);
michael@0 299 vector<const CodeModule*> modules_without_symbols;
michael@0 300 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 301 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 302 frames = call_stack.frames();
michael@0 303 ASSERT_EQ(2U, frames->size());
michael@0 304
michael@0 305 StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
michael@0 306 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 307 ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 308 EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
michael@0 309 EXPECT_EQ("monotreme", frame0->function_name);
michael@0 310 EXPECT_EQ(0x40000100U, frame0->function_base);
michael@0 311
michael@0 312 StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
michael@0 313 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
michael@0 314 ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
michael@0 315 StackFrameARM::CONTEXT_VALID_SP),
michael@0 316 frame1->context_validity);
michael@0 317 EXPECT_EQ(return_address, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 318 EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 319 EXPECT_EQ("marsupial", frame1->function_name);
michael@0 320 EXPECT_EQ(0x50000100U, frame1->function_base);
michael@0 321 }
michael@0 322
michael@0 323 TEST_F(GetCallerFrame, ScanFirstFrame) {
michael@0 324 // If the stackwalker resorts to stack scanning, it will scan much
michael@0 325 // farther to find the caller of the context frame.
michael@0 326 stack_section.start() = 0x80000000;
michael@0 327 uint32_t return_address1 = 0x50000100;
michael@0 328 uint32_t return_address2 = 0x50000900;
michael@0 329 Label frame1_sp, frame2_sp;
michael@0 330 stack_section
michael@0 331 // frame 0
michael@0 332 .Append(32, 0) // space
michael@0 333
michael@0 334 .D32(0x40090000) // junk that's not
michael@0 335 .D32(0x60000000) // a return address
michael@0 336
michael@0 337 .Append(96, 0) // more space
michael@0 338
michael@0 339 .D32(return_address1) // actual return address
michael@0 340 // frame 1
michael@0 341 .Mark(&frame1_sp)
michael@0 342 .Append(32, 0) // space
michael@0 343
michael@0 344 .D32(0xF0000000) // more junk
michael@0 345 .D32(0x0000000D)
michael@0 346
michael@0 347 .Append(96, 0) // more space
michael@0 348
michael@0 349 .D32(return_address2) // actual return address
michael@0 350 // (won't be found)
michael@0 351 // frame 2
michael@0 352 .Mark(&frame2_sp)
michael@0 353 .Append(32, 0); // end of stack
michael@0 354 RegionFromSection();
michael@0 355
michael@0 356 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510;
michael@0 357 raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value();
michael@0 358
michael@0 359 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 360 StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
michael@0 361 &frame_symbolizer);
michael@0 362 vector<const CodeModule*> modules_without_symbols;
michael@0 363 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 364 ASSERT_EQ(2U, modules_without_symbols.size());
michael@0 365 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 366 ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
michael@0 367 frames = call_stack.frames();
michael@0 368 ASSERT_EQ(2U, frames->size());
michael@0 369
michael@0 370 StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
michael@0 371 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 372 ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 373 EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
michael@0 374
michael@0 375 StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
michael@0 376 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
michael@0 377 ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
michael@0 378 StackFrameARM::CONTEXT_VALID_SP),
michael@0 379 frame1->context_validity);
michael@0 380 EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 381 EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 382 }
michael@0 383
michael@0 384 struct CFIFixture: public StackwalkerARMFixture {
michael@0 385 CFIFixture() {
michael@0 386 // Provide a bunch of STACK CFI records; we'll walk to the caller
michael@0 387 // from every point in this series, expecting to find the same set
michael@0 388 // of register values.
michael@0 389 SetModuleSymbols(&module1,
michael@0 390 // The youngest frame's function.
michael@0 391 "FUNC 4000 1000 10 enchiridion\n"
michael@0 392 // Initially, nothing has been pushed on the stack,
michael@0 393 // and the return address is still in the link register.
michael@0 394 "STACK CFI INIT 4000 100 .cfa: sp .ra: lr\n"
michael@0 395 // Push r4, the frame pointer, and the link register.
michael@0 396 "STACK CFI 4001 .cfa: sp 12 + r4: .cfa 12 - ^"
michael@0 397 " r11: .cfa 8 - ^ .ra: .cfa 4 - ^\n"
michael@0 398 // Save r4..r7 in r0..r3: verify that we populate
michael@0 399 // the youngest frame with all the values we have.
michael@0 400 "STACK CFI 4002 r4: r0 r5: r1 r6: r2 r7: r3\n"
michael@0 401 // Restore r4..r7. Save the non-callee-saves register r1.
michael@0 402 "STACK CFI 4003 .cfa: sp 16 + r1: .cfa 16 - ^"
michael@0 403 " r4: r4 r5: r5 r6: r6 r7: r7\n"
michael@0 404 // Move the .cfa back four bytes, to point at the return
michael@0 405 // address, and restore the sp explicitly.
michael@0 406 "STACK CFI 4005 .cfa: sp 12 + r1: .cfa 12 - ^"
michael@0 407 " r11: .cfa 4 - ^ .ra: .cfa ^ sp: .cfa 4 +\n"
michael@0 408 // Recover the PC explicitly from a new stack slot;
michael@0 409 // provide garbage for the .ra.
michael@0 410 "STACK CFI 4006 .cfa: sp 16 + pc: .cfa 16 - ^\n"
michael@0 411
michael@0 412 // The calling function.
michael@0 413 "FUNC 5000 1000 10 epictetus\n"
michael@0 414 // Mark it as end of stack.
michael@0 415 "STACK CFI INIT 5000 1000 .cfa: 0 .ra: 0\n"
michael@0 416
michael@0 417 // A function whose CFI makes the stack pointer
michael@0 418 // go backwards.
michael@0 419 "FUNC 6000 1000 20 palinal\n"
michael@0 420 "STACK CFI INIT 6000 1000 .cfa: sp 4 - .ra: lr\n"
michael@0 421
michael@0 422 // A function with CFI expressions that can't be
michael@0 423 // evaluated.
michael@0 424 "FUNC 7000 1000 20 rhetorical\n"
michael@0 425 "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n");
michael@0 426
michael@0 427 // Provide some distinctive values for the caller's registers.
michael@0 428 expected.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510;
michael@0 429 expected.iregs[MD_CONTEXT_ARM_REG_SP] = 0x80000000;
michael@0 430 expected.iregs[4] = 0xb5d55e68;
michael@0 431 expected.iregs[5] = 0xebd134f3;
michael@0 432 expected.iregs[6] = 0xa31e74bc;
michael@0 433 expected.iregs[7] = 0x2dcb16b3;
michael@0 434 expected.iregs[8] = 0x2ada2137;
michael@0 435 expected.iregs[9] = 0xbbbb557d;
michael@0 436 expected.iregs[10] = 0x48bf8ca7;
michael@0 437 expected.iregs[MD_CONTEXT_ARM_REG_FP] = 0x8112e110;
michael@0 438
michael@0 439 // Expect CFI to recover all callee-saves registers. Since CFI is the
michael@0 440 // only stack frame construction technique we have, aside from the
michael@0 441 // context frame itself, there's no way for us to have a set of valid
michael@0 442 // registers smaller than this.
michael@0 443 expected_validity = (StackFrameARM::CONTEXT_VALID_PC |
michael@0 444 StackFrameARM::CONTEXT_VALID_SP |
michael@0 445 StackFrameARM::CONTEXT_VALID_R4 |
michael@0 446 StackFrameARM::CONTEXT_VALID_R5 |
michael@0 447 StackFrameARM::CONTEXT_VALID_R6 |
michael@0 448 StackFrameARM::CONTEXT_VALID_R7 |
michael@0 449 StackFrameARM::CONTEXT_VALID_R8 |
michael@0 450 StackFrameARM::CONTEXT_VALID_R9 |
michael@0 451 StackFrameARM::CONTEXT_VALID_R10 |
michael@0 452 StackFrameARM::CONTEXT_VALID_FP);
michael@0 453
michael@0 454 // By default, context frames provide all registers, as normal.
michael@0 455 context_frame_validity = StackFrameARM::CONTEXT_VALID_ALL;
michael@0 456
michael@0 457 // By default, registers are unchanged.
michael@0 458 raw_context = expected;
michael@0 459 }
michael@0 460
michael@0 461 // Walk the stack, using stack_section as the contents of the stack
michael@0 462 // and raw_context as the current register values. (Set the stack
michael@0 463 // pointer to the stack's starting address.) Expect two stack
michael@0 464 // frames; in the older frame, expect the callee-saves registers to
michael@0 465 // have values matching those in 'expected'.
michael@0 466 void CheckWalk() {
michael@0 467 RegionFromSection();
michael@0 468 raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value();
michael@0 469
michael@0 470 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 471 StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region,
michael@0 472 &modules, &frame_symbolizer);
michael@0 473 walker.SetContextFrameValidity(context_frame_validity);
michael@0 474 vector<const CodeModule*> modules_without_symbols;
michael@0 475 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 476 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 477 frames = call_stack.frames();
michael@0 478 ASSERT_EQ(2U, frames->size());
michael@0 479
michael@0 480 StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
michael@0 481 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 482 ASSERT_EQ(context_frame_validity, frame0->context_validity);
michael@0 483 EXPECT_EQ("enchiridion", frame0->function_name);
michael@0 484 EXPECT_EQ(0x40004000U, frame0->function_base);
michael@0 485
michael@0 486 StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
michael@0 487 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
michael@0 488 ASSERT_EQ(expected_validity, frame1->context_validity);
michael@0 489 if (expected_validity & StackFrameARM::CONTEXT_VALID_R1)
michael@0 490 EXPECT_EQ(expected.iregs[1], frame1->context.iregs[1]);
michael@0 491 if (expected_validity & StackFrameARM::CONTEXT_VALID_R4)
michael@0 492 EXPECT_EQ(expected.iregs[4], frame1->context.iregs[4]);
michael@0 493 if (expected_validity & StackFrameARM::CONTEXT_VALID_R5)
michael@0 494 EXPECT_EQ(expected.iregs[5], frame1->context.iregs[5]);
michael@0 495 if (expected_validity & StackFrameARM::CONTEXT_VALID_R6)
michael@0 496 EXPECT_EQ(expected.iregs[6], frame1->context.iregs[6]);
michael@0 497 if (expected_validity & StackFrameARM::CONTEXT_VALID_R7)
michael@0 498 EXPECT_EQ(expected.iregs[7], frame1->context.iregs[7]);
michael@0 499 if (expected_validity & StackFrameARM::CONTEXT_VALID_R8)
michael@0 500 EXPECT_EQ(expected.iregs[8], frame1->context.iregs[8]);
michael@0 501 if (expected_validity & StackFrameARM::CONTEXT_VALID_R9)
michael@0 502 EXPECT_EQ(expected.iregs[9], frame1->context.iregs[9]);
michael@0 503 if (expected_validity & StackFrameARM::CONTEXT_VALID_R10)
michael@0 504 EXPECT_EQ(expected.iregs[10], frame1->context.iregs[10]);
michael@0 505 if (expected_validity & StackFrameARM::CONTEXT_VALID_FP)
michael@0 506 EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM_REG_FP],
michael@0 507 frame1->context.iregs[MD_CONTEXT_ARM_REG_FP]);
michael@0 508
michael@0 509 // We would never have gotten a frame in the first place if the SP
michael@0 510 // and PC weren't valid or ->instruction weren't set.
michael@0 511 EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM_REG_SP],
michael@0 512 frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 513 EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM_REG_PC],
michael@0 514 frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 515 EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM_REG_PC],
michael@0 516 frame1->instruction + 2);
michael@0 517 EXPECT_EQ("epictetus", frame1->function_name);
michael@0 518 }
michael@0 519
michael@0 520 // The values we expect to find for the caller's registers.
michael@0 521 MDRawContextARM expected;
michael@0 522
michael@0 523 // The validity mask for expected.
michael@0 524 int expected_validity;
michael@0 525
michael@0 526 // The validity mask to impose on the context frame.
michael@0 527 int context_frame_validity;
michael@0 528 };
michael@0 529
michael@0 530 class CFI: public CFIFixture, public Test { };
michael@0 531
michael@0 532 TEST_F(CFI, At4000) {
michael@0 533 stack_section.start() = expected.iregs[MD_CONTEXT_ARM_REG_SP];
michael@0 534 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004000;
michael@0 535 raw_context.iregs[MD_CONTEXT_ARM_REG_LR] = 0x40005510;
michael@0 536 CheckWalk();
michael@0 537 }
michael@0 538
michael@0 539 TEST_F(CFI, At4001) {
michael@0 540 Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP];
michael@0 541 stack_section
michael@0 542 .D32(0xb5d55e68) // saved r4
michael@0 543 .D32(0x8112e110) // saved fp
michael@0 544 .D32(0x40005510) // return address
michael@0 545 .Mark(&frame1_sp); // This effectively sets stack_section.start().
michael@0 546 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004001;
michael@0 547 raw_context.iregs[4] = 0x635adc9f; // distinct callee r4
michael@0 548 raw_context.iregs[MD_CONTEXT_ARM_REG_FP] = 0xbe145fc4; // distinct callee fp
michael@0 549 CheckWalk();
michael@0 550 }
michael@0 551
michael@0 552 // As above, but unwind from a context that has only the PC and SP.
michael@0 553 TEST_F(CFI, At4001LimitedValidity) {
michael@0 554 context_frame_validity =
michael@0 555 StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_SP;
michael@0 556 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004001;
michael@0 557 raw_context.iregs[MD_CONTEXT_ARM_REG_FP] = 0xbe145fc4; // distinct callee fp
michael@0 558 Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP];
michael@0 559 stack_section
michael@0 560 .D32(0xb5d55e68) // saved r4
michael@0 561 .D32(0x8112e110) // saved fp
michael@0 562 .D32(0x40005510) // return address
michael@0 563 .Mark(&frame1_sp); // This effectively sets stack_section.start().
michael@0 564 expected_validity = (StackFrameARM::CONTEXT_VALID_PC
michael@0 565 | StackFrameARM::CONTEXT_VALID_SP
michael@0 566 | StackFrameARM::CONTEXT_VALID_FP
michael@0 567 | StackFrameARM::CONTEXT_VALID_R4);
michael@0 568 CheckWalk();
michael@0 569 }
michael@0 570
michael@0 571 TEST_F(CFI, At4002) {
michael@0 572 Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP];
michael@0 573 stack_section
michael@0 574 .D32(0xfb81ff3d) // no longer saved r4
michael@0 575 .D32(0x8112e110) // saved fp
michael@0 576 .D32(0x40005510) // return address
michael@0 577 .Mark(&frame1_sp); // This effectively sets stack_section.start().
michael@0 578 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004002;
michael@0 579 raw_context.iregs[0] = 0xb5d55e68; // saved r4
michael@0 580 raw_context.iregs[1] = 0xebd134f3; // saved r5
michael@0 581 raw_context.iregs[2] = 0xa31e74bc; // saved r6
michael@0 582 raw_context.iregs[3] = 0x2dcb16b3; // saved r7
michael@0 583 raw_context.iregs[4] = 0xfdd35466; // distinct callee r4
michael@0 584 raw_context.iregs[5] = 0xf18c946c; // distinct callee r5
michael@0 585 raw_context.iregs[6] = 0xac2079e8; // distinct callee r6
michael@0 586 raw_context.iregs[7] = 0xa449829f; // distinct callee r7
michael@0 587 raw_context.iregs[MD_CONTEXT_ARM_REG_FP] = 0xbe145fc4; // distinct callee fp
michael@0 588 CheckWalk();
michael@0 589 }
michael@0 590
michael@0 591 TEST_F(CFI, At4003) {
michael@0 592 Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP];
michael@0 593 stack_section
michael@0 594 .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves)
michael@0 595 .D32(0xcb78040e) // no longer saved r4
michael@0 596 .D32(0x8112e110) // saved fp
michael@0 597 .D32(0x40005510) // return address
michael@0 598 .Mark(&frame1_sp); // This effectively sets stack_section.start().
michael@0 599 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004003;
michael@0 600 raw_context.iregs[1] = 0xfb756319; // distinct callee r1
michael@0 601 raw_context.iregs[MD_CONTEXT_ARM_REG_FP] = 0x0a2857ea; // distinct callee fp
michael@0 602 expected.iregs[1] = 0x48c8dd5a; // caller's r1
michael@0 603 expected_validity |= StackFrameARM::CONTEXT_VALID_R1;
michael@0 604 CheckWalk();
michael@0 605 }
michael@0 606
michael@0 607 // We have no new rule at module offset 0x4004, so the results here should
michael@0 608 // be the same as those at module offset 0x4003.
michael@0 609 TEST_F(CFI, At4004) {
michael@0 610 Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP];
michael@0 611 stack_section
michael@0 612 .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves)
michael@0 613 .D32(0xcb78040e) // no longer saved r4
michael@0 614 .D32(0x8112e110) // saved fp
michael@0 615 .D32(0x40005510) // return address
michael@0 616 .Mark(&frame1_sp); // This effectively sets stack_section.start().
michael@0 617 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004004;
michael@0 618 raw_context.iregs[1] = 0xfb756319; // distinct callee r1
michael@0 619 expected.iregs[1] = 0x48c8dd5a; // caller's r1
michael@0 620 expected_validity |= StackFrameARM::CONTEXT_VALID_R1;
michael@0 621 CheckWalk();
michael@0 622 }
michael@0 623
michael@0 624 // Here we move the .cfa, but provide an explicit rule to recover the SP,
michael@0 625 // so again there should be no change in the registers recovered.
michael@0 626 TEST_F(CFI, At4005) {
michael@0 627 Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP];
michael@0 628 stack_section
michael@0 629 .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves)
michael@0 630 .D32(0xf013f841) // no longer saved r4
michael@0 631 .D32(0x8112e110) // saved fp
michael@0 632 .D32(0x40005510) // return address
michael@0 633 .Mark(&frame1_sp); // This effectively sets stack_section.start().
michael@0 634 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004005;
michael@0 635 raw_context.iregs[1] = 0xfb756319; // distinct callee r1
michael@0 636 expected.iregs[1] = 0x48c8dd5a; // caller's r1
michael@0 637 expected_validity |= StackFrameARM::CONTEXT_VALID_R1;
michael@0 638 CheckWalk();
michael@0 639 }
michael@0 640
michael@0 641 // Here we provide an explicit rule for the PC, and have the saved .ra be
michael@0 642 // bogus.
michael@0 643 TEST_F(CFI, At4006) {
michael@0 644 Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP];
michael@0 645 stack_section
michael@0 646 .D32(0x40005510) // saved pc
michael@0 647 .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves)
michael@0 648 .D32(0xf013f841) // no longer saved r4
michael@0 649 .D32(0x8112e110) // saved fp
michael@0 650 .D32(0xf8d15783) // .ra rule recovers this, which is garbage
michael@0 651 .Mark(&frame1_sp); // This effectively sets stack_section.start().
michael@0 652 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004006;
michael@0 653 raw_context.iregs[1] = 0xfb756319; // callee's r1, different from caller's
michael@0 654 expected.iregs[1] = 0x48c8dd5a; // caller's r1
michael@0 655 expected_validity |= StackFrameARM::CONTEXT_VALID_R1;
michael@0 656 CheckWalk();
michael@0 657 }
michael@0 658
michael@0 659 // Check that we reject rules that would cause the stack pointer to
michael@0 660 // move in the wrong direction.
michael@0 661 TEST_F(CFI, RejectBackwards) {
michael@0 662 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40006000;
michael@0 663 raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = 0x80000000;
michael@0 664 raw_context.iregs[MD_CONTEXT_ARM_REG_LR] = 0x40005510;
michael@0 665 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 666 StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
michael@0 667 &frame_symbolizer);
michael@0 668 vector<const CodeModule*> modules_without_symbols;
michael@0 669 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 670 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 671 frames = call_stack.frames();
michael@0 672 ASSERT_EQ(1U, frames->size());
michael@0 673 }
michael@0 674
michael@0 675 // Check that we reject rules whose expressions' evaluation fails.
michael@0 676 TEST_F(CFI, RejectBadExpressions) {
michael@0 677 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40007000;
michael@0 678 raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = 0x80000000;
michael@0 679 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 680 StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
michael@0 681 &frame_symbolizer);
michael@0 682 vector<const CodeModule*> modules_without_symbols;
michael@0 683 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 684 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 685 frames = call_stack.frames();
michael@0 686 ASSERT_EQ(1U, frames->size());
michael@0 687 }
michael@0 688
michael@0 689 class StackwalkerARMFixtureIOS : public StackwalkerARMFixture {
michael@0 690 public:
michael@0 691 StackwalkerARMFixtureIOS() {
michael@0 692 system_info.os = "iOS";
michael@0 693 system_info.os_short = "ios";
michael@0 694 }
michael@0 695 };
michael@0 696
michael@0 697 class GetFramesByFramePointer: public StackwalkerARMFixtureIOS, public Test { };
michael@0 698
michael@0 699 TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
michael@0 700 stack_section.start() = 0x80000000;
michael@0 701 uint32_t return_address1 = 0x50000100;
michael@0 702 uint32_t return_address2 = 0x50000900;
michael@0 703 Label frame1_sp, frame2_sp;
michael@0 704 Label frame1_fp, frame2_fp;
michael@0 705 stack_section
michael@0 706 // frame 0
michael@0 707 .Append(32, 0) // Whatever values on the stack.
michael@0 708 .D32(0x0000000D) // junk that's not
michael@0 709 .D32(0xF0000000) // a return address.
michael@0 710
michael@0 711 .Mark(&frame1_fp) // Next fp will point to the next value.
michael@0 712 .D32(frame2_fp) // Save current frame pointer.
michael@0 713 .D32(return_address2) // Save current link register.
michael@0 714 .Mark(&frame1_sp)
michael@0 715
michael@0 716 // frame 1
michael@0 717 .Append(32, 0) // Whatever values on the stack.
michael@0 718 .D32(0x0000000D) // junk that's not
michael@0 719 .D32(0xF0000000) // a return address.
michael@0 720
michael@0 721 .Mark(&frame2_fp)
michael@0 722 .D32(0)
michael@0 723 .D32(0)
michael@0 724 .Mark(&frame2_sp)
michael@0 725
michael@0 726 // frame 2
michael@0 727 .Append(32, 0) // Whatever values on the stack.
michael@0 728 .D32(0x0000000D) // junk that's not
michael@0 729 .D32(0xF0000000); // a return address.
michael@0 730 RegionFromSection();
michael@0 731
michael@0 732
michael@0 733 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510;
michael@0 734 raw_context.iregs[MD_CONTEXT_ARM_REG_LR] = return_address1;
michael@0 735 raw_context.iregs[MD_CONTEXT_ARM_REG_IOS_FP] = frame1_fp.Value();
michael@0 736 raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value();
michael@0 737
michael@0 738 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 739 StackwalkerARM walker(&system_info, &raw_context, MD_CONTEXT_ARM_REG_IOS_FP,
michael@0 740 &stack_region, &modules, &frame_symbolizer);
michael@0 741
michael@0 742 vector<const CodeModule*> modules_without_symbols;
michael@0 743 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 744 ASSERT_EQ(2U, modules_without_symbols.size());
michael@0 745 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 746 ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
michael@0 747 frames = call_stack.frames();
michael@0 748 ASSERT_EQ(3U, frames->size());
michael@0 749
michael@0 750 StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
michael@0 751 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 752 ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 753 EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
michael@0 754
michael@0 755 StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
michael@0 756 EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
michael@0 757 ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
michael@0 758 StackFrameARM::CONTEXT_VALID_LR |
michael@0 759 StackFrameARM::RegisterValidFlag(MD_CONTEXT_ARM_REG_IOS_FP) |
michael@0 760 StackFrameARM::CONTEXT_VALID_SP),
michael@0 761 frame1->context_validity);
michael@0 762 EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 763 EXPECT_EQ(return_address2, frame1->context.iregs[MD_CONTEXT_ARM_REG_LR]);
michael@0 764 EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 765 EXPECT_EQ(frame2_fp.Value(),
michael@0 766 frame1->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]);
michael@0 767
michael@0 768 StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2));
michael@0 769 EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust);
michael@0 770 ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
michael@0 771 StackFrameARM::CONTEXT_VALID_LR |
michael@0 772 StackFrameARM::RegisterValidFlag(MD_CONTEXT_ARM_REG_IOS_FP) |
michael@0 773 StackFrameARM::CONTEXT_VALID_SP),
michael@0 774 frame2->context_validity);
michael@0 775 EXPECT_EQ(return_address2, frame2->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 776 EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM_REG_LR]);
michael@0 777 EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 778 EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]);
michael@0 779 }
michael@0 780
michael@0 781 TEST_F(GetFramesByFramePointer, FramePointerAndCFI) {
michael@0 782 // Provide the standatd STACK CFI records that is obtained when exmining an
michael@0 783 // executable produced by XCode.
michael@0 784 SetModuleSymbols(&module1,
michael@0 785 // Adding a function in CFI.
michael@0 786 "FUNC 4000 1000 10 enchiridion\n"
michael@0 787
michael@0 788 "STACK CFI INIT 4000 100 .cfa: sp 0 + .ra: lr\n"
michael@0 789 "STACK CFI 4001 .cfa: sp 8 + .ra: .cfa -4 + ^"
michael@0 790 " r7: .cfa -8 + ^\n"
michael@0 791 "STACK CFI 4002 .cfa: r7 8 +\n"
michael@0 792 );
michael@0 793
michael@0 794 stack_section.start() = 0x80000000;
michael@0 795 uint32_t return_address1 = 0x40004010;
michael@0 796 uint32_t return_address2 = 0x50000900;
michael@0 797 Label frame1_sp, frame2_sp;
michael@0 798 Label frame1_fp, frame2_fp;
michael@0 799 stack_section
michael@0 800 // frame 0
michael@0 801 .Append(32, 0) // Whatever values on the stack.
michael@0 802 .D32(0x0000000D) // junk that's not
michael@0 803 .D32(0xF0000000) // a return address.
michael@0 804
michael@0 805 .Mark(&frame1_fp) // Next fp will point to the next value.
michael@0 806 .D32(frame2_fp) // Save current frame pointer.
michael@0 807 .D32(return_address2) // Save current link register.
michael@0 808 .Mark(&frame1_sp)
michael@0 809
michael@0 810 // frame 1
michael@0 811 .Append(32, 0) // Whatever values on the stack.
michael@0 812 .D32(0x0000000D) // junk that's not
michael@0 813 .D32(0xF0000000) // a return address.
michael@0 814
michael@0 815 .Mark(&frame2_fp)
michael@0 816 .D32(0)
michael@0 817 .D32(0)
michael@0 818 .Mark(&frame2_sp)
michael@0 819
michael@0 820 // frame 2
michael@0 821 .Append(32, 0) // Whatever values on the stack.
michael@0 822 .D32(0x0000000D) // junk that's not
michael@0 823 .D32(0xF0000000); // a return address.
michael@0 824 RegionFromSection();
michael@0 825
michael@0 826
michael@0 827 raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x50000400;
michael@0 828 raw_context.iregs[MD_CONTEXT_ARM_REG_LR] = return_address1;
michael@0 829 raw_context.iregs[MD_CONTEXT_ARM_REG_IOS_FP] = frame1_fp.Value();
michael@0 830 raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value();
michael@0 831
michael@0 832 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 833 StackwalkerARM walker(&system_info, &raw_context, MD_CONTEXT_ARM_REG_IOS_FP,
michael@0 834 &stack_region, &modules, &frame_symbolizer);
michael@0 835
michael@0 836 vector<const CodeModule*> modules_without_symbols;
michael@0 837 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 838 ASSERT_EQ(1U, modules_without_symbols.size());
michael@0 839 ASSERT_EQ("module2", modules_without_symbols[0]->debug_file());
michael@0 840 frames = call_stack.frames();
michael@0 841 ASSERT_EQ(3U, frames->size());
michael@0 842
michael@0 843 StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
michael@0 844 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 845 ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 846 EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
michael@0 847
michael@0 848 StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
michael@0 849 EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
michael@0 850 ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
michael@0 851 StackFrameARM::CONTEXT_VALID_LR |
michael@0 852 StackFrameARM::RegisterValidFlag(MD_CONTEXT_ARM_REG_IOS_FP) |
michael@0 853 StackFrameARM::CONTEXT_VALID_SP),
michael@0 854 frame1->context_validity);
michael@0 855 EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 856 EXPECT_EQ(return_address2, frame1->context.iregs[MD_CONTEXT_ARM_REG_LR]);
michael@0 857 EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 858 EXPECT_EQ(frame2_fp.Value(),
michael@0 859 frame1->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]);
michael@0 860 EXPECT_EQ("enchiridion", frame1->function_name);
michael@0 861 EXPECT_EQ(0x40004000U, frame1->function_base);
michael@0 862
michael@0 863
michael@0 864 StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2));
michael@0 865 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
michael@0 866 ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
michael@0 867 StackFrameARM::CONTEXT_VALID_LR |
michael@0 868 StackFrameARM::RegisterValidFlag(MD_CONTEXT_ARM_REG_IOS_FP) |
michael@0 869 StackFrameARM::CONTEXT_VALID_SP),
michael@0 870 frame2->context_validity);
michael@0 871 EXPECT_EQ(return_address2, frame2->context.iregs[MD_CONTEXT_ARM_REG_PC]);
michael@0 872 EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM_REG_LR]);
michael@0 873 EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_ARM_REG_SP]);
michael@0 874 EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]);
michael@0 875 }

mercurial