/thirdparty/breakpad/processor/postfix_evaluator-inl.h

http://github.com/tomahawk-player/tomahawk · C++ Header · 363 lines · 233 code · 49 blank · 81 comment · 71 complexity · df9857d2b62967333ed1b2518c2dc419 MD5 · raw file

  1. // -*- mode: c++ -*-
  2. // Copyright (c) 2010 Google Inc.
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // postfix_evaluator-inl.h: Postfix (reverse Polish) notation expression
  31. // evaluator.
  32. //
  33. // Documentation in postfix_evaluator.h.
  34. //
  35. // Author: Mark Mentovai
  36. #ifndef PROCESSOR_POSTFIX_EVALUATOR_INL_H__
  37. #define PROCESSOR_POSTFIX_EVALUATOR_INL_H__
  38. #include "processor/postfix_evaluator.h"
  39. #include <stdio.h>
  40. #include <sstream>
  41. #include "google_breakpad/processor/memory_region.h"
  42. #include "processor/logging.h"
  43. namespace google_breakpad {
  44. using std::istringstream;
  45. using std::ostringstream;
  46. // A small class used in Evaluate to make sure to clean up the stack
  47. // before returning failure.
  48. class AutoStackClearer {
  49. public:
  50. explicit AutoStackClearer(vector<string> *stack) : stack_(stack) {}
  51. ~AutoStackClearer() { stack_->clear(); }
  52. private:
  53. vector<string> *stack_;
  54. };
  55. template<typename ValueType>
  56. bool PostfixEvaluator<ValueType>::EvaluateToken(
  57. const string &token,
  58. const string &expression,
  59. DictionaryValidityType *assigned) {
  60. // There are enough binary operations that do exactly the same thing
  61. // (other than the specific operation, of course) that it makes sense
  62. // to share as much code as possible.
  63. enum BinaryOperation {
  64. BINARY_OP_NONE = 0,
  65. BINARY_OP_ADD,
  66. BINARY_OP_SUBTRACT,
  67. BINARY_OP_MULTIPLY,
  68. BINARY_OP_DIVIDE_QUOTIENT,
  69. BINARY_OP_DIVIDE_MODULUS,
  70. BINARY_OP_ALIGN
  71. };
  72. BinaryOperation operation = BINARY_OP_NONE;
  73. if (token == "+")
  74. operation = BINARY_OP_ADD;
  75. else if (token == "-")
  76. operation = BINARY_OP_SUBTRACT;
  77. else if (token == "*")
  78. operation = BINARY_OP_MULTIPLY;
  79. else if (token == "/")
  80. operation = BINARY_OP_DIVIDE_QUOTIENT;
  81. else if (token == "%")
  82. operation = BINARY_OP_DIVIDE_MODULUS;
  83. else if (token == "@")
  84. operation = BINARY_OP_ALIGN;
  85. if (operation != BINARY_OP_NONE) {
  86. // Get the operands.
  87. ValueType operand1 = ValueType();
  88. ValueType operand2 = ValueType();
  89. if (!PopValues(&operand1, &operand2)) {
  90. BPLOG(ERROR) << "Could not PopValues to get two values for binary "
  91. "operation " << token << ": " << expression;
  92. return false;
  93. }
  94. // Perform the operation.
  95. ValueType result;
  96. switch (operation) {
  97. case BINARY_OP_ADD:
  98. result = operand1 + operand2;
  99. break;
  100. case BINARY_OP_SUBTRACT:
  101. result = operand1 - operand2;
  102. break;
  103. case BINARY_OP_MULTIPLY:
  104. result = operand1 * operand2;
  105. break;
  106. case BINARY_OP_DIVIDE_QUOTIENT:
  107. result = operand1 / operand2;
  108. break;
  109. case BINARY_OP_DIVIDE_MODULUS:
  110. result = operand1 % operand2;
  111. break;
  112. case BINARY_OP_ALIGN:
  113. result =
  114. operand1 & (static_cast<ValueType>(-1) ^ (operand2 - 1));
  115. break;
  116. case BINARY_OP_NONE:
  117. // This will not happen, but compilers will want a default or
  118. // BINARY_OP_NONE case.
  119. BPLOG(ERROR) << "Not reached!";
  120. return false;
  121. break;
  122. }
  123. // Save the result.
  124. PushValue(result);
  125. } else if (token == "^") {
  126. // ^ for unary dereference. Can't dereference without memory.
  127. if (!memory_) {
  128. BPLOG(ERROR) << "Attempt to dereference without memory: " <<
  129. expression;
  130. return false;
  131. }
  132. ValueType address;
  133. if (!PopValue(&address)) {
  134. BPLOG(ERROR) << "Could not PopValue to get value to derefence: " <<
  135. expression;
  136. return false;
  137. }
  138. ValueType value;
  139. if (!memory_->GetMemoryAtAddress(address, &value)) {
  140. BPLOG(ERROR) << "Could not dereference memory at address " <<
  141. HexString(address) << ": " << expression;
  142. return false;
  143. }
  144. PushValue(value);
  145. } else if (token == "=") {
  146. // = for assignment.
  147. ValueType value;
  148. if (!PopValue(&value)) {
  149. BPLOG(INFO) << "Could not PopValue to get value to assign: " <<
  150. expression;
  151. return false;
  152. }
  153. // Assignment is only meaningful when assigning into an identifier.
  154. // The identifier must name a variable, not a constant. Variables
  155. // begin with '$'.
  156. string identifier;
  157. if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER) {
  158. BPLOG(ERROR) << "PopValueOrIdentifier returned a value, but an "
  159. "identifier is needed to assign " <<
  160. HexString(value) << ": " << expression;
  161. return false;
  162. }
  163. if (identifier.empty() || identifier[0] != '$') {
  164. BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " <<
  165. identifier << ": " << expression;
  166. return false;
  167. }
  168. (*dictionary_)[identifier] = value;
  169. if (assigned)
  170. (*assigned)[identifier] = true;
  171. } else {
  172. // The token is not an operator, it's a literal value or an identifier.
  173. // Push it onto the stack as-is. Use push_back instead of PushValue
  174. // because PushValue pushes ValueType as a string, but token is already
  175. // a string.
  176. stack_.push_back(token);
  177. }
  178. return true;
  179. }
  180. template<typename ValueType>
  181. bool PostfixEvaluator<ValueType>::EvaluateInternal(
  182. const string &expression,
  183. DictionaryValidityType *assigned) {
  184. // Tokenize, splitting on whitespace.
  185. istringstream stream(expression);
  186. string token;
  187. while (stream >> token) {
  188. // Normally, tokens are whitespace-separated, but occasionally, the
  189. // assignment operator is smashed up against the next token, i.e.
  190. // $T0 $ebp 128 + =$eip $T0 4 + ^ =$ebp $T0 ^ =
  191. // This has been observed in program strings produced by MSVS 2010 in LTO
  192. // mode.
  193. if (token.size() > 1 && token[0] == '=') {
  194. if (!EvaluateToken("=", expression, assigned)) {
  195. return false;
  196. }
  197. if (!EvaluateToken(token.substr(1), expression, assigned)) {
  198. return false;
  199. }
  200. } else if (!EvaluateToken(token, expression, assigned)) {
  201. return false;
  202. }
  203. }
  204. return true;
  205. }
  206. template<typename ValueType>
  207. bool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
  208. DictionaryValidityType *assigned) {
  209. // Ensure that the stack is cleared before returning.
  210. AutoStackClearer clearer(&stack_);
  211. if (!EvaluateInternal(expression, assigned))
  212. return false;
  213. // If there's anything left on the stack, it indicates incomplete execution.
  214. // This is a failure case. If the stack is empty, evalution was complete
  215. // and successful.
  216. if (stack_.empty())
  217. return true;
  218. BPLOG(ERROR) << "Incomplete execution: " << expression;
  219. return false;
  220. }
  221. template<typename ValueType>
  222. bool PostfixEvaluator<ValueType>::EvaluateForValue(const string &expression,
  223. ValueType *result) {
  224. // Ensure that the stack is cleared before returning.
  225. AutoStackClearer clearer(&stack_);
  226. if (!EvaluateInternal(expression, NULL))
  227. return false;
  228. // A successful execution should leave exactly one value on the stack.
  229. if (stack_.size() != 1) {
  230. BPLOG(ERROR) << "Expression yielded bad number of results: "
  231. << "'" << expression << "'";
  232. return false;
  233. }
  234. return PopValue(result);
  235. }
  236. template<typename ValueType>
  237. typename PostfixEvaluator<ValueType>::PopResult
  238. PostfixEvaluator<ValueType>::PopValueOrIdentifier(
  239. ValueType *value, string *identifier) {
  240. // There needs to be at least one element on the stack to pop.
  241. if (!stack_.size())
  242. return POP_RESULT_FAIL;
  243. string token = stack_.back();
  244. stack_.pop_back();
  245. // First, try to treat the value as a literal. Literals may have leading
  246. // '-' sign, and the entire remaining string must be parseable as
  247. // ValueType. If this isn't possible, it can't be a literal, so treat it
  248. // as an identifier instead.
  249. //
  250. // Some versions of the libstdc++, the GNU standard C++ library, have
  251. // stream extractors for unsigned integer values that permit a leading
  252. // '-' sign (6.0.13); others do not (6.0.9). Since we require it, we
  253. // handle it explicitly here.
  254. istringstream token_stream(token);
  255. ValueType literal = ValueType();
  256. bool negative;
  257. if (token_stream.peek() == '-') {
  258. negative = true;
  259. token_stream.get();
  260. } else {
  261. negative = false;
  262. }
  263. if (token_stream >> literal && token_stream.peek() == EOF) {
  264. if (value) {
  265. *value = literal;
  266. }
  267. if (negative)
  268. *value = -*value;
  269. return POP_RESULT_VALUE;
  270. } else {
  271. if (identifier) {
  272. *identifier = token;
  273. }
  274. return POP_RESULT_IDENTIFIER;
  275. }
  276. }
  277. template<typename ValueType>
  278. bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) {
  279. ValueType literal = ValueType();
  280. string token;
  281. PopResult result;
  282. if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) {
  283. return false;
  284. } else if (result == POP_RESULT_VALUE) {
  285. // This is the easy case.
  286. *value = literal;
  287. } else { // result == POP_RESULT_IDENTIFIER
  288. // There was an identifier at the top of the stack. Resolve it to a
  289. // value by looking it up in the dictionary.
  290. typename DictionaryType::const_iterator iterator =
  291. dictionary_->find(token);
  292. if (iterator == dictionary_->end()) {
  293. // The identifier wasn't found in the dictionary. Don't imply any
  294. // default value, just fail.
  295. BPLOG(INFO) << "Identifier " << token << " not in dictionary";
  296. return false;
  297. }
  298. *value = iterator->second;
  299. }
  300. return true;
  301. }
  302. template<typename ValueType>
  303. bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1,
  304. ValueType *value2) {
  305. return PopValue(value2) && PopValue(value1);
  306. }
  307. template<typename ValueType>
  308. void PostfixEvaluator<ValueType>::PushValue(const ValueType &value) {
  309. ostringstream token_stream;
  310. token_stream << value;
  311. stack_.push_back(token_stream.str());
  312. }
  313. } // namespace google_breakpad
  314. #endif // PROCESSOR_POSTFIX_EVALUATOR_INL_H__