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 // 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