/ src / processor / stackwalker_unittest_utils.h
stackwalker_unittest_utils.h
  1  // -*- mode: C++ -*-
  2  
  3  // Copyright 2010 Google LLC
  4  //
  5  // Redistribution and use in source and binary forms, with or without
  6  // modification, are permitted provided that the following conditions are
  7  // met:
  8  //
  9  //     * Redistributions of source code must retain the above copyright
 10  // notice, this list of conditions and the following disclaimer.
 11  //     * Redistributions in binary form must reproduce the above
 12  // copyright notice, this list of conditions and the following disclaimer
 13  // in the documentation and/or other materials provided with the
 14  // distribution.
 15  //     * Neither the name of Google LLC nor the names of its
 16  // contributors may be used to endorse or promote products derived from
 17  // this software without specific prior written permission.
 18  //
 19  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 20  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 21  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 22  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 23  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 24  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 25  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 26  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 27  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 28  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 29  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 30  
 31  // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
 32  
 33  // Mock classes for writing stackwalker tests, shared amongst architectures.
 34  
 35  #ifndef PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_
 36  #define PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_
 37  
 38  #include <assert.h>
 39  #include <stdlib.h>
 40  #include <string>
 41  #include <vector>
 42  
 43  #include "common/using_std_string.h"
 44  #include "google_breakpad/common/breakpad_types.h"
 45  #include "google_breakpad/processor/code_module.h"
 46  #include "google_breakpad/processor/code_modules.h"
 47  #include "google_breakpad/processor/memory_region.h"
 48  #include "google_breakpad/processor/symbol_supplier.h"
 49  #include "google_breakpad/processor/system_info.h"
 50  #include "processor/linked_ptr.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    google_breakpad::CodeModule* Copy() const {
118      abort(); // Tests won't use this.
119    }
120    virtual bool is_unloaded() const { return false; }
121    virtual uint64_t shrink_down_delta() const { return 0; }
122    virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {}
123  
124   private:
125    uint64_t base_address_;
126    uint64_t size_;
127    string code_file_;
128    string version_;
129  };
130  
131  class MockCodeModules: public google_breakpad::CodeModules {
132   public:
133    typedef google_breakpad::CodeModule CodeModule;
134    typedef google_breakpad::CodeModules CodeModules;
135  
136    void Add(const MockCodeModule* module) {
137      modules_.push_back(module);
138    }
139  
140    unsigned int module_count() const { return modules_.size(); }
141  
142    const CodeModule* GetModuleForAddress(uint64_t address) const {
143      for (ModuleVector::const_iterator i = modules_.begin();
144           i != modules_.end(); i++) {
145        const MockCodeModule* module = *i;
146        if (module->base_address() <= address &&
147            address - module->base_address() < module->size())
148          return module;
149      }
150      return NULL;
151    };
152  
153    const CodeModule* GetMainModule() const { return modules_[0]; }
154  
155    const CodeModule* GetModuleAtSequence(unsigned int sequence) const {
156      return modules_.at(sequence);
157    }
158  
159    const CodeModule* GetModuleAtIndex(unsigned int index) const {
160      return modules_.at(index);
161    }
162  
163    CodeModules* Copy() const { abort(); }  // Tests won't use this
164  
165    virtual std::vector<google_breakpad::linked_ptr<const CodeModule> >
166    GetShrunkRangeModules() const {
167      return std::vector<google_breakpad::linked_ptr<const CodeModule> >();
168    }
169  
170   private:
171    typedef std::vector<const MockCodeModule*> ModuleVector;
172    ModuleVector modules_;
173  };
174  
175  class MockSymbolSupplier: public google_breakpad::SymbolSupplier {
176   public:
177    typedef google_breakpad::CodeModule CodeModule;
178    typedef google_breakpad::SystemInfo SystemInfo;
179    MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule* module,
180                                             const SystemInfo* system_info,
181                                             string* symbol_file));
182    MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule* module,
183                                             const SystemInfo* system_info,
184                                             string* symbol_file,
185                                             string* symbol_data));
186    MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule* module,
187                                                    const SystemInfo* system_info,
188                                                    string* symbol_file,
189                                                    char** symbol_data,
190                                                    size_t* symbol_data_size));
191    MOCK_METHOD1(FreeSymbolData, void(const CodeModule* module));
192  
193    // Copies the passed string contents into a newly allocated buffer.
194    // The newly allocated buffer will be freed during destruction.
195    char* CopySymbolDataAndOwnTheCopy(const string& info,
196                                      size_t* symbol_data_size) {
197      *symbol_data_size = info.size() + 1;
198      char* symbol_data = new char[*symbol_data_size];
199      memcpy(symbol_data, info.c_str(), info.size());
200      symbol_data[info.size()] = '\0';
201      symbol_data_to_free_.push_back(symbol_data);
202      return symbol_data;
203    }
204  
205    virtual ~MockSymbolSupplier() {
206      for (SymbolDataVector::const_iterator i = symbol_data_to_free_.begin();
207           i != symbol_data_to_free_.end(); i++) {
208        char* symbol_data = *i;
209        delete [] symbol_data;
210      }
211    }
212  
213   private:
214    // List of symbol data to be freed upon destruction
215    typedef std::vector<char*> SymbolDataVector;
216    SymbolDataVector symbol_data_to_free_;
217  };
218  
219  #endif // PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_