Home | History | Annotate | Download | only in processor
      1 // -*- mode: C++ -*-
      2 
      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.
     31 
     32 // postfix_evaluator.h: Postfix (reverse Polish) notation expression evaluator.
     33 //
     34 // PostfixEvaluator evaluates an expression, using the expression itself
     35 // in postfix (reverse Polish) notation and a dictionary mapping constants
     36 // and variables to their values.  The evaluator supports standard
     37 // arithmetic operations, assignment into variables, and when an optional
     38 // MemoryRange is provided, dereferencing.  (Any unary key-to-value operation
     39 // may be used with a MemoryRange implementation that returns the appropriate
     40 // values, but PostfixEvaluator was written with dereferencing in mind.)
     41 //
     42 // The expression language is simple.  Expressions are supplied as strings,
     43 // with operands and operators delimited by whitespace.  Operands may be
     44 // either literal values suitable for ValueType, or constants or variables,
     45 // which reference the dictionary.  The supported binary operators are +
     46 // (addition), - (subtraction), * (multiplication), / (quotient of division),
     47 // % (modulus of division), and @ (data alignment). The alignment operator (@)
     48 // accepts a value and an alignment size, and produces a result that is a
     49 // multiple of the alignment size by truncating the input value.
     50 // The unary ^ (dereference) operator is also provided.  These operators
     51 // allow any operand to be either a literal value, constant, or variable.
     52 // Assignment (=) of any type of operand into a variable is also supported.
     53 //
     54 // The dictionary is provided as a map with string keys.  Keys beginning
     55 // with the '$' character are treated as variables.  All other keys are
     56 // treated as constants.  Any results must be assigned into variables in the
     57 // dictionary.  These variables do not need to exist prior to calling
     58 // Evaluate, unless used in an expression prior to being assigned to.  The
     59 // internal stack state is not made available after evaluation, and any
     60 // values remaining on the stack are treated as evidence of incomplete
     61 // execution and cause the evaluator to indicate failure.
     62 //
     63 // PostfixEvaluator is intended to support evaluation of "program strings"
     64 // obtained from MSVC frame data debugging information in pdb files as
     65 // returned by the DIA APIs.
     66 //
     67 // Author: Mark Mentovai
     68 
     69 #ifndef PROCESSOR_POSTFIX_EVALUATOR_H__
     70 #define PROCESSOR_POSTFIX_EVALUATOR_H__
     71 
     72 
     73 #include <map>
     74 #include <string>
     75 #include <vector>
     76 
     77 #include "common/using_std_string.h"
     78 
     79 namespace google_breakpad {
     80 
     81 using std::map;
     82 using std::vector;
     83 
     84 class MemoryRegion;
     85 
     86 template<typename ValueType>
     87 class PostfixEvaluator {
     88  public:
     89   typedef map<string, ValueType> DictionaryType;
     90   typedef map<string, bool> DictionaryValidityType;
     91 
     92   // Create a PostfixEvaluator object that may be used (with Evaluate) on
     93   // one or more expressions.  PostfixEvaluator does not take ownership of
     94   // either argument.  |memory| may be NULL, in which case dereferencing
     95   // (^) will not be supported.  |dictionary| may be NULL, but evaluation
     96   // will fail in that case unless set_dictionary is used before calling
     97   // Evaluate.
     98   PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory)
     99       : dictionary_(dictionary), memory_(memory), stack_() {}
    100 
    101   // Evaluate the expression, starting with an empty stack. The results of
    102   // execution will be stored in one (or more) variables in the dictionary.
    103   // Returns false if any failures occur during execution, leaving
    104   // variables in the dictionary in an indeterminate state. If assigned is
    105   // non-NULL, any keys set in the dictionary as a result of evaluation
    106   // will also be set to true in assigned, providing a way to determine if
    107   // an expression modifies any of its input variables.
    108   bool Evaluate(const string &expression, DictionaryValidityType *assigned);
    109 
    110   // Like Evaluate, but provides the value left on the stack to the
    111   // caller. If evaluation succeeds and leaves exactly one value on
    112   // the stack, pop that value, store it in *result, and return true.
    113   // Otherwise, return false.
    114   bool EvaluateForValue(const string &expression, ValueType *result);
    115 
    116   DictionaryType* dictionary() const { return dictionary_; }
    117 
    118   // Reset the dictionary.  PostfixEvaluator does not take ownership.
    119   void set_dictionary(DictionaryType *dictionary) {dictionary_ = dictionary; }
    120 
    121  private:
    122   // Return values for PopValueOrIdentifier
    123   enum PopResult {
    124     POP_RESULT_FAIL = 0,
    125     POP_RESULT_VALUE,
    126     POP_RESULT_IDENTIFIER
    127   };
    128 
    129   // Retrieves the topmost literal value, constant, or variable from the
    130   // stack.  Returns POP_RESULT_VALUE if the topmost entry is a literal
    131   // value, and sets |value| accordingly.  Returns POP_RESULT_IDENTIFIER
    132   // if the topmost entry is a constant or variable identifier, and sets
    133   // |identifier| accordingly.  Returns POP_RESULT_FAIL on failure, such
    134   // as when the stack is empty.
    135   PopResult PopValueOrIdentifier(ValueType *value, string *identifier);
    136 
    137   // Retrieves the topmost value on the stack.  If the topmost entry is
    138   // an identifier, the dictionary is queried for the identifier's value.
    139   // Returns false on failure, such as when the stack is empty or when
    140   // a nonexistent identifier is named.
    141   bool PopValue(ValueType *value);
    142 
    143   // Retrieves the top two values on the stack, in the style of PopValue.
    144   // value2 is popped before value1, so that value1 corresponds to the
    145   // entry that was pushed prior to value2.  Returns false on failure.
    146   bool PopValues(ValueType *value1, ValueType *value2);
    147 
    148   // Pushes a new value onto the stack.
    149   void PushValue(const ValueType &value);
    150 
    151   // Evaluate expression, updating *assigned if it is non-zero. Return
    152   // true if evaluation completes successfully. Do not clear the stack
    153   // upon successful evaluation.
    154   bool EvaluateInternal(const string &expression,
    155                         DictionaryValidityType *assigned);
    156 
    157   bool EvaluateToken(const string &token,
    158                      const string &expression,
    159                      DictionaryValidityType *assigned);
    160 
    161   // The dictionary mapping constant and variable identifiers (strings) to
    162   // values.  Keys beginning with '$' are treated as variable names, and
    163   // PostfixEvaluator is free to create and modify these keys.  Weak pointer.
    164   DictionaryType *dictionary_;
    165 
    166   // If non-NULL, the MemoryRegion used for dereference (^) operations.
    167   // If NULL, dereferencing is unsupported and will fail.  Weak pointer.
    168   const MemoryRegion *memory_;
    169 
    170   // The stack contains state information as execution progresses.  Values
    171   // are pushed on to it as the expression string is read and as operations
    172   // yield values; values are popped when used as operands to operators.
    173   vector<string> stack_;
    174 };
    175 
    176 }  // namespace google_breakpad
    177 
    178 
    179 #endif  // PROCESSOR_POSTFIX_EVALUATOR_H__
    180