1 // Copyright (c) 2010, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 // Original author: Jim Blandy <jimb (at) mozilla.com> <jimb (at) red-bean.com> 31 32 // cfi_frame_info_unittest.cc: Unit tests for CFIFrameInfo, 33 // CFIRuleParser, CFIFrameInfoParseHandler, and SimpleCFIWalker. 34 35 #include <string.h> 36 37 #include "breakpad_googletest_includes.h" 38 #include "common/using_std_string.h" 39 #include "processor/cfi_frame_info.h" 40 #include "google_breakpad/processor/memory_region.h" 41 42 using google_breakpad::CFIFrameInfo; 43 using google_breakpad::CFIFrameInfoParseHandler; 44 using google_breakpad::CFIRuleParser; 45 using google_breakpad::MemoryRegion; 46 using google_breakpad::SimpleCFIWalker; 47 using testing::_; 48 using testing::A; 49 using testing::AtMost; 50 using testing::DoAll; 51 using testing::Return; 52 using testing::SetArgumentPointee; 53 using testing::Test; 54 55 class MockMemoryRegion: public MemoryRegion { 56 public: 57 MOCK_CONST_METHOD0(GetBase, uint64_t()); 58 MOCK_CONST_METHOD0(GetSize, uint32_t()); 59 MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint8_t *)); 60 MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint16_t *)); 61 MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint32_t *)); 62 MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint64_t *)); 63 MOCK_CONST_METHOD0(Print, void()); 64 }; 65 66 // Handy definitions for all tests. 67 struct CFIFixture { 68 69 // Set up the mock memory object to expect no references. 70 void ExpectNoMemoryReferences() { 71 EXPECT_CALL(memory, GetBase()).Times(0); 72 EXPECT_CALL(memory, GetSize()).Times(0); 73 EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint8_t *>())).Times(0); 74 EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint16_t *>())).Times(0); 75 EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint32_t *>())).Times(0); 76 EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint64_t *>())).Times(0); 77 } 78 79 CFIFrameInfo cfi; 80 MockMemoryRegion memory; 81 CFIFrameInfo::RegisterValueMap<uint64_t> registers, caller_registers; 82 }; 83 84 class Simple: public CFIFixture, public Test { }; 85 86 // FindCallerRegs should fail if no .cfa rule is provided. 87 TEST_F(Simple, NoCFA) { 88 ExpectNoMemoryReferences(); 89 90 cfi.SetRARule("0"); 91 ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory, 92 &caller_registers)); 93 ASSERT_EQ(".ra: 0", cfi.Serialize()); 94 } 95 96 // FindCallerRegs should fail if no .ra rule is provided. 97 TEST_F(Simple, NoRA) { 98 ExpectNoMemoryReferences(); 99 100 cfi.SetCFARule("0"); 101 ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory, 102 &caller_registers)); 103 ASSERT_EQ(".cfa: 0", cfi.Serialize()); 104 } 105 106 TEST_F(Simple, SetCFAAndRARule) { 107 ExpectNoMemoryReferences(); 108 109 cfi.SetCFARule("330903416631436410"); 110 cfi.SetRARule("5870666104170902211"); 111 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 112 &caller_registers)); 113 ASSERT_EQ(2U, caller_registers.size()); 114 ASSERT_EQ(330903416631436410ULL, caller_registers[".cfa"]); 115 ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]); 116 117 ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211", 118 cfi.Serialize()); 119 } 120 121 TEST_F(Simple, SetManyRules) { 122 ExpectNoMemoryReferences(); 123 124 cfi.SetCFARule("$temp1 68737028 = $temp2 61072337 = $temp1 $temp2 -"); 125 cfi.SetRARule(".cfa 99804755 +"); 126 cfi.SetRegisterRule("register1", ".cfa 54370437 *"); 127 cfi.SetRegisterRule("vodkathumbscrewingly", "24076308 .cfa +"); 128 cfi.SetRegisterRule("pubvexingfjordschmaltzy", ".cfa 29801007 -"); 129 cfi.SetRegisterRule("uncopyrightables", "92642917 .cfa /"); 130 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 131 &caller_registers)); 132 ASSERT_EQ(6U, caller_registers.size()); 133 ASSERT_EQ(7664691U, caller_registers[".cfa"]); 134 ASSERT_EQ(107469446U, caller_registers[".ra"]); 135 ASSERT_EQ(416732599139967ULL, caller_registers["register1"]); 136 ASSERT_EQ(31740999U, caller_registers["vodkathumbscrewingly"]); 137 ASSERT_EQ(-22136316ULL, caller_registers["pubvexingfjordschmaltzy"]); 138 ASSERT_EQ(12U, caller_registers["uncopyrightables"]); 139 ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - " 140 ".ra: .cfa 99804755 + " 141 "pubvexingfjordschmaltzy: .cfa 29801007 - " 142 "register1: .cfa 54370437 * " 143 "uncopyrightables: 92642917 .cfa / " 144 "vodkathumbscrewingly: 24076308 .cfa +", 145 cfi.Serialize()); 146 } 147 148 TEST_F(Simple, RulesOverride) { 149 ExpectNoMemoryReferences(); 150 151 cfi.SetCFARule("330903416631436410"); 152 cfi.SetRARule("5870666104170902211"); 153 cfi.SetCFARule("2828089117179001"); 154 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 155 &caller_registers)); 156 ASSERT_EQ(2U, caller_registers.size()); 157 ASSERT_EQ(2828089117179001ULL, caller_registers[".cfa"]); 158 ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]); 159 ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211", 160 cfi.Serialize()); 161 } 162 163 class Scope: public CFIFixture, public Test { }; 164 165 // There should be no value for .cfa in scope when evaluating the CFA rule. 166 TEST_F(Scope, CFALacksCFA) { 167 ExpectNoMemoryReferences(); 168 169 cfi.SetCFARule(".cfa"); 170 cfi.SetRARule("0"); 171 ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory, 172 &caller_registers)); 173 } 174 175 // There should be no value for .ra in scope when evaluating the CFA rule. 176 TEST_F(Scope, CFALacksRA) { 177 ExpectNoMemoryReferences(); 178 179 cfi.SetCFARule(".ra"); 180 cfi.SetRARule("0"); 181 ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory, 182 &caller_registers)); 183 } 184 185 // The current frame's registers should be in scope when evaluating 186 // the CFA rule. 187 TEST_F(Scope, CFASeesCurrentRegs) { 188 ExpectNoMemoryReferences(); 189 190 registers[".baraminology"] = 0x06a7bc63e4f13893ULL; 191 registers[".ornithorhynchus"] = 0x5e0bf850bafce9d2ULL; 192 cfi.SetCFARule(".baraminology .ornithorhynchus +"); 193 cfi.SetRARule("0"); 194 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 195 &caller_registers)); 196 ASSERT_EQ(2U, caller_registers.size()); 197 ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL, 198 caller_registers[".cfa"]); 199 } 200 201 // .cfa should be in scope in the return address expression. 202 TEST_F(Scope, RASeesCFA) { 203 ExpectNoMemoryReferences(); 204 205 cfi.SetCFARule("48364076"); 206 cfi.SetRARule(".cfa"); 207 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 208 &caller_registers)); 209 ASSERT_EQ(2U, caller_registers.size()); 210 ASSERT_EQ(48364076U, caller_registers[".ra"]); 211 } 212 213 // There should be no value for .ra in scope when evaluating the CFA rule. 214 TEST_F(Scope, RALacksRA) { 215 ExpectNoMemoryReferences(); 216 217 cfi.SetCFARule("0"); 218 cfi.SetRARule(".ra"); 219 ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory, 220 &caller_registers)); 221 } 222 223 // The current frame's registers should be in scope in the return 224 // address expression. 225 TEST_F(Scope, RASeesCurrentRegs) { 226 ExpectNoMemoryReferences(); 227 228 registers["noachian"] = 0x54dc4a5d8e5eb503ULL; 229 cfi.SetCFARule("10359370"); 230 cfi.SetRARule("noachian"); 231 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 232 &caller_registers)); 233 ASSERT_EQ(2U, caller_registers.size()); 234 ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[".ra"]); 235 } 236 237 // .cfa should be in scope for register rules. 238 TEST_F(Scope, RegistersSeeCFA) { 239 ExpectNoMemoryReferences(); 240 241 cfi.SetCFARule("6515179"); 242 cfi.SetRARule(".cfa"); 243 cfi.SetRegisterRule("rogerian", ".cfa"); 244 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 245 &caller_registers)); 246 ASSERT_EQ(3U, caller_registers.size()); 247 ASSERT_EQ(6515179U, caller_registers["rogerian"]); 248 } 249 250 // The return address should not be in scope for register rules. 251 TEST_F(Scope, RegsLackRA) { 252 ExpectNoMemoryReferences(); 253 254 cfi.SetCFARule("42740329"); 255 cfi.SetRARule("27045204"); 256 cfi.SetRegisterRule("$r1", ".ra"); 257 ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory, 258 &caller_registers)); 259 } 260 261 // Register rules can see the current frame's register values. 262 TEST_F(Scope, RegsSeeRegs) { 263 ExpectNoMemoryReferences(); 264 265 registers["$r1"] = 0x6ed3582c4bedb9adULL; 266 registers["$r2"] = 0xd27d9e742b8df6d0ULL; 267 cfi.SetCFARule("88239303"); 268 cfi.SetRARule("30503835"); 269 cfi.SetRegisterRule("$r1", "$r1 42175211 = $r2"); 270 cfi.SetRegisterRule("$r2", "$r2 21357221 = $r1"); 271 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 272 &caller_registers)); 273 ASSERT_EQ(4U, caller_registers.size()); 274 ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers["$r1"]); 275 ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers["$r2"]); 276 } 277 278 // Each rule's temporaries are separate. 279 TEST_F(Scope, SeparateTempsRA) { 280 ExpectNoMemoryReferences(); 281 282 cfi.SetCFARule("$temp1 76569129 = $temp1"); 283 cfi.SetRARule("0"); 284 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 285 &caller_registers)); 286 287 cfi.SetCFARule("$temp1 76569129 = $temp1"); 288 cfi.SetRARule("$temp1"); 289 ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory, 290 &caller_registers)); 291 } 292 293 class MockCFIRuleParserHandler: public CFIRuleParser::Handler { 294 public: 295 MOCK_METHOD1(CFARule, void(const string &)); 296 MOCK_METHOD1(RARule, void(const string &)); 297 MOCK_METHOD2(RegisterRule, void(const string &, const string &)); 298 }; 299 300 // A fixture class for testing CFIRuleParser. 301 class CFIParserFixture { 302 public: 303 CFIParserFixture() : parser(&mock_handler) { 304 // Expect no parsing results to be reported to mock_handler. Individual 305 // tests can override this. 306 EXPECT_CALL(mock_handler, CFARule(_)).Times(0); 307 EXPECT_CALL(mock_handler, RARule(_)).Times(0); 308 EXPECT_CALL(mock_handler, RegisterRule(_, _)).Times(0); 309 } 310 311 MockCFIRuleParserHandler mock_handler; 312 CFIRuleParser parser; 313 }; 314 315 class Parser: public CFIParserFixture, public Test { }; 316 317 TEST_F(Parser, Empty) { 318 EXPECT_FALSE(parser.Parse("")); 319 } 320 321 TEST_F(Parser, LoneColon) { 322 EXPECT_FALSE(parser.Parse(":")); 323 } 324 325 TEST_F(Parser, CFANoExpr) { 326 EXPECT_FALSE(parser.Parse(".cfa:")); 327 } 328 329 TEST_F(Parser, CFANoColonNoExpr) { 330 EXPECT_FALSE(parser.Parse(".cfa")); 331 } 332 333 TEST_F(Parser, RANoExpr) { 334 EXPECT_FALSE(parser.Parse(".ra:")); 335 } 336 337 TEST_F(Parser, RANoColonNoExpr) { 338 EXPECT_FALSE(parser.Parse(".ra")); 339 } 340 341 TEST_F(Parser, RegNoExpr) { 342 EXPECT_FALSE(parser.Parse("reg:")); 343 } 344 345 TEST_F(Parser, NoName) { 346 EXPECT_FALSE(parser.Parse("expr")); 347 } 348 349 TEST_F(Parser, NoNameTwo) { 350 EXPECT_FALSE(parser.Parse("expr1 expr2")); 351 } 352 353 TEST_F(Parser, StartsWithExpr) { 354 EXPECT_FALSE(parser.Parse("expr1 reg: expr2")); 355 } 356 357 TEST_F(Parser, CFA) { 358 EXPECT_CALL(mock_handler, CFARule("spleen")).WillOnce(Return()); 359 EXPECT_TRUE(parser.Parse(".cfa: spleen")); 360 } 361 362 TEST_F(Parser, RA) { 363 EXPECT_CALL(mock_handler, RARule("notoriety")).WillOnce(Return()); 364 EXPECT_TRUE(parser.Parse(".ra: notoriety")); 365 } 366 367 TEST_F(Parser, Reg) { 368 EXPECT_CALL(mock_handler, RegisterRule("nemo", "mellifluous")) 369 .WillOnce(Return()); 370 EXPECT_TRUE(parser.Parse("nemo: mellifluous")); 371 } 372 373 TEST_F(Parser, CFARARegs) { 374 EXPECT_CALL(mock_handler, CFARule("cfa expression")).WillOnce(Return()); 375 EXPECT_CALL(mock_handler, RARule("ra expression")).WillOnce(Return()); 376 EXPECT_CALL(mock_handler, RegisterRule("galba", "praetorian")) 377 .WillOnce(Return()); 378 EXPECT_CALL(mock_handler, RegisterRule("otho", "vitellius")) 379 .WillOnce(Return()); 380 EXPECT_TRUE(parser.Parse(".cfa: cfa expression .ra: ra expression " 381 "galba: praetorian otho: vitellius")); 382 } 383 384 TEST_F(Parser, Whitespace) { 385 EXPECT_CALL(mock_handler, RegisterRule("r1", "r1 expression")) 386 .WillOnce(Return()); 387 EXPECT_CALL(mock_handler, RegisterRule("r2", "r2 expression")) 388 .WillOnce(Return()); 389 EXPECT_TRUE(parser.Parse(" r1:\tr1\nexpression \tr2:\t\rr2\r\n " 390 "expression \n")); 391 } 392 393 TEST_F(Parser, WhitespaceLoneColon) { 394 EXPECT_FALSE(parser.Parse(" \n:\t ")); 395 } 396 397 TEST_F(Parser, EmptyName) { 398 EXPECT_CALL(mock_handler, RegisterRule("reg", _)) 399 .Times(AtMost(1)) 400 .WillRepeatedly(Return()); 401 EXPECT_FALSE(parser.Parse("reg: expr1 : expr2")); 402 } 403 404 TEST_F(Parser, RuleLoneColon) { 405 EXPECT_CALL(mock_handler, RegisterRule("r1", "expr")) 406 .Times(AtMost(1)) 407 .WillRepeatedly(Return()); 408 EXPECT_FALSE(parser.Parse(" r1: expr :")); 409 } 410 411 TEST_F(Parser, RegNoExprRule) { 412 EXPECT_CALL(mock_handler, RegisterRule("r1", "expr")) 413 .Times(AtMost(1)) 414 .WillRepeatedly(Return()); 415 EXPECT_FALSE(parser.Parse("r0: r1: expr")); 416 } 417 418 class ParseHandlerFixture: public CFIFixture { 419 public: 420 ParseHandlerFixture() : CFIFixture(), handler(&cfi) { } 421 CFIFrameInfoParseHandler handler; 422 }; 423 424 class ParseHandler: public ParseHandlerFixture, public Test { }; 425 426 TEST_F(ParseHandler, CFARARule) { 427 handler.CFARule("reg-for-cfa"); 428 handler.RARule("reg-for-ra"); 429 registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL; 430 registers["reg-for-ra"] = 0x6301b475b8b91c02ULL; 431 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 432 &caller_registers)); 433 ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]); 434 ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]); 435 } 436 437 TEST_F(ParseHandler, RegisterRules) { 438 handler.CFARule("reg-for-cfa"); 439 handler.RARule("reg-for-ra"); 440 handler.RegisterRule("reg1", "reg-for-reg1"); 441 handler.RegisterRule("reg2", "reg-for-reg2"); 442 registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL; 443 registers["reg-for-ra"] = 0x6301b475b8b91c02ULL; 444 registers["reg-for-reg1"] = 0x06cde8e2ff062481ULL; 445 registers["reg-for-reg2"] = 0xff0c4f76403173e2ULL; 446 ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 447 &caller_registers)); 448 ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]); 449 ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]); 450 ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers["reg1"]); 451 ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers["reg2"]); 452 } 453 454 struct SimpleCFIWalkerFixture { 455 struct RawContext { 456 uint64_t r0, r1, r2, r3, r4, sp, pc; 457 }; 458 enum Validity { 459 R0_VALID = 0x01, 460 R1_VALID = 0x02, 461 R2_VALID = 0x04, 462 R3_VALID = 0x08, 463 R4_VALID = 0x10, 464 SP_VALID = 0x20, 465 PC_VALID = 0x40 466 }; 467 typedef SimpleCFIWalker<uint64_t, RawContext> CFIWalker; 468 469 SimpleCFIWalkerFixture() 470 : walker(register_map, 471 sizeof(register_map) / sizeof(register_map[0])) { } 472 473 static CFIWalker::RegisterSet register_map[7]; 474 CFIFrameInfo call_frame_info; 475 CFIWalker walker; 476 MockMemoryRegion memory; 477 RawContext callee_context, caller_context; 478 }; 479 480 SimpleCFIWalkerFixture::CFIWalker::RegisterSet 481 SimpleCFIWalkerFixture::register_map[7] = { 482 { "r0", NULL, true, R0_VALID, &RawContext::r0 }, 483 { "r1", NULL, true, R1_VALID, &RawContext::r1 }, 484 { "r2", NULL, false, R2_VALID, &RawContext::r2 }, 485 { "r3", NULL, false, R3_VALID, &RawContext::r3 }, 486 { "r4", NULL, true, R4_VALID, &RawContext::r4 }, 487 { "sp", ".cfa", true, SP_VALID, &RawContext::sp }, 488 { "pc", ".ra", true, PC_VALID, &RawContext::pc }, 489 }; 490 491 class SimpleWalker: public SimpleCFIWalkerFixture, public Test { }; 492 493 TEST_F(SimpleWalker, Walk) { 494 // Stack_top is the current stack pointer, pointing to the lowest 495 // address of a frame that looks like this (all 64-bit words): 496 // 497 // sp -> saved r0 498 // garbage 499 // return address 500 // cfa -> 501 // 502 // r0 has been saved on the stack. 503 // r1 has been saved in r2. 504 // r2 and r3 are not recoverable. 505 // r4 is not recoverable, even though it is a callee-saves register. 506 // Some earlier frame's unwinder must have failed to recover it. 507 508 uint64_t stack_top = 0x83254944b20d5512ULL; 509 510 // Saved r0. 511 EXPECT_CALL(memory, 512 GetMemoryAtAddress(stack_top, A<uint64_t *>())) 513 .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xdc1975eba8602302ULL), 514 Return(true))); 515 // Saved return address. 516 EXPECT_CALL(memory, 517 GetMemoryAtAddress(stack_top + 16, A<uint64_t *>())) 518 .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xba5ad6d9acce28deULL), 519 Return(true))); 520 521 call_frame_info.SetCFARule("sp 24 +"); 522 call_frame_info.SetRARule(".cfa 8 - ^"); 523 call_frame_info.SetRegisterRule("r0", ".cfa 24 - ^"); 524 call_frame_info.SetRegisterRule("r1", "r2"); 525 526 callee_context.r0 = 0x94e030ca79edd119ULL; 527 callee_context.r1 = 0x937b4d7e95ce52d9ULL; 528 callee_context.r2 = 0x5fe0027416b8b62aULL; // caller's r1 529 // callee_context.r3 is not valid in callee. 530 // callee_context.r4 is not valid in callee. 531 callee_context.sp = stack_top; 532 callee_context.pc = 0x25b21b224311d280ULL; 533 int callee_validity = R0_VALID | R1_VALID | R2_VALID | SP_VALID | PC_VALID; 534 535 memset(&caller_context, 0, sizeof(caller_context)); 536 537 int caller_validity; 538 EXPECT_TRUE(walker.FindCallerRegisters(memory, call_frame_info, 539 callee_context, callee_validity, 540 &caller_context, &caller_validity)); 541 EXPECT_EQ(R0_VALID | R1_VALID | SP_VALID | PC_VALID, caller_validity); 542 EXPECT_EQ(0xdc1975eba8602302ULL, caller_context.r0); 543 EXPECT_EQ(0x5fe0027416b8b62aULL, caller_context.r1); 544 EXPECT_EQ(stack_top + 24, caller_context.sp); 545 EXPECT_EQ(0xba5ad6d9acce28deULL, caller_context.pc); 546 } 547