Home | History | Annotate | Download | only in processor
      1 // Copyright (c) 2010 Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // postfix_evaluator_unittest.cc: Unit tests for PostfixEvaluator.
     31 //
     32 // Author: Mark Mentovai
     33 
     34 #include <assert.h>
     35 #include <stdio.h>
     36 
     37 #include <map>
     38 #include <string>
     39 
     40 #include "processor/postfix_evaluator-inl.h"
     41 
     42 #include "common/using_std_string.h"
     43 #include "google_breakpad/common/breakpad_types.h"
     44 #include "google_breakpad/processor/memory_region.h"
     45 #include "processor/logging.h"
     46 
     47 
     48 namespace {
     49 
     50 
     51 using std::map;
     52 using google_breakpad::MemoryRegion;
     53 using google_breakpad::PostfixEvaluator;
     54 
     55 
     56 // FakeMemoryRegion is used to test PostfixEvaluator's dereference (^)
     57 // operator.  The result of dereferencing a value is one greater than
     58 // the value.
     59 class FakeMemoryRegion : public MemoryRegion {
     60  public:
     61   virtual uint64_t GetBase() const { return 0; }
     62   virtual uint32_t GetSize() const { return 0; }
     63   virtual bool GetMemoryAtAddress(uint64_t address, uint8_t  *value) const {
     64     *value = address + 1;
     65     return true;
     66   }
     67   virtual bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
     68     *value = address + 1;
     69     return true;
     70   }
     71   virtual bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
     72     *value = address + 1;
     73     return true;
     74   }
     75   virtual bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
     76     *value = address + 1;
     77     return true;
     78   }
     79   virtual void Print() const {
     80     assert(false);
     81   }
     82 };
     83 
     84 
     85 struct EvaluateTest {
     86   // Expression passed to PostfixEvaluator::Evaluate.
     87   const string expression;
     88 
     89   // True if the expression is expected to be evaluable, false if evaluation
     90   // is expected to fail.
     91   bool evaluable;
     92 };
     93 
     94 
     95 struct EvaluateTestSet {
     96   // The dictionary used for all tests in the set.
     97   PostfixEvaluator<unsigned int>::DictionaryType *dictionary;
     98 
     99   // The list of tests.
    100   const EvaluateTest *evaluate_tests;
    101 
    102   // The number of tests.
    103   unsigned int evaluate_test_count;
    104 
    105   // Identifiers and their expected values upon completion of the Evaluate
    106   // tests in the set.
    107   map<string, unsigned int> *validate_data;
    108 };
    109 
    110 
    111 struct EvaluateForValueTest {
    112   // Expression passed to PostfixEvaluator::Evaluate.
    113   const string expression;
    114 
    115   // True if the expression is expected to be evaluable, false if evaluation
    116   // is expected to fail.
    117   bool evaluable;
    118 
    119   // If evaluable, the value we expect it to yield.
    120   unsigned int value;
    121 };
    122 
    123 static bool RunTests() {
    124   // The first test set checks the basic operations and failure modes.
    125   PostfixEvaluator<unsigned int>::DictionaryType dictionary_0;
    126   const EvaluateTest evaluate_tests_0[] = {
    127     { "$rAdd 2 2 + =",     true },   // $rAdd = 2 + 2 = 4
    128     { "$rAdd $rAdd 2 + =", true },   // $rAdd = $rAdd + 2 = 6
    129     { "$rAdd 2 $rAdd + =", true },   // $rAdd = 2 + $rAdd = 8
    130     { "99",                false },  // put some junk on the stack...
    131     { "$rAdd2 2 2 + =",    true },   // ...and make sure things still work
    132     { "$rAdd2\t2\n2 + =",  true },   // same but with different whitespace
    133     { "$rAdd2 2 2 + = ",   true },   // trailing whitespace
    134     { " $rAdd2 2 2 + =",   true },   // leading whitespace
    135     { "$rAdd2  2 2 +   =", true },   // extra whitespace
    136     { "$T0 2 = +",         false },  // too few operands for add
    137     { "2 + =",             false },  // too few operands for add
    138     { "2 +",               false },  // too few operands for add
    139     { "+",                 false },  // too few operands for add
    140     { "^",                 false },  // too few operands for dereference
    141     { "=",                 false },  // too few operands for assignment
    142     { "2 =",               false },  // too few operands for assignment
    143     { "2 2 + =",           false },  // too few operands for assignment
    144     { "2 2 =",             false },  // can't assign into a literal
    145     { "k 2 =",             false },  // can't assign into a constant
    146     { "2",                 false },  // leftover data on stack
    147     { "2 2 +",             false },  // leftover data on stack
    148     { "$rAdd",             false },  // leftover data on stack
    149     { "0 $T1 0 0 + =",     false },  // leftover data on stack
    150     { "$T2 $T2 2 + =",     false },  // can't operate on an undefined value
    151     { "$rMul 9 6 * =",     true },   // $rMul = 9 * 6 = 54
    152     { "$rSub 9 6 - =",     true },   // $rSub = 9 - 6 = 3
    153     { "$rDivQ 9 6 / =",    true },   // $rDivQ = 9 / 6 = 1
    154     { "$rDivM 9 6 % =",    true },   // $rDivM = 9 % 6 = 3
    155     { "$rDeref 9 ^ =",     true },   // $rDeref = ^9 = 10 (FakeMemoryRegion)
    156     { "$rAlign 36 8 @ =",  true },   // $rAlign = 36 @ 8
    157     { "$rAdd3 2 2 + =$rMul2 9 6 * =", true } // smashed-equals tokenization
    158   };
    159   map<string, unsigned int> validate_data_0;
    160   validate_data_0["$rAdd"]   = 8;
    161   validate_data_0["$rAdd2"]  = 4;
    162   validate_data_0["$rSub"]   = 3;
    163   validate_data_0["$rMul"]   = 54;
    164   validate_data_0["$rDivQ"]  = 1;
    165   validate_data_0["$rDivM"]  = 3;
    166   validate_data_0["$rDeref"] = 10;
    167   validate_data_0["$rAlign"] = 32;
    168   validate_data_0["$rAdd3"]  = 4;
    169   validate_data_0["$rMul2"]  = 54;
    170 
    171   // The second test set simulates a couple of MSVC program strings.
    172   // The data is fudged a little bit because the tests use FakeMemoryRegion
    173   // instead of a real stack snapshot, but the program strings are real and
    174   // the implementation doesn't know or care that the data is not real.
    175   PostfixEvaluator<unsigned int>::DictionaryType dictionary_1;
    176   dictionary_1["$ebp"] = 0xbfff0010;
    177   dictionary_1["$eip"] = 0x10000000;
    178   dictionary_1["$esp"] = 0xbfff0000;
    179   dictionary_1[".cbSavedRegs"] = 4;
    180   dictionary_1[".cbParams"] = 4;
    181   dictionary_1[".raSearchStart"] = 0xbfff0020;
    182   const EvaluateTest evaluate_tests_1[] = {
    183     { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = "
    184       "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true },
    185     // Intermediate state: $T0  = 0xbfff0010, $eip = 0xbfff0015,
    186     //                     $ebp = 0xbfff0011, $esp = 0xbfff0018,
    187     //                     $L   = 0xbfff000c, $P   = 0xbfff001c
    188     { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = "
    189       "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =",
    190       true },
    191     // Intermediate state: $T0  = 0xbfff0011, $eip = 0xbfff0016,
    192     //                     $ebp = 0xbfff0012, $esp = 0xbfff0019,
    193     //                     $L   = 0xbfff000d, $P   = 0xbfff001d,
    194     //                     $ebx = 0xbffefff6
    195     { "$T0 $ebp = $T2 $esp = $T1 .raSearchStart = $eip $T1 ^ = $ebp $T0 = "
    196       "$esp $T1 4 + = $L $T0 .cbSavedRegs - = $P $T1 4 + .cbParams + = "
    197       "$ebx $T0 28 - ^ =",
    198       true }
    199   };
    200   map<string, unsigned int> validate_data_1;
    201   validate_data_1["$T0"]  = 0xbfff0012;
    202   validate_data_1["$T1"]  = 0xbfff0020;
    203   validate_data_1["$T2"]  = 0xbfff0019;
    204   validate_data_1["$eip"] = 0xbfff0021;
    205   validate_data_1["$ebp"] = 0xbfff0012;
    206   validate_data_1["$esp"] = 0xbfff0024;
    207   validate_data_1["$L"]   = 0xbfff000e;
    208   validate_data_1["$P"]   = 0xbfff0028;
    209   validate_data_1["$ebx"] = 0xbffefff7;
    210   validate_data_1[".cbSavedRegs"] = 4;
    211   validate_data_1[".cbParams"] = 4;
    212 
    213   EvaluateTestSet evaluate_test_sets[] = {
    214     { &dictionary_0, evaluate_tests_0,
    215           sizeof(evaluate_tests_0) / sizeof(EvaluateTest), &validate_data_0 },
    216     { &dictionary_1, evaluate_tests_1,
    217           sizeof(evaluate_tests_1) / sizeof(EvaluateTest), &validate_data_1 },
    218   };
    219 
    220   unsigned int evaluate_test_set_count = sizeof(evaluate_test_sets) /
    221                                          sizeof(EvaluateTestSet);
    222 
    223   FakeMemoryRegion fake_memory;
    224   PostfixEvaluator<unsigned int> postfix_evaluator =
    225       PostfixEvaluator<unsigned int>(NULL, &fake_memory);
    226 
    227   for (unsigned int evaluate_test_set_index = 0;
    228        evaluate_test_set_index < evaluate_test_set_count;
    229        ++evaluate_test_set_index) {
    230     EvaluateTestSet *evaluate_test_set =
    231         &evaluate_test_sets[evaluate_test_set_index];
    232     const EvaluateTest *evaluate_tests = evaluate_test_set->evaluate_tests;
    233     unsigned int evaluate_test_count = evaluate_test_set->evaluate_test_count;
    234 
    235     // The same dictionary will be used for each test in the set.  Earlier
    236     // tests can affect the state of the dictionary for later tests.
    237     postfix_evaluator.set_dictionary(evaluate_test_set->dictionary);
    238 
    239     // Use a new validity dictionary for each test set.
    240     PostfixEvaluator<unsigned int>::DictionaryValidityType assigned;
    241 
    242     for (unsigned int evaluate_test_index = 0;
    243          evaluate_test_index < evaluate_test_count;
    244          ++evaluate_test_index) {
    245       const EvaluateTest *evaluate_test = &evaluate_tests[evaluate_test_index];
    246 
    247       // Do the test.
    248       bool result = postfix_evaluator.Evaluate(evaluate_test->expression,
    249                                                &assigned);
    250       if (result != evaluate_test->evaluable) {
    251         fprintf(stderr, "FAIL: evaluate set %d/%d, test %d/%d, "
    252                         "expression \"%s\", expected %s, observed %s\n",
    253                 evaluate_test_set_index, evaluate_test_set_count,
    254                 evaluate_test_index, evaluate_test_count,
    255                 evaluate_test->expression.c_str(),
    256                 evaluate_test->evaluable ? "evaluable" : "not evaluable",
    257                 result ? "evaluted" : "not evaluated");
    258         return false;
    259       }
    260     }
    261 
    262     // Validate the results.
    263     for (map<string, unsigned int>::const_iterator validate_iterator =
    264             evaluate_test_set->validate_data->begin();
    265         validate_iterator != evaluate_test_set->validate_data->end();
    266         ++validate_iterator) {
    267       const string identifier = validate_iterator->first;
    268       unsigned int expected_value = validate_iterator->second;
    269 
    270       map<string, unsigned int>::const_iterator dictionary_iterator =
    271           evaluate_test_set->dictionary->find(identifier);
    272 
    273       // The identifier must exist in the dictionary.
    274       if (dictionary_iterator == evaluate_test_set->dictionary->end()) {
    275         fprintf(stderr, "FAIL: evaluate test set %d/%d, "
    276                         "validate identifier \"%s\", "
    277                         "expected %d, observed not found\n",
    278                 evaluate_test_set_index, evaluate_test_set_count,
    279                 identifier.c_str(), expected_value);
    280         return false;
    281       }
    282 
    283       // The value in the dictionary must be the same as the expected value.
    284       unsigned int observed_value = dictionary_iterator->second;
    285       if (expected_value != observed_value) {
    286         fprintf(stderr, "FAIL: evaluate test set %d/%d, "
    287                         "validate identifier \"%s\", "
    288                         "expected %d, observed %d\n",
    289                 evaluate_test_set_index, evaluate_test_set_count,
    290                 identifier.c_str(), expected_value, observed_value);
    291         return false;
    292       }
    293 
    294       // The value must be set in the "assigned" dictionary if it was a
    295       // variable.  It must not have been assigned if it was a constant.
    296       bool expected_assigned = identifier[0] == '$';
    297       bool observed_assigned = false;
    298       PostfixEvaluator<unsigned int>::DictionaryValidityType::const_iterator
    299           iterator_assigned = assigned.find(identifier);
    300       if (iterator_assigned != assigned.end()) {
    301         observed_assigned = iterator_assigned->second;
    302       }
    303       if (expected_assigned != observed_assigned) {
    304         fprintf(stderr, "FAIL: evaluate test set %d/%d, "
    305                         "validate assignment of \"%s\", "
    306                         "expected %d, observed %d\n",
    307                 evaluate_test_set_index, evaluate_test_set_count,
    308                 identifier.c_str(), expected_assigned, observed_assigned);
    309         return false;
    310       }
    311     }
    312   }
    313 
    314   // EvaluateForValue tests.
    315   PostfixEvaluator<unsigned int>::DictionaryType dictionary_2;
    316   dictionary_2["$ebp"] = 0xbfff0010;
    317   dictionary_2["$eip"] = 0x10000000;
    318   dictionary_2["$esp"] = 0xbfff0000;
    319   dictionary_2[".cbSavedRegs"] = 4;
    320   dictionary_2[".cbParams"] = 4;
    321   dictionary_2[".raSearchStart"] = 0xbfff0020;
    322   const EvaluateForValueTest evaluate_for_value_tests_2[] = {
    323     { "28907223",               true,  28907223 },      // simple constant
    324     { "89854293 40010015 +",    true,  89854293 + 40010015 }, // arithmetic
    325     { "-870245 8769343 +",      true,  7899098 },       // negative constants
    326     { "$ebp $esp - $eip +",     true,  0x10000010 },    // variable references
    327     { "18929794 34015074",      false, 0 },             // too many values
    328     { "$ebp $ebp 4 - =",        false, 0 },             // too few values
    329     { "$new $eip = $new",       true,  0x10000000 },    // make new variable
    330     { "$new 4 +",               true,  0x10000004 },    // see prior assignments
    331     { ".cfa 42 = 10",           false, 0 }              // can't set constants
    332   };
    333   const int evaluate_for_value_tests_2_size
    334       = (sizeof (evaluate_for_value_tests_2)
    335          / sizeof (evaluate_for_value_tests_2[0]));
    336   map<string, unsigned int> validate_data_2;
    337   validate_data_2["$eip"] = 0x10000000;
    338   validate_data_2["$ebp"] = 0xbfff000c;
    339   validate_data_2["$esp"] = 0xbfff0000;
    340   validate_data_2["$new"] = 0x10000000;
    341   validate_data_2[".cbSavedRegs"] = 4;
    342   validate_data_2[".cbParams"] = 4;
    343   validate_data_2[".raSearchStart"] = 0xbfff0020;
    344 
    345   postfix_evaluator.set_dictionary(&dictionary_2);
    346   for (int i = 0; i < evaluate_for_value_tests_2_size; i++) {
    347     const EvaluateForValueTest *test = &evaluate_for_value_tests_2[i];
    348     unsigned int result;
    349     if (postfix_evaluator.EvaluateForValue(test->expression, &result)
    350         != test->evaluable) {
    351       fprintf(stderr, "FAIL: evaluate for value test %d, "
    352               "expected evaluation to %s, but it %s\n",
    353               i, test->evaluable ? "succeed" : "fail",
    354               test->evaluable ? "failed" : "succeeded");
    355       return false;
    356     }
    357     if (test->evaluable && result != test->value) {
    358       fprintf(stderr, "FAIL: evaluate for value test %d, "
    359               "expected value to be 0x%x, but it was 0x%x\n",
    360               i, test->value, result);
    361       return false;
    362     }
    363   }
    364 
    365   for (map<string, unsigned int>::iterator v = validate_data_2.begin();
    366        v != validate_data_2.end(); v++) {
    367     map<string, unsigned int>::iterator a = dictionary_2.find(v->first);
    368     if (a == dictionary_2.end()) {
    369       fprintf(stderr, "FAIL: evaluate for value dictionary check: "
    370               "expected dict[\"%s\"] to be 0x%x, but it was unset\n",
    371               v->first.c_str(), v->second);
    372       return false;
    373     } else if (a->second != v->second) {
    374       fprintf(stderr, "FAIL: evaluate for value dictionary check: "
    375               "expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n",
    376               v->first.c_str(), v->second, a->second);
    377       return false;
    378     }
    379     dictionary_2.erase(a);
    380   }
    381 
    382   map<string, unsigned int>::iterator remaining = dictionary_2.begin();
    383   if (remaining != dictionary_2.end()) {
    384     fprintf(stderr, "FAIL: evaluation of test expressions put unexpected "
    385             "values in dictionary:\n");
    386     for (; remaining != dictionary_2.end(); remaining++)
    387       fprintf(stderr, "    dict[\"%s\"] == 0x%x\n",
    388               remaining->first.c_str(), remaining->second);
    389     return false;
    390   }
    391 
    392   return true;
    393 }
    394 
    395 
    396 }  // namespace
    397 
    398 
    399 int main(int argc, char **argv) {
    400   BPLOG_INIT(&argc, &argv);
    401 
    402   return RunTests() ? 0 : 1;
    403 }
    404