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 <[email protected]> <[email protected]> 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: MockMemoryRegion()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. Init(uint64_t base_address,const string & contents)59 void Init(uint64_t base_address, const string& contents) { 60 base_address_ = base_address; 61 contents_ = contents; 62 } 63 GetBase()64 uint64_t GetBase() const { return base_address_; } GetSize()65 uint32_t GetSize() const { return contents_.size(); } 66 GetMemoryAtAddress(uint64_t address,uint8_t * value)67 bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { 68 return GetMemoryLittleEndian(address, value); 69 } GetMemoryAtAddress(uint64_t address,uint16_t * value)70 bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { 71 return GetMemoryLittleEndian(address, value); 72 } GetMemoryAtAddress(uint64_t address,uint32_t * value)73 bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { 74 return GetMemoryLittleEndian(address, value); 75 } GetMemoryAtAddress(uint64_t address,uint64_t * value)76 bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { 77 return GetMemoryLittleEndian(address, value); 78 } Print()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> GetMemoryLittleEndian(uint64_t address,ValueType * value)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: MockCodeModule(uint64_t base_address,uint64_t size,const string & code_file,const string & version)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 base_address()110 uint64_t base_address() const { return base_address_; } size()111 uint64_t size() const { return size_; } code_file()112 string code_file() const { return code_file_; } code_identifier()113 string code_identifier() const { return code_file_; } debug_file()114 string debug_file() const { return code_file_; } debug_identifier()115 string debug_identifier() const { return code_file_; } version()116 string version() const { return version_; } Copy()117 google_breakpad::CodeModule* Copy() const { 118 abort(); // Tests won't use this. 119 } is_unloaded()120 virtual bool is_unloaded() const { return false; } shrink_down_delta()121 virtual uint64_t shrink_down_delta() const { return 0; } SetShrinkDownDelta(uint64_t shrink_down_delta)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 Add(const MockCodeModule * module)136 void Add(const MockCodeModule* module) { 137 modules_.push_back(module); 138 } 139 module_count()140 unsigned int module_count() const { return modules_.size(); } 141 GetModuleForAddress(uint64_t address)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 GetMainModule()153 const CodeModule* GetMainModule() const { return modules_[0]; } 154 GetModuleAtSequence(unsigned int sequence)155 const CodeModule* GetModuleAtSequence(unsigned int sequence) const { 156 return modules_.at(sequence); 157 } 158 GetModuleAtIndex(unsigned int index)159 const CodeModule* GetModuleAtIndex(unsigned int index) const { 160 return modules_.at(index); 161 } 162 Copy()163 CodeModules* Copy() const { abort(); } // Tests won't use this 164 165 virtual std::vector<google_breakpad::linked_ptr<const CodeModule> > GetShrunkRangeModules()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. CopySymbolDataAndOwnTheCopy(const string & info,size_t * symbol_data_size)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 ~MockSymbolSupplier()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_ 220