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
52class 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
104class 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
128class 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
167class 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