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