Home | History | Annotate | Download | only in processor
      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