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