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@mozilla.com> <jimb@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 
generate_duplicate_function(const string & name)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 
TEST(Write,Header)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 
TEST(Write,OneLineFunc)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 
TEST(Write,RelativeLoadAddress)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 
TEST(Write,OmitUnusedFiles)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 
TEST(Write,NoCFI)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 
TEST(Construct,AddFunctions)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 
TEST(Construct,AddFrames)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 
TEST(Construct,UniqueFiles)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 
TEST(Construct,DuplicateFunctions)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 
TEST(Construct,FunctionsWithSameAddress)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.
TEST(Construct,Externs)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.
TEST(Construct,DuplicateExterns)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.
TEST(Construct,FunctionsAndExternsWithSameAddress)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.
TEST(Construct,FunctionsAndThumbExternsWithSameAddress)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