/thirdparty/breakpad/processor/fast_source_line_resolver_unittest.cc

http://github.com/tomahawk-player/tomahawk · C++ · 480 lines · 371 code · 51 blank · 58 comment · 14 complexity · 81ee460d834924e4858a09d5ec4e40bd 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. // fast_source_line_resolver_unittest.cc: Unit tests for FastSourceLineResolver.
  31. // Two different approaches for testing fast source line resolver:
  32. // First, use the same unit test data for basic source line resolver.
  33. // Second, read data from symbol files, load them as basic modules, and then
  34. // serialize them and load the serialized data as fast modules. Then compare
  35. // modules to assure the fast module contains exactly the same data as
  36. // basic module.
  37. //
  38. // Author: Siyang Xie (lambxsy@google.com)
  39. #include <stdio.h>
  40. #include <sstream>
  41. #include <string>
  42. #include "breakpad_googletest_includes.h"
  43. #include "google_breakpad/processor/code_module.h"
  44. #include "google_breakpad/processor/stack_frame.h"
  45. #include "google_breakpad/processor/memory_region.h"
  46. #include "processor/logging.h"
  47. #include "processor/module_serializer.h"
  48. #include "processor/module_comparer.h"
  49. namespace {
  50. using std::string;
  51. using google_breakpad::SourceLineResolverBase;
  52. using google_breakpad::BasicSourceLineResolver;
  53. using google_breakpad::FastSourceLineResolver;
  54. using google_breakpad::ModuleSerializer;
  55. using google_breakpad::ModuleComparer;
  56. using google_breakpad::CFIFrameInfo;
  57. using google_breakpad::CodeModule;
  58. using google_breakpad::MemoryRegion;
  59. using google_breakpad::StackFrame;
  60. using google_breakpad::WindowsFrameInfo;
  61. using google_breakpad::linked_ptr;
  62. using google_breakpad::scoped_ptr;
  63. class TestCodeModule : public CodeModule {
  64. public:
  65. explicit TestCodeModule(string code_file) : code_file_(code_file) {}
  66. virtual ~TestCodeModule() {}
  67. virtual u_int64_t base_address() const { return 0; }
  68. virtual u_int64_t size() const { return 0xb000; }
  69. virtual string code_file() const { return code_file_; }
  70. virtual string code_identifier() const { return ""; }
  71. virtual string debug_file() const { return ""; }
  72. virtual string debug_identifier() const { return ""; }
  73. virtual string version() const { return ""; }
  74. virtual const CodeModule* Copy() const {
  75. return new TestCodeModule(code_file_);
  76. }
  77. private:
  78. string code_file_;
  79. };
  80. // A mock memory region object, for use by the STACK CFI tests.
  81. class MockMemoryRegion: public MemoryRegion {
  82. u_int64_t GetBase() const { return 0x10000; }
  83. u_int32_t GetSize() const { return 0x01000; }
  84. bool GetMemoryAtAddress(u_int64_t address, u_int8_t *value) const {
  85. *value = address & 0xff;
  86. return true;
  87. }
  88. bool GetMemoryAtAddress(u_int64_t address, u_int16_t *value) const {
  89. *value = address & 0xffff;
  90. return true;
  91. }
  92. bool GetMemoryAtAddress(u_int64_t address, u_int32_t *value) const {
  93. switch (address) {
  94. case 0x10008: *value = 0x98ecadc3; break; // saved %ebx
  95. case 0x1000c: *value = 0x878f7524; break; // saved %esi
  96. case 0x10010: *value = 0x6312f9a5; break; // saved %edi
  97. case 0x10014: *value = 0x10038; break; // caller's %ebp
  98. case 0x10018: *value = 0xf6438648; break; // return address
  99. default: *value = 0xdeadbeef; break; // junk
  100. }
  101. return true;
  102. }
  103. bool GetMemoryAtAddress(u_int64_t address, u_int64_t *value) const {
  104. *value = address;
  105. return true;
  106. }
  107. };
  108. // Verify that, for every association in ACTUAL, EXPECTED has the same
  109. // association. (That is, ACTUAL's associations should be a subset of
  110. // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
  111. // ".cfa".
  112. static bool VerifyRegisters(
  113. const char *file, int line,
  114. const CFIFrameInfo::RegisterValueMap<u_int32_t> &expected,
  115. const CFIFrameInfo::RegisterValueMap<u_int32_t> &actual) {
  116. CFIFrameInfo::RegisterValueMap<u_int32_t>::const_iterator a;
  117. a = actual.find(".cfa");
  118. if (a == actual.end())
  119. return false;
  120. a = actual.find(".ra");
  121. if (a == actual.end())
  122. return false;
  123. for (a = actual.begin(); a != actual.end(); a++) {
  124. CFIFrameInfo::RegisterValueMap<u_int32_t>::const_iterator e =
  125. expected.find(a->first);
  126. if (e == expected.end()) {
  127. fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
  128. file, line, a->first.c_str(), a->second);
  129. return false;
  130. }
  131. if (e->second != a->second) {
  132. fprintf(stderr,
  133. "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n",
  134. file, line, a->first.c_str(), a->second, e->second);
  135. return false;
  136. }
  137. // Don't complain if this doesn't recover all registers. Although
  138. // the DWARF spec says that unmentioned registers are undefined,
  139. // GCC uses omission to mean that they are unchanged.
  140. }
  141. return true;
  142. }
  143. static bool VerifyEmpty(const StackFrame &frame) {
  144. if (frame.function_name.empty() &&
  145. frame.source_file_name.empty() &&
  146. frame.source_line == 0)
  147. return true;
  148. return false;
  149. }
  150. static void ClearSourceLineInfo(StackFrame *frame) {
  151. frame->function_name.clear();
  152. frame->module = NULL;
  153. frame->source_file_name.clear();
  154. frame->source_line = 0;
  155. }
  156. class TestFastSourceLineResolver : public ::testing::Test {
  157. public:
  158. void SetUp() {
  159. testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") +
  160. "/src/processor/testdata";
  161. }
  162. string symbol_file(int file_index) {
  163. std::stringstream ss;
  164. ss << testdata_dir << "/module" << file_index << ".out";
  165. return ss.str();
  166. }
  167. ModuleSerializer serializer;
  168. BasicSourceLineResolver basic_resolver;
  169. FastSourceLineResolver fast_resolver;
  170. ModuleComparer module_comparer;
  171. string testdata_dir;
  172. };
  173. // Test adapted from basic_source_line_resolver_unittest.
  174. TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
  175. TestCodeModule module1("module1");
  176. ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
  177. ASSERT_TRUE(basic_resolver.HasModule(&module1));
  178. // Convert module1 to fast_module:
  179. ASSERT_TRUE(serializer.ConvertOneModule(
  180. module1.code_file(), &basic_resolver, &fast_resolver));
  181. ASSERT_TRUE(fast_resolver.HasModule(&module1));
  182. TestCodeModule module2("module2");
  183. ASSERT_TRUE(basic_resolver.LoadModule(&module2, symbol_file(2)));
  184. ASSERT_TRUE(basic_resolver.HasModule(&module2));
  185. // Convert module2 to fast_module:
  186. ASSERT_TRUE(serializer.ConvertOneModule(
  187. module2.code_file(), &basic_resolver, &fast_resolver));
  188. ASSERT_TRUE(fast_resolver.HasModule(&module2));
  189. StackFrame frame;
  190. scoped_ptr<WindowsFrameInfo> windows_frame_info;
  191. scoped_ptr<CFIFrameInfo> cfi_frame_info;
  192. frame.instruction = 0x1000;
  193. frame.module = NULL;
  194. fast_resolver.FillSourceLineInfo(&frame);
  195. ASSERT_FALSE(frame.module);
  196. ASSERT_TRUE(frame.function_name.empty());
  197. ASSERT_EQ(frame.function_base, 0);
  198. ASSERT_TRUE(frame.source_file_name.empty());
  199. ASSERT_EQ(frame.source_line, 0);
  200. ASSERT_EQ(frame.source_line_base, 0);
  201. frame.module = &module1;
  202. fast_resolver.FillSourceLineInfo(&frame);
  203. ASSERT_EQ(frame.function_name, "Function1_1");
  204. ASSERT_TRUE(frame.module);
  205. ASSERT_EQ(frame.module->code_file(), "module1");
  206. ASSERT_EQ(frame.function_base, 0x1000);
  207. ASSERT_EQ(frame.source_file_name, "file1_1.cc");
  208. ASSERT_EQ(frame.source_line, 44);
  209. ASSERT_EQ(frame.source_line_base, 0x1000);
  210. windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
  211. ASSERT_TRUE(windows_frame_info.get());
  212. ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
  213. ASSERT_EQ(windows_frame_info->program_string,
  214. "$eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =");
  215. ClearSourceLineInfo(&frame);
  216. frame.instruction = 0x800;
  217. frame.module = &module1;
  218. fast_resolver.FillSourceLineInfo(&frame);
  219. ASSERT_TRUE(VerifyEmpty(frame));
  220. windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
  221. ASSERT_FALSE(windows_frame_info.get());
  222. frame.instruction = 0x1280;
  223. fast_resolver.FillSourceLineInfo(&frame);
  224. ASSERT_EQ(frame.function_name, "Function1_3");
  225. ASSERT_TRUE(frame.source_file_name.empty());
  226. ASSERT_EQ(frame.source_line, 0);
  227. windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
  228. ASSERT_TRUE(windows_frame_info.get());
  229. ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_UNKNOWN);
  230. ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
  231. ASSERT_TRUE(windows_frame_info->program_string.empty());
  232. frame.instruction = 0x1380;
  233. fast_resolver.FillSourceLineInfo(&frame);
  234. ASSERT_EQ(frame.function_name, "Function1_4");
  235. ASSERT_TRUE(frame.source_file_name.empty());
  236. ASSERT_EQ(frame.source_line, 0);
  237. windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
  238. ASSERT_TRUE(windows_frame_info.get());
  239. ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
  240. ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
  241. ASSERT_FALSE(windows_frame_info->program_string.empty());
  242. frame.instruction = 0x2000;
  243. windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
  244. ASSERT_FALSE(windows_frame_info.get());
  245. // module1 has STACK CFI records covering 3d40..3def;
  246. // module2 has STACK CFI records covering 3df0..3e9f;
  247. // check that FindCFIFrameInfo doesn't claim to find any outside those ranges.
  248. frame.instruction = 0x3d3f;
  249. frame.module = &module1;
  250. cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  251. ASSERT_FALSE(cfi_frame_info.get());
  252. frame.instruction = 0x3e9f;
  253. frame.module = &module1;
  254. cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  255. ASSERT_FALSE(cfi_frame_info.get());
  256. CFIFrameInfo::RegisterValueMap<u_int32_t> current_registers;
  257. CFIFrameInfo::RegisterValueMap<u_int32_t> caller_registers;
  258. CFIFrameInfo::RegisterValueMap<u_int32_t> expected_caller_registers;
  259. MockMemoryRegion memory;
  260. // Regardless of which instruction evaluation takes place at, it
  261. // should produce the same values for the caller's registers.
  262. expected_caller_registers[".cfa"] = 0x1001c;
  263. expected_caller_registers[".ra"] = 0xf6438648;
  264. expected_caller_registers["$ebp"] = 0x10038;
  265. expected_caller_registers["$ebx"] = 0x98ecadc3;
  266. expected_caller_registers["$esi"] = 0x878f7524;
  267. expected_caller_registers["$edi"] = 0x6312f9a5;
  268. frame.instruction = 0x3d40;
  269. frame.module = &module1;
  270. current_registers.clear();
  271. current_registers["$esp"] = 0x10018;
  272. current_registers["$ebp"] = 0x10038;
  273. current_registers["$ebx"] = 0x98ecadc3;
  274. current_registers["$esi"] = 0x878f7524;
  275. current_registers["$edi"] = 0x6312f9a5;
  276. cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  277. ASSERT_TRUE(cfi_frame_info.get());
  278. ASSERT_TRUE(cfi_frame_info.get()
  279. ->FindCallerRegs<u_int32_t>(current_registers, memory,
  280. &caller_registers));
  281. ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
  282. expected_caller_registers, caller_registers));
  283. frame.instruction = 0x3d41;
  284. current_registers["$esp"] = 0x10014;
  285. cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  286. ASSERT_TRUE(cfi_frame_info.get());
  287. ASSERT_TRUE(cfi_frame_info.get()
  288. ->FindCallerRegs<u_int32_t>(current_registers, memory,
  289. &caller_registers));
  290. ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
  291. expected_caller_registers, caller_registers));
  292. frame.instruction = 0x3d43;
  293. current_registers["$ebp"] = 0x10014;
  294. cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  295. ASSERT_TRUE(cfi_frame_info.get());
  296. ASSERT_TRUE(cfi_frame_info.get()
  297. ->FindCallerRegs<u_int32_t>(current_registers, memory,
  298. &caller_registers));
  299. VerifyRegisters(__FILE__, __LINE__,
  300. expected_caller_registers, caller_registers);
  301. frame.instruction = 0x3d54;
  302. current_registers["$ebx"] = 0x6864f054U;
  303. cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  304. ASSERT_TRUE(cfi_frame_info.get());
  305. ASSERT_TRUE(cfi_frame_info.get()
  306. ->FindCallerRegs<u_int32_t>(current_registers, memory,
  307. &caller_registers));
  308. VerifyRegisters(__FILE__, __LINE__,
  309. expected_caller_registers, caller_registers);
  310. frame.instruction = 0x3d5a;
  311. current_registers["$esi"] = 0x6285f79aU;
  312. cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  313. ASSERT_TRUE(cfi_frame_info.get());
  314. ASSERT_TRUE(cfi_frame_info.get()
  315. ->FindCallerRegs<u_int32_t>(current_registers, memory,
  316. &caller_registers));
  317. VerifyRegisters(__FILE__, __LINE__,
  318. expected_caller_registers, caller_registers);
  319. frame.instruction = 0x3d84;
  320. current_registers["$edi"] = 0x64061449U;
  321. cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  322. ASSERT_TRUE(cfi_frame_info.get());
  323. ASSERT_TRUE(cfi_frame_info.get()
  324. ->FindCallerRegs<u_int32_t>(current_registers, memory,
  325. &caller_registers));
  326. VerifyRegisters(__FILE__, __LINE__,
  327. expected_caller_registers, caller_registers);
  328. frame.instruction = 0x2900;
  329. frame.module = &module1;
  330. fast_resolver.FillSourceLineInfo(&frame);
  331. ASSERT_EQ(frame.function_name, string("PublicSymbol"));
  332. frame.instruction = 0x4000;
  333. frame.module = &module1;
  334. fast_resolver.FillSourceLineInfo(&frame);
  335. ASSERT_EQ(frame.function_name, string("LargeFunction"));
  336. frame.instruction = 0x2181;
  337. frame.module = &module2;
  338. fast_resolver.FillSourceLineInfo(&frame);
  339. ASSERT_EQ(frame.function_name, "Function2_2");
  340. ASSERT_EQ(frame.function_base, 0x2170);
  341. ASSERT_TRUE(frame.module);
  342. ASSERT_EQ(frame.module->code_file(), "module2");
  343. ASSERT_EQ(frame.source_file_name, "file2_2.cc");
  344. ASSERT_EQ(frame.source_line, 21);
  345. ASSERT_EQ(frame.source_line_base, 0x2180);
  346. windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
  347. ASSERT_TRUE(windows_frame_info.get());
  348. ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
  349. ASSERT_EQ(windows_frame_info->prolog_size, 1);
  350. frame.instruction = 0x216f;
  351. fast_resolver.FillSourceLineInfo(&frame);
  352. ASSERT_EQ(frame.function_name, "Public2_1");
  353. ClearSourceLineInfo(&frame);
  354. frame.instruction = 0x219f;
  355. frame.module = &module2;
  356. fast_resolver.FillSourceLineInfo(&frame);
  357. ASSERT_TRUE(frame.function_name.empty());
  358. frame.instruction = 0x21a0;
  359. frame.module = &module2;
  360. fast_resolver.FillSourceLineInfo(&frame);
  361. ASSERT_EQ(frame.function_name, "Public2_2");
  362. }
  363. TEST_F(TestFastSourceLineResolver, TestInvalidLoads) {
  364. TestCodeModule module3("module3");
  365. ASSERT_FALSE(basic_resolver.LoadModule(&module3,
  366. testdata_dir + "/module3_bad.out"));
  367. ASSERT_FALSE(basic_resolver.HasModule(&module3));
  368. // Convert module3 to fast_module:
  369. ASSERT_FALSE(serializer.ConvertOneModule(module3.code_file(),
  370. &basic_resolver,
  371. &fast_resolver));
  372. ASSERT_FALSE(fast_resolver.HasModule(&module3));
  373. TestCodeModule module4("module4");
  374. ASSERT_FALSE(basic_resolver.LoadModule(&module4,
  375. testdata_dir + "/module4_bad.out"));
  376. ASSERT_FALSE(basic_resolver.HasModule(&module4));
  377. // Convert module4 to fast_module:
  378. ASSERT_FALSE(serializer.ConvertOneModule(module4.code_file(),
  379. &basic_resolver,
  380. &fast_resolver));
  381. ASSERT_FALSE(fast_resolver.HasModule(&module4));
  382. TestCodeModule module5("module5");
  383. ASSERT_FALSE(fast_resolver.LoadModule(&module5,
  384. testdata_dir + "/invalid-filename"));
  385. ASSERT_FALSE(fast_resolver.HasModule(&module5));
  386. TestCodeModule invalidmodule("invalid-module");
  387. ASSERT_FALSE(fast_resolver.HasModule(&invalidmodule));
  388. }
  389. TEST_F(TestFastSourceLineResolver, TestUnload) {
  390. TestCodeModule module1("module1");
  391. ASSERT_FALSE(basic_resolver.HasModule(&module1));
  392. ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
  393. ASSERT_TRUE(basic_resolver.HasModule(&module1));
  394. // Convert module1 to fast_module.
  395. ASSERT_TRUE(serializer.ConvertOneModule(module1.code_file(),
  396. &basic_resolver,
  397. &fast_resolver));
  398. ASSERT_TRUE(fast_resolver.HasModule(&module1));
  399. basic_resolver.UnloadModule(&module1);
  400. fast_resolver.UnloadModule(&module1);
  401. ASSERT_FALSE(fast_resolver.HasModule(&module1));
  402. ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1)));
  403. ASSERT_TRUE(basic_resolver.HasModule(&module1));
  404. // Convert module1 to fast_module.
  405. ASSERT_TRUE(serializer.ConvertOneModule(module1.code_file(),
  406. &basic_resolver,
  407. &fast_resolver));
  408. ASSERT_TRUE(fast_resolver.HasModule(&module1));
  409. }
  410. TEST_F(TestFastSourceLineResolver, CompareModule) {
  411. char *symbol_data;
  412. string symbol_data_string;
  413. string filename;
  414. for (int module_index = 0; module_index < 3; ++module_index) {
  415. std::stringstream ss;
  416. ss << testdata_dir << "/module" << module_index << ".out";
  417. filename = ss.str();
  418. ASSERT_TRUE(SourceLineResolverBase::ReadSymbolFile(
  419. &symbol_data, symbol_file(module_index)));
  420. symbol_data_string = symbol_data;
  421. delete [] symbol_data;
  422. ASSERT_TRUE(module_comparer.Compare(symbol_data_string));
  423. }
  424. }
  425. } // namespace
  426. int main(int argc, char *argv[]) {
  427. ::testing::InitGoogleTest(&argc, argv);
  428. return RUN_ALL_TESTS();
  429. }