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