/thirdparty/breakpad/processor/basic_source_line_resolver_unittest.cc

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