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