PageRenderTime 80ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/thirdparty/breakpad/processor/cfi_frame_info_unittest.cc

http://github.com/tomahawk-player/tomahawk
C++ | 545 lines | 396 code | 82 blank | 67 comment | 0 complexity | 310f0c41926d5ea1c244cad48b41e723 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, GPL-3.0, GPL-2.0
  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. // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
  30. // cfi_frame_info_unittest.cc: Unit tests for CFIFrameInfo,
  31. // CFIRuleParser, CFIFrameInfoParseHandler, and SimpleCFIWalker.
  32. #include <string.h>
  33. #include "breakpad_googletest_includes.h"
  34. #include "processor/cfi_frame_info.h"
  35. #include "google_breakpad/processor/memory_region.h"
  36. using google_breakpad::CFIFrameInfo;
  37. using google_breakpad::CFIFrameInfoParseHandler;
  38. using google_breakpad::CFIRuleParser;
  39. using google_breakpad::MemoryRegion;
  40. using google_breakpad::SimpleCFIWalker;
  41. using std::string;
  42. using testing::_;
  43. using testing::A;
  44. using testing::AtMost;
  45. using testing::DoAll;
  46. using testing::Return;
  47. using testing::SetArgumentPointee;
  48. using testing::Test;
  49. class MockMemoryRegion: public MemoryRegion {
  50. public:
  51. MOCK_CONST_METHOD0(GetBase, u_int64_t());
  52. MOCK_CONST_METHOD0(GetSize, u_int32_t());
  53. MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(u_int64_t, u_int8_t *));
  54. MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(u_int64_t, u_int16_t *));
  55. MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(u_int64_t, u_int32_t *));
  56. MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(u_int64_t, u_int64_t *));
  57. };
  58. // Handy definitions for all tests.
  59. struct CFIFixture {
  60. // Set up the mock memory object to expect no references.
  61. void ExpectNoMemoryReferences() {
  62. EXPECT_CALL(memory, GetBase()).Times(0);
  63. EXPECT_CALL(memory, GetSize()).Times(0);
  64. EXPECT_CALL(memory, GetMemoryAtAddress(_, A<u_int8_t *>())).Times(0);
  65. EXPECT_CALL(memory, GetMemoryAtAddress(_, A<u_int16_t *>())).Times(0);
  66. EXPECT_CALL(memory, GetMemoryAtAddress(_, A<u_int32_t *>())).Times(0);
  67. EXPECT_CALL(memory, GetMemoryAtAddress(_, A<u_int64_t *>())).Times(0);
  68. }
  69. CFIFrameInfo cfi;
  70. MockMemoryRegion memory;
  71. CFIFrameInfo::RegisterValueMap<u_int64_t> registers, caller_registers;
  72. };
  73. class Simple: public CFIFixture, public Test { };
  74. // FindCallerRegs should fail if no .cfa rule is provided.
  75. TEST_F(Simple, NoCFA) {
  76. ExpectNoMemoryReferences();
  77. cfi.SetRARule("0");
  78. ASSERT_FALSE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  79. &caller_registers));
  80. ASSERT_EQ(".ra: 0", cfi.Serialize());
  81. }
  82. // FindCallerRegs should fail if no .ra rule is provided.
  83. TEST_F(Simple, NoRA) {
  84. ExpectNoMemoryReferences();
  85. cfi.SetCFARule("0");
  86. ASSERT_FALSE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  87. &caller_registers));
  88. ASSERT_EQ(".cfa: 0", cfi.Serialize());
  89. }
  90. TEST_F(Simple, SetCFAAndRARule) {
  91. ExpectNoMemoryReferences();
  92. cfi.SetCFARule("330903416631436410");
  93. cfi.SetRARule("5870666104170902211");
  94. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  95. &caller_registers));
  96. ASSERT_EQ(2U, caller_registers.size());
  97. ASSERT_EQ(330903416631436410ULL, caller_registers[".cfa"]);
  98. ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]);
  99. ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211",
  100. cfi.Serialize());
  101. }
  102. TEST_F(Simple, SetManyRules) {
  103. ExpectNoMemoryReferences();
  104. cfi.SetCFARule("$temp1 68737028 = $temp2 61072337 = $temp1 $temp2 -");
  105. cfi.SetRARule(".cfa 99804755 +");
  106. cfi.SetRegisterRule("register1", ".cfa 54370437 *");
  107. cfi.SetRegisterRule("vodkathumbscrewingly", "24076308 .cfa +");
  108. cfi.SetRegisterRule("pubvexingfjordschmaltzy", ".cfa 29801007 -");
  109. cfi.SetRegisterRule("uncopyrightables", "92642917 .cfa /");
  110. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  111. &caller_registers));
  112. ASSERT_EQ(6U, caller_registers.size());
  113. ASSERT_EQ(7664691U, caller_registers[".cfa"]);
  114. ASSERT_EQ(107469446U, caller_registers[".ra"]);
  115. ASSERT_EQ(416732599139967ULL, caller_registers["register1"]);
  116. ASSERT_EQ(31740999U, caller_registers["vodkathumbscrewingly"]);
  117. ASSERT_EQ(-22136316ULL, caller_registers["pubvexingfjordschmaltzy"]);
  118. ASSERT_EQ(12U, caller_registers["uncopyrightables"]);
  119. ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - "
  120. ".ra: .cfa 99804755 + "
  121. "pubvexingfjordschmaltzy: .cfa 29801007 - "
  122. "register1: .cfa 54370437 * "
  123. "uncopyrightables: 92642917 .cfa / "
  124. "vodkathumbscrewingly: 24076308 .cfa +",
  125. cfi.Serialize());
  126. }
  127. TEST_F(Simple, RulesOverride) {
  128. ExpectNoMemoryReferences();
  129. cfi.SetCFARule("330903416631436410");
  130. cfi.SetRARule("5870666104170902211");
  131. cfi.SetCFARule("2828089117179001");
  132. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  133. &caller_registers));
  134. ASSERT_EQ(2U, caller_registers.size());
  135. ASSERT_EQ(2828089117179001ULL, caller_registers[".cfa"]);
  136. ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]);
  137. ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211",
  138. cfi.Serialize());
  139. }
  140. class Scope: public CFIFixture, public Test { };
  141. // There should be no value for .cfa in scope when evaluating the CFA rule.
  142. TEST_F(Scope, CFALacksCFA) {
  143. ExpectNoMemoryReferences();
  144. cfi.SetCFARule(".cfa");
  145. cfi.SetRARule("0");
  146. ASSERT_FALSE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  147. &caller_registers));
  148. }
  149. // There should be no value for .ra in scope when evaluating the CFA rule.
  150. TEST_F(Scope, CFALacksRA) {
  151. ExpectNoMemoryReferences();
  152. cfi.SetCFARule(".ra");
  153. cfi.SetRARule("0");
  154. ASSERT_FALSE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  155. &caller_registers));
  156. }
  157. // The current frame's registers should be in scope when evaluating
  158. // the CFA rule.
  159. TEST_F(Scope, CFASeesCurrentRegs) {
  160. ExpectNoMemoryReferences();
  161. registers[".baraminology"] = 0x06a7bc63e4f13893ULL;
  162. registers[".ornithorhynchus"] = 0x5e0bf850bafce9d2ULL;
  163. cfi.SetCFARule(".baraminology .ornithorhynchus +");
  164. cfi.SetRARule("0");
  165. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  166. &caller_registers));
  167. ASSERT_EQ(2U, caller_registers.size());
  168. ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL,
  169. caller_registers[".cfa"]);
  170. }
  171. // .cfa should be in scope in the return address expression.
  172. TEST_F(Scope, RASeesCFA) {
  173. ExpectNoMemoryReferences();
  174. cfi.SetCFARule("48364076");
  175. cfi.SetRARule(".cfa");
  176. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  177. &caller_registers));
  178. ASSERT_EQ(2U, caller_registers.size());
  179. ASSERT_EQ(48364076U, caller_registers[".ra"]);
  180. }
  181. // There should be no value for .ra in scope when evaluating the CFA rule.
  182. TEST_F(Scope, RALacksRA) {
  183. ExpectNoMemoryReferences();
  184. cfi.SetCFARule("0");
  185. cfi.SetRARule(".ra");
  186. ASSERT_FALSE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  187. &caller_registers));
  188. }
  189. // The current frame's registers should be in scope in the return
  190. // address expression.
  191. TEST_F(Scope, RASeesCurrentRegs) {
  192. ExpectNoMemoryReferences();
  193. registers["noachian"] = 0x54dc4a5d8e5eb503ULL;
  194. cfi.SetCFARule("10359370");
  195. cfi.SetRARule("noachian");
  196. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  197. &caller_registers));
  198. ASSERT_EQ(2U, caller_registers.size());
  199. ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[".ra"]);
  200. }
  201. // .cfa should be in scope for register rules.
  202. TEST_F(Scope, RegistersSeeCFA) {
  203. ExpectNoMemoryReferences();
  204. cfi.SetCFARule("6515179");
  205. cfi.SetRARule(".cfa");
  206. cfi.SetRegisterRule("rogerian", ".cfa");
  207. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  208. &caller_registers));
  209. ASSERT_EQ(3U, caller_registers.size());
  210. ASSERT_EQ(6515179U, caller_registers["rogerian"]);
  211. }
  212. // The return address should not be in scope for register rules.
  213. TEST_F(Scope, RegsLackRA) {
  214. ExpectNoMemoryReferences();
  215. cfi.SetCFARule("42740329");
  216. cfi.SetRARule("27045204");
  217. cfi.SetRegisterRule("$r1", ".ra");
  218. ASSERT_FALSE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  219. &caller_registers));
  220. }
  221. // Register rules can see the current frame's register values.
  222. TEST_F(Scope, RegsSeeRegs) {
  223. ExpectNoMemoryReferences();
  224. registers["$r1"] = 0x6ed3582c4bedb9adULL;
  225. registers["$r2"] = 0xd27d9e742b8df6d0ULL;
  226. cfi.SetCFARule("88239303");
  227. cfi.SetRARule("30503835");
  228. cfi.SetRegisterRule("$r1", "$r1 42175211 = $r2");
  229. cfi.SetRegisterRule("$r2", "$r2 21357221 = $r1");
  230. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  231. &caller_registers));
  232. ASSERT_EQ(4U, caller_registers.size());
  233. ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers["$r1"]);
  234. ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers["$r2"]);
  235. }
  236. // Each rule's temporaries are separate.
  237. TEST_F(Scope, SeparateTempsRA) {
  238. ExpectNoMemoryReferences();
  239. cfi.SetCFARule("$temp1 76569129 = $temp1");
  240. cfi.SetRARule("0");
  241. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  242. &caller_registers));
  243. cfi.SetCFARule("$temp1 76569129 = $temp1");
  244. cfi.SetRARule("$temp1");
  245. ASSERT_FALSE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  246. &caller_registers));
  247. }
  248. class MockCFIRuleParserHandler: public CFIRuleParser::Handler {
  249. public:
  250. MOCK_METHOD1(CFARule, void(const string &));
  251. MOCK_METHOD1(RARule, void(const string &));
  252. MOCK_METHOD2(RegisterRule, void(const string &, const string &));
  253. };
  254. // A fixture class for testing CFIRuleParser.
  255. class CFIParserFixture {
  256. public:
  257. CFIParserFixture() : parser(&mock_handler) {
  258. // Expect no parsing results to be reported to mock_handler. Individual
  259. // tests can override this.
  260. EXPECT_CALL(mock_handler, CFARule(_)).Times(0);
  261. EXPECT_CALL(mock_handler, RARule(_)).Times(0);
  262. EXPECT_CALL(mock_handler, RegisterRule(_, _)).Times(0);
  263. }
  264. MockCFIRuleParserHandler mock_handler;
  265. CFIRuleParser parser;
  266. };
  267. class Parser: public CFIParserFixture, public Test { };
  268. TEST_F(Parser, Empty) {
  269. EXPECT_FALSE(parser.Parse(""));
  270. }
  271. TEST_F(Parser, LoneColon) {
  272. EXPECT_FALSE(parser.Parse(":"));
  273. }
  274. TEST_F(Parser, CFANoExpr) {
  275. EXPECT_FALSE(parser.Parse(".cfa:"));
  276. }
  277. TEST_F(Parser, CFANoColonNoExpr) {
  278. EXPECT_FALSE(parser.Parse(".cfa"));
  279. }
  280. TEST_F(Parser, RANoExpr) {
  281. EXPECT_FALSE(parser.Parse(".ra:"));
  282. }
  283. TEST_F(Parser, RANoColonNoExpr) {
  284. EXPECT_FALSE(parser.Parse(".ra"));
  285. }
  286. TEST_F(Parser, RegNoExpr) {
  287. EXPECT_FALSE(parser.Parse("reg:"));
  288. }
  289. TEST_F(Parser, NoName) {
  290. EXPECT_FALSE(parser.Parse("expr"));
  291. }
  292. TEST_F(Parser, NoNameTwo) {
  293. EXPECT_FALSE(parser.Parse("expr1 expr2"));
  294. }
  295. TEST_F(Parser, StartsWithExpr) {
  296. EXPECT_FALSE(parser.Parse("expr1 reg: expr2"));
  297. }
  298. TEST_F(Parser, CFA) {
  299. EXPECT_CALL(mock_handler, CFARule("spleen")).WillOnce(Return());
  300. EXPECT_TRUE(parser.Parse(".cfa: spleen"));
  301. }
  302. TEST_F(Parser, RA) {
  303. EXPECT_CALL(mock_handler, RARule("notoriety")).WillOnce(Return());
  304. EXPECT_TRUE(parser.Parse(".ra: notoriety"));
  305. }
  306. TEST_F(Parser, Reg) {
  307. EXPECT_CALL(mock_handler, RegisterRule("nemo", "mellifluous"))
  308. .WillOnce(Return());
  309. EXPECT_TRUE(parser.Parse("nemo: mellifluous"));
  310. }
  311. TEST_F(Parser, CFARARegs) {
  312. EXPECT_CALL(mock_handler, CFARule("cfa expression")).WillOnce(Return());
  313. EXPECT_CALL(mock_handler, RARule("ra expression")).WillOnce(Return());
  314. EXPECT_CALL(mock_handler, RegisterRule("galba", "praetorian"))
  315. .WillOnce(Return());
  316. EXPECT_CALL(mock_handler, RegisterRule("otho", "vitellius"))
  317. .WillOnce(Return());
  318. EXPECT_TRUE(parser.Parse(".cfa: cfa expression .ra: ra expression "
  319. "galba: praetorian otho: vitellius"));
  320. }
  321. TEST_F(Parser, Whitespace) {
  322. EXPECT_CALL(mock_handler, RegisterRule("r1", "r1 expression"))
  323. .WillOnce(Return());
  324. EXPECT_CALL(mock_handler, RegisterRule("r2", "r2 expression"))
  325. .WillOnce(Return());
  326. EXPECT_TRUE(parser.Parse(" r1:\tr1\nexpression \tr2:\t\rr2\r\n "
  327. "expression \n"));
  328. }
  329. TEST_F(Parser, WhitespaceLoneColon) {
  330. EXPECT_FALSE(parser.Parse(" \n:\t "));
  331. }
  332. TEST_F(Parser, EmptyName) {
  333. EXPECT_CALL(mock_handler, RegisterRule("reg", _))
  334. .Times(AtMost(1))
  335. .WillRepeatedly(Return());
  336. EXPECT_FALSE(parser.Parse("reg: expr1 : expr2"));
  337. }
  338. TEST_F(Parser, RuleLoneColon) {
  339. EXPECT_CALL(mock_handler, RegisterRule("r1", "expr"))
  340. .Times(AtMost(1))
  341. .WillRepeatedly(Return());
  342. EXPECT_FALSE(parser.Parse(" r1: expr :"));
  343. }
  344. TEST_F(Parser, RegNoExprRule) {
  345. EXPECT_CALL(mock_handler, RegisterRule("r1", "expr"))
  346. .Times(AtMost(1))
  347. .WillRepeatedly(Return());
  348. EXPECT_FALSE(parser.Parse("r0: r1: expr"));
  349. }
  350. class ParseHandlerFixture: public CFIFixture {
  351. public:
  352. ParseHandlerFixture() : CFIFixture(), handler(&cfi) { }
  353. CFIFrameInfoParseHandler handler;
  354. };
  355. class ParseHandler: public ParseHandlerFixture, public Test { };
  356. TEST_F(ParseHandler, CFARARule) {
  357. handler.CFARule("reg-for-cfa");
  358. handler.RARule("reg-for-ra");
  359. registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL;
  360. registers["reg-for-ra"] = 0x6301b475b8b91c02ULL;
  361. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  362. &caller_registers));
  363. ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]);
  364. ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]);
  365. }
  366. TEST_F(ParseHandler, RegisterRules) {
  367. handler.CFARule("reg-for-cfa");
  368. handler.RARule("reg-for-ra");
  369. handler.RegisterRule("reg1", "reg-for-reg1");
  370. handler.RegisterRule("reg2", "reg-for-reg2");
  371. registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL;
  372. registers["reg-for-ra"] = 0x6301b475b8b91c02ULL;
  373. registers["reg-for-reg1"] = 0x06cde8e2ff062481ULL;
  374. registers["reg-for-reg2"] = 0xff0c4f76403173e2ULL;
  375. ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
  376. &caller_registers));
  377. ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]);
  378. ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]);
  379. ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers["reg1"]);
  380. ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers["reg2"]);
  381. }
  382. struct SimpleCFIWalkerFixture {
  383. struct RawContext {
  384. u_int64_t r0, r1, r2, r3, r4, sp, pc;
  385. };
  386. enum Validity {
  387. R0_VALID = 0x01,
  388. R1_VALID = 0x02,
  389. R2_VALID = 0x04,
  390. R3_VALID = 0x08,
  391. R4_VALID = 0x10,
  392. SP_VALID = 0x20,
  393. PC_VALID = 0x40
  394. };
  395. typedef SimpleCFIWalker<u_int64_t, RawContext> CFIWalker;
  396. SimpleCFIWalkerFixture()
  397. : walker(register_map,
  398. sizeof(register_map) / sizeof(register_map[0])) { }
  399. static CFIWalker::RegisterSet register_map[7];
  400. CFIFrameInfo call_frame_info;
  401. CFIWalker walker;
  402. MockMemoryRegion memory;
  403. RawContext callee_context, caller_context;
  404. };
  405. SimpleCFIWalkerFixture::CFIWalker::RegisterSet
  406. SimpleCFIWalkerFixture::register_map[7] = {
  407. { "r0", NULL, true, R0_VALID, &RawContext::r0 },
  408. { "r1", NULL, true, R1_VALID, &RawContext::r1 },
  409. { "r2", NULL, false, R2_VALID, &RawContext::r2 },
  410. { "r3", NULL, false, R3_VALID, &RawContext::r3 },
  411. { "r4", NULL, true, R4_VALID, &RawContext::r4 },
  412. { "sp", ".cfa", true, SP_VALID, &RawContext::sp },
  413. { "pc", ".ra", true, PC_VALID, &RawContext::pc },
  414. };
  415. class SimpleWalker: public SimpleCFIWalkerFixture, public Test { };
  416. TEST_F(SimpleWalker, Walk) {
  417. // Stack_top is the current stack pointer, pointing to the lowest
  418. // address of a frame that looks like this (all 64-bit words):
  419. //
  420. // sp -> saved r0
  421. // garbage
  422. // return address
  423. // cfa ->
  424. //
  425. // r0 has been saved on the stack.
  426. // r1 has been saved in r2.
  427. // r2 and r3 are not recoverable.
  428. // r4 is not recoverable, even though it is a callee-saves register.
  429. // Some earlier frame's unwinder must have failed to recover it.
  430. u_int64_t stack_top = 0x83254944b20d5512ULL;
  431. // Saved r0.
  432. EXPECT_CALL(memory,
  433. GetMemoryAtAddress(stack_top, A<u_int64_t *>()))
  434. .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xdc1975eba8602302ULL),
  435. Return(true)));
  436. // Saved return address.
  437. EXPECT_CALL(memory,
  438. GetMemoryAtAddress(stack_top + 16, A<u_int64_t *>()))
  439. .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xba5ad6d9acce28deULL),
  440. Return(true)));
  441. call_frame_info.SetCFARule("sp 24 +");
  442. call_frame_info.SetRARule(".cfa 8 - ^");
  443. call_frame_info.SetRegisterRule("r0", ".cfa 24 - ^");
  444. call_frame_info.SetRegisterRule("r1", "r2");
  445. callee_context.r0 = 0x94e030ca79edd119ULL;
  446. callee_context.r1 = 0x937b4d7e95ce52d9ULL;
  447. callee_context.r2 = 0x5fe0027416b8b62aULL; // caller's r1
  448. // callee_context.r3 is not valid in callee.
  449. // callee_context.r4 is not valid in callee.
  450. callee_context.sp = stack_top;
  451. callee_context.pc = 0x25b21b224311d280ULL;
  452. int callee_validity = R0_VALID | R1_VALID | R2_VALID | SP_VALID | PC_VALID;
  453. memset(&caller_context, 0, sizeof(caller_context));
  454. int caller_validity;
  455. EXPECT_TRUE(walker.FindCallerRegisters(memory, call_frame_info,
  456. callee_context, callee_validity,
  457. &caller_context, &caller_validity));
  458. EXPECT_EQ(R0_VALID | R1_VALID | SP_VALID | PC_VALID, caller_validity);
  459. EXPECT_EQ(0xdc1975eba8602302ULL, caller_context.r0);
  460. EXPECT_EQ(0x5fe0027416b8b62aULL, caller_context.r1);
  461. EXPECT_EQ(stack_top + 24, caller_context.sp);
  462. EXPECT_EQ(0xba5ad6d9acce28deULL, caller_context.pc);
  463. }