/thirdparty/breakpad/processor/postfix_evaluator_unittest.cc

http://github.com/tomahawk-player/tomahawk · C++ · 399 lines · 283 code · 48 blank · 68 comment · 32 complexity · cae0b45b0eb061ab4a75ae907235fc98 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. // postfix_evaluator_unittest.cc: Unit tests for PostfixEvaluator.
  30. //
  31. // Author: Mark Mentovai
  32. #include <stdio.h>
  33. #include <map>
  34. #include <string>
  35. #include "processor/postfix_evaluator-inl.h"
  36. #include "google_breakpad/common/breakpad_types.h"
  37. #include "google_breakpad/processor/memory_region.h"
  38. #include "processor/logging.h"
  39. namespace {
  40. using std::map;
  41. using std::string;
  42. using google_breakpad::MemoryRegion;
  43. using google_breakpad::PostfixEvaluator;
  44. // FakeMemoryRegion is used to test PostfixEvaluator's dereference (^)
  45. // operator. The result of dereferencing a value is one greater than
  46. // the value.
  47. class FakeMemoryRegion : public MemoryRegion {
  48. public:
  49. virtual u_int64_t GetBase() const { return 0; }
  50. virtual u_int32_t GetSize() const { return 0; }
  51. virtual bool GetMemoryAtAddress(u_int64_t address, u_int8_t *value) const {
  52. *value = address + 1;
  53. return true;
  54. }
  55. virtual bool GetMemoryAtAddress(u_int64_t address, u_int16_t *value) const {
  56. *value = address + 1;
  57. return true;
  58. }
  59. virtual bool GetMemoryAtAddress(u_int64_t address, u_int32_t *value) const {
  60. *value = address + 1;
  61. return true;
  62. }
  63. virtual bool GetMemoryAtAddress(u_int64_t address, u_int64_t *value) const {
  64. *value = address + 1;
  65. return true;
  66. }
  67. };
  68. struct EvaluateTest {
  69. // Expression passed to PostfixEvaluator::Evaluate.
  70. const string expression;
  71. // True if the expression is expected to be evaluable, false if evaluation
  72. // is expected to fail.
  73. bool evaluable;
  74. };
  75. struct EvaluateTestSet {
  76. // The dictionary used for all tests in the set.
  77. PostfixEvaluator<unsigned int>::DictionaryType *dictionary;
  78. // The list of tests.
  79. const EvaluateTest *evaluate_tests;
  80. // The number of tests.
  81. unsigned int evaluate_test_count;
  82. // Identifiers and their expected values upon completion of the Evaluate
  83. // tests in the set.
  84. map<string, unsigned int> *validate_data;
  85. };
  86. struct EvaluateForValueTest {
  87. // Expression passed to PostfixEvaluator::Evaluate.
  88. const string expression;
  89. // True if the expression is expected to be evaluable, false if evaluation
  90. // is expected to fail.
  91. bool evaluable;
  92. // If evaluable, the value we expect it to yield.
  93. unsigned int value;
  94. };
  95. static bool RunTests() {
  96. // The first test set checks the basic operations and failure modes.
  97. PostfixEvaluator<unsigned int>::DictionaryType dictionary_0;
  98. const EvaluateTest evaluate_tests_0[] = {
  99. { "$rAdd 2 2 + =", true }, // $rAdd = 2 + 2 = 4
  100. { "$rAdd $rAdd 2 + =", true }, // $rAdd = $rAdd + 2 = 6
  101. { "$rAdd 2 $rAdd + =", true }, // $rAdd = 2 + $rAdd = 8
  102. { "99", false }, // put some junk on the stack...
  103. { "$rAdd2 2 2 + =", true }, // ...and make sure things still work
  104. { "$rAdd2\t2\n2 + =", true }, // same but with different whitespace
  105. { "$rAdd2 2 2 + = ", true }, // trailing whitespace
  106. { " $rAdd2 2 2 + =", true }, // leading whitespace
  107. { "$rAdd2 2 2 + =", true }, // extra whitespace
  108. { "$T0 2 = +", false }, // too few operands for add
  109. { "2 + =", false }, // too few operands for add
  110. { "2 +", false }, // too few operands for add
  111. { "+", false }, // too few operands for add
  112. { "^", false }, // too few operands for dereference
  113. { "=", false }, // too few operands for assignment
  114. { "2 =", false }, // too few operands for assignment
  115. { "2 2 + =", false }, // too few operands for assignment
  116. { "2 2 =", false }, // can't assign into a literal
  117. { "k 2 =", false }, // can't assign into a constant
  118. { "2", false }, // leftover data on stack
  119. { "2 2 +", false }, // leftover data on stack
  120. { "$rAdd", false }, // leftover data on stack
  121. { "0 $T1 0 0 + =", false }, // leftover data on stack
  122. { "$T2 $T2 2 + =", false }, // can't operate on an undefined value
  123. { "$rMul 9 6 * =", true }, // $rMul = 9 * 6 = 54
  124. { "$rSub 9 6 - =", true }, // $rSub = 9 - 6 = 3
  125. { "$rDivQ 9 6 / =", true }, // $rDivQ = 9 / 6 = 1
  126. { "$rDivM 9 6 % =", true }, // $rDivM = 9 % 6 = 3
  127. { "$rDeref 9 ^ =", true }, // $rDeref = ^9 = 10 (FakeMemoryRegion)
  128. { "$rAlign 36 8 @ =", true }, // $rAlign = 36 @ 8
  129. { "$rAdd3 2 2 + =$rMul2 9 6 * =", true } // smashed-equals tokenization
  130. };
  131. map<string, unsigned int> validate_data_0;
  132. validate_data_0["$rAdd"] = 8;
  133. validate_data_0["$rAdd2"] = 4;
  134. validate_data_0["$rSub"] = 3;
  135. validate_data_0["$rMul"] = 54;
  136. validate_data_0["$rDivQ"] = 1;
  137. validate_data_0["$rDivM"] = 3;
  138. validate_data_0["$rDeref"] = 10;
  139. validate_data_0["$rAlign"] = 32;
  140. validate_data_0["$rAdd3"] = 4;
  141. validate_data_0["$rMul2"] = 54;
  142. // The second test set simulates a couple of MSVC program strings.
  143. // The data is fudged a little bit because the tests use FakeMemoryRegion
  144. // instead of a real stack snapshot, but the program strings are real and
  145. // the implementation doesn't know or care that the data is not real.
  146. PostfixEvaluator<unsigned int>::DictionaryType dictionary_1;
  147. dictionary_1["$ebp"] = 0xbfff0010;
  148. dictionary_1["$eip"] = 0x10000000;
  149. dictionary_1["$esp"] = 0xbfff0000;
  150. dictionary_1[".cbSavedRegs"] = 4;
  151. dictionary_1[".cbParams"] = 4;
  152. dictionary_1[".raSearchStart"] = 0xbfff0020;
  153. const EvaluateTest evaluate_tests_1[] = {
  154. { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = "
  155. "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true },
  156. // Intermediate state: $T0 = 0xbfff0010, $eip = 0xbfff0015,
  157. // $ebp = 0xbfff0011, $esp = 0xbfff0018,
  158. // $L = 0xbfff000c, $P = 0xbfff001c
  159. { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = "
  160. "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =",
  161. true },
  162. // Intermediate state: $T0 = 0xbfff0011, $eip = 0xbfff0016,
  163. // $ebp = 0xbfff0012, $esp = 0xbfff0019,
  164. // $L = 0xbfff000d, $P = 0xbfff001d,
  165. // $ebx = 0xbffefff6
  166. { "$T0 $ebp = $T2 $esp = $T1 .raSearchStart = $eip $T1 ^ = $ebp $T0 = "
  167. "$esp $T1 4 + = $L $T0 .cbSavedRegs - = $P $T1 4 + .cbParams + = "
  168. "$ebx $T0 28 - ^ =",
  169. true }
  170. };
  171. map<string, unsigned int> validate_data_1;
  172. validate_data_1["$T0"] = 0xbfff0012;
  173. validate_data_1["$T1"] = 0xbfff0020;
  174. validate_data_1["$T2"] = 0xbfff0019;
  175. validate_data_1["$eip"] = 0xbfff0021;
  176. validate_data_1["$ebp"] = 0xbfff0012;
  177. validate_data_1["$esp"] = 0xbfff0024;
  178. validate_data_1["$L"] = 0xbfff000e;
  179. validate_data_1["$P"] = 0xbfff0028;
  180. validate_data_1["$ebx"] = 0xbffefff7;
  181. validate_data_1[".cbSavedRegs"] = 4;
  182. validate_data_1[".cbParams"] = 4;
  183. EvaluateTestSet evaluate_test_sets[] = {
  184. { &dictionary_0, evaluate_tests_0,
  185. sizeof(evaluate_tests_0) / sizeof(EvaluateTest), &validate_data_0 },
  186. { &dictionary_1, evaluate_tests_1,
  187. sizeof(evaluate_tests_1) / sizeof(EvaluateTest), &validate_data_1 },
  188. };
  189. unsigned int evaluate_test_set_count = sizeof(evaluate_test_sets) /
  190. sizeof(EvaluateTestSet);
  191. FakeMemoryRegion fake_memory;
  192. PostfixEvaluator<unsigned int> postfix_evaluator =
  193. PostfixEvaluator<unsigned int>(NULL, &fake_memory);
  194. for (unsigned int evaluate_test_set_index = 0;
  195. evaluate_test_set_index < evaluate_test_set_count;
  196. ++evaluate_test_set_index) {
  197. EvaluateTestSet *evaluate_test_set =
  198. &evaluate_test_sets[evaluate_test_set_index];
  199. const EvaluateTest *evaluate_tests = evaluate_test_set->evaluate_tests;
  200. unsigned int evaluate_test_count = evaluate_test_set->evaluate_test_count;
  201. // The same dictionary will be used for each test in the set. Earlier
  202. // tests can affect the state of the dictionary for later tests.
  203. postfix_evaluator.set_dictionary(evaluate_test_set->dictionary);
  204. // Use a new validity dictionary for each test set.
  205. PostfixEvaluator<unsigned int>::DictionaryValidityType assigned;
  206. for (unsigned int evaluate_test_index = 0;
  207. evaluate_test_index < evaluate_test_count;
  208. ++evaluate_test_index) {
  209. const EvaluateTest *evaluate_test = &evaluate_tests[evaluate_test_index];
  210. // Do the test.
  211. bool result = postfix_evaluator.Evaluate(evaluate_test->expression,
  212. &assigned);
  213. if (result != evaluate_test->evaluable) {
  214. fprintf(stderr, "FAIL: evaluate set %d/%d, test %d/%d, "
  215. "expression \"%s\", expected %s, observed %s\n",
  216. evaluate_test_set_index, evaluate_test_set_count,
  217. evaluate_test_index, evaluate_test_count,
  218. evaluate_test->expression.c_str(),
  219. evaluate_test->evaluable ? "evaluable" : "not evaluable",
  220. result ? "evaluted" : "not evaluated");
  221. return false;
  222. }
  223. }
  224. // Validate the results.
  225. for (map<string, unsigned int>::const_iterator validate_iterator =
  226. evaluate_test_set->validate_data->begin();
  227. validate_iterator != evaluate_test_set->validate_data->end();
  228. ++validate_iterator) {
  229. const string identifier = validate_iterator->first;
  230. unsigned int expected_value = validate_iterator->second;
  231. map<string, unsigned int>::const_iterator dictionary_iterator =
  232. evaluate_test_set->dictionary->find(identifier);
  233. // The identifier must exist in the dictionary.
  234. if (dictionary_iterator == evaluate_test_set->dictionary->end()) {
  235. fprintf(stderr, "FAIL: evaluate test set %d/%d, "
  236. "validate identifier \"%s\", "
  237. "expected %d, observed not found\n",
  238. evaluate_test_set_index, evaluate_test_set_count,
  239. identifier.c_str(), expected_value);
  240. return false;
  241. }
  242. // The value in the dictionary must be the same as the expected value.
  243. unsigned int observed_value = dictionary_iterator->second;
  244. if (expected_value != observed_value) {
  245. fprintf(stderr, "FAIL: evaluate test set %d/%d, "
  246. "validate identifier \"%s\", "
  247. "expected %d, observed %d\n",
  248. evaluate_test_set_index, evaluate_test_set_count,
  249. identifier.c_str(), expected_value, observed_value);
  250. return false;
  251. }
  252. // The value must be set in the "assigned" dictionary if it was a
  253. // variable. It must not have been assigned if it was a constant.
  254. bool expected_assigned = identifier[0] == '$';
  255. bool observed_assigned = false;
  256. PostfixEvaluator<unsigned int>::DictionaryValidityType::const_iterator
  257. iterator_assigned = assigned.find(identifier);
  258. if (iterator_assigned != assigned.end()) {
  259. observed_assigned = iterator_assigned->second;
  260. }
  261. if (expected_assigned != observed_assigned) {
  262. fprintf(stderr, "FAIL: evaluate test set %d/%d, "
  263. "validate assignment of \"%s\", "
  264. "expected %d, observed %d\n",
  265. evaluate_test_set_index, evaluate_test_set_count,
  266. identifier.c_str(), expected_assigned, observed_assigned);
  267. return false;
  268. }
  269. }
  270. }
  271. // EvaluateForValue tests.
  272. PostfixEvaluator<unsigned int>::DictionaryType dictionary_2;
  273. dictionary_2["$ebp"] = 0xbfff0010;
  274. dictionary_2["$eip"] = 0x10000000;
  275. dictionary_2["$esp"] = 0xbfff0000;
  276. dictionary_2[".cbSavedRegs"] = 4;
  277. dictionary_2[".cbParams"] = 4;
  278. dictionary_2[".raSearchStart"] = 0xbfff0020;
  279. const EvaluateForValueTest evaluate_for_value_tests_2[] = {
  280. { "28907223", true, 28907223 }, // simple constant
  281. { "89854293 40010015 +", true, 89854293 + 40010015 }, // arithmetic
  282. { "-870245 8769343 +", true, 7899098 }, // negative constants
  283. { "$ebp $esp - $eip +", true, 0x10000010 }, // variable references
  284. { "18929794 34015074", false, 0 }, // too many values
  285. { "$ebp $ebp 4 - =", false, 0 }, // too few values
  286. { "$new $eip = $new", true, 0x10000000 }, // make new variable
  287. { "$new 4 +", true, 0x10000004 }, // see prior assignments
  288. { ".cfa 42 = 10", false, 0 } // can't set constants
  289. };
  290. const int evaluate_for_value_tests_2_size
  291. = (sizeof (evaluate_for_value_tests_2)
  292. / sizeof (evaluate_for_value_tests_2[0]));
  293. map<string, unsigned int> validate_data_2;
  294. validate_data_2["$eip"] = 0x10000000;
  295. validate_data_2["$ebp"] = 0xbfff000c;
  296. validate_data_2["$esp"] = 0xbfff0000;
  297. validate_data_2["$new"] = 0x10000000;
  298. validate_data_2[".cbSavedRegs"] = 4;
  299. validate_data_2[".cbParams"] = 4;
  300. validate_data_2[".raSearchStart"] = 0xbfff0020;
  301. postfix_evaluator.set_dictionary(&dictionary_2);
  302. for (int i = 0; i < evaluate_for_value_tests_2_size; i++) {
  303. const EvaluateForValueTest *test = &evaluate_for_value_tests_2[i];
  304. unsigned int result;
  305. if (postfix_evaluator.EvaluateForValue(test->expression, &result)
  306. != test->evaluable) {
  307. fprintf(stderr, "FAIL: evaluate for value test %d, "
  308. "expected evaluation to %s, but it %s\n",
  309. i, test->evaluable ? "succeed" : "fail",
  310. test->evaluable ? "failed" : "succeeded");
  311. return false;
  312. }
  313. if (test->evaluable && result != test->value) {
  314. fprintf(stderr, "FAIL: evaluate for value test %d, "
  315. "expected value to be 0x%x, but it was 0x%x\n",
  316. i, test->value, result);
  317. return false;
  318. }
  319. }
  320. for (map<string, unsigned int>::iterator v = validate_data_2.begin();
  321. v != validate_data_2.end(); v++) {
  322. map<string, unsigned int>::iterator a = dictionary_2.find(v->first);
  323. if (a == dictionary_2.end()) {
  324. fprintf(stderr, "FAIL: evaluate for value dictionary check: "
  325. "expected dict[\"%s\"] to be 0x%x, but it was unset\n",
  326. v->first.c_str(), v->second);
  327. return false;
  328. } else if (a->second != v->second) {
  329. fprintf(stderr, "FAIL: evaluate for value dictionary check: "
  330. "expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n",
  331. v->first.c_str(), v->second, a->second);
  332. return false;
  333. }
  334. dictionary_2.erase(a);
  335. }
  336. map<string, unsigned int>::iterator remaining = dictionary_2.begin();
  337. if (remaining != dictionary_2.end()) {
  338. fprintf(stderr, "FAIL: evaluation of test expressions put unexpected "
  339. "values in dictionary:\n");
  340. for (; remaining != dictionary_2.end(); remaining++)
  341. fprintf(stderr, " dict[\"%s\"] == 0x%x\n",
  342. remaining->first.c_str(), remaining->second);
  343. return false;
  344. }
  345. return true;
  346. }
  347. } // namespace
  348. int main(int argc, char **argv) {
  349. BPLOG_INIT(&argc, &argv);
  350. return RunTests() ? 0 : 1;
  351. }