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 // module_unittest.cc: Unit tests for google_breakpad::Module. 33 34 #include <errno.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 39 #include <algorithm> 40 #include <sstream> 41 #include <string> 42 43 #include "breakpad_googletest_includes.h" 44 #include "common/module.h" 45 #include "common/using_std_string.h" 46 47 using google_breakpad::Module; 48 using std::stringstream; 49 using std::vector; 50 using testing::ContainerEq; 51 52 static Module::Function *generate_duplicate_function(const string &name) { 53 const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL; 54 const Module::Address DUP_SIZE = 0x200b26e605f99071LL; 55 const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL; 56 57 Module::Function *function = new Module::Function(name, DUP_ADDRESS); 58 function->size = DUP_SIZE; 59 function->parameter_size = DUP_PARAMETER_SIZE; 60 return function; 61 } 62 63 #define MODULE_NAME "name with spaces" 64 #define MODULE_OS "os-name" 65 #define MODULE_ARCH "architecture" 66 #define MODULE_ID "id-string" 67 68 TEST(Write, Header) { 69 stringstream s; 70 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 71 m.Write(s, ALL_SYMBOL_DATA); 72 string contents = s.str(); 73 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", 74 contents.c_str()); 75 } 76 77 TEST(Write, OneLineFunc) { 78 stringstream s; 79 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 80 81 Module::File *file = m.FindFile("file_name.cc"); 82 Module::Function *function = new Module::Function( 83 "function_name", 0xe165bf8023b9d9abLL); 84 function->size = 0x1e4bb0eb1cbf5b09LL; 85 function->parameter_size = 0x772beee89114358aLL; 86 Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL, 87 file, 67519080 }; 88 function->lines.push_back(line); 89 m.AddFunction(function); 90 91 m.Write(s, ALL_SYMBOL_DATA); 92 string contents = s.str(); 93 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 94 "FILE 0 file_name.cc\n" 95 "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" 96 " function_name\n" 97 "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", 98 contents.c_str()); 99 } 100 101 TEST(Write, RelativeLoadAddress) { 102 stringstream s; 103 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 104 105 // Some source files. We will expect to see them in lexicographic order. 106 Module::File *file1 = m.FindFile("filename-b.cc"); 107 Module::File *file2 = m.FindFile("filename-a.cc"); 108 109 // A function. 110 Module::Function *function = new Module::Function( 111 "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL); 112 function->size = 0x2922088f98d3f6fcLL; 113 function->parameter_size = 0xe5e9aa008bd5f0d0LL; 114 115 // Some source lines. The module should not sort these. 116 Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, 117 file1, 41676901 }; 118 Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL, 119 file2, 67519080 }; 120 function->lines.push_back(line2); 121 function->lines.push_back(line1); 122 123 m.AddFunction(function); 124 125 // Some stack information. 126 Module::StackFrameEntry *entry = new Module::StackFrameEntry(); 127 entry->address = 0x30f9e5c83323973dULL; 128 entry->size = 0x49fc9ca7c7c13dc2ULL; 129 entry->initial_rules[".cfa"] = "he was a handsome man"; 130 entry->initial_rules["and"] = "what i want to know is"; 131 entry->rule_changes[0x30f9e5c83323973eULL]["how"] = 132 "do you like your blueeyed boy"; 133 entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; 134 m.AddStackFrameEntry(entry); 135 136 // Set the load address. Doing this after adding all the data to 137 // the module must work fine. 138 m.SetLoadAddress(0x2ab698b0b6407073LL); 139 140 m.Write(s, ALL_SYMBOL_DATA); 141 string contents = s.str(); 142 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 143 "FILE 0 filename-a.cc\n" 144 "FILE 1 filename-b.cc\n" 145 "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" 146 " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" 147 "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" 148 "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" 149 "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" 150 " .cfa: he was a handsome man" 151 " and: what i want to know is\n" 152 "STACK CFI 6434d177ce326cb" 153 " Mister: Death" 154 " how: do you like your blueeyed boy\n", 155 contents.c_str()); 156 } 157 158 TEST(Write, OmitUnusedFiles) { 159 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 160 161 // Create some source files. 162 Module::File *file1 = m.FindFile("filename1"); 163 m.FindFile("filename2"); // not used by any line 164 Module::File *file3 = m.FindFile("filename3"); 165 166 // Create a function. 167 Module::Function *function = new Module::Function( 168 "function_name", 0x9b926d464f0b9384LL); 169 function->size = 0x4f524a4ba795e6a6LL; 170 function->parameter_size = 0xbbe8133a6641c9b7LL; 171 172 // Source files that refer to some files, but not others. 173 Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL, 174 file1, 137850127 }; 175 Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL, 176 file3, 28113549 }; 177 function->lines.push_back(line1); 178 function->lines.push_back(line2); 179 m.AddFunction(function); 180 181 m.AssignSourceIds(); 182 183 vector<Module::File *> vec; 184 m.GetFiles(&vec); 185 EXPECT_EQ((size_t) 3, vec.size()); 186 EXPECT_STREQ("filename1", vec[0]->name.c_str()); 187 EXPECT_NE(-1, vec[0]->source_id); 188 // Expect filename2 not to be used. 189 EXPECT_STREQ("filename2", vec[1]->name.c_str()); 190 EXPECT_EQ(-1, vec[1]->source_id); 191 EXPECT_STREQ("filename3", vec[2]->name.c_str()); 192 EXPECT_NE(-1, vec[2]->source_id); 193 194 stringstream s; 195 m.Write(s, ALL_SYMBOL_DATA); 196 string contents = s.str(); 197 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 198 "FILE 0 filename1\n" 199 "FILE 1 filename3\n" 200 "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" 201 " function_name\n" 202 "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n" 203 "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n", 204 contents.c_str()); 205 } 206 207 TEST(Write, NoCFI) { 208 stringstream s; 209 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 210 211 // Some source files. We will expect to see them in lexicographic order. 212 Module::File *file1 = m.FindFile("filename.cc"); 213 214 // A function. 215 Module::Function *function = new Module::Function( 216 "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL); 217 function->size = 0x2922088f98d3f6fcLL; 218 function->parameter_size = 0xe5e9aa008bd5f0d0LL; 219 220 // Some source lines. The module should not sort these. 221 Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, 222 file1, 41676901 }; 223 function->lines.push_back(line1); 224 225 m.AddFunction(function); 226 227 // Some stack information. 228 Module::StackFrameEntry *entry = new Module::StackFrameEntry(); 229 entry->address = 0x30f9e5c83323973dULL; 230 entry->size = 0x49fc9ca7c7c13dc2ULL; 231 entry->initial_rules[".cfa"] = "he was a handsome man"; 232 entry->initial_rules["and"] = "what i want to know is"; 233 entry->rule_changes[0x30f9e5c83323973eULL]["how"] = 234 "do you like your blueeyed boy"; 235 entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; 236 m.AddStackFrameEntry(entry); 237 238 // Set the load address. Doing this after adding all the data to 239 // the module must work fine. 240 m.SetLoadAddress(0x2ab698b0b6407073LL); 241 242 m.Write(s, NO_CFI); 243 string contents = s.str(); 244 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 245 "FILE 0 filename.cc\n" 246 "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" 247 " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" 248 "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n", 249 contents.c_str()); 250 } 251 252 TEST(Construct, AddFunctions) { 253 stringstream s; 254 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 255 256 // Two functions. 257 Module::Function *function1 = new Module::Function( 258 "_without_form", 0xd35024aa7ca7da5cLL); 259 function1->size = 0x200b26e605f99071LL; 260 function1->parameter_size = 0xf14ac4fed48c4a99LL; 261 262 Module::Function *function2 = new Module::Function( 263 "_and_void", 0x2987743d0b35b13fLL); 264 function2->size = 0xb369db048deb3010LL; 265 function2->parameter_size = 0x938e556cb5a79988LL; 266 267 // Put them in a vector. 268 vector<Module::Function *> vec; 269 vec.push_back(function1); 270 vec.push_back(function2); 271 272 m.AddFunctions(vec.begin(), vec.end()); 273 274 m.Write(s, ALL_SYMBOL_DATA); 275 string contents = s.str(); 276 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 277 "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" 278 " _and_void\n" 279 "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" 280 " _without_form\n", 281 contents.c_str()); 282 283 // Check that m.GetFunctions returns the functions we expect. 284 vec.clear(); 285 m.GetFunctions(&vec, vec.end()); 286 EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); 287 EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); 288 EXPECT_EQ((size_t) 2, vec.size()); 289 } 290 291 TEST(Construct, AddFrames) { 292 stringstream s; 293 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 294 295 // First STACK CFI entry, with no initial rules or deltas. 296 Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); 297 entry1->address = 0xddb5f41285aa7757ULL; 298 entry1->size = 0x1486493370dc5073ULL; 299 m.AddStackFrameEntry(entry1); 300 301 // Second STACK CFI entry, with initial rules but no deltas. 302 Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); 303 entry2->address = 0x8064f3af5e067e38ULL; 304 entry2->size = 0x0de2a5ee55509407ULL; 305 entry2->initial_rules[".cfa"] = "I think that I shall never see"; 306 entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; 307 entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; 308 m.AddStackFrameEntry(entry2); 309 310 // Third STACK CFI entry, with initial rules and deltas. 311 Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); 312 entry3->address = 0x5e8d0db0a7075c6cULL; 313 entry3->size = 0x1c7edb12a7aea229ULL; 314 entry3->initial_rules[".cfa"] = "Whose woods are these"; 315 entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = 316 "the village though"; 317 entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = 318 "he will not see me stopping here"; 319 entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = 320 "his house is in"; 321 entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = 322 "I think I know"; 323 m.AddStackFrameEntry(entry3); 324 325 // Check that Write writes STACK CFI records properly. 326 m.Write(s, ALL_SYMBOL_DATA); 327 string contents = s.str(); 328 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 329 "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n" 330 "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" 331 " .cfa: I think that I shall never see" 332 " cannoli: a tree whose hungry mouth is prest" 333 " stromboli: a poem lovely as a tree\n" 334 "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" 335 " .cfa: Whose woods are these\n" 336 "STACK CFI 36682fad3763ffff" 337 " .cfa: I think I know" 338 " stromboli: his house is in\n" 339 "STACK CFI 47ceb0f63c269d7f" 340 " calzone: the village though" 341 " cannoli: he will not see me stopping here\n", 342 contents.c_str()); 343 344 // Check that GetStackFrameEntries works. 345 vector<Module::StackFrameEntry *> entries; 346 m.GetStackFrameEntries(&entries); 347 ASSERT_EQ(3U, entries.size()); 348 // Check first entry. 349 EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address); 350 EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size); 351 ASSERT_EQ(0U, entries[0]->initial_rules.size()); 352 ASSERT_EQ(0U, entries[0]->rule_changes.size()); 353 // Check second entry. 354 EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); 355 EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); 356 ASSERT_EQ(3U, entries[1]->initial_rules.size()); 357 Module::RuleMap entry2_initial; 358 entry2_initial[".cfa"] = "I think that I shall never see"; 359 entry2_initial["stromboli"] = "a poem lovely as a tree"; 360 entry2_initial["cannoli"] = "a tree whose hungry mouth is prest"; 361 EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); 362 ASSERT_EQ(0U, entries[1]->rule_changes.size()); 363 // Check third entry. 364 EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address); 365 EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size); 366 Module::RuleMap entry3_initial; 367 entry3_initial[".cfa"] = "Whose woods are these"; 368 EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial)); 369 Module::RuleChangeMap entry3_changes; 370 entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; 371 entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; 372 entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; 373 entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] = 374 "he will not see me stopping here"; 375 EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes)); 376 } 377 378 TEST(Construct, UniqueFiles) { 379 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 380 Module::File *file1 = m.FindFile("foo"); 381 Module::File *file2 = m.FindFile(string("bar")); 382 Module::File *file3 = m.FindFile(string("foo")); 383 Module::File *file4 = m.FindFile("bar"); 384 EXPECT_NE(file1, file2); 385 EXPECT_EQ(file1, file3); 386 EXPECT_EQ(file2, file4); 387 EXPECT_EQ(file1, m.FindExistingFile("foo")); 388 EXPECT_TRUE(m.FindExistingFile("baz") == NULL); 389 } 390 391 TEST(Construct, DuplicateFunctions) { 392 stringstream s; 393 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 394 395 // Two functions. 396 Module::Function *function1 = generate_duplicate_function("_without_form"); 397 Module::Function *function2 = generate_duplicate_function("_without_form"); 398 399 m.AddFunction(function1); 400 m.AddFunction(function2); 401 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 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" 406 " _without_form\n", 407 contents.c_str()); 408 } 409 410 TEST(Construct, FunctionsWithSameAddress) { 411 stringstream s; 412 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 413 414 // Two functions. 415 Module::Function *function1 = generate_duplicate_function("_without_form"); 416 Module::Function *function2 = generate_duplicate_function("_and_void"); 417 418 m.AddFunction(function1); 419 m.AddFunction(function2); 420 421 m.Write(s, ALL_SYMBOL_DATA); 422 string contents = s.str(); 423 EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" 424 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" 425 " _and_void\n" 426 "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" 427 " _without_form\n", 428 contents.c_str()); 429 } 430 431 // Externs should be written out as PUBLIC records, sorted by 432 // address. 433 TEST(Construct, Externs) { 434 stringstream s; 435 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 436 437 // Two externs. 438 Module::Extern *extern1 = new Module::Extern(0xffff); 439 extern1->name = "_abc"; 440 Module::Extern *extern2 = new Module::Extern(0xaaaa); 441 extern2->name = "_xyz"; 442 443 m.AddExtern(extern1); 444 m.AddExtern(extern2); 445 446 m.Write(s, ALL_SYMBOL_DATA); 447 string contents = s.str(); 448 449 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " 450 MODULE_ID " " MODULE_NAME "\n" 451 "PUBLIC aaaa 0 _xyz\n" 452 "PUBLIC ffff 0 _abc\n", 453 contents.c_str()); 454 } 455 456 // Externs with the same address should only keep the first entry 457 // added. 458 TEST(Construct, DuplicateExterns) { 459 stringstream s; 460 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 461 462 // Two externs. 463 Module::Extern *extern1 = new Module::Extern(0xffff); 464 extern1->name = "_xyz"; 465 Module::Extern *extern2 = new Module::Extern(0xffff); 466 extern2->name = "_abc"; 467 468 m.AddExtern(extern1); 469 m.AddExtern(extern2); 470 471 m.Write(s, ALL_SYMBOL_DATA); 472 string contents = s.str(); 473 474 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " 475 MODULE_ID " " MODULE_NAME "\n" 476 "PUBLIC ffff 0 _xyz\n", 477 contents.c_str()); 478 } 479 480 // If there exists an extern and a function at the same address, only write 481 // out the FUNC entry. 482 TEST(Construct, FunctionsAndExternsWithSameAddress) { 483 stringstream s; 484 Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); 485 486 // Two externs. 487 Module::Extern* extern1 = new Module::Extern(0xabc0); 488 extern1->name = "abc"; 489 Module::Extern* extern2 = new Module::Extern(0xfff0); 490 extern2->name = "xyz"; 491 492 m.AddExtern(extern1); 493 m.AddExtern(extern2); 494 495 Module::Function* function = new Module::Function("_xyz", 0xfff0); 496 function->size = 0x10; 497 function->parameter_size = 0; 498 m.AddFunction(function); 499 500 m.Write(s, ALL_SYMBOL_DATA); 501 string contents = s.str(); 502 503 EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " 504 MODULE_ID " " MODULE_NAME "\n" 505 "FUNC fff0 10 0 _xyz\n" 506 "PUBLIC abc0 0 abc\n", 507 contents.c_str()); 508 } 509 510 // If there exists an extern and a function at the same address, only write 511 // out the FUNC entry. For ARM THUMB, the extern that comes from the ELF 512 // symbol section has bit 0 set. 513 TEST(Construct, FunctionsAndThumbExternsWithSameAddress) { 514 stringstream s; 515 Module m(MODULE_NAME, MODULE_OS, "arm", MODULE_ID); 516 517 // Two THUMB externs. 518 Module::Extern* thumb_extern1 = new Module::Extern(0xabc1); 519 thumb_extern1->name = "thumb_abc"; 520 Module::Extern* thumb_extern2 = new Module::Extern(0xfff1); 521 thumb_extern2->name = "thumb_xyz"; 522 523 Module::Extern* arm_extern1 = new Module::Extern(0xcc00); 524 arm_extern1->name = "arm_func"; 525 526 m.AddExtern(thumb_extern1); 527 m.AddExtern(thumb_extern2); 528 m.AddExtern(arm_extern1); 529 530 // The corresponding function from the DWARF debug data have the actual 531 // address. 532 Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0); 533 function->size = 0x10; 534 function->parameter_size = 0; 535 m.AddFunction(function); 536 537 m.Write(s, ALL_SYMBOL_DATA); 538 string contents = s.str(); 539 540 EXPECT_STREQ("MODULE " MODULE_OS " arm " 541 MODULE_ID " " MODULE_NAME "\n" 542 "FUNC fff0 10 0 _thumb_xyz\n" 543 "PUBLIC abc1 0 thumb_abc\n" 544 "PUBLIC cc00 0 arm_func\n", 545 contents.c_str()); 546 } 547