| // -*- 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" | |
| #include "processor/linked_ptr.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_; } | |
| google_breakpad::CodeModule* Copy() const { | |
| abort(); // Tests won't use this. | |
| } | |
| virtual bool is_unloaded() const { return false; } | |
| virtual uint64_t shrink_down_delta() const { return 0; } | |
| virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {} | |
| 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); | |
| } | |
| CodeModules* Copy() const { abort(); } // Tests won't use this | |
| virtual std::vector<google_breakpad::linked_ptr<const CodeModule> > | |
| GetShrunkRangeModules() const { | |
| return std::vector<google_breakpad::linked_ptr<const CodeModule> >(); | |
| } | |
| 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 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_ |