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 // module_unittest.cc: Unit tests for google_breakpad::Module. 32 33 #ifdef HAVE_CONFIG_H 34 #include <config.h> // Must come first 35 #endif 36 37 #include <errno.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 42 #include <algorithm> 43 #include <memory> 44 #include <sstream> 45 #include <string> 46 #include <utility> 47 48 #include "breakpad_googletest_includes.h" 49 #include "common/module.h" 50 #include "common/using_std_string.h" 51 52 using google_breakpad::Module; 53 using google_breakpad::StringView; 54 using std::stringstream; 55 using std::vector; 56 using testing::ContainerEq; 57 58 static Module::Function* generate_duplicate_function(StringView name) { 59 const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cULL; 60 const Module::Address DUP_SIZE = 0x200b26e605f99071ULL; 61 const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99ULL; 62 63 Module::Function* function = new Module::Function(name, DUP_ADDRESS); 64 Module::Range range(DUP_ADDRESS, DUP_SIZE); 65 function->ranges.push_back(range); 66 function->parameter_size = DUP_PARAMETER_SIZE; 67 return function; 68 } 69 70 #define MODULE_NAME "name with spaces" 71 #define MODULE_OS "os-name" 72 #define MODULE_ARCH "architecture" 73 #define MODULE_ID "id-string" 74 #define MODULE_CODE_ID "code-id-string" 75 76 TEST(Module, WriteHeader) { 77 stringstream s; 78 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 79 m.Write(s, ALL_SYMBOL_DATA); 80 string contents = s.str(); 81 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", 82 contents.c_str()); 83 } 84 85 TEST(Module, WriteHeaderCodeId) { 86 stringstream s; 87 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, MODULE_CODE_ID); 88 m.Write(s, ALL_SYMBOL_DATA); 89 string contents = s.str(); 90 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 91 "INFO CODE_ID code-id-string\n", 92 contents.c_str()); 93 } 94 95 TEST(Module, WriteOneLineFunc) { 96 stringstream s; 97 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 98 99 Module::File* file = m.FindFile("file_name.cc"); 100 Module::Function* function = new Module::Function( 101 "function_name", 0xe165bf8023b9d9abULL); 102 Module::Range range(0xe165bf8023b9d9abULL, 0x1e4bb0eb1cbf5b09ULL); 103 function->ranges.push_back(range); 104 function->parameter_size = 0x772beee89114358aULL; 105 Module::Line line = { 0xe165bf8023b9d9abULL, 0x1e4bb0eb1cbf5b09ULL, 106 file, 67519080 }; 107 function->lines.push_back(line); 108 m.AddFunction(function); 109 110 m.Write(s, ALL_SYMBOL_DATA); 111 string contents = s.str(); 112 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 113 "FILE 0 file_name.cc\n" 114 "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" 115 " function_name\n" 116 "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", 117 contents.c_str()); 118 } 119 120 TEST(Module, WriteRelativeLoadAddress) { 121 stringstream s; 122 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 123 124 // Some source files. We will expect to see them in lexicographic order. 125 Module::File* file1 = m.FindFile("filename-b.cc"); 126 Module::File* file2 = m.FindFile("filename-a.cc"); 127 128 // A function. 129 Module::Function* function = new Module::Function( 130 "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3ULL); 131 Module::Range range(0xbec774ea5dd935f3ULL, 0x2922088f98d3f6fcULL); 132 function->ranges.push_back(range); 133 function->parameter_size = 0xe5e9aa008bd5f0d0ULL; 134 135 // Some source lines. The module should not sort these. 136 Module::Line line1 = { 0xbec774ea5dd935f3ULL, 0x1c2be6d6c5af2611ULL, 137 file1, 41676901 }; 138 Module::Line line2 = { 0xdaf35bc123885c04ULL, 0xcf621b8d324d0ebULL, 139 file2, 67519080 }; 140 function->lines.push_back(line2); 141 function->lines.push_back(line1); 142 143 m.AddFunction(function); 144 145 // Some stack information. 146 auto entry = std::make_unique<Module::StackFrameEntry>(); 147 entry->address = 0x30f9e5c83323973dULL; 148 entry->size = 0x49fc9ca7c7c13dc2ULL; 149 entry->initial_rules[".cfa"] = "he was a handsome man"; 150 entry->initial_rules["and"] = "what i want to know is"; 151 entry->rule_changes[0x30f9e5c83323973eULL]["how"] = 152 "do you like your blueeyed boy"; 153 entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; 154 m.AddStackFrameEntry(std::move(entry)); 155 156 // Set the load address. Doing this after adding all the data to 157 // the module must work fine. 158 m.SetLoadAddress(0x2ab698b0b6407073ULL); 159 160 m.Write(s, ALL_SYMBOL_DATA); 161 string contents = s.str(); 162 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 163 "FILE 0 filename-a.cc\n" 164 "FILE 1 filename-b.cc\n" 165 "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" 166 " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" 167 "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" 168 "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" 169 "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" 170 " .cfa: he was a handsome man" 171 " and: what i want to know is\n" 172 "STACK CFI 6434d177ce326cb" 173 " Mister: Death" 174 " how: do you like your blueeyed boy\n", 175 contents.c_str()); 176 } 177 178 TEST(Module, WriteOmitUnusedFiles) { 179 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 180 181 // Create some source files. 182 Module::File* file1 = m.FindFile("filename1"); 183 m.FindFile("filename2"); // not used by any line 184 Module::File* file3 = m.FindFile("filename3"); 185 186 // Create a function. 187 Module::Function* function = new Module::Function( 188 "function_name", 0x9b926d464f0b9384ULL); 189 Module::Range range(0x9b926d464f0b9384ULL, 0x4f524a4ba795e6a6ULL); 190 function->ranges.push_back(range); 191 function->parameter_size = 0xbbe8133a6641c9b7ULL; 192 193 // Source files that refer to some files, but not others. 194 Module::Line line1 = { 0xab415089485e1a20ULL, 0x126e3124979291f2ULL, 195 file1, 137850127 }; 196 Module::Line line2 = { 0xb2675b5c3c2ed33fULL, 0x1df77f5551dbd68cULL, 197 file3, 28113549 }; 198 function->lines.push_back(line1); 199 function->lines.push_back(line2); 200 m.AddFunction(function); 201 m.AssignSourceIds(); 202 203 vector<Module::File*> vec; 204 m.GetFiles(&vec); 205 EXPECT_EQ((size_t) 3, vec.size()); 206 EXPECT_STREQ("filename1", vec[0]->name.c_str()); 207 EXPECT_NE(-1, vec[0]->source_id); 208 // Expect filename2 not to be used. 209 EXPECT_STREQ("filename2", vec[1]->name.c_str()); 210 EXPECT_EQ(-1, vec[1]->source_id); 211 EXPECT_STREQ("filename3", vec[2]->name.c_str()); 212 EXPECT_NE(-1, vec[2]->source_id); 213 214 stringstream s; 215 m.Write(s, ALL_SYMBOL_DATA); 216 string contents = s.str(); 217 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 218 "FILE 0 filename1\n" 219 "FILE 1 filename3\n" 220 "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" 221 " function_name\n" 222 "ab415089485e1a20 126e3124979291f2 137850127 0\n" 223 "b2675b5c3c2ed33f 1df77f5551dbd68c 28113549 1\n", 224 contents.c_str()); 225 } 226 227 TEST(Module, WriteNoCFI) { 228 stringstream s; 229 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 230 231 // Some source files. We will expect to see them in lexicographic order. 232 Module::File* file1 = m.FindFile("filename.cc"); 233 234 // A function. 235 Module::Function* function = new Module::Function( 236 "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3ULL); 237 Module::Range range(0xbec774ea5dd935f3ULL, 0x2922088f98d3f6fcULL); 238 function->ranges.push_back(range); 239 function->parameter_size = 0xe5e9aa008bd5f0d0ULL; 240 241 // Some source lines. The module should not sort these. 242 Module::Line line1 = { 0xbec774ea5dd935f3ULL, 0x1c2be6d6c5af2611ULL, 243 file1, 41676901 }; 244 function->lines.push_back(line1); 245 246 m.AddFunction(function); 247 248 // Some stack information. 249 auto entry = std::make_unique<Module::StackFrameEntry>(); 250 entry->address = 0x30f9e5c83323973dULL; 251 entry->size = 0x49fc9ca7c7c13dc2ULL; 252 entry->initial_rules[".cfa"] = "he was a handsome man"; 253 entry->initial_rules["and"] = "what i want to know is"; 254 entry->rule_changes[0x30f9e5c83323973eULL]["how"] = 255 "do you like your blueeyed boy"; 256 entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; 257 m.AddStackFrameEntry(std::move(entry)); 258 259 // Set the load address. Doing this after adding all the data to 260 // the module must work fine. 261 m.SetLoadAddress(0x2ab698b0b6407073ULL); 262 263 m.Write(s, SYMBOLS_AND_FILES | INLINES); 264 string contents = s.str(); 265 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 266 "FILE 0 filename.cc\n" 267 "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" 268 " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" 269 "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n", 270 contents.c_str()); 271 } 272 273 TEST(Module, ConstructAddFunction) { 274 stringstream s; 275 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 276 277 // Two functions. 278 Module::Function* function1 = new Module::Function( 279 "_without_form", 0xd35024aa7ca7da5cULL); 280 Module::Range r1(0xd35024aa7ca7da5cULL, 0x200b26e605f99071ULL); 281 function1->ranges.push_back(r1); 282 function1->parameter_size = 0xf14ac4fed48c4a99ULL; 283 284 Module::Function* function2 = new Module::Function( 285 "_and_void", 0x2987743d0b35b13fULL); 286 Module::Range r2(0x2987743d0b35b13fULL, 0xb369db048deb3010ULL); 287 function2->ranges.push_back(r2); 288 function2->parameter_size = 0x938e556cb5a79988ULL; 289 290 // Put them in a vector. 291 vector<Module::Function*> vec; 292 vec.push_back(function1); 293 vec.push_back(function2); 294 295 for (Module::Function* func: vec) 296 m.AddFunction(func); 297 298 m.Write(s, ALL_SYMBOL_DATA); 299 string contents = s.str(); 300 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 301 "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" 302 " _and_void\n" 303 "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" 304 " _without_form\n", 305 contents.c_str()); 306 307 // Check that m.GetFunctions returns the functions we expect. 308 vec.clear(); 309 m.GetFunctions(&vec, vec.end()); 310 EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); 311 EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); 312 EXPECT_EQ((size_t) 2, vec.size()); 313 } 314 315 TEST(Module, WriteOutOfRangeAddresses) { 316 stringstream s; 317 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 318 319 // Specify an allowed address range, representing a PT_LOAD segment in a 320 // module. 321 vector<Module::Range> address_ranges = { 322 Module::Range(0x2000ULL, 0x1000ULL), 323 }; 324 m.SetAddressRanges(address_ranges); 325 326 // Add three stack frames (one lower, one in, and one higher than the allowed 327 // address range). Only the middle frame should be captured. 328 auto entry1 = std::make_unique<Module::StackFrameEntry>(); 329 entry1->address = 0x1000ULL; 330 entry1->size = 0x100ULL; 331 m.AddStackFrameEntry(std::move(entry1)); 332 auto entry2 = std::make_unique<Module::StackFrameEntry>(); 333 entry2->address = 0x2000ULL; 334 entry2->size = 0x100ULL; 335 m.AddStackFrameEntry(std::move(entry2)); 336 auto entry3 = std::make_unique<Module::StackFrameEntry>(); 337 entry3->address = 0x3000ULL; 338 entry3->size = 0x100ULL; 339 m.AddStackFrameEntry(std::move(entry3)); 340 341 // Add a function outside the allowed range. 342 Module::File* file = m.FindFile("file_name.cc"); 343 Module::Function* function = new Module::Function( 344 "function_name", 0x4000ULL); 345 Module::Range range(0x4000ULL, 0x1000ULL); 346 function->ranges.push_back(range); 347 function->parameter_size = 0x100ULL; 348 Module::Line line = { 0x4000ULL, 0x100ULL, file, 67519080 }; 349 function->lines.push_back(line); 350 m.AddFunction(function); 351 352 // Add an extern outside the allowed range. 353 auto extern1 = std::make_unique<Module::Extern>(0x5000ULL); 354 extern1->name = "_xyz"; 355 m.AddExtern(std::move(extern1)); 356 357 m.Write(s, ALL_SYMBOL_DATA); 358 359 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 360 "STACK CFI INIT 2000 100 \n", 361 s.str().c_str()); 362 363 // Cleanup - Prevent Memory Leak errors. 364 delete (function); 365 } 366 367 TEST(Module, ConstructAddFrames) { 368 stringstream s; 369 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 370 371 // First STACK CFI entry, with no initial rules or deltas. 372 auto entry1 = std::make_unique<Module::StackFrameEntry>(); 373 entry1->address = 0xddb5f41285aa7757ULL; 374 entry1->size = 0x1486493370dc5073ULL; 375 m.AddStackFrameEntry(std::move(entry1)); 376 377 // Second STACK CFI entry, with initial rules but no deltas. 378 auto entry2 = std::make_unique<Module::StackFrameEntry>(); 379 entry2->address = 0x8064f3af5e067e38ULL; 380 entry2->size = 0x0de2a5ee55509407ULL; 381 entry2->initial_rules[".cfa"] = "I think that I shall never see"; 382 entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; 383 entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; 384 m.AddStackFrameEntry(std::move(entry2)); 385 386 // Third STACK CFI entry, with initial rules and deltas. 387 auto entry3 = std::make_unique<Module::StackFrameEntry>(); 388 entry3->address = 0x5e8d0db0a7075c6cULL; 389 entry3->size = 0x1c7edb12a7aea229ULL; 390 entry3->initial_rules[".cfa"] = "Whose woods are these"; 391 entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = 392 "the village though"; 393 entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = 394 "he will not see me stopping here"; 395 entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = 396 "his house is in"; 397 entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = 398 "I think I know"; 399 m.AddStackFrameEntry(std::move(entry3)); 400 401 // Check that Write writes STACK CFI records properly. 402 m.Write(s, ALL_SYMBOL_DATA); 403 string contents = s.str(); 404 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 405 "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n" 406 "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" 407 " .cfa: I think that I shall never see" 408 " cannoli: a tree whose hungry mouth is prest" 409 " stromboli: a poem lovely as a tree\n" 410 "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" 411 " .cfa: Whose woods are these\n" 412 "STACK CFI 36682fad3763ffff" 413 " .cfa: I think I know" 414 " stromboli: his house is in\n" 415 "STACK CFI 47ceb0f63c269d7f" 416 " calzone: the village though" 417 " cannoli: he will not see me stopping here\n", 418 contents.c_str()); 419 420 // Check that GetStackFrameEntries works. 421 vector<Module::StackFrameEntry*> entries; 422 m.GetStackFrameEntries(&entries); 423 ASSERT_EQ(3U, entries.size()); 424 // Check first entry. 425 EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address); 426 EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size); 427 ASSERT_EQ(0U, entries[0]->initial_rules.size()); 428 ASSERT_EQ(0U, entries[0]->rule_changes.size()); 429 // Check second entry. 430 EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); 431 EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); 432 ASSERT_EQ(3U, entries[1]->initial_rules.size()); 433 Module::RuleMap entry2_initial; 434 entry2_initial[".cfa"] = "I think that I shall never see"; 435 entry2_initial["stromboli"] = "a poem lovely as a tree"; 436 entry2_initial["cannoli"] = "a tree whose hungry mouth is prest"; 437 EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); 438 ASSERT_EQ(0U, entries[1]->rule_changes.size()); 439 // Check third entry. 440 EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address); 441 EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size); 442 Module::RuleMap entry3_initial; 443 entry3_initial[".cfa"] = "Whose woods are these"; 444 EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial)); 445 Module::RuleChangeMap entry3_changes; 446 entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; 447 entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; 448 entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; 449 entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] = 450 "he will not see me stopping here"; 451 EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes)); 452 } 453 454 TEST(Module, ConstructUniqueFiles) { 455 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 456 Module::File* file1 = m.FindFile("foo"); 457 Module::File* file2 = m.FindFile(string("bar")); 458 Module::File* file3 = m.FindFile(string("foo")); 459 Module::File* file4 = m.FindFile("bar"); 460 EXPECT_NE(file1, file2); 461 EXPECT_EQ(file1, file3); 462 EXPECT_EQ(file2, file4); 463 EXPECT_EQ(file1, m.FindExistingFile("foo")); 464 EXPECT_TRUE(m.FindExistingFile("baz") == NULL); 465 } 466 467 TEST(Module, ConstructDuplicateFunctions) { 468 stringstream s; 469 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 470 471 // Two functions. 472 Module::Function* function1 = generate_duplicate_function("_without_form"); 473 Module::Function* function2 = generate_duplicate_function("_without_form"); 474 475 m.AddFunction(function1); 476 // If this succeeds, we'll have a double-free with the `delete` below. Avoid 477 // that. 478 ASSERT_FALSE(m.AddFunction(function2)); 479 delete function2; 480 481 m.Write(s, ALL_SYMBOL_DATA); 482 string contents = s.str(); 483 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 484 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" 485 " _without_form\n", 486 contents.c_str()); 487 } 488 489 TEST(Module, ConstructFunctionsWithSameAddress) { 490 stringstream s; 491 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 492 493 // Two functions. 494 Module::Function* function1 = generate_duplicate_function("_without_form"); 495 Module::Function* function2 = generate_duplicate_function("_and_void"); 496 497 m.AddFunction(function1); 498 m.AddFunction(function2); 499 500 m.Write(s, ALL_SYMBOL_DATA); 501 string contents = s.str(); 502 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 503 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" 504 " _and_void\n" 505 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" 506 " _without_form\n", 507 contents.c_str()); 508 } 509 510 // If multiple fields are enabled, only one function is included per address. 511 // The entry will be tagged with `m` to show that there are multiple symbols 512 // at that address. 513 // TODO(lgrey): Remove the non-multiple versions of these tests and remove the 514 // suffixes from the suffxed ones when removing `enable_multiple_field_`. 515 TEST(Module, ConstructFunctionsWithSameAddressMultiple) { 516 stringstream s; 517 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true); 518 519 // Two functions. 520 Module::Function* function1 = generate_duplicate_function("_without_form"); 521 Module::Function* function2 = generate_duplicate_function("_and_void"); 522 523 m.AddFunction(function1); 524 // If this succeeds, we'll have a double-free with the `delete` below. Avoid 525 // that. 526 ASSERT_FALSE(m.AddFunction(function2)); 527 delete function2; 528 529 m.Write(s, ALL_SYMBOL_DATA); 530 string contents = s.str(); 531 EXPECT_STREQ( 532 "MODULE os-name architecture id-string name with spaces\n" 533 "FUNC m d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" 534 " _without_form\n", 535 contents.c_str()); 536 } 537 538 // Externs should be written out as PUBLIC records, sorted by 539 // address. 540 TEST(Module, ConstructExterns) { 541 stringstream s; 542 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 543 544 // Two externs. 545 auto extern1 = std::make_unique<Module::Extern>(0xffff); 546 extern1->name = "_abc"; 547 auto extern2 = std::make_unique<Module::Extern>(0xaaaa); 548 extern2->name = "_xyz"; 549 550 m.AddExtern(std::move(extern1)); 551 m.AddExtern(std::move(extern2)); 552 553 m.Write(s, ALL_SYMBOL_DATA); 554 string contents = s.str(); 555 556 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " 557 MODULE_ID " " MODULE_NAME "\n" 558 "PUBLIC aaaa 0 _xyz\n" 559 "PUBLIC ffff 0 _abc\n", 560 contents.c_str()); 561 } 562 563 // Externs with the same address should only keep the first entry 564 // added. 565 TEST(Module, ConstructDuplicateExterns) { 566 stringstream s; 567 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 568 569 // Two externs. 570 auto extern1 = std::make_unique<Module::Extern>(0xffff); 571 extern1->name = "_xyz"; 572 auto extern2 = std::make_unique<Module::Extern>(0xffff); 573 extern2->name = "_abc"; 574 575 m.AddExtern(std::move(extern1)); 576 m.AddExtern(std::move(extern2)); 577 578 m.Write(s, ALL_SYMBOL_DATA); 579 string contents = s.str(); 580 581 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " 582 MODULE_ID " " MODULE_NAME "\n" 583 "PUBLIC ffff 0 _xyz\n", 584 contents.c_str()); 585 } 586 // Externs with the same address have the `m` tag if the multiple field are 587 // enabled. 588 TEST(Module, ConstructDuplicateExternsMultiple) { 589 stringstream s; 590 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true); 591 592 // Two externs. 593 auto extern1 = std::make_unique<Module::Extern>(0xffff); 594 extern1->name = "_xyz"; 595 auto extern2 = std::make_unique<Module::Extern>(0xffff); 596 extern2->name = "_abc"; 597 598 m.AddExtern(std::move(extern1)); 599 m.AddExtern(std::move(extern2)); 600 601 m.Write(s, ALL_SYMBOL_DATA); 602 string contents = s.str(); 603 604 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME 605 "\n" 606 "PUBLIC m ffff 0 _xyz\n", 607 contents.c_str()); 608 } 609 610 // If there exists an extern and a function at the same address, only write 611 // out the FUNC entry. 612 TEST(Module, ConstructFunctionsAndExternsWithSameAddress) { 613 stringstream s; 614 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 615 616 // Two externs. 617 auto extern1 = std::make_unique<Module::Extern>(0xabc0); 618 extern1->name = "abc"; 619 auto extern2 = std::make_unique<Module::Extern>(0xfff0); 620 extern2->name = "xyz"; 621 622 m.AddExtern(std::move(extern1)); 623 m.AddExtern(std::move(extern2)); 624 625 Module::Function* function = new Module::Function("_xyz", 0xfff0); 626 Module::Range range(0xfff0, 0x10); 627 function->ranges.push_back(range); 628 function->parameter_size = 0; 629 m.AddFunction(function); 630 631 m.Write(s, ALL_SYMBOL_DATA); 632 string contents = s.str(); 633 634 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " 635 MODULE_ID " " MODULE_NAME "\n" 636 "FUNC fff0 10 0 _xyz\n" 637 "PUBLIC abc0 0 abc\n", 638 contents.c_str()); 639 } 640 641 // If there exists an extern and a function at the same address, only write 642 // out the FUNC entry. 643 TEST(Module, ConstructFunctionsAndExternsWithSameAddressPreferExternName) { 644 stringstream s; 645 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", false, true); 646 647 // Two externs. 648 auto extern1 = std::make_unique<Module::Extern>(0xabc0); 649 extern1->name = "extern1"; 650 auto extern2 = std::make_unique<Module::Extern>(0xfff0); 651 extern2->name = "extern2"; 652 653 m.AddExtern(std::move(extern1)); 654 m.AddExtern(std::move(extern2)); 655 656 Module::Function* function = new Module::Function("function2", 0xfff0); 657 Module::Range range(0xfff0, 0x10); 658 function->ranges.push_back(range); 659 function->parameter_size = 0; 660 m.AddFunction(function); 661 662 m.Write(s, ALL_SYMBOL_DATA); 663 string contents = s.str(); 664 665 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME 666 "\n" 667 "FUNC fff0 10 0 extern2\n" 668 "PUBLIC abc0 0 extern1\n", 669 contents.c_str()); 670 } 671 672 // If there exists an extern and a function at the same address, only write 673 // out the FUNC entry, and mark it with `m` if the multiple field is enabled. 674 TEST(Module, ConstructFunctionsAndExternsWithSameAddressMultiple) { 675 stringstream s; 676 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true); 677 678 // Two externs. 679 auto extern1 = std::make_unique<Module::Extern>(0xabc0); 680 extern1->name = "abc"; 681 auto extern2 = std::make_unique<Module::Extern>(0xfff0); 682 extern2->name = "xyz"; 683 684 m.AddExtern(std::move(extern1)); 685 m.AddExtern(std::move(extern2)); 686 687 Module::Function* function = new Module::Function("_xyz", 0xfff0); 688 Module::Range range(0xfff0, 0x10); 689 function->ranges.push_back(range); 690 function->parameter_size = 0; 691 m.AddFunction(function); 692 693 m.Write(s, ALL_SYMBOL_DATA); 694 string contents = s.str(); 695 696 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME 697 "\n" 698 "FUNC m fff0 10 0 _xyz\n" 699 "PUBLIC abc0 0 abc\n", 700 contents.c_str()); 701 } 702 703 // If there exists an extern and a function at the same address, only write 704 // out the FUNC entry. For ARM THUMB, the extern that comes from the ELF 705 // symbol section has bit 0 set. 706 TEST(Module, ConstructFunctionsAndThumbExternsWithSameAddress) { 707 stringstream s; 708 Module m(MODULE_NAME, MODULE_OS, "arm", MODULE_ID); 709 710 // Two THUMB externs. 711 auto thumb_extern1 = std::make_unique<Module::Extern>(0xabc1); 712 thumb_extern1->name = "thumb_abc"; 713 auto thumb_extern2 = std::make_unique<Module::Extern>(0xfff1); 714 thumb_extern2->name = "thumb_xyz"; 715 716 auto arm_extern1 = std::make_unique<Module::Extern>(0xcc00); 717 arm_extern1->name = "arm_func"; 718 719 m.AddExtern(std::move(thumb_extern1)); 720 m.AddExtern(std::move(thumb_extern2)); 721 m.AddExtern(std::move(arm_extern1)); 722 723 // The corresponding function from the DWARF debug data have the actual 724 // address. 725 Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0); 726 Module::Range range(0xfff0, 0x10); 727 function->ranges.push_back(range); 728 function->parameter_size = 0; 729 m.AddFunction(function); 730 731 m.Write(s, ALL_SYMBOL_DATA); 732 string contents = s.str(); 733 734 EXPECT_STREQ("MODULE " MODULE_OS " arm " 735 MODULE_ID " " MODULE_NAME "\n" 736 "FUNC fff0 10 0 _thumb_xyz\n" 737 "PUBLIC abc1 0 thumb_abc\n" 738 "PUBLIC cc00 0 arm_func\n", 739 contents.c_str()); 740 }