3
// Copyright (c) 2010 Google Inc.
4
// All rights reserved.
6
// Redistribution and use in source and binary forms, with or without
7
// modification, are permitted provided that the following conditions are
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
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.
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
35
// Documentation in postfix_evaluator.h.
37
// Author: Mark Mentovai
39
#ifndef PROCESSOR_POSTFIX_EVALUATOR_INL_H__
40
#define PROCESSOR_POSTFIX_EVALUATOR_INL_H__
42
#include "processor/postfix_evaluator.h"
48
#include "google_breakpad/processor/memory_region.h"
49
#include "processor/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
class AutoStackClearer {
61
explicit AutoStackClearer(vector<string> *stack) : stack_(stack) {}
62
~AutoStackClearer() { stack_->clear(); }
65
vector<string> *stack_;
69
template<typename ValueType>
70
bool PostfixEvaluator<ValueType>::EvaluateToken(
72
const string &expression,
73
DictionaryValidityType *assigned) {
74
// There are enough binary operations that do exactly the same thing
75
// (other than the specific operation, of course) that it makes sense
76
// to share as much code as possible.
77
enum BinaryOperation {
82
BINARY_OP_DIVIDE_QUOTIENT,
83
BINARY_OP_DIVIDE_MODULUS,
87
BinaryOperation operation = BINARY_OP_NONE;
89
operation = BINARY_OP_ADD;
90
else if (token == "-")
91
operation = BINARY_OP_SUBTRACT;
92
else if (token == "*")
93
operation = BINARY_OP_MULTIPLY;
94
else if (token == "/")
95
operation = BINARY_OP_DIVIDE_QUOTIENT;
96
else if (token == "%")
97
operation = BINARY_OP_DIVIDE_MODULUS;
98
else if (token == "@")
99
operation = BINARY_OP_ALIGN;
101
if (operation != BINARY_OP_NONE) {
103
ValueType operand1 = ValueType();
104
ValueType operand2 = ValueType();
105
if (!PopValues(&operand1, &operand2)) {
106
BPLOG(ERROR) << "Could not PopValues to get two values for binary "
107
"operation " << token << ": " << expression;
111
// Perform the operation.
115
result = operand1 + operand2;
117
case BINARY_OP_SUBTRACT:
118
result = operand1 - operand2;
120
case BINARY_OP_MULTIPLY:
121
result = operand1 * operand2;
123
case BINARY_OP_DIVIDE_QUOTIENT:
124
result = operand1 / operand2;
126
case BINARY_OP_DIVIDE_MODULUS:
127
result = operand1 % operand2;
129
case BINARY_OP_ALIGN:
131
operand1 & (static_cast<ValueType>(-1) ^ (operand2 - 1));
134
// This will not happen, but compilers will want a default or
135
// BINARY_OP_NONE case.
136
BPLOG(ERROR) << "Not reached!";
143
} else if (token == "^") {
144
// ^ for unary dereference. Can't dereference without memory.
146
BPLOG(ERROR) << "Attempt to dereference without memory: " <<
152
if (!PopValue(&address)) {
153
BPLOG(ERROR) << "Could not PopValue to get value to derefence: " <<
159
if (!memory_->GetMemoryAtAddress(address, &value)) {
160
BPLOG(ERROR) << "Could not dereference memory at address " <<
161
HexString(address) << ": " << expression;
166
} else if (token == "=") {
169
if (!PopValue(&value)) {
170
BPLOG(INFO) << "Could not PopValue to get value to assign: " <<
175
// Assignment is only meaningful when assigning into an identifier.
176
// The identifier must name a variable, not a constant. Variables
179
if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER) {
180
BPLOG(ERROR) << "PopValueOrIdentifier returned a value, but an "
181
"identifier is needed to assign " <<
182
HexString(value) << ": " << expression;
185
if (identifier.empty() || identifier[0] != '$') {
186
BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " <<
187
identifier << ": " << expression;
191
(*dictionary_)[identifier] = value;
193
(*assigned)[identifier] = true;
195
// The token is not an operator, it's a literal value or an identifier.
196
// Push it onto the stack as-is. Use push_back instead of PushValue
197
// because PushValue pushes ValueType as a string, but token is already
199
stack_.push_back(token);
204
template<typename ValueType>
205
bool PostfixEvaluator<ValueType>::EvaluateInternal(
206
const string &expression,
207
DictionaryValidityType *assigned) {
208
// Tokenize, splitting on whitespace.
209
istringstream stream(expression);
211
while (stream >> token) {
212
// Normally, tokens are whitespace-separated, but occasionally, the
213
// assignment operator is smashed up against the next token, i.e.
214
// $T0 $ebp 128 + =$eip $T0 4 + ^ =$ebp $T0 ^ =
215
// This has been observed in program strings produced by MSVS 2010 in LTO
217
if (token.size() > 1 && token[0] == '=') {
218
if (!EvaluateToken("=", expression, assigned)) {
222
if (!EvaluateToken(token.substr(1), expression, assigned)) {
225
} else if (!EvaluateToken(token, expression, assigned)) {
233
template<typename ValueType>
234
bool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
235
DictionaryValidityType *assigned) {
236
// Ensure that the stack is cleared before returning.
237
AutoStackClearer clearer(&stack_);
239
if (!EvaluateInternal(expression, assigned))
242
// If there's anything left on the stack, it indicates incomplete execution.
243
// This is a failure case. If the stack is empty, evalution was complete
248
BPLOG(ERROR) << "Incomplete execution: " << expression;
252
template<typename ValueType>
253
bool PostfixEvaluator<ValueType>::EvaluateForValue(const string &expression,
255
// Ensure that the stack is cleared before returning.
256
AutoStackClearer clearer(&stack_);
258
if (!EvaluateInternal(expression, NULL))
261
// A successful execution should leave exactly one value on the stack.
262
if (stack_.size() != 1) {
263
BPLOG(ERROR) << "Expression yielded bad number of results: "
264
<< "'" << expression << "'";
268
return PopValue(result);
271
template<typename ValueType>
272
typename PostfixEvaluator<ValueType>::PopResult
273
PostfixEvaluator<ValueType>::PopValueOrIdentifier(
274
ValueType *value, string *identifier) {
275
// There needs to be at least one element on the stack to pop.
277
return POP_RESULT_FAIL;
279
string token = stack_.back();
282
// First, try to treat the value as a literal. Literals may have leading
283
// '-' sign, and the entire remaining string must be parseable as
284
// ValueType. If this isn't possible, it can't be a literal, so treat it
285
// as an identifier instead.
287
// Some versions of the libstdc++, the GNU standard C++ library, have
288
// stream extractors for unsigned integer values that permit a leading
289
// '-' sign (6.0.13); others do not (6.0.9). Since we require it, we
290
// handle it explicitly here.
291
istringstream token_stream(token);
292
ValueType literal = ValueType();
294
if (token_stream.peek() == '-') {
300
if (token_stream >> literal && token_stream.peek() == EOF) {
306
return POP_RESULT_VALUE;
311
return POP_RESULT_IDENTIFIER;
316
template<typename ValueType>
317
bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) {
318
ValueType literal = ValueType();
321
if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) {
323
} else if (result == POP_RESULT_VALUE) {
324
// This is the easy case.
326
} else { // result == POP_RESULT_IDENTIFIER
327
// There was an identifier at the top of the stack. Resolve it to a
328
// value by looking it up in the dictionary.
329
typename DictionaryType::const_iterator iterator =
330
dictionary_->find(token);
331
if (iterator == dictionary_->end()) {
332
// The identifier wasn't found in the dictionary. Don't imply any
333
// default value, just fail.
334
BPLOG(INFO) << "Identifier " << token << " not in dictionary";
338
*value = iterator->second;
345
template<typename ValueType>
346
bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1,
348
return PopValue(value2) && PopValue(value1);
352
template<typename ValueType>
353
void PostfixEvaluator<ValueType>::PushValue(const ValueType &value) {
354
ostringstream token_stream;
355
token_stream << value;
356
stack_.push_back(token_stream.str());
360
} // namespace google_breakpad
363
#endif // PROCESSOR_POSTFIX_EVALUATOR_INL_H__