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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial