16d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Copyright (c) 2010, Google Inc.
26d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// All rights reserved.
36d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//
46d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Redistribution and use in source and binary forms, with or without
56d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// modification, are permitted provided that the following conditions are
66d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// met:
76d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//
86d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//     * Redistributions of source code must retain the above copyright
96d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// notice, this list of conditions and the following disclaimer.
106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//     * Redistributions in binary form must reproduce the above
116d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// copyright notice, this list of conditions and the following disclaimer
126d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// in the documentation and/or other materials provided with the
136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// distribution.
146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//     * Neither the name of Google Inc. nor the names of its
156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// contributors may be used to endorse or promote products derived from
166d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// this software without specific prior written permission.
176d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//
186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
196d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
316d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// cfi_frame_info_unittest.cc: Unit tests for CFIFrameInfo,
336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// CFIRuleParser, CFIFrameInfoParseHandler, and SimpleCFIWalker.
346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy#include <string.h>
366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy#include "breakpad_googletest_includes.h"
384e518a4357a2d1c379d4a91df6d4e153ee791101ivan.penkov@gmail.com#include "common/using_std_string.h"
396d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy#include "processor/cfi_frame_info.h"
406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy#include "google_breakpad/processor/memory_region.h"
416d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing google_breakpad::CFIFrameInfo;
436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing google_breakpad::CFIFrameInfoParseHandler;
446d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing google_breakpad::CFIRuleParser;
456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing google_breakpad::MemoryRegion;
466d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing google_breakpad::SimpleCFIWalker;
476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing testing::_;
486d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing testing::A;
496d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing testing::AtMost;
506d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing testing::DoAll;
516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing testing::Return;
526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing testing::SetArgumentPointee;
536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyusing testing::Test;
546d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
556d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass MockMemoryRegion: public MemoryRegion {
566d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy public:
576162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  MOCK_CONST_METHOD0(GetBase, uint64_t());
586162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  MOCK_CONST_METHOD0(GetSize, uint32_t());
596162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint8_t *));
606162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint16_t *));
616162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint32_t *));
626162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint64_t *));
63c5e242b8cd4280db5162e5a3084f2dc9e16e8ffbmmandlis@chromium.org  MOCK_CONST_METHOD0(Print, void());
646d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy};
656d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Handy definitions for all tests.
676d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandystruct CFIFixture {
686d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
696d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // Set up the mock memory object to expect no references.
706d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  void ExpectNoMemoryReferences() {
716d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    EXPECT_CALL(memory, GetBase()).Times(0);
726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    EXPECT_CALL(memory, GetSize()).Times(0);
736162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint8_t *>())).Times(0);
746162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint16_t *>())).Times(0);
756162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint32_t *>())).Times(0);
766162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint64_t *>())).Times(0);
776d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  }
786d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
796d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CFIFrameInfo cfi;
806d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  MockMemoryRegion memory;
816162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  CFIFrameInfo::RegisterValueMap<uint64_t> registers, caller_registers;
826d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy};
836d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
846d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass Simple: public CFIFixture, public Test { };
856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// FindCallerRegs should fail if no .cfa rule is provided.
876d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Simple, NoCFA) {
886d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
896d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
906d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("0");
916162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
926d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                             &caller_registers));
93b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  ASSERT_EQ(".ra: 0", cfi.Serialize());
946d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
956d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
966d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// FindCallerRegs should fail if no .ra rule is provided.
976d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Simple, NoRA) {
986d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
996d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1006d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("0");
1016162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
1026d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                             &caller_registers));
103b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  ASSERT_EQ(".cfa: 0", cfi.Serialize());
1046d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1056d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1066d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Simple, SetCFAAndRARule) {
1076d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
1086d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1096d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("330903416631436410");
1106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("5870666104170902211");
1116162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
1126d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
1136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(2U, caller_registers.size());
1146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(330903416631436410ULL, caller_registers[".cfa"]);
1156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]);
116b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek
117b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211",
118b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek            cfi.Serialize());
1196d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Simple, SetManyRules) {
1226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
1236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("$temp1 68737028 = $temp2 61072337 = $temp1 $temp2 -");
1256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule(".cfa 99804755 +");
1266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRegisterRule("register1", ".cfa 54370437 *");
1276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRegisterRule("vodkathumbscrewingly", "24076308 .cfa +");
1286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRegisterRule("pubvexingfjordschmaltzy", ".cfa 29801007 -");
1296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRegisterRule("uncopyrightables", "92642917 .cfa /");
1306162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
1316d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
1326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(6U, caller_registers.size());
1336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(7664691U,           caller_registers[".cfa"]);
1346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(107469446U,         caller_registers[".ra"]);
1356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(416732599139967ULL, caller_registers["register1"]);
1366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(31740999U,          caller_registers["vodkathumbscrewingly"]);
1376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(-22136316ULL,       caller_registers["pubvexingfjordschmaltzy"]);
1386d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(12U,                caller_registers["uncopyrightables"]);
139b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - "
140b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek            ".ra: .cfa 99804755 + "
141b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek            "pubvexingfjordschmaltzy: .cfa 29801007 - "
142b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek            "register1: .cfa 54370437 * "
143b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek            "uncopyrightables: 92642917 .cfa / "
144b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek            "vodkathumbscrewingly: 24076308 .cfa +",
145b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek            cfi.Serialize());
1466d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1486d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Simple, RulesOverride) {
1496d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
1506d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("330903416631436410");
1526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("5870666104170902211");
1536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("2828089117179001");
1546162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
1556d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
1566d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(2U, caller_registers.size());
1576d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(2828089117179001ULL, caller_registers[".cfa"]);
1586d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]);
159b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211",
160b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek            cfi.Serialize());
1616d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1626d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1636d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass Scope: public CFIFixture, public Test { };
1646d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1656d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// There should be no value for .cfa in scope when evaluating the CFA rule.
1666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, CFALacksCFA) {
1676d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
1686d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1696d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule(".cfa");
1706d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("0");
1716162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
1726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                             &caller_registers));
1736d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1746d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1756d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// There should be no value for .ra in scope when evaluating the CFA rule.
1766d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, CFALacksRA) {
1776d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
1786d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1796d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule(".ra");
1806d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("0");
1816162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
1826d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                             &caller_registers));
1836d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1846d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// The current frame's registers should be in scope when evaluating
1866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// the CFA rule.
1876d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, CFASeesCurrentRegs) {
1886d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
1896d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1906d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers[".baraminology"] = 0x06a7bc63e4f13893ULL;
1916d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers[".ornithorhynchus"] = 0x5e0bf850bafce9d2ULL;
1926d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule(".baraminology .ornithorhynchus +");
1936d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("0");
1946162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
1956d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
1966d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(2U, caller_registers.size());
1976d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL,
1986d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy            caller_registers[".cfa"]);
1996d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
2006d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2016d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// .cfa should be in scope in the return address expression.
2026d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, RASeesCFA) {
2036d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
2046d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2056d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("48364076");
2066d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule(".cfa");
2076162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
2086d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
2096d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(2U, caller_registers.size());
2106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(48364076U, caller_registers[".ra"]);
2116d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
2126d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// There should be no value for .ra in scope when evaluating the CFA rule.
2146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, RALacksRA) {
2156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
2166d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2176d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("0");
2186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule(".ra");
2196162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
2206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                             &caller_registers));
2216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
2226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// The current frame's registers should be in scope in the return
2246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// address expression.
2256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, RASeesCurrentRegs) {
2266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
2276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["noachian"] = 0x54dc4a5d8e5eb503ULL;
2296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("10359370");
2306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("noachian");
2316162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
2326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
2336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(2U, caller_registers.size());
2346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[".ra"]);
2356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
2366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// .cfa should be in scope for register rules.
2386d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, RegistersSeeCFA) {
2396d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
2406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2416d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("6515179");
2426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule(".cfa");
2436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRegisterRule("rogerian", ".cfa");
2446162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
2456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
2466d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(3U, caller_registers.size());
2476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(6515179U, caller_registers["rogerian"]);
2486d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
2496d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2506d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// The return address should not be in scope for register rules.
2516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, RegsLackRA) {
2526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
2536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2546d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("42740329");
2556d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("27045204");
2566d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRegisterRule("$r1", ".ra");
2576162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
2586d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                             &caller_registers));
2596d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
2606d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2616d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Register rules can see the current frame's register values.
2626d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, RegsSeeRegs) {
2636d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
2646d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2656d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["$r1"] = 0x6ed3582c4bedb9adULL;
2666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["$r2"] = 0xd27d9e742b8df6d0ULL;
2676d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("88239303");
2686d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("30503835");
2696d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRegisterRule("$r1", "$r1 42175211 = $r2");
2706d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRegisterRule("$r2", "$r2 21357221 = $r1");
2716162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
2726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
2736d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(4U, caller_registers.size());
2746d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers["$r1"]);
2756d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers["$r2"]);
2766d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
2776d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2786d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Each rule's temporaries are separate.
2796d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Scope, SeparateTempsRA) {
2806d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ExpectNoMemoryReferences();
2816d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2826d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("$temp1 76569129 = $temp1");
2836d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("0");
2846162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
2856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
2866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2876d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetCFARule("$temp1 76569129 = $temp1");
2886d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  cfi.SetRARule("$temp1");
2896162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
2906d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                             &caller_registers));
2916d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
2926d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
2936d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass MockCFIRuleParserHandler: public CFIRuleParser::Handler {
2946d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy public:
2956d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  MOCK_METHOD1(CFARule, void(const string &));
2966d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  MOCK_METHOD1(RARule,  void(const string &));
2976d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  MOCK_METHOD2(RegisterRule, void(const string &, const string &));
2986d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy};
2996d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3006d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// A fixture class for testing CFIRuleParser.
3016d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass CFIParserFixture {
3026d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy public:
3036d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CFIParserFixture() : parser(&mock_handler) {
3046d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // Expect no parsing results to be reported to mock_handler. Individual
3056d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // tests can override this.
3066d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    EXPECT_CALL(mock_handler, CFARule(_)).Times(0);
3076d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    EXPECT_CALL(mock_handler, RARule(_)).Times(0);
3086d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    EXPECT_CALL(mock_handler, RegisterRule(_, _)).Times(0);
3096d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  }
3106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3116d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  MockCFIRuleParserHandler mock_handler;
3126d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CFIRuleParser parser;
3136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy};
3146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass Parser: public CFIParserFixture, public Test { };
3166d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3176d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, Empty) {
3186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse(""));
3196d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, LoneColon) {
3226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse(":"));
3236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, CFANoExpr) {
3266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse(".cfa:"));
3276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, CFANoColonNoExpr) {
3306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse(".cfa"));
3316d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, RANoExpr) {
3346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse(".ra:"));
3356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, RANoColonNoExpr) {
3386d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse(".ra"));
3396d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3416d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, RegNoExpr) {
3426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse("reg:"));
3436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3446d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, NoName) {
3466d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse("expr"));
3476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3486d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3496d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, NoNameTwo) {
3506d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse("expr1 expr2"));
3516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, StartsWithExpr) {
3546d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse("expr1 reg: expr2"));
3556d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3566d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3576d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, CFA) {
3586d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, CFARule("spleen")).WillOnce(Return());
3596d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_TRUE(parser.Parse(".cfa: spleen"));
3606d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3616d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3626d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, RA) {
3636d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RARule("notoriety")).WillOnce(Return());
3646d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_TRUE(parser.Parse(".ra: notoriety"));
3656d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3676d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, Reg) {
3686d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RegisterRule("nemo", "mellifluous"))
3696d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillOnce(Return());
3706d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_TRUE(parser.Parse("nemo: mellifluous"));
3716d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3736d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, CFARARegs) {
3746d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, CFARule("cfa expression")).WillOnce(Return());
3756d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RARule("ra expression")).WillOnce(Return());
3766d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RegisterRule("galba", "praetorian"))
3776d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillOnce(Return());
3786d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RegisterRule("otho", "vitellius"))
3796d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillOnce(Return());
3806d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_TRUE(parser.Parse(".cfa: cfa expression .ra: ra expression "
3816d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                    "galba: praetorian otho: vitellius"));
3826d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3836d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3846d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, Whitespace) {
3856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RegisterRule("r1", "r1 expression"))
3866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillOnce(Return());
3876d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RegisterRule("r2", "r2 expression"))
3886d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillOnce(Return());
3896d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_TRUE(parser.Parse(" r1:\tr1\nexpression \tr2:\t\rr2\r\n "
3906d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                           "expression  \n"));
3916d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3926d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3936d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, WhitespaceLoneColon) {
3946d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse("  \n:\t  "));
3956d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
3966d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
3976d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, EmptyName) {
3986d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RegisterRule("reg", _))
3996d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .Times(AtMost(1))
4006d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillRepeatedly(Return());
4016d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse("reg: expr1 : expr2"));
4026d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
4036d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4046d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, RuleLoneColon) {
4056d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RegisterRule("r1", "expr"))
4066d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .Times(AtMost(1))
4076d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillRepeatedly(Return());
4086d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse(" r1:   expr   :"));
4096d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
4106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4116d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(Parser, RegNoExprRule) {
4126d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(mock_handler, RegisterRule("r1", "expr"))
4136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .Times(AtMost(1))
4146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillRepeatedly(Return());
4156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_FALSE(parser.Parse("r0: r1:   expr"));
4166d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
4176d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass ParseHandlerFixture: public CFIFixture {
4196d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy public:
4206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ParseHandlerFixture() : CFIFixture(), handler(&cfi) { }
4216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CFIFrameInfoParseHandler handler;
4226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy};
4236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass ParseHandler: public ParseHandlerFixture, public Test { };
4256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(ParseHandler, CFARARule) {
4276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  handler.CFARule("reg-for-cfa");
4286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  handler.RARule("reg-for-ra");
4296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL;
4306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["reg-for-ra"] = 0x6301b475b8b91c02ULL;
4316162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
4326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
4336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]);
4346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]);
4356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
4366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(ParseHandler, RegisterRules) {
4386d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  handler.CFARule("reg-for-cfa");
4396d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  handler.RARule("reg-for-ra");
4406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  handler.RegisterRule("reg1", "reg-for-reg1");
4416d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  handler.RegisterRule("reg2", "reg-for-reg2");
4426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL;
4436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["reg-for-ra"] = 0x6301b475b8b91c02ULL;
4446d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["reg-for-reg1"] = 0x06cde8e2ff062481ULL;
4456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  registers["reg-for-reg2"] = 0xff0c4f76403173e2ULL;
4466162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
4476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            &caller_registers));
4486d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]);
4496d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]);
4506d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers["reg1"]);
4516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers["reg2"]);
4526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
4536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4546d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandystruct SimpleCFIWalkerFixture {
4556d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  struct RawContext {
4566162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    uint64_t r0, r1, r2, r3, r4, sp, pc;
4576d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  };
4586d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  enum Validity {
4596d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    R0_VALID = 0x01,
4606d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    R1_VALID = 0x02,
4616d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    R2_VALID = 0x04,
4626d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    R3_VALID = 0x08,
4636d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    R4_VALID = 0x10,
4646d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    SP_VALID = 0x20,
4656d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    PC_VALID = 0x40
4666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  };
4676162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  typedef SimpleCFIWalker<uint64_t, RawContext> CFIWalker;
4686d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4696d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  SimpleCFIWalkerFixture()
4706d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      : walker(register_map,
4716d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy               sizeof(register_map) / sizeof(register_map[0])) { }
4726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4736d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  static CFIWalker::RegisterSet register_map[7];
4746d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CFIFrameInfo call_frame_info;
4756d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CFIWalker walker;
4766d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  MockMemoryRegion memory;
4776d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  RawContext callee_context, caller_context;
4786d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy};
4796d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4806d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandySimpleCFIWalkerFixture::CFIWalker::RegisterSet
4816d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandySimpleCFIWalkerFixture::register_map[7] = {
4826d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  { "r0", NULL,   true,  R0_VALID, &RawContext::r0 },
4836d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  { "r1", NULL,   true,  R1_VALID, &RawContext::r1 },
4846d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  { "r2", NULL,   false, R2_VALID, &RawContext::r2 },
4856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  { "r3", NULL,   false, R3_VALID, &RawContext::r3 },
4866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  { "r4", NULL,   true,  R4_VALID, &RawContext::r4 },
4876d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  { "sp", ".cfa", true,  SP_VALID, &RawContext::sp },
4886d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  { "pc", ".ra",  true,  PC_VALID, &RawContext::pc },
4896d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy};
4906d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4916d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass SimpleWalker: public SimpleCFIWalkerFixture, public Test { };
4926d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
4936d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(SimpleWalker, Walk) {
4946d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // Stack_top is the current stack pointer, pointing to the lowest
4956d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // address of a frame that looks like this (all 64-bit words):
4966d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  //
4976d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // sp ->  saved r0
4986d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  //        garbage
4996d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  //        return address
5006d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // cfa ->
5016d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  //
5026d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // r0 has been saved on the stack.
5036d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // r1 has been saved in r2.
5046d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // r2 and r3 are not recoverable.
5056d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // r4 is not recoverable, even though it is a callee-saves register.
5066d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  //    Some earlier frame's unwinder must have failed to recover it.
5076d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
5086162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com  uint64_t stack_top = 0x83254944b20d5512ULL;
5096d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
5106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // Saved r0.
5116d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(memory,
5126162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com              GetMemoryAtAddress(stack_top, A<uint64_t *>()))
5136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xdc1975eba8602302ULL),
5146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                            Return(true)));
5156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // Saved return address.
5166d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_CALL(memory,
5176162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com              GetMemoryAtAddress(stack_top + 16, A<uint64_t *>()))
5186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xba5ad6d9acce28deULL),
5196d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                            Return(true)));
5206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
5216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  call_frame_info.SetCFARule("sp 24 +");
5226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  call_frame_info.SetRARule(".cfa 8 - ^");
5236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  call_frame_info.SetRegisterRule("r0", ".cfa 24 - ^");
5246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  call_frame_info.SetRegisterRule("r1", "r2");
5256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
5266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  callee_context.r0 = 0x94e030ca79edd119ULL;
5276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  callee_context.r1 = 0x937b4d7e95ce52d9ULL;
5286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  callee_context.r2 = 0x5fe0027416b8b62aULL; // caller's r1
5296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // callee_context.r3 is not valid in callee.
5306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // callee_context.r4 is not valid in callee.
5316d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  callee_context.sp = stack_top;
5326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  callee_context.pc = 0x25b21b224311d280ULL;
5336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  int callee_validity = R0_VALID | R1_VALID | R2_VALID | SP_VALID | PC_VALID;
5346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
5356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  memset(&caller_context, 0, sizeof(caller_context));
5366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
5376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  int caller_validity;
5386d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_TRUE(walker.FindCallerRegisters(memory, call_frame_info,
5396d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                         callee_context, callee_validity,
5406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                         &caller_context, &caller_validity));
5416d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_EQ(R0_VALID | R1_VALID | SP_VALID | PC_VALID, caller_validity);
5426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_EQ(0xdc1975eba8602302ULL, caller_context.r0);
5436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_EQ(0x5fe0027416b8b62aULL, caller_context.r1);
5446d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_EQ(stack_top + 24,        caller_context.sp);
5456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  EXPECT_EQ(0xba5ad6d9acce28deULL, caller_context.pc);
5466d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
547