|
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__ |