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

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:2fb639a02fc2
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-inl.h: Postfix (reverse Polish) notation expression
33 // evaluator.
34 //
35 // Documentation in postfix_evaluator.h.
36 //
37 // Author: Mark Mentovai
38
39 #ifndef PROCESSOR_POSTFIX_EVALUATOR_INL_H__
40 #define PROCESSOR_POSTFIX_EVALUATOR_INL_H__
41
42 #include "processor/postfix_evaluator.h"
43
44 #include <stdio.h>
45
46 #include <sstream>
47
48 #include "google_breakpad/processor/memory_region.h"
49 #include "common/logging.h"
50
51 namespace google_breakpad {
52
53 using std::istringstream;
54 using std::ostringstream;
55
56
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(); }
65
66 private:
67 vector<StackElem<ValueType> > *stack_;
68 };
69
70
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 };
88
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;
102
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 }
112
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 }
142
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 }
152
153 ValueType address;
154 if (!PopValue(&address)) {
155 BPLOG(ERROR) << "Could not PopValue to get value to dereference: " <<
156 expression;
157 return false;
158 }
159
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 }
166
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 }
176
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 }
192
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 }
224
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 }
242
243 if (!EvaluateToken(token.substr(1), expression, assigned)) {
244 return false;
245 }
246 } else if (!EvaluateToken(token, expression, assigned)) {
247 return false;
248 }
249 }
250
251 return true;
252 }
253
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 }
263
264 // Ensure that the stack is cleared before returning.
265 AutoStackClearer<ValueType> clearer(&stack_);
266
267 if (!EvaluateInternal(expr.postfix_, assigned))
268 return false;
269
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;
275
276 BPLOG(ERROR) << "Incomplete execution: " << expr;
277 return false;
278 }
279
280 template<typename ValueType>
281 bool PostfixEvaluator<ValueType>::EvaluateForValue(const Module::Expr& expr,
282 ValueType* result) {
283 switch (expr.how_) {
284
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_);
290
291 if (!EvaluateInternal(expr.postfix_, NULL))
292 return false;
293
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 }
300
301 return PopValue(result);
302 }
303
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 }
322
323 // Form the sum
324 ValueType sum = v + (int64_t)expr.offset_;
325
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 }
338
339 default:
340 return false;
341 }
342 }
343
344
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;
352
353 StackElem<ValueType> el = stack_.back();
354 stack_.pop_back();
355
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 }
366
367
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 }
390
391 *value = v;
392 }
393
394 return true;
395 }
396
397
398 template<typename ValueType>
399 bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1,
400 ValueType *value2) {
401 return PopValue(value2) && PopValue(value1);
402 }
403
404
405 template<typename ValueType>
406 void PostfixEvaluator<ValueType>::PushValue(const ValueType &value) {
407 StackElem<ValueType> el(value);
408 stack_.push_back(el);
409 }
410
411 template<typename ValueType>
412 void PostfixEvaluator<ValueType>::PushIdentifier(const UniqueString* str) {
413 StackElem<ValueType> el(str);
414 stack_.push_back(el);
415 }
416
417
418 } // namespace google_breakpad
419
420
421 #endif // PROCESSOR_POSTFIX_EVALUATOR_INL_H__

mercurial