toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator-inl.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial