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