/ src / processor / cfi_frame_info_unittest.cc
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  }