/thirdparty/breakpad/common/dwarf_cfi_to_module_unittest.cc

http://github.com/tomahawk-player/tomahawk · C++ · 294 lines · 231 code · 32 blank · 31 comment · 0 complexity · 51b09ff2d7c48b76d7b47e90e1ea1886 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. // dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule.
  31. #include <string>
  32. #include <vector>
  33. #include "breakpad_googletest_includes.h"
  34. #include "common/dwarf_cfi_to_module.h"
  35. using std::string;
  36. using std::vector;
  37. using google_breakpad::Module;
  38. using google_breakpad::DwarfCFIToModule;
  39. using testing::ContainerEq;
  40. using testing::Test;
  41. using testing::_;
  42. struct MockCFIReporter: public DwarfCFIToModule::Reporter {
  43. MockCFIReporter(const string &file, const string &section)
  44. : Reporter(file, section) { }
  45. MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg));
  46. MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string &reg));
  47. MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string &reg));
  48. };
  49. struct DwarfCFIToModuleFixture {
  50. DwarfCFIToModuleFixture()
  51. : module("module name", "module os", "module arch", "module id"),
  52. reporter("reporter file", "reporter section"),
  53. handler(&module, register_names, &reporter) {
  54. register_names.push_back("reg0");
  55. register_names.push_back("reg1");
  56. register_names.push_back("reg2");
  57. register_names.push_back("reg3");
  58. register_names.push_back("reg4");
  59. register_names.push_back("reg5");
  60. register_names.push_back("reg6");
  61. register_names.push_back("reg7");
  62. register_names.push_back("sp");
  63. register_names.push_back("pc");
  64. EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0);
  65. EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0);
  66. EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0);
  67. }
  68. Module module;
  69. vector<string> register_names;
  70. MockCFIReporter reporter;
  71. DwarfCFIToModule handler;
  72. vector<Module::StackFrameEntry *> entries;
  73. };
  74. class Entry: public DwarfCFIToModuleFixture, public Test { };
  75. TEST_F(Entry, Accept) {
  76. ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL,
  77. 0xb440ce248169c8d6ULL, 3, "", 0xea93c106));
  78. ASSERT_TRUE(handler.End());
  79. module.GetStackFrameEntries(&entries);
  80. EXPECT_EQ(1U, entries.size());
  81. EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address);
  82. EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size);
  83. EXPECT_EQ(0U, entries[0]->initial_rules.size());
  84. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  85. }
  86. TEST_F(Entry, AcceptOldVersion) {
  87. ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL,
  88. 0xc771f44958d40bbcULL, 1, "", 0x093c945e));
  89. ASSERT_TRUE(handler.End());
  90. module.GetStackFrameEntries(&entries);
  91. EXPECT_EQ(1U, entries.size());
  92. EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address);
  93. EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size);
  94. EXPECT_EQ(0U, entries[0]->initial_rules.size());
  95. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  96. }
  97. struct RuleFixture: public DwarfCFIToModuleFixture {
  98. RuleFixture() : DwarfCFIToModuleFixture() {
  99. entry_address = 0x89327ebf86b47492ULL;
  100. entry_size = 0x2f8cd573072fe02aULL;
  101. return_reg = 0x7886a346;
  102. }
  103. void StartEntry() {
  104. ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size,
  105. 3, "", return_reg));
  106. }
  107. void CheckEntry() {
  108. module.GetStackFrameEntries(&entries);
  109. EXPECT_EQ(1U, entries.size());
  110. EXPECT_EQ(entry_address, entries[0]->address);
  111. EXPECT_EQ(entry_size, entries[0]->size);
  112. }
  113. uint64 entry_address, entry_size;
  114. unsigned return_reg;
  115. };
  116. class Rule: public RuleFixture, public Test { };
  117. TEST_F(Rule, UndefinedRule) {
  118. EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7"));
  119. StartEntry();
  120. ASSERT_TRUE(handler.UndefinedRule(entry_address, 7));
  121. ASSERT_TRUE(handler.End());
  122. CheckEntry();
  123. EXPECT_EQ(0U, entries[0]->initial_rules.size());
  124. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  125. }
  126. TEST_F(Rule, SameValueRule) {
  127. StartEntry();
  128. ASSERT_TRUE(handler.SameValueRule(entry_address, 6));
  129. ASSERT_TRUE(handler.End());
  130. CheckEntry();
  131. Module::RuleMap expected_initial;
  132. expected_initial["reg6"] = "reg6";
  133. EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  134. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  135. }
  136. TEST_F(Rule, OffsetRule) {
  137. StartEntry();
  138. ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg,
  139. DwarfCFIToModule::kCFARegister,
  140. 16927065));
  141. ASSERT_TRUE(handler.End());
  142. CheckEntry();
  143. EXPECT_EQ(0U, entries[0]->initial_rules.size());
  144. Module::RuleChangeMap expected_changes;
  145. expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^";
  146. EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
  147. }
  148. TEST_F(Rule, OffsetRuleNegative) {
  149. StartEntry();
  150. ASSERT_TRUE(handler.OffsetRule(entry_address + 1,
  151. DwarfCFIToModule::kCFARegister, 4, -34530721));
  152. ASSERT_TRUE(handler.End());
  153. CheckEntry();
  154. EXPECT_EQ(0U, entries[0]->initial_rules.size());
  155. Module::RuleChangeMap expected_changes;
  156. expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^";
  157. EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
  158. }
  159. TEST_F(Rule, ValOffsetRule) {
  160. // Use an unnamed register number, to exercise that branch of RegisterName.
  161. EXPECT_CALL(reporter, UnnamedRegister(_, 10));
  162. StartEntry();
  163. ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7,
  164. DwarfCFIToModule::kCFARegister,
  165. 10, 61812979));
  166. ASSERT_TRUE(handler.End());
  167. CheckEntry();
  168. EXPECT_EQ(0U, entries[0]->initial_rules.size());
  169. Module::RuleChangeMap expected_changes;
  170. expected_changes[entry_address + 0x5ab7][".cfa"] =
  171. "unnamed_register10 61812979 +";
  172. EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
  173. }
  174. TEST_F(Rule, RegisterRule) {
  175. StartEntry();
  176. ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3));
  177. ASSERT_TRUE(handler.End());
  178. CheckEntry();
  179. Module::RuleMap expected_initial;
  180. expected_initial[".ra"] = "reg3";
  181. EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  182. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  183. }
  184. TEST_F(Rule, ExpressionRule) {
  185. EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2"));
  186. StartEntry();
  187. ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2,
  188. "it takes two to tango"));
  189. ASSERT_TRUE(handler.End());
  190. CheckEntry();
  191. EXPECT_EQ(0U, entries[0]->initial_rules.size());
  192. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  193. }
  194. TEST_F(Rule, ValExpressionRule) {
  195. EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0"));
  196. StartEntry();
  197. ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0,
  198. "bit off more than he could chew"));
  199. ASSERT_TRUE(handler.End());
  200. CheckEntry();
  201. EXPECT_EQ(0U, entries[0]->initial_rules.size());
  202. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  203. }
  204. TEST_F(Rule, DefaultReturnAddressRule) {
  205. return_reg = 2;
  206. StartEntry();
  207. ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1));
  208. ASSERT_TRUE(handler.End());
  209. CheckEntry();
  210. Module::RuleMap expected_initial;
  211. expected_initial[".ra"] = "reg2";
  212. expected_initial["reg0"] = "reg1";
  213. EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  214. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  215. }
  216. TEST_F(Rule, DefaultReturnAddressRuleOverride) {
  217. return_reg = 2;
  218. StartEntry();
  219. ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1));
  220. ASSERT_TRUE(handler.End());
  221. CheckEntry();
  222. Module::RuleMap expected_initial;
  223. expected_initial[".ra"] = "reg1";
  224. EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  225. EXPECT_EQ(0U, entries[0]->rule_changes.size());
  226. }
  227. TEST_F(Rule, DefaultReturnAddressRuleLater) {
  228. return_reg = 2;
  229. StartEntry();
  230. ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1));
  231. ASSERT_TRUE(handler.End());
  232. CheckEntry();
  233. Module::RuleMap expected_initial;
  234. expected_initial[".ra"] = "reg2";
  235. EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  236. Module::RuleChangeMap expected_changes;
  237. expected_changes[entry_address + 1][".ra"] = "reg1";
  238. EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
  239. }
  240. TEST(RegisterNames, I386) {
  241. vector<string> names = DwarfCFIToModule::RegisterNames::I386();
  242. EXPECT_EQ("$eax", names[0]);
  243. EXPECT_EQ("$ecx", names[1]);
  244. EXPECT_EQ("$esp", names[4]);
  245. EXPECT_EQ("$eip", names[8]);
  246. }
  247. TEST(RegisterNames, ARM) {
  248. vector<string> names = DwarfCFIToModule::RegisterNames::ARM();
  249. EXPECT_EQ("r0", names[0]);
  250. EXPECT_EQ("r10", names[10]);
  251. EXPECT_EQ("sp", names[13]);
  252. EXPECT_EQ("lr", names[14]);
  253. EXPECT_EQ("pc", names[15]);
  254. }
  255. TEST(RegisterNames, X86_64) {
  256. vector<string> names = DwarfCFIToModule::RegisterNames::X86_64();
  257. EXPECT_EQ("$rax", names[0]);
  258. EXPECT_EQ("$rdx", names[1]);
  259. EXPECT_EQ("$rbp", names[6]);
  260. EXPECT_EQ("$rsp", names[7]);
  261. EXPECT_EQ("$rip", names[16]);
  262. }