/ src / common / dwarf_cfi_to_module_unittest.cc
dwarf_cfi_to_module_unittest.cc
  1  // Copyright 2010 Google LLC
  2  //
  3  // Redistribution and use in source and binary forms, with or without
  4  // modification, are permitted provided that the following conditions are
  5  // met:
  6  //
  7  //     * Redistributions of source code must retain the above copyright
  8  // notice, this list of conditions and the following disclaimer.
  9  //     * Redistributions in binary form must reproduce the above
 10  // copyright notice, this list of conditions and the following disclaimer
 11  // in the documentation and/or other materials provided with the
 12  // distribution.
 13  //     * Neither the name of Google LLC nor the names of its
 14  // contributors may be used to endorse or promote products derived from
 15  // this software without specific prior written permission.
 16  //
 17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  
 29  // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
 30  
 31  // dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule.
 32  
 33  #ifdef HAVE_CONFIG_H
 34  #include <config.h>  // Must come first
 35  #endif
 36  
 37  #include <string>
 38  #include <vector>
 39  
 40  #include "breakpad_googletest_includes.h"
 41  #include "common/dwarf_cfi_to_module.h"
 42  #include "common/using_std_string.h"
 43  
 44  using std::vector;
 45  
 46  using google_breakpad::Module;
 47  using google_breakpad::DwarfCFIToModule;
 48  using testing::ContainerEq;
 49  using testing::Test;
 50  using testing::_;
 51  
 52  struct MockCFIReporter: public DwarfCFIToModule::Reporter {
 53    MockCFIReporter(const string& file, const string& section)
 54        : Reporter(file, section) { }
 55    MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg));
 56    MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string& reg));
 57    MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string& reg));
 58  };
 59  
 60  struct DwarfCFIToModuleFixture {
 61    DwarfCFIToModuleFixture()
 62        : module("module name", "module os", "module arch", "module id"),
 63          reporter("reporter file", "reporter section"),
 64          handler(&module, register_names, &reporter) {
 65      register_names.push_back("reg0");
 66      register_names.push_back("reg1");
 67      register_names.push_back("reg2");
 68      register_names.push_back("reg3");
 69      register_names.push_back("reg4");
 70      register_names.push_back("reg5");
 71      register_names.push_back("reg6");
 72      register_names.push_back("reg7");
 73      register_names.push_back("sp");
 74      register_names.push_back("pc");
 75      register_names.push_back("");
 76  
 77      EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0);
 78      EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0);
 79      EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0);
 80    }
 81  
 82    Module module;
 83    vector<string> register_names;
 84    MockCFIReporter reporter;
 85    DwarfCFIToModule handler;
 86    vector<Module::StackFrameEntry*> entries;
 87  };
 88  
 89  class Entry: public DwarfCFIToModuleFixture, public Test { };
 90  
 91  TEST_F(Entry, Accept) {
 92    ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL,
 93                              0xb440ce248169c8d6ULL, 3, "", 0xea93c106));
 94    ASSERT_TRUE(handler.End());
 95    module.GetStackFrameEntries(&entries);
 96    EXPECT_EQ(1U, entries.size());
 97    EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address);
 98    EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size);
 99    EXPECT_EQ(0U, entries[0]->initial_rules.size());
100    EXPECT_EQ(0U, entries[0]->rule_changes.size());
101  }
102  
103  TEST_F(Entry, AcceptOldVersion) {
104    ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL,
105                              0xc771f44958d40bbcULL, 1, "", 0x093c945e));
106    ASSERT_TRUE(handler.End());
107    module.GetStackFrameEntries(&entries);
108    EXPECT_EQ(1U, entries.size());
109    EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address);
110    EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size);
111    EXPECT_EQ(0U, entries[0]->initial_rules.size());
112    EXPECT_EQ(0U, entries[0]->rule_changes.size());
113  }
114  
115  struct RuleFixture: public DwarfCFIToModuleFixture {
116    RuleFixture() : DwarfCFIToModuleFixture() {
117      entry_address = 0x89327ebf86b47492ULL;
118      entry_size    = 0x2f8cd573072fe02aULL;
119      return_reg    = 0x7886a346;
120    }
121    void StartEntry() {
122      ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size,
123                                3, "", return_reg));
124    }
125    void CheckEntry() {
126      module.GetStackFrameEntries(&entries);
127      EXPECT_EQ(1U, entries.size());
128      EXPECT_EQ(entry_address, entries[0]->address);
129      EXPECT_EQ(entry_size, entries[0]->size);
130    }
131    uint64_t entry_address, entry_size;
132    unsigned return_reg;
133  };
134  
135  class Rule: public RuleFixture, public Test { };
136  
137  TEST_F(Rule, UndefinedRule) {
138    EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7"));
139    StartEntry();
140    ASSERT_TRUE(handler.UndefinedRule(entry_address, 7));
141    ASSERT_TRUE(handler.End());
142    CheckEntry();
143    EXPECT_EQ(0U, entries[0]->initial_rules.size());
144    EXPECT_EQ(0U, entries[0]->rule_changes.size());
145  }
146  
147  TEST_F(Rule, RegisterWithEmptyName) {
148    EXPECT_CALL(reporter, UnnamedRegister(_, 10));
149    EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10"));
150    StartEntry();
151    ASSERT_TRUE(handler.UndefinedRule(entry_address, 10));
152    ASSERT_TRUE(handler.End());
153    CheckEntry();
154    EXPECT_EQ(0U, entries[0]->initial_rules.size());
155    EXPECT_EQ(0U, entries[0]->rule_changes.size());
156  }
157  
158  TEST_F(Rule, SameValueRule) {
159    StartEntry();
160    ASSERT_TRUE(handler.SameValueRule(entry_address, 6));
161    ASSERT_TRUE(handler.End());
162    CheckEntry();
163    Module::RuleMap expected_initial;
164    expected_initial["reg6"] = "reg6";
165    EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
166    EXPECT_EQ(0U, entries[0]->rule_changes.size());
167  }
168  
169  TEST_F(Rule, OffsetRule) {
170    StartEntry();
171    ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg,
172                                   DwarfCFIToModule::kCFARegister,
173                                   16927065));
174    ASSERT_TRUE(handler.End());
175    CheckEntry();
176    EXPECT_EQ(0U, entries[0]->initial_rules.size());
177    Module::RuleChangeMap expected_changes;
178    expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^";
179    EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
180  }
181  
182  TEST_F(Rule, OffsetRuleNegative) {
183    StartEntry();
184    ASSERT_TRUE(handler.OffsetRule(entry_address + 1,
185                                   DwarfCFIToModule::kCFARegister, 4, -34530721));
186    ASSERT_TRUE(handler.End());
187    CheckEntry();
188    EXPECT_EQ(0U, entries[0]->initial_rules.size());
189    Module::RuleChangeMap expected_changes;
190    expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^";
191    EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
192  }
193  
194  TEST_F(Rule, ValOffsetRule) {
195    // Use an unnamed register number, to exercise that branch of RegisterName.
196    EXPECT_CALL(reporter, UnnamedRegister(_, 11));
197    StartEntry();
198    ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7,
199                                      DwarfCFIToModule::kCFARegister,
200                                      11, 61812979));
201    ASSERT_TRUE(handler.End());
202    CheckEntry();
203    EXPECT_EQ(0U, entries[0]->initial_rules.size());
204    Module::RuleChangeMap expected_changes;
205    expected_changes[entry_address + 0x5ab7][".cfa"] =
206        "unnamed_register11 61812979 +";
207    EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
208  }
209  
210  TEST_F(Rule, RegisterRule) {
211    StartEntry();
212    ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3));
213    ASSERT_TRUE(handler.End());
214    CheckEntry();
215    Module::RuleMap expected_initial;
216    expected_initial[".ra"] = "reg3";
217    EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
218    EXPECT_EQ(0U, entries[0]->rule_changes.size());
219  }
220  
221  TEST_F(Rule, ExpressionRule) {
222    EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2"));
223    StartEntry();
224    ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2,
225                                       "it takes two to tango"));
226    ASSERT_TRUE(handler.End());
227    CheckEntry();
228    EXPECT_EQ(0U, entries[0]->initial_rules.size());
229    EXPECT_EQ(0U, entries[0]->rule_changes.size());
230  }
231  
232  TEST_F(Rule, ValExpressionRule) {
233    EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0"));
234    StartEntry();
235    ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0,
236                                          "bit off more than he could chew"));
237    ASSERT_TRUE(handler.End());
238    CheckEntry();
239    EXPECT_EQ(0U, entries[0]->initial_rules.size());
240    EXPECT_EQ(0U, entries[0]->rule_changes.size());
241  }
242  
243  TEST_F(Rule, DefaultReturnAddressRule) {
244    return_reg = 2;
245    StartEntry();
246    ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1));
247    ASSERT_TRUE(handler.End());
248    CheckEntry();
249    Module::RuleMap expected_initial;
250    expected_initial[".ra"] = "reg2";
251    expected_initial["reg0"] = "reg1";
252    EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
253    EXPECT_EQ(0U, entries[0]->rule_changes.size());
254  }
255  
256  TEST_F(Rule, DefaultReturnAddressRuleOverride) {
257    return_reg = 2;
258    StartEntry();
259    ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1));
260    ASSERT_TRUE(handler.End());
261    CheckEntry();
262    Module::RuleMap expected_initial;
263    expected_initial[".ra"] = "reg1";
264    EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
265    EXPECT_EQ(0U, entries[0]->rule_changes.size());
266  }
267  
268  TEST_F(Rule, DefaultReturnAddressRuleLater) {
269    return_reg = 2;
270    StartEntry();
271    ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1));
272    ASSERT_TRUE(handler.End());
273    CheckEntry();
274    Module::RuleMap expected_initial;
275    expected_initial[".ra"] = "reg2";
276    EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
277    Module::RuleChangeMap expected_changes;
278    expected_changes[entry_address + 1][".ra"] = "reg1";
279    EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
280  }
281  
282  TEST(RegisterNames, I386) {
283    vector<string> names = DwarfCFIToModule::RegisterNames::I386();
284  
285    EXPECT_EQ("$eax", names[0]);
286    EXPECT_EQ("$ecx", names[1]);
287    EXPECT_EQ("$esp", names[4]);
288    EXPECT_EQ("$eip", names[8]);
289  }
290  
291  TEST(RegisterNames, ARM) {
292    vector<string> names = DwarfCFIToModule::RegisterNames::ARM();
293  
294    EXPECT_EQ("r0", names[0]);
295    EXPECT_EQ("r10", names[10]);
296    EXPECT_EQ("sp", names[13]);
297    EXPECT_EQ("lr", names[14]);
298    EXPECT_EQ("pc", names[15]);
299  }
300  
301  TEST(RegisterNames, X86_64) {
302    vector<string> names = DwarfCFIToModule::RegisterNames::X86_64();
303  
304    EXPECT_EQ("$rax", names[0]);
305    EXPECT_EQ("$rdx", names[1]);
306    EXPECT_EQ("$rbp", names[6]);
307    EXPECT_EQ("$rsp", names[7]);
308    EXPECT_EQ("$rip", names[16]);
309  }
310  
311  TEST(RegisterNames, RISCV) {
312    vector<string> names = DwarfCFIToModule::RegisterNames::RISCV();
313  
314    EXPECT_EQ("pc", names[0]);
315    EXPECT_EQ("t6", names[31]);
316    EXPECT_EQ("f0", names[32]);
317    EXPECT_EQ("f31", names[63]);
318    EXPECT_EQ("v0", names[96]);
319    EXPECT_EQ("v31", names[127]);
320  }
321