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 // Original author: Jim Blandy <jimb (at) mozilla.com> <jimb (at) red-bean.com>
     33 
     34 // Mock classes for writing stackwalker tests, shared amongst architectures.
     35 
     36 #ifndef PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_
     37 #define PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_
     38 
     39 #include <assert.h>
     40 #include <stdlib.h>
     41 #include <string>
     42 #include <vector>
     43 
     44 #include "common/using_std_string.h"
     45 #include "google_breakpad/common/breakpad_types.h"
     46 #include "google_breakpad/processor/code_module.h"
     47 #include "google_breakpad/processor/code_modules.h"
     48 #include "google_breakpad/processor/memory_region.h"
     49 #include "google_breakpad/processor/symbol_supplier.h"
     50 #include "google_breakpad/processor/system_info.h"
     51 
     52 class MockMemoryRegion: public google_breakpad::MemoryRegion {
     53  public:
     54   MockMemoryRegion(): base_address_(0) { }
     55 
     56   // Set this region's address and contents. If we have placed an
     57   // instance of this class in a test fixture class, individual tests
     58   // can use this to provide the region's contents.
     59   void Init(uint64_t base_address, const string &contents) {
     60     base_address_ = base_address;
     61     contents_ = contents;
     62   }
     63 
     64   uint64_t GetBase() const { return base_address_; }
     65   uint32_t GetSize() const { return contents_.size(); }
     66 
     67   bool GetMemoryAtAddress(uint64_t address, uint8_t  *value) const {
     68     return GetMemoryLittleEndian(address, value);
     69   }
     70   bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
     71     return GetMemoryLittleEndian(address, value);
     72   }
     73   bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
     74     return GetMemoryLittleEndian(address, value);
     75   }
     76   bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
     77     return GetMemoryLittleEndian(address, value);
     78   }
     79   void Print() const {
     80     assert(false);
     81   }
     82 
     83  private:
     84   // Fetch a little-endian value from ADDRESS in contents_ whose size
     85   // is BYTES, and store it in *VALUE. Return true on success.
     86   template<typename ValueType>
     87   bool GetMemoryLittleEndian(uint64_t address, ValueType *value) const {
     88     if (address < base_address_ ||
     89         address - base_address_ + sizeof(ValueType) > contents_.size())
     90       return false;
     91     ValueType v = 0;
     92     int start = address - base_address_;
     93     // The loop condition is odd, but it's correct for size_t.
     94     for (size_t i = sizeof(ValueType) - 1; i < sizeof(ValueType); i--)
     95       v = (v << 8) | static_cast<unsigned char>(contents_[start + i]);
     96     *value = v;
     97     return true;
     98   }
     99 
    100   uint64_t base_address_;
    101   string contents_;
    102 };
    103 
    104 class MockCodeModule: public google_breakpad::CodeModule {
    105  public:
    106   MockCodeModule(uint64_t base_address, uint64_t size,
    107                  const string &code_file, const string &version)
    108       : base_address_(base_address), size_(size), code_file_(code_file) { }
    109 
    110   uint64_t base_address()       const { return base_address_; }
    111   uint64_t size()               const { return size_; }
    112   string code_file()        const { return code_file_; }
    113   string code_identifier()  const { return code_file_; }
    114   string debug_file()       const { return code_file_; }
    115   string debug_identifier() const { return code_file_; }
    116   string version()          const { return version_; }
    117   const google_breakpad::CodeModule *Copy() const {
    118     abort(); // Tests won't use this.
    119   }
    120 
    121  private:
    122   uint64_t base_address_;
    123   uint64_t size_;
    124   string code_file_;
    125   string version_;
    126 };
    127 
    128 class MockCodeModules: public google_breakpad::CodeModules {
    129  public:
    130   typedef google_breakpad::CodeModule CodeModule;
    131   typedef google_breakpad::CodeModules CodeModules;
    132 
    133   void Add(const MockCodeModule *module) {
    134     modules_.push_back(module);
    135   }
    136 
    137   unsigned int module_count() const { return modules_.size(); }
    138 
    139   const CodeModule *GetModuleForAddress(uint64_t address) const {
    140     for (ModuleVector::const_iterator i = modules_.begin();
    141          i != modules_.end(); i++) {
    142       const MockCodeModule *module = *i;
    143       if (module->base_address() <= address &&
    144           address - module->base_address() < module->size())
    145         return module;
    146     }
    147     return NULL;
    148   };
    149 
    150   const CodeModule *GetMainModule() const { return modules_[0]; }
    151 
    152   const CodeModule *GetModuleAtSequence(unsigned int sequence) const {
    153     return modules_.at(sequence);
    154   }
    155 
    156   const CodeModule *GetModuleAtIndex(unsigned int index) const {
    157     return modules_.at(index);
    158   }
    159 
    160   const CodeModules *Copy() const { abort(); } // Tests won't use this.
    161 
    162  private:
    163   typedef std::vector<const MockCodeModule *> ModuleVector;
    164   ModuleVector modules_;
    165 };
    166 
    167 class MockSymbolSupplier: public google_breakpad::SymbolSupplier {
    168  public:
    169   typedef google_breakpad::CodeModule CodeModule;
    170   typedef google_breakpad::SystemInfo SystemInfo;
    171   MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule *module,
    172                                            const SystemInfo *system_info,
    173                                            string *symbol_file));
    174   MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule *module,
    175                                            const SystemInfo *system_info,
    176                                            string *symbol_file,
    177                                            string *symbol_data));
    178   MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule *module,
    179                                                   const SystemInfo *system_info,
    180                                                   string *symbol_file,
    181                                                   char **symbol_data,
    182                                                   size_t *symbol_data_size));
    183   MOCK_METHOD1(FreeSymbolData, void(const CodeModule *module));
    184 
    185   // Copies the passed string contents into a newly allocated buffer.
    186   // The newly allocated buffer will be freed during destruction.
    187   char* CopySymbolDataAndOwnTheCopy(const std::string &info,
    188                                     size_t *symbol_data_size) {
    189     *symbol_data_size = info.size() + 1;
    190     char *symbol_data = new char[*symbol_data_size];
    191     memcpy(symbol_data, info.c_str(), info.size());
    192     symbol_data[info.size()] = '\0';
    193     symbol_data_to_free_.push_back(symbol_data);
    194     return symbol_data;
    195   }
    196 
    197   virtual ~MockSymbolSupplier() {
    198     for (SymbolDataVector::const_iterator i = symbol_data_to_free_.begin();
    199          i != symbol_data_to_free_.end(); i++) {
    200       char* symbol_data = *i;
    201       delete [] symbol_data;
    202     }
    203   }
    204 
    205  private:
    206   // List of symbol data to be freed upon destruction
    207   typedef std::vector<char*> SymbolDataVector;
    208   SymbolDataVector symbol_data_to_free_;
    209 };
    210 
    211 #endif // PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_
    212