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