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