// -*- mode: C++ -*- // Copyright (c) 2010, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> // Mock classes for writing stackwalker tests, shared amongst architectures. #ifndef PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_ #define PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_ #include <assert.h> #include <stdlib.h> #include <string> #include <vector> #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" #include "google_breakpad/processor/code_module.h" #include "google_breakpad/processor/code_modules.h" #include "google_breakpad/processor/memory_region.h" #include "google_breakpad/processor/symbol_supplier.h" #include "google_breakpad/processor/system_info.h" class MockMemoryRegion: public google_breakpad::MemoryRegion { public: MockMemoryRegion(): base_address_(0) { } // Set this region's address and contents. If we have placed an // instance of this class in a test fixture class, individual tests // can use this to provide the region's contents. void Init(uint64_t base_address, const string &contents) { base_address_ = base_address; contents_ = contents; } uint64_t GetBase() const { return base_address_; } uint32_t GetSize() const { return contents_.size(); } bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { return GetMemoryLittleEndian(address, value); } bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { return GetMemoryLittleEndian(address, value); } bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { return GetMemoryLittleEndian(address, value); } bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { return GetMemoryLittleEndian(address, value); } void Print() const { assert(false); } private: // Fetch a little-endian value from ADDRESS in contents_ whose size // is BYTES, and store it in *VALUE. Return true on success. template<typename ValueType> bool GetMemoryLittleEndian(uint64_t address, ValueType *value) const { if (address < base_address_ || address - base_address_ + sizeof(ValueType) > contents_.size()) return false; ValueType v = 0; int start = address - base_address_; // The loop condition is odd, but it's correct for size_t. for (size_t i = sizeof(ValueType) - 1; i < sizeof(ValueType); i--) v = (v << 8) | static_cast<unsigned char>(contents_[start + i]); *value = v; return true; } uint64_t base_address_; string contents_; }; class MockCodeModule: public google_breakpad::CodeModule { public: MockCodeModule(uint64_t base_address, uint64_t size, const string &code_file, const string &version) : base_address_(base_address), size_(size), code_file_(code_file) { } uint64_t base_address() const { return base_address_; } uint64_t size() const { return size_; } string code_file() const { return code_file_; } string code_identifier() const { return code_file_; } string debug_file() const { return code_file_; } string debug_identifier() const { return code_file_; } string version() const { return version_; } const google_breakpad::CodeModule *Copy() const { abort(); // Tests won't use this. } private: uint64_t base_address_; uint64_t size_; string code_file_; string version_; }; class MockCodeModules: public google_breakpad::CodeModules { public: typedef google_breakpad::CodeModule CodeModule; typedef google_breakpad::CodeModules CodeModules; void Add(const MockCodeModule *module) { modules_.push_back(module); } unsigned int module_count() const { return modules_.size(); } const CodeModule *GetModuleForAddress(uint64_t address) const { for (ModuleVector::const_iterator i = modules_.begin(); i != modules_.end(); i++) { const MockCodeModule *module = *i; if (module->base_address() <= address && address - module->base_address() < module->size()) return module; } return NULL; }; const CodeModule *GetMainModule() const { return modules_[0]; } const CodeModule *GetModuleAtSequence(unsigned int sequence) const { return modules_.at(sequence); } const CodeModule *GetModuleAtIndex(unsigned int index) const { return modules_.at(index); } const CodeModules *Copy() const { abort(); } // Tests won't use this. private: typedef std::vector<const MockCodeModule *> ModuleVector; ModuleVector modules_; }; class MockSymbolSupplier: public google_breakpad::SymbolSupplier { public: typedef google_breakpad::CodeModule CodeModule; typedef google_breakpad::SystemInfo SystemInfo; MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule *module, const SystemInfo *system_info, string *symbol_file)); MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule *module, const SystemInfo *system_info, string *symbol_file, string *symbol_data)); MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule *module, const SystemInfo *system_info, string *symbol_file, char **symbol_data, size_t *symbol_data_size)); MOCK_METHOD1(FreeSymbolData, void(const CodeModule *module)); // Copies the passed string contents into a newly allocated buffer. // The newly allocated buffer will be freed during destruction. char* CopySymbolDataAndOwnTheCopy(const std::string &info, size_t *symbol_data_size) { *symbol_data_size = info.size() + 1; char *symbol_data = new char[*symbol_data_size]; memcpy(symbol_data, info.c_str(), info.size()); symbol_data[info.size()] = '\0'; symbol_data_to_free_.push_back(symbol_data); return symbol_data; } virtual ~MockSymbolSupplier() { for (SymbolDataVector::const_iterator i = symbol_data_to_free_.begin(); i != symbol_data_to_free_.end(); i++) { char* symbol_data = *i; delete [] symbol_data; } } private: // List of symbol data to be freed upon destruction typedef std::vector<char*> SymbolDataVector; SymbolDataVector symbol_data_to_free_; }; #endif // PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_