Home | History | Annotate | Download | only in common
      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 // dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule.
     33 
     34 #include <string>
     35 #include <vector>
     36 
     37 #include "breakpad_googletest_includes.h"
     38 #include "common/dwarf_cfi_to_module.h"
     39 #include "common/using_std_string.h"
     40 
     41 using std::vector;
     42 
     43 using google_breakpad::Module;
     44 using google_breakpad::DwarfCFIToModule;
     45 using testing::ContainerEq;
     46 using testing::Test;
     47 using testing::_;
     48 
     49 struct MockCFIReporter: public DwarfCFIToModule::Reporter {
     50   MockCFIReporter(const string &file, const string &section)
     51       : Reporter(file, section) { }
     52   MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg));
     53   MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string &reg));
     54   MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string &reg));
     55 };
     56 
     57 struct DwarfCFIToModuleFixture {
     58   DwarfCFIToModuleFixture()
     59       : module("module name", "module os", "module arch", "module id"),
     60         reporter("reporter file", "reporter section"),
     61         handler(&module, register_names, &reporter) {
     62     register_names.push_back("reg0");
     63     register_names.push_back("reg1");
     64     register_names.push_back("reg2");
     65     register_names.push_back("reg3");
     66     register_names.push_back("reg4");
     67     register_names.push_back("reg5");
     68     register_names.push_back("reg6");
     69     register_names.push_back("reg7");
     70     register_names.push_back("sp");
     71     register_names.push_back("pc");
     72     register_names.push_back("");
     73 
     74     EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0);
     75     EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0);
     76     EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0);
     77   }
     78 
     79   Module module;
     80   vector<string> register_names;
     81   MockCFIReporter reporter;
     82   DwarfCFIToModule handler;
     83   vector<Module::StackFrameEntry *> entries;
     84 };
     85 
     86 class Entry: public DwarfCFIToModuleFixture, public Test { };
     87 
     88 TEST_F(Entry, Accept) {
     89   ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL,
     90                             0xb440ce248169c8d6ULL, 3, "", 0xea93c106));
     91   ASSERT_TRUE(handler.End());
     92   module.GetStackFrameEntries(&entries);
     93   EXPECT_EQ(1U, entries.size());
     94   EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address);
     95   EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size);
     96   EXPECT_EQ(0U, entries[0]->initial_rules.size());
     97   EXPECT_EQ(0U, entries[0]->rule_changes.size());
     98 }
     99 
    100 TEST_F(Entry, AcceptOldVersion) {
    101   ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL,
    102                             0xc771f44958d40bbcULL, 1, "", 0x093c945e));
    103   ASSERT_TRUE(handler.End());
    104   module.GetStackFrameEntries(&entries);
    105   EXPECT_EQ(1U, entries.size());
    106   EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address);
    107   EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size);
    108   EXPECT_EQ(0U, entries[0]->initial_rules.size());
    109   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    110 }
    111 
    112 struct RuleFixture: public DwarfCFIToModuleFixture {
    113   RuleFixture() : DwarfCFIToModuleFixture() {
    114     entry_address = 0x89327ebf86b47492ULL;
    115     entry_size    = 0x2f8cd573072fe02aULL;
    116     return_reg    = 0x7886a346;
    117   }
    118   void StartEntry() {
    119     ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size,
    120                               3, "", return_reg));
    121   }
    122   void CheckEntry() {
    123     module.GetStackFrameEntries(&entries);
    124     EXPECT_EQ(1U, entries.size());
    125     EXPECT_EQ(entry_address, entries[0]->address);
    126     EXPECT_EQ(entry_size, entries[0]->size);
    127   }
    128   uint64 entry_address, entry_size;
    129   unsigned return_reg;
    130 };
    131 
    132 class Rule: public RuleFixture, public Test { };
    133 
    134 TEST_F(Rule, UndefinedRule) {
    135   EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7"));
    136   StartEntry();
    137   ASSERT_TRUE(handler.UndefinedRule(entry_address, 7));
    138   ASSERT_TRUE(handler.End());
    139   CheckEntry();
    140   EXPECT_EQ(0U, entries[0]->initial_rules.size());
    141   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    142 }
    143 
    144 TEST_F(Rule, RegisterWithEmptyName) {
    145   EXPECT_CALL(reporter, UnnamedRegister(_, 10));
    146   EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10"));
    147   StartEntry();
    148   ASSERT_TRUE(handler.UndefinedRule(entry_address, 10));
    149   ASSERT_TRUE(handler.End());
    150   CheckEntry();
    151   EXPECT_EQ(0U, entries[0]->initial_rules.size());
    152   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    153 }
    154 
    155 TEST_F(Rule, SameValueRule) {
    156   StartEntry();
    157   ASSERT_TRUE(handler.SameValueRule(entry_address, 6));
    158   ASSERT_TRUE(handler.End());
    159   CheckEntry();
    160   Module::RuleMap expected_initial;
    161   expected_initial["reg6"] = "reg6";
    162   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
    163   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    164 }
    165 
    166 TEST_F(Rule, OffsetRule) {
    167   StartEntry();
    168   ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg,
    169                                  DwarfCFIToModule::kCFARegister,
    170                                  16927065));
    171   ASSERT_TRUE(handler.End());
    172   CheckEntry();
    173   EXPECT_EQ(0U, entries[0]->initial_rules.size());
    174   Module::RuleChangeMap expected_changes;
    175   expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^";
    176   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
    177 }
    178 
    179 TEST_F(Rule, OffsetRuleNegative) {
    180   StartEntry();
    181   ASSERT_TRUE(handler.OffsetRule(entry_address + 1,
    182                                  DwarfCFIToModule::kCFARegister, 4, -34530721));
    183   ASSERT_TRUE(handler.End());
    184   CheckEntry();
    185   EXPECT_EQ(0U, entries[0]->initial_rules.size());
    186   Module::RuleChangeMap expected_changes;
    187   expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^";
    188   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
    189 }
    190 
    191 TEST_F(Rule, ValOffsetRule) {
    192   // Use an unnamed register number, to exercise that branch of RegisterName.
    193   EXPECT_CALL(reporter, UnnamedRegister(_, 11));
    194   StartEntry();
    195   ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7,
    196                                     DwarfCFIToModule::kCFARegister,
    197                                     11, 61812979));
    198   ASSERT_TRUE(handler.End());
    199   CheckEntry();
    200   EXPECT_EQ(0U, entries[0]->initial_rules.size());
    201   Module::RuleChangeMap expected_changes;
    202   expected_changes[entry_address + 0x5ab7][".cfa"] =
    203       "unnamed_register11 61812979 +";
    204   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
    205 }
    206 
    207 TEST_F(Rule, RegisterRule) {
    208   StartEntry();
    209   ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3));
    210   ASSERT_TRUE(handler.End());
    211   CheckEntry();
    212   Module::RuleMap expected_initial;
    213   expected_initial[".ra"] = "reg3";
    214   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
    215   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    216 }
    217 
    218 TEST_F(Rule, ExpressionRule) {
    219   EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2"));
    220   StartEntry();
    221   ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2,
    222                                      "it takes two to tango"));
    223   ASSERT_TRUE(handler.End());
    224   CheckEntry();
    225   EXPECT_EQ(0U, entries[0]->initial_rules.size());
    226   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    227 }
    228 
    229 TEST_F(Rule, ValExpressionRule) {
    230   EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0"));
    231   StartEntry();
    232   ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0,
    233                                         "bit off more than he could chew"));
    234   ASSERT_TRUE(handler.End());
    235   CheckEntry();
    236   EXPECT_EQ(0U, entries[0]->initial_rules.size());
    237   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    238 }
    239 
    240 TEST_F(Rule, DefaultReturnAddressRule) {
    241   return_reg = 2;
    242   StartEntry();
    243   ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1));
    244   ASSERT_TRUE(handler.End());
    245   CheckEntry();
    246   Module::RuleMap expected_initial;
    247   expected_initial[".ra"] = "reg2";
    248   expected_initial["reg0"] = "reg1";
    249   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
    250   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    251 }
    252 
    253 TEST_F(Rule, DefaultReturnAddressRuleOverride) {
    254   return_reg = 2;
    255   StartEntry();
    256   ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1));
    257   ASSERT_TRUE(handler.End());
    258   CheckEntry();
    259   Module::RuleMap expected_initial;
    260   expected_initial[".ra"] = "reg1";
    261   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
    262   EXPECT_EQ(0U, entries[0]->rule_changes.size());
    263 }
    264 
    265 TEST_F(Rule, DefaultReturnAddressRuleLater) {
    266   return_reg = 2;
    267   StartEntry();
    268   ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1));
    269   ASSERT_TRUE(handler.End());
    270   CheckEntry();
    271   Module::RuleMap expected_initial;
    272   expected_initial[".ra"] = "reg2";
    273   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
    274   Module::RuleChangeMap expected_changes;
    275   expected_changes[entry_address + 1][".ra"] = "reg1";
    276   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
    277 }
    278 
    279 TEST(RegisterNames, I386) {
    280   vector<string> names = DwarfCFIToModule::RegisterNames::I386();
    281 
    282   EXPECT_EQ("$eax", names[0]);
    283   EXPECT_EQ("$ecx", names[1]);
    284   EXPECT_EQ("$esp", names[4]);
    285   EXPECT_EQ("$eip", names[8]);
    286 }
    287 
    288 TEST(RegisterNames, ARM) {
    289   vector<string> names = DwarfCFIToModule::RegisterNames::ARM();
    290 
    291   EXPECT_EQ("r0", names[0]);
    292   EXPECT_EQ("r10", names[10]);
    293   EXPECT_EQ("sp", names[13]);
    294   EXPECT_EQ("lr", names[14]);
    295   EXPECT_EQ("pc", names[15]);
    296 }
    297 
    298 TEST(RegisterNames, X86_64) {
    299   vector<string> names = DwarfCFIToModule::RegisterNames::X86_64();
    300 
    301   EXPECT_EQ("$rax", names[0]);
    302   EXPECT_EQ("$rdx", names[1]);
    303   EXPECT_EQ("$rbp", names[6]);
    304   EXPECT_EQ("$rsp", names[7]);
    305   EXPECT_EQ("$rip", names[16]);
    306 }
    307