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