PageRenderTime 51ms CodeModel.GetById 14ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/common/module_unittest.cc

http://github.com/tomahawk-player/tomahawk
C++ | 490 lines | 357 code | 68 blank | 65 comment | 3 complexity | ee6bea59f5462bbdea0506f6c17aa587 MD5 | raw file
  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
 46using google_breakpad::Module;
 47using std::string;
 48using std::stringstream;
 49using std::vector;
 50using testing::ContainerEq;
 51
 52static 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);
 58  function->name = name;
 59  function->address = DUP_ADDRESS;
 60  function->size = DUP_SIZE;
 61  function->parameter_size = DUP_PARAMETER_SIZE;
 62  return function;
 63}
 64
 65#define MODULE_NAME "name with spaces"
 66#define MODULE_OS "os-name"
 67#define MODULE_ARCH "architecture"
 68#define MODULE_ID "id-string"
 69
 70TEST(Write, Header) {
 71  stringstream s;
 72  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
 73  m.Write(s, true);
 74  string contents = s.str();
 75  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
 76               contents.c_str());
 77}
 78
 79TEST(Write, OneLineFunc) {
 80  stringstream s;
 81  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
 82
 83  Module::File *file = m.FindFile("file_name.cc");
 84  Module::Function *function = new(Module::Function);
 85  function->name = "function_name";
 86  function->address = 0xe165bf8023b9d9abLL;
 87  function->size = 0x1e4bb0eb1cbf5b09LL;
 88  function->parameter_size = 0x772beee89114358aLL;
 89  Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL,
 90                        file, 67519080 };
 91  function->lines.push_back(line);
 92  m.AddFunction(function);
 93
 94  m.Write(s, true);
 95  string contents = s.str();
 96  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
 97               "FILE 0 file_name.cc\n"
 98               "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a"
 99               " function_name\n"
100               "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n",
101               contents.c_str());
102}
103
104TEST(Write, RelativeLoadAddress) {
105  stringstream s;
106  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
107
108  // Some source files.  We will expect to see them in lexicographic order.
109  Module::File *file1 = m.FindFile("filename-b.cc");
110  Module::File *file2 = m.FindFile("filename-a.cc");
111
112  // A function.
113  Module::Function *function = new(Module::Function);
114  function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)";
115  function->address = 0xbec774ea5dd935f3LL;
116  function->size = 0x2922088f98d3f6fcLL;
117  function->parameter_size = 0xe5e9aa008bd5f0d0LL;
118
119  // Some source lines.  The module should not sort these.
120  Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL,
121                         file1, 41676901 };
122  Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL,
123                         file2, 67519080 };
124  function->lines.push_back(line2);
125  function->lines.push_back(line1);
126
127  m.AddFunction(function);
128
129  // Some stack information.
130  Module::StackFrameEntry *entry = new Module::StackFrameEntry();
131  entry->address = 0x30f9e5c83323973dULL;
132  entry->size = 0x49fc9ca7c7c13dc2ULL;
133  entry->initial_rules[".cfa"] = "he was a handsome man";
134  entry->initial_rules["and"] = "what i want to know is";
135  entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
136    "do you like your blueeyed boy";
137  entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death";
138  m.AddStackFrameEntry(entry);
139
140  // Set the load address.  Doing this after adding all the data to
141  // the module must work fine.
142  m.SetLoadAddress(0x2ab698b0b6407073LL);
143
144  m.Write(s, true);
145  string contents = s.str();
146  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
147               "FILE 0 filename-a.cc\n"
148               "FILE 1 filename-b.cc\n"
149               "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0"
150               " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n"
151               "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n"
152               "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n"
153               "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2"
154               " .cfa: he was a handsome man"
155               " and: what i want to know is\n"
156               "STACK CFI 6434d177ce326cb"
157               " Mister: Death"
158               " how: do you like your blueeyed boy\n",
159               contents.c_str());
160}
161
162TEST(Write, OmitUnusedFiles) {
163  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
164
165  // Create some source files.
166  Module::File *file1 = m.FindFile("filename1");
167  m.FindFile("filename2");  // not used by any line
168  Module::File *file3 = m.FindFile("filename3");
169
170  // Create a function.
171  Module::Function *function = new(Module::Function);
172  function->name = "function_name";
173  function->address = 0x9b926d464f0b9384LL;
174  function->size = 0x4f524a4ba795e6a6LL;
175  function->parameter_size = 0xbbe8133a6641c9b7LL;
176
177  // Source files that refer to some files, but not others.
178  Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL,
179                         file1, 137850127 };
180  Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL,
181                         file3, 28113549 };
182  function->lines.push_back(line1);
183  function->lines.push_back(line2);
184  m.AddFunction(function);
185
186  m.AssignSourceIds();
187
188  vector<Module::File *> vec;
189  m.GetFiles(&vec);
190  EXPECT_EQ((size_t) 3, vec.size());
191  EXPECT_STREQ("filename1", vec[0]->name.c_str());
192  EXPECT_NE(-1, vec[0]->source_id);
193  // Expect filename2 not to be used.
194  EXPECT_STREQ("filename2", vec[1]->name.c_str());
195  EXPECT_EQ(-1, vec[1]->source_id);
196  EXPECT_STREQ("filename3", vec[2]->name.c_str());
197  EXPECT_NE(-1, vec[2]->source_id);
198
199  stringstream s;
200  m.Write(s, true);
201  string contents = s.str();
202  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
203               "FILE 0 filename1\n"
204               "FILE 1 filename3\n"
205               "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7"
206               " function_name\n"
207               "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n"
208               "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n",
209               contents.c_str());
210}
211
212TEST(Write, NoCFI) {
213  stringstream s;
214  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
215
216  // Some source files.  We will expect to see them in lexicographic order.
217  Module::File *file1 = m.FindFile("filename.cc");
218
219  // A function.
220  Module::Function *function = new(Module::Function);
221  function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)";
222  function->address = 0xbec774ea5dd935f3LL;
223  function->size = 0x2922088f98d3f6fcLL;
224  function->parameter_size = 0xe5e9aa008bd5f0d0LL;
225
226  // Some source lines.  The module should not sort these.
227  Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL,
228                         file1, 41676901 };
229  function->lines.push_back(line1);
230
231  m.AddFunction(function);
232
233  // Some stack information.
234  Module::StackFrameEntry *entry = new Module::StackFrameEntry();
235  entry->address = 0x30f9e5c83323973dULL;
236  entry->size = 0x49fc9ca7c7c13dc2ULL;
237  entry->initial_rules[".cfa"] = "he was a handsome man";
238  entry->initial_rules["and"] = "what i want to know is";
239  entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
240    "do you like your blueeyed boy";
241  entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death";
242  m.AddStackFrameEntry(entry);
243
244  // Set the load address.  Doing this after adding all the data to
245  // the module must work fine.
246  m.SetLoadAddress(0x2ab698b0b6407073LL);
247
248  m.Write(s, false);
249  string contents = s.str();
250  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
251               "FILE 0 filename.cc\n"
252               "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0"
253               " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n"
254               "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n",
255               contents.c_str());
256}
257
258TEST(Construct, AddFunctions) {
259  stringstream s;
260  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
261
262  // Two functions.
263  Module::Function *function1 = new(Module::Function);
264  function1->name = "_without_form";
265  function1->address = 0xd35024aa7ca7da5cLL;
266  function1->size = 0x200b26e605f99071LL;
267  function1->parameter_size = 0xf14ac4fed48c4a99LL;
268
269  Module::Function *function2 = new(Module::Function);
270  function2->name = "_and_void";
271  function2->address = 0x2987743d0b35b13fLL;
272  function2->size = 0xb369db048deb3010LL;
273  function2->parameter_size = 0x938e556cb5a79988LL;
274
275  // Put them in a vector.
276  vector<Module::Function *> vec;
277  vec.push_back(function1);
278  vec.push_back(function2);
279
280  m.AddFunctions(vec.begin(), vec.end());
281
282  m.Write(s, true);
283  string contents = s.str();
284  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
285               "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
286               " _and_void\n"
287               "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99"
288               " _without_form\n",
289               contents.c_str());
290
291  // Check that m.GetFunctions returns the functions we expect.
292  vec.clear();
293  m.GetFunctions(&vec, vec.end());
294  EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1));
295  EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2));
296  EXPECT_EQ((size_t) 2, vec.size());
297}
298
299TEST(Construct, AddFrames) {
300  stringstream s;
301  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
302
303  // First STACK CFI entry, with no initial rules or deltas.
304  Module::StackFrameEntry *entry1 = new Module::StackFrameEntry();
305  entry1->address = 0xddb5f41285aa7757ULL;
306  entry1->size = 0x1486493370dc5073ULL;
307  m.AddStackFrameEntry(entry1);
308
309  // Second STACK CFI entry, with initial rules but no deltas.
310  Module::StackFrameEntry *entry2 = new Module::StackFrameEntry();
311  entry2->address = 0x8064f3af5e067e38ULL;
312  entry2->size = 0x0de2a5ee55509407ULL;
313  entry2->initial_rules[".cfa"] = "I think that I shall never see";
314  entry2->initial_rules["stromboli"] = "a poem lovely as a tree";
315  entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest";
316  m.AddStackFrameEntry(entry2);
317
318  // Third STACK CFI entry, with initial rules and deltas.
319  Module::StackFrameEntry *entry3 = new Module::StackFrameEntry();
320  entry3->address = 0x5e8d0db0a7075c6cULL;
321  entry3->size = 0x1c7edb12a7aea229ULL;
322  entry3->initial_rules[".cfa"] = "Whose woods are these";
323  entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] =
324    "the village though";
325  entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] =
326    "he will not see me stopping here";
327  entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] =
328    "his house is in";
329  entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] =
330    "I think I know";
331  m.AddStackFrameEntry(entry3);
332
333  // Check that Write writes STACK CFI records properly.
334  m.Write(s, true);
335  string contents = s.str();
336  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
337               "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
338               "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407"
339               " .cfa: I think that I shall never see"
340               " cannoli: a tree whose hungry mouth is prest"
341               " stromboli: a poem lovely as a tree\n"
342               "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229"
343               " .cfa: Whose woods are these\n"
344               "STACK CFI 36682fad3763ffff"
345               " .cfa: I think I know"
346               " stromboli: his house is in\n"
347               "STACK CFI 47ceb0f63c269d7f"
348               " calzone: the village though"
349               " cannoli: he will not see me stopping here\n",
350               contents.c_str());
351
352  // Check that GetStackFrameEntries works.
353  vector<Module::StackFrameEntry *> entries;
354  m.GetStackFrameEntries(&entries);
355  ASSERT_EQ(3U, entries.size());
356  // Check first entry.
357  EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address);
358  EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size);
359  ASSERT_EQ(0U, entries[0]->initial_rules.size());
360  ASSERT_EQ(0U, entries[0]->rule_changes.size());
361  // Check second entry.
362  EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address);
363  EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size);
364  ASSERT_EQ(3U, entries[1]->initial_rules.size());
365  Module::RuleMap entry2_initial;
366  entry2_initial[".cfa"] = "I think that I shall never see";
367  entry2_initial["stromboli"] = "a poem lovely as a tree";
368  entry2_initial["cannoli"] = "a tree whose hungry mouth is prest";
369  EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial));
370  ASSERT_EQ(0U, entries[1]->rule_changes.size());
371  // Check third entry.
372  EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address);
373  EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size);
374  Module::RuleMap entry3_initial;
375  entry3_initial[".cfa"] = "Whose woods are these";
376  EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial));
377  Module::RuleChangeMap entry3_changes;
378  entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know";
379  entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in";
380  entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though";
381  entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] =
382    "he will not see me stopping here";
383  EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes));
384}
385
386TEST(Construct, UniqueFiles) {
387  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
388  Module::File *file1 = m.FindFile("foo");
389  Module::File *file2 = m.FindFile(string("bar"));
390  Module::File *file3 = m.FindFile(string("foo"));
391  Module::File *file4 = m.FindFile("bar");
392  EXPECT_NE(file1, file2);
393  EXPECT_EQ(file1, file3);
394  EXPECT_EQ(file2, file4);
395  EXPECT_EQ(file1, m.FindExistingFile("foo"));
396  EXPECT_TRUE(m.FindExistingFile("baz") == NULL);
397}
398
399TEST(Construct, DuplicateFunctions) {
400  stringstream s;
401  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
402
403  // Two functions.
404  Module::Function *function1 = generate_duplicate_function("_without_form");
405  Module::Function *function2 = generate_duplicate_function("_without_form");
406
407  m.AddFunction(function1);
408  m.AddFunction(function2);
409
410  m.Write(s, true);
411  string contents = s.str();
412  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
413               "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
414               " _without_form\n",
415               contents.c_str());
416}
417
418TEST(Construct, FunctionsWithSameAddress) {
419  stringstream s;
420  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
421
422  // Two functions.
423  Module::Function *function1 = generate_duplicate_function("_without_form");
424  Module::Function *function2 = generate_duplicate_function("_and_void");
425
426  m.AddFunction(function1);
427  m.AddFunction(function2);
428
429  m.Write(s, true);
430  string contents = s.str();
431  EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
432               "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
433               " _and_void\n"
434               "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
435               " _without_form\n",
436               contents.c_str());
437}
438
439// Externs should be written out as PUBLIC records, sorted by
440// address.
441TEST(Construct, Externs) {
442  stringstream s;
443  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
444
445  // Two externs.
446  Module::Extern *extern1 = new(Module::Extern);
447  extern1->address = 0xffff;
448  extern1->name = "_abc";
449  Module::Extern *extern2 = new(Module::Extern);
450  extern2->address = 0xaaaa;
451  extern2->name = "_xyz";
452
453  m.AddExtern(extern1);
454  m.AddExtern(extern2);
455
456  m.Write(s, true);
457  string contents = s.str();
458
459  EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
460               MODULE_ID " " MODULE_NAME "\n"
461               "PUBLIC aaaa 0 _xyz\n"
462               "PUBLIC ffff 0 _abc\n",
463               contents.c_str());
464}
465
466// Externs with the same address should only keep the first entry
467// added.
468TEST(Construct, DuplicateExterns) {
469  stringstream s;
470  Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
471
472  // Two externs.
473  Module::Extern *extern1 = new(Module::Extern);
474  extern1->address = 0xffff;
475  extern1->name = "_xyz";
476  Module::Extern *extern2 = new(Module::Extern);
477  extern2->address = 0xffff;
478  extern2->name = "_abc";
479
480  m.AddExtern(extern1);
481  m.AddExtern(extern2);
482
483  m.Write(s, true);
484  string contents = s.str();
485
486  EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
487               MODULE_ID " " MODULE_NAME "\n"
488               "PUBLIC ffff 0 _xyz\n",
489               contents.c_str());
490}