aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/google_breakpad/processor/basic_source_line_resolver.h63
-rw-r--r--src/google_breakpad/processor/network_source_line_resolver.h13
-rw-r--r--src/google_breakpad/processor/source_line_resolver_base.h117
-rw-r--r--src/google_breakpad/processor/source_line_resolver_interface.h6
-rw-r--r--src/google_breakpad/processor/symbol_supplier.h9
-rw-r--r--src/processor/basic_source_line_resolver.cc384
-rw-r--r--src/processor/basic_source_line_resolver_types.h159
-rw-r--r--src/processor/exploitability_unittest.cc13
-rw-r--r--src/processor/minidump_processor_unittest.cc36
-rw-r--r--src/processor/module_factory.h62
-rw-r--r--src/processor/network_source_line_resolver.cc19
-rw-r--r--src/processor/network_source_line_server_unittest.cc6
-rw-r--r--src/processor/simple_symbol_supplier.cc21
-rw-r--r--src/processor/simple_symbol_supplier.h6
-rw-r--r--src/processor/source_line_resolver_base.cc283
-rw-r--r--src/processor/source_line_resolver_base_types.h149
-rw-r--r--src/processor/stackwalker.cc22
-rw-r--r--src/processor/stackwalker_amd64_unittest.cc9
-rw-r--r--src/processor/stackwalker_arm_unittest.cc9
-rw-r--r--src/processor/stackwalker_unittest_utils.h4
-rw-r--r--src/processor/stackwalker_x86_unittest.cc9
-rw-r--r--src/processor/windows_frame_info.h1
22 files changed, 982 insertions, 418 deletions
diff --git a/src/google_breakpad/processor/basic_source_line_resolver.h b/src/google_breakpad/processor/basic_source_line_resolver.h
index fe93f4d2..e6c13532 100644
--- a/src/google_breakpad/processor/basic_source_line_resolver.h
+++ b/src/google_breakpad/processor/basic_source_line_resolver.h
@@ -27,59 +27,56 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// BasicSourceLineResolver implements SourceLineResolverInterface, using
-// address map files produced by a compatible writer, e.g. PDBSourceLineWriter.
+// basic_source_line_resolver.h: BasicSourceLineResolver is derived from
+// SourceLineResolverBase, and is a concrete implementation of
+// SourceLineResolverInterface, using address map files produced by a
+// compatible writer, e.g. PDBSourceLineWriter.
+//
+// see "processor/source_line_resolver_base.h"
+// and "source_line_resolver_interface.h" for more documentation.
#ifndef GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__
#define GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__
#include <map>
-#include "google_breakpad/processor/source_line_resolver_interface.h"
+#include "google_breakpad/processor/source_line_resolver_base.h"
namespace google_breakpad {
using std::string;
using std::map;
-class BasicSourceLineResolver : public SourceLineResolverInterface {
+class BasicSourceLineResolver : public SourceLineResolverBase {
public:
BasicSourceLineResolver();
- virtual ~BasicSourceLineResolver();
-
- // SourceLineResolverInterface methods, see source_line_resolver_interface.h
- // for more details.
-
- // Adds a module to this resolver, returning true on success.
- // The given map_file is read into memory, and its symbols will be
- // retained until the BasicSourceLineResolver is destroyed.
- virtual bool LoadModule(const CodeModule *module, const string &map_file);
+ virtual ~BasicSourceLineResolver() { }
- // Exactly the same as above, except the given map_buffer is used
- // for symbols.
- virtual bool LoadModuleUsingMapBuffer(const CodeModule *module,
- const string &map_buffer);
-
- void UnloadModule(const CodeModule *module);
- virtual bool HasModule(const CodeModule *module);
- virtual void FillSourceLineInfo(StackFrame *frame);
- virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame);
- virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame);
+ using SourceLineResolverBase::LoadModule;
+ using SourceLineResolverBase::LoadModuleUsingMapBuffer;
+ using SourceLineResolverBase::LoadModuleUsingMemoryBuffer;
+ using SourceLineResolverBase::UnloadModule;
+ using SourceLineResolverBase::HasModule;
+ using SourceLineResolverBase::FillSourceLineInfo;
+ using SourceLineResolverBase::FindWindowsFrameInfo;
+ using SourceLineResolverBase::FindCFIFrameInfo;
private:
- template<class T> class MemAddrMap;
- struct Line;
+ // friend declarations:
+ friend class BasicModuleFactory;
+
+ // Function derives from SourceLineResolverBase::Function.
struct Function;
- struct PublicSymbol;
- struct File;
- struct CompareString {
- bool operator()(const string &s1, const string &s2) const;
- };
+ // Module implements SourceLineResolverBase::Module interface.
class Module;
- // All of the modules we've loaded
- typedef map<string, Module*, CompareString> ModuleMap;
- ModuleMap *modules_;
+ // Helper method.
+ virtual void DeleteDataAfterLoad(char *symbol_data);
+ // No-op helper methods.
+ virtual void DeleteDataUnload(const CodeModule *module) { }
+ virtual void ClearLocalMemory() { }
+ virtual void StoreDataBeforeLoad(const CodeModule *module,
+ char *symbol_data) { }
// Disallow unwanted copy ctor and assignment operator
BasicSourceLineResolver(const BasicSourceLineResolver&);
diff --git a/src/google_breakpad/processor/network_source_line_resolver.h b/src/google_breakpad/processor/network_source_line_resolver.h
index f2c7732d..f60ff701 100644
--- a/src/google_breakpad/processor/network_source_line_resolver.h
+++ b/src/google_breakpad/processor/network_source_line_resolver.h
@@ -37,8 +37,8 @@
// An implementation of the server side of the protocol is provided there
// as NetworkSourceLineServer.
-#ifndef GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_H_
-#define GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_H_
+#ifndef GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_H__
+#define GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_H__
#include <sys/socket.h>
@@ -81,6 +81,8 @@ class NetworkSourceLineResolver : public SourceLineResolverInterface,
virtual bool LoadModule(const CodeModule *module, const string &map_file);
virtual bool LoadModuleUsingMapBuffer(const CodeModule *module,
const string &map_buffer);
+ virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module,
+ char *memory_buffer);
void UnloadModule(const CodeModule *module);
@@ -104,6 +106,11 @@ class NetworkSourceLineResolver : public SourceLineResolverInterface,
const SystemInfo *system_info,
string *symbol_file,
string *symbol_data);
+ // Similar as the above GetSymbolFile() method, see the comment above.
+ virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data);
private:
int wait_milliseconds_;
@@ -165,4 +172,4 @@ class NetworkSourceLineResolver : public SourceLineResolverInterface,
} // namespace google_breakpad
-#endif // GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_H_
+#endif // GOOGLE_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_H__
diff --git a/src/google_breakpad/processor/source_line_resolver_base.h b/src/google_breakpad/processor/source_line_resolver_base.h
new file mode 100644
index 00000000..3d978877
--- /dev/null
+++ b/src/google_breakpad/processor/source_line_resolver_base.h
@@ -0,0 +1,117 @@
+// 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.
+//
+// source_line_resolver_base.h: SourceLineResolverBase, an (incomplete)
+// implementation of SourceLineResolverInterface. It serves as a common base
+// class for concrete implementations: FastSourceLineResolver and
+// BasicSourceLineResolver. It is designed for refactoring that removes
+// code redundancy in the two concrete source line resolver classes.
+//
+// See "google_breakpad/processor/source_line_resolver_interface.h" for more
+// documentation.
+
+// Author: Siyang Xie (lambxsy@google.com)
+
+#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__
+#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__
+
+#include <map>
+#include <string>
+
+#include "google_breakpad/processor/source_line_resolver_interface.h"
+
+namespace google_breakpad {
+
+using std::map;
+
+// Forward declaration.
+// ModuleFactory is a simple factory interface for creating a Module instance
+// at run-time.
+class ModuleFactory;
+
+class SourceLineResolverBase : public SourceLineResolverInterface {
+ public:
+ // Read the symbol_data from a file with given file_name.
+ // The part of code was originally in BasicSourceLineResolver::Module's
+ // LoadMap() method.
+ static bool ReadSymbolFile(char **symbol_data, const string &file_name);
+
+ protected:
+ // Users are not allowed create SourceLineResolverBase instance directly.
+ SourceLineResolverBase(ModuleFactory *module_factory);
+ virtual ~SourceLineResolverBase();
+
+ // Virtual methods inherited from SourceLineResolverInterface.
+ virtual bool LoadModule(const CodeModule *module, const string &map_file);
+ virtual bool LoadModuleUsingMapBuffer(const CodeModule *module,
+ const string &map_buffer);
+ virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module,
+ char *memory_buffer);
+ virtual void UnloadModule(const CodeModule *module);
+ virtual bool HasModule(const CodeModule *module);
+ virtual void FillSourceLineInfo(StackFrame *frame);
+ virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame);
+ virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame);
+
+ // Helper methods to manage C-String format symbol data.
+ virtual void StoreDataBeforeLoad(const CodeModule *module, char *symbol_data);
+ virtual void DeleteDataAfterLoad(char *symbol_data);
+ virtual void DeleteDataUnload(const CodeModule *module);
+ virtual void ClearLocalMemory();
+
+ // Nested structs and classes.
+ struct Line;
+ struct Function;
+ struct PublicSymbol;
+ struct CompareString {
+ bool operator()(const string &s1, const string &s2) const;
+ };
+ // Module is an interface for an in-memory symbol file.
+ class Module;
+ class AutoFileCloser;
+
+ // All of the modules we've loaded
+ typedef map<string, Module*, CompareString> ModuleMap;
+ ModuleMap *modules_;
+
+ // Creates a concrete module at run-time.
+ ModuleFactory *module_factory_;
+
+ private:
+ // ModuleFactory needs to have access to protected type Module.
+ friend class ModuleFactory;
+
+ // Disallow unwanted copy ctor and assignment operator
+ SourceLineResolverBase(const SourceLineResolverBase&);
+ void operator=(const SourceLineResolverBase&);
+};
+
+} // namespace google_breakpad
+
+#endif // GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__
diff --git a/src/google_breakpad/processor/source_line_resolver_interface.h b/src/google_breakpad/processor/source_line_resolver_interface.h
index fa45d75f..bd6a12d6 100644
--- a/src/google_breakpad/processor/source_line_resolver_interface.h
+++ b/src/google_breakpad/processor/source_line_resolver_interface.h
@@ -64,6 +64,12 @@ class SourceLineResolverInterface {
virtual bool LoadModuleUsingMapBuffer(const CodeModule *module,
const string &map_buffer) = 0;
+ // Add an interface to load symbol using C-String data insteading string.
+ // This is useful in the optimization design for avoiding unnecessary copying
+ // of symbol data, in order to improve memory efficiency.
+ virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module,
+ char *memory_buffer) = 0;
+
// Request that the specified module be unloaded from this resolver.
// A resolver may choose to ignore such a request.
virtual void UnloadModule(const CodeModule *module) = 0;
diff --git a/src/google_breakpad/processor/symbol_supplier.h b/src/google_breakpad/processor/symbol_supplier.h
index 7b9d00e4..4a41688e 100644
--- a/src/google_breakpad/processor/symbol_supplier.h
+++ b/src/google_breakpad/processor/symbol_supplier.h
@@ -75,6 +75,15 @@ class SymbolSupplier {
const SystemInfo *system_info,
string *symbol_file,
string *symbol_data) = 0;
+
+ // Same as above, except places symbol data into symbol_data as C-string in
+ // dynamically allocated memory. Using C-string as type of symbol data enables
+ // passing data by pointer, and thus avoids unncessary copying of data (to
+ // improve memory efficiency).
+ virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data) = 0;
};
} // namespace google_breakpad
diff --git a/src/processor/basic_source_line_resolver.cc b/src/processor/basic_source_line_resolver.cc
index 828f25e9..a795c4ae 100644
--- a/src/processor/basic_source_line_resolver.cc
+++ b/src/processor/basic_source_line_resolver.cc
@@ -26,6 +26,12 @@
// 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.
+//
+// basic_source_line_resolver.cc: BasicSourceLineResolver implementation.
+//
+// See basic_source_line_resolver.h and basic_source_line_resolver_types.h
+// for documentation.
+
#include <stdio.h>
#include <string.h>
@@ -37,17 +43,10 @@
#include <utility>
#include <vector>
-#include "processor/address_map-inl.h"
-#include "processor/contained_range_map-inl.h"
-#include "processor/range_map-inl.h"
-
#include "google_breakpad/processor/basic_source_line_resolver.h"
-#include "google_breakpad/processor/code_module.h"
-#include "google_breakpad/processor/stack_frame.h"
-#include "processor/cfi_frame_info.h"
-#include "processor/linked_ptr.h"
-#include "processor/scoped_ptr.h"
-#include "processor/windows_frame_info.h"
+#include "processor/basic_source_line_resolver_types.h"
+#include "processor/module_factory.h"
+
#include "processor/tokenize.h"
using std::map;
@@ -58,299 +57,33 @@ namespace google_breakpad {
static const char *kWhitespace = " \r\n";
-struct BasicSourceLineResolver::Line {
- Line(MemAddr addr, MemAddr code_size, int file_id, int source_line)
- : address(addr)
- , size(code_size)
- , source_file_id(file_id)
- , line(source_line) { }
-
- MemAddr address;
- MemAddr size;
- int source_file_id;
- int line;
-};
-
-struct BasicSourceLineResolver::Function {
- Function(const string &function_name,
- MemAddr function_address,
- MemAddr code_size,
- int set_parameter_size)
- : name(function_name), address(function_address), size(code_size),
- parameter_size(set_parameter_size) { }
-
- string name;
- MemAddr address;
- MemAddr size;
-
- // The size of parameters passed to this function on the stack.
- int parameter_size;
-
- RangeMap< MemAddr, linked_ptr<Line> > lines;
-};
-
-struct BasicSourceLineResolver::PublicSymbol {
- PublicSymbol(const string& set_name,
- MemAddr set_address,
- int set_parameter_size)
- : name(set_name),
- address(set_address),
- parameter_size(set_parameter_size) {}
-
- string name;
- MemAddr address;
-
- // If the public symbol is used as a function entry point, parameter_size
- // is set to the size of the parameters passed to the funciton on the
- // stack, if known.
- int parameter_size;
-};
-
-class BasicSourceLineResolver::Module {
- public:
- Module(const string &name) : name_(name) { }
-
- // Loads the given map file, returning true on success. Reads the
- // map file into memory and calls LoadMapFromBuffer
- bool LoadMap(const string &map_file);
-
- // Loads a map from the given buffer, returning true on success
- bool LoadMapFromBuffer(const string &map_buffer);
-
- // Looks up the given relative address, and fills the StackFrame struct
- // with the result.
- void LookupAddress(StackFrame *frame) const;
-
- // If Windows stack walking information is available covering ADDRESS,
- // return a WindowsFrameInfo structure describing it. If the information
- // is not available, returns NULL. A NULL return value does not indicate
- // an error. The caller takes ownership of any returned WindowsFrameInfo
- // object.
- WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) const;
-
- // If CFI stack walking information is available covering ADDRESS,
- // return a CFIFrameInfo structure describing it. If the information
- // is not available, return NULL. The caller takes ownership of any
- // returned CFIFrameInfo object.
- CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const;
-
- private:
- friend class BasicSourceLineResolver;
- typedef map<int, string> FileMap;
-
- // Parses a file declaration
- bool ParseFile(char *file_line);
-
- // Parses a function declaration, returning a new Function object.
- Function* ParseFunction(char *function_line);
-
- // Parses a line declaration, returning a new Line object.
- Line* ParseLine(char *line_line);
-
- // Parses a PUBLIC symbol declaration, storing it in public_symbols_.
- // Returns false if an error occurs.
- bool ParsePublicSymbol(char *public_line);
-
- // Parses a STACK WIN or STACK CFI frame info declaration, storing
- // it in the appropriate table.
- bool ParseStackInfo(char *stack_info_line);
-
- // Parses a STACK CFI record, storing it in cfi_frame_info_.
- bool ParseCFIFrameInfo(char *stack_info_line);
-
- // Parse RULE_SET, a series of rules of the sort appearing in STACK
- // CFI records, and store the given rules in FRAME_INFO.
- bool ParseCFIRuleSet(const string &rule_set, CFIFrameInfo *frame_info) const;
-
- string name_;
- FileMap files_;
- RangeMap< MemAddr, linked_ptr<Function> > functions_;
- AddressMap< MemAddr, linked_ptr<PublicSymbol> > public_symbols_;
-
- // Each element in the array is a ContainedRangeMap for a type
- // listed in WindowsFrameInfoTypes. These are split by type because
- // there may be overlaps between maps of different types, but some
- // information is only available as certain types.
- ContainedRangeMap< MemAddr, linked_ptr<WindowsFrameInfo> >
- windows_frame_info_[WindowsFrameInfo::STACK_INFO_LAST];
-
- // DWARF CFI stack walking data. The Module stores the initial rule sets
- // and rule deltas as strings, just as they appear in the symbol file:
- // although the file may contain hundreds of thousands of STACK CFI
- // records, walking a stack will only ever use a few of them, so it's
- // best to delay parsing a record until it's actually needed.
-
- // STACK CFI INIT records: for each range, an initial set of register
- // recovery rules. The RangeMap's itself gives the starting and ending
- // addresses.
- RangeMap<MemAddr, string> cfi_initial_rules_;
-
- // STACK CFI records: at a given address, the changes to the register
- // recovery rules that take effect at that address. The map key is the
- // starting address; the ending address is the key of the next entry in
- // this map, or the end of the range as given by the cfi_initial_rules_
- // entry (which FindCFIFrameInfo looks up first).
- map<MemAddr, string> cfi_delta_rules_;
-};
-
-BasicSourceLineResolver::BasicSourceLineResolver() : modules_(new ModuleMap) {
-}
-
-BasicSourceLineResolver::~BasicSourceLineResolver() {
- ModuleMap::iterator it;
- for (it = modules_->begin(); it != modules_->end(); ++it) {
- delete it->second;
- }
- delete modules_;
-}
-
-bool BasicSourceLineResolver::LoadModule(const CodeModule *module,
- const string &map_file) {
- if (module == NULL)
- return false;
-
- // Make sure we don't already have a module with the given name.
- if (modules_->find(module->code_file()) != modules_->end()) {
- BPLOG(INFO) << "Symbols for module " << module->code_file()
- << " already loaded";
- return false;
- }
-
- BPLOG(INFO) << "Loading symbols for module " << module->code_file()
- << " from " << map_file;
-
- Module *basic_module = new Module(module->code_file());
- if (!basic_module->LoadMap(map_file)) {
- delete basic_module;
- return false;
- }
-
- modules_->insert(make_pair(module->code_file(), basic_module));
- return true;
-}
-
-bool BasicSourceLineResolver::LoadModuleUsingMapBuffer(
- const CodeModule *module,
- const string &map_buffer) {
- if (!module)
- return false;
-
- // Make sure we don't already have a module with the given name.
- if (modules_->find(module->code_file()) != modules_->end()) {
- BPLOG(INFO) << "Symbols for module " << module->code_file()
- << " already loaded";
- return false;
- }
-
- BPLOG(INFO) << "Loading symbols for module " << module->code_file()
- << " from buffer";
-
- Module *basic_module = new Module(module->code_file());
- if (!basic_module->LoadMapFromBuffer(map_buffer)) {
- delete basic_module;
- return false;
- }
-
- modules_->insert(make_pair(module->code_file(), basic_module));
- return true;
-}
-
-void BasicSourceLineResolver::UnloadModule(const CodeModule *module)
-{
- if (!module)
- return;
-
- ModuleMap::iterator iter = modules_->find(module->code_file());
- if (iter != modules_->end()) {
- Module *basic_module = iter->second;
- modules_->erase(iter);
- delete basic_module;
- }
-}
-
-bool BasicSourceLineResolver::HasModule(const CodeModule *module) {
- if (!module)
- return false;
- return modules_->find(module->code_file()) != modules_->end();
-}
-
-void BasicSourceLineResolver::FillSourceLineInfo(StackFrame *frame) {
- if (frame->module) {
- ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
- if (it != modules_->end()) {
- it->second->LookupAddress(frame);
- }
- }
-}
-
-WindowsFrameInfo *BasicSourceLineResolver::FindWindowsFrameInfo(
- const StackFrame *frame) {
- if (frame->module) {
- ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
- if (it != modules_->end()) {
- return it->second->FindWindowsFrameInfo(frame);
- }
- }
- return NULL;
-}
+BasicSourceLineResolver::BasicSourceLineResolver() :
+ SourceLineResolverBase(new BasicModuleFactory) { }
-CFIFrameInfo *BasicSourceLineResolver::FindCFIFrameInfo(
- const StackFrame *frame) {
- if (frame->module) {
- ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
- if (it != modules_->end()) {
- return it->second->FindCFIFrameInfo(frame);
- }
- }
- return NULL;
+void BasicSourceLineResolver::DeleteDataAfterLoad(char *symbol_data) {
+ // Always delete allocated memory after loading symbol.
+ delete symbol_data;
}
-class AutoFileCloser {
- public:
- AutoFileCloser(FILE *file) : file_(file) {}
- ~AutoFileCloser() {
- if (file_)
- fclose(file_);
- }
-
- private:
- FILE *file_;
-};
-
-bool BasicSourceLineResolver::Module::LoadMapFromBuffer(
- const string &map_buffer) {
+bool BasicSourceLineResolver::Module::LoadMapFromMemory(char *memory_buffer) {
linked_ptr<Function> cur_func;
int line_number = 0;
- const char *map_buffer_c_str = map_buffer.c_str();
char *save_ptr;
-
- // set up our input buffer as a c-style string so we
- // can we use strtok()
- // have to copy because modifying the result of string::c_str is not
- // permitted
- size_t map_buffer_length = strlen(map_buffer_c_str);
+ size_t map_buffer_length = strlen(memory_buffer);
// If the length is 0, we can still pretend we have a symbol file. This is
- // for scenarios that want to test symbol lookup, but don't necessarily care if
- // certain modules do not have any information, like system libraries.
+ // for scenarios that want to test symbol lookup, but don't necessarily care
+ // if certain modules do not have any information, like system libraries.
if (map_buffer_length == 0) {
return true;
}
- scoped_array<char> map_buffer_chars(new char[map_buffer_length]);
- if (map_buffer_chars == NULL) {
- BPLOG(ERROR) << "Memory allocation of " << map_buffer_length <<
- " bytes failed";
- return false;
+ if (memory_buffer[map_buffer_length - 1] == '\n') {
+ memory_buffer[map_buffer_length - 1] = '\0';
}
- strncpy(map_buffer_chars.get(), map_buffer_c_str, map_buffer_length);
-
- if (map_buffer_chars[map_buffer_length - 1] == '\n') {
- map_buffer_chars[map_buffer_length - 1] = '\0';
- }
char *buffer;
- buffer = strtok_r(map_buffer_chars.get(), "\r\n", &save_ptr);
+ buffer = strtok_r(memory_buffer, "\r\n", &save_ptr);
while (buffer != NULL) {
++line_number;
@@ -413,68 +146,11 @@ bool BasicSourceLineResolver::Module::LoadMapFromBuffer(
cur_func->lines.StoreRange(line->address, line->size,
linked_ptr<Line>(line));
}
-
buffer = strtok_r(NULL, "\r\n", &save_ptr);
}
-
return true;
}
-bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
- struct stat buf;
- int error_code = stat(map_file.c_str(), &buf);
- if (error_code == -1) {
- string error_string;
- int error_code = ErrnoString(&error_string);
- BPLOG(ERROR) << "Could not open " << map_file <<
- ", error " << error_code << ": " << error_string;
- return false;
- }
-
- off_t file_size = buf.st_size;
-
- // Allocate memory for file contents, plus a null terminator
- // since we'll use strtok() on the contents.
- char *file_buffer = new char[sizeof(char)*file_size + 1];
-
- if (file_buffer == NULL) {
- BPLOG(ERROR) << "Could not allocate memory for " << map_file;
- return false;
- }
-
- BPLOG(INFO) << "Opening " << map_file;
-
- FILE *f = fopen(map_file.c_str(), "rt");
- if (!f) {
- string error_string;
- int error_code = ErrnoString(&error_string);
- BPLOG(ERROR) << "Could not open " << map_file <<
- ", error " << error_code << ": " << error_string;
- delete [] file_buffer;
- return false;
- }
-
- AutoFileCloser closer(f);
-
- int items_read = 0;
-
- items_read = fread(file_buffer, 1, file_size, f);
-
- if (items_read != file_size) {
- string error_string;
- int error_code = ErrnoString(&error_string);
- BPLOG(ERROR) << "Could not slurp " << map_file <<
- ", error " << error_code << ": " << error_string;
- delete [] file_buffer;
- return false;
- }
- file_buffer[file_size] = '\0';
- string map_buffer(file_buffer);
- delete [] file_buffer;
-
- return LoadMapFromBuffer(map_buffer);
-}
-
void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
MemAddr address = frame->instruction - frame->module->base_address();
@@ -543,7 +219,7 @@ WindowsFrameInfo *BasicSourceLineResolver::Module::FindWindowsFrameInfo(
linked_ptr<Function> function;
MemAddr function_base, function_size;
if (functions_.RetrieveNearestRange(address, &function,
- &function_base, &function_size) &&
+ &function_base, &function_size) &&
address >= function_base && address - function_base < function_size) {
result->parameter_size = function->parameter_size;
result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE;
@@ -558,7 +234,7 @@ WindowsFrameInfo *BasicSourceLineResolver::Module::FindWindowsFrameInfo(
(!function.get() || public_address > function_base)) {
result->parameter_size = public_symbol->parameter_size;
}
-
+
return NULL;
}
@@ -596,13 +272,6 @@ CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo(
return rules.release();
}
-bool BasicSourceLineResolver::Module::ParseCFIRuleSet(
- const string &rule_set, CFIFrameInfo *frame_info) const {
- CFIFrameInfoParseHandler handler(frame_info);
- CFIRuleParser parser(&handler);
- return parser.Parse(rule_set);
-}
-
bool BasicSourceLineResolver::Module::ParseFile(char *file_line) {
// FILE <id> <filename>
file_line += 5; // skip prefix
@@ -762,7 +431,7 @@ bool BasicSourceLineResolver::Module::ParseCFIFrameInfo(
// This record has the form "STACK INIT <address> <size> <rules...>".
char *address_field = strtok_r(NULL, " \r\n", &cursor);
if (!address_field) return false;
-
+
char *size_field = strtok_r(NULL, " \r\n", &cursor);
if (!size_field) return false;
@@ -784,9 +453,4 @@ bool BasicSourceLineResolver::Module::ParseCFIFrameInfo(
return true;
}
-bool BasicSourceLineResolver::CompareString::operator()(
- const string &s1, const string &s2) const {
- return strcmp(s1.c_str(), s2.c_str()) < 0;
-}
-
} // namespace google_breakpad
diff --git a/src/processor/basic_source_line_resolver_types.h b/src/processor/basic_source_line_resolver_types.h
new file mode 100644
index 00000000..f40b15b1
--- /dev/null
+++ b/src/processor/basic_source_line_resolver_types.h
@@ -0,0 +1,159 @@
+// 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.
+//
+// basic_source_line_types.h: definition of nested classes/structs in
+// BasicSourceLineResolver. It moves the definitions out of
+// basic_source_line_resolver.cc, so that other classes could have access
+// to these private nested types without including basic_source_line_resolver.cc
+//
+// Author: Siyang Xie (lambxsy@google.com)
+
+#ifndef PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_TYPES_H__
+#define PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_TYPES_H__
+
+#include <map>
+#include <string>
+
+#include "google_breakpad/processor/basic_source_line_resolver.h"
+#include "processor/source_line_resolver_base_types.h"
+
+#include "processor/address_map-inl.h"
+#include "processor/range_map-inl.h"
+#include "processor/contained_range_map-inl.h"
+
+#include "processor/linked_ptr.h"
+#include "processor/scoped_ptr.h"
+#include "google_breakpad/processor/stack_frame.h"
+#include "processor/cfi_frame_info.h"
+#include "processor/windows_frame_info.h"
+
+namespace google_breakpad {
+
+struct
+BasicSourceLineResolver::Function : public SourceLineResolverBase::Function {
+ Function(const string &function_name,
+ MemAddr function_address,
+ MemAddr code_size,
+ int set_parameter_size) : Base(function_name,
+ function_address,
+ code_size,
+ set_parameter_size),
+ lines() { }
+ RangeMap< MemAddr, linked_ptr<Line> > lines;
+ private:
+ typedef SourceLineResolverBase::Function Base;
+};
+
+
+class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
+ public:
+ explicit Module(const string &name) : name_(name) { }
+ virtual ~Module() { }
+
+ // Loads a map from the given buffer in char* type.
+ // Does NOT have ownership of memory_buffer.
+ virtual bool LoadMapFromMemory(char *memory_buffer);
+
+ // Looks up the given relative address, and fills the StackFrame struct
+ // with the result.
+ virtual void LookupAddress(StackFrame *frame) const;
+
+ // If Windows stack walking information is available covering ADDRESS,
+ // return a WindowsFrameInfo structure describing it. If the information
+ // is not available, returns NULL. A NULL return value does not indicate
+ // an error. The caller takes ownership of any returned WindowsFrameInfo
+ // object.
+ virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) const;
+
+ // If CFI stack walking information is available covering ADDRESS,
+ // return a CFIFrameInfo structure describing it. If the information
+ // is not available, return NULL. The caller takes ownership of any
+ // returned CFIFrameInfo object.
+ virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const;
+
+ private:
+ // Friend declarations.
+ friend class BasicSourceLineResolver;
+
+ typedef std::map<int, string> FileMap;
+
+ // Parses a file declaration
+ bool ParseFile(char *file_line);
+
+ // Parses a function declaration, returning a new Function object.
+ Function* ParseFunction(char *function_line);
+
+ // Parses a line declaration, returning a new Line object.
+ Line* ParseLine(char *line_line);
+
+ // Parses a PUBLIC symbol declaration, storing it in public_symbols_.
+ // Returns false if an error occurs.
+ bool ParsePublicSymbol(char *public_line);
+
+ // Parses a STACK WIN or STACK CFI frame info declaration, storing
+ // it in the appropriate table.
+ bool ParseStackInfo(char *stack_info_line);
+
+ // Parses a STACK CFI record, storing it in cfi_frame_info_.
+ bool ParseCFIFrameInfo(char *stack_info_line);
+
+ string name_;
+ FileMap files_;
+ RangeMap< MemAddr, linked_ptr<Function> > functions_;
+ AddressMap< MemAddr, linked_ptr<PublicSymbol> > public_symbols_;
+
+ // Each element in the array is a ContainedRangeMap for a type
+ // listed in WindowsFrameInfoTypes. These are split by type because
+ // there may be overlaps between maps of different types, but some
+ // information is only available as certain types.
+ ContainedRangeMap< MemAddr, linked_ptr<WindowsFrameInfo> >
+ windows_frame_info_[WindowsFrameInfo::STACK_INFO_LAST];
+
+ // DWARF CFI stack walking data. The Module stores the initial rule sets
+ // and rule deltas as strings, just as they appear in the symbol file:
+ // although the file may contain hundreds of thousands of STACK CFI
+ // records, walking a stack will only ever use a few of them, so it's
+ // best to delay parsing a record until it's actually needed.
+
+ // STACK CFI INIT records: for each range, an initial set of register
+ // recovery rules. The RangeMap's itself gives the starting and ending
+ // addresses.
+ RangeMap<MemAddr, string> cfi_initial_rules_;
+
+ // STACK CFI records: at a given address, the changes to the register
+ // recovery rules that take effect at that address. The map key is the
+ // starting address; the ending address is the key of the next entry in
+ // this map, or the end of the range as given by the cfi_initial_rules_
+ // entry (which FindCFIFrameInfo looks up first).
+ std::map<MemAddr, string> cfi_delta_rules_;
+};
+
+} // namespace google_breakpad
+
+#endif // PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_TYPES_H__
diff --git a/src/processor/exploitability_unittest.cc b/src/processor/exploitability_unittest.cc
index d365e610..b23c2de7 100644
--- a/src/processor/exploitability_unittest.cc
+++ b/src/processor/exploitability_unittest.cc
@@ -93,6 +93,11 @@ class TestSymbolSupplier : public SymbolSupplier {
string *symbol_file,
string *symbol_data);
+ virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data);
+
// When set to true, causes the SymbolSupplier to return INTERRUPT
void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
@@ -112,6 +117,14 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
return NOT_FOUND;
}
+SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
+ const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data) {
+ return GetSymbolFile(module, system_info, symbol_file);
+}
+
SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
const CodeModule *module,
const SystemInfo *system_info,
diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc
index 8ceda743..ac0368d5 100644
--- a/src/processor/minidump_processor_unittest.cc
+++ b/src/processor/minidump_processor_unittest.cc
@@ -113,6 +113,11 @@ class TestSymbolSupplier : public SymbolSupplier {
string *symbol_file,
string *symbol_data);
+ virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data);
+
// When set to true, causes the SymbolSupplier to return INTERRUPT
void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
@@ -164,6 +169,25 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
return s;
}
+SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
+ const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data) {
+ string symbol_data_string;
+ SymbolSupplier::SymbolResult s = GetSymbolFile(module,
+ system_info,
+ symbol_file,
+ &symbol_data_string);
+ if (s == FOUND) {
+ unsigned int size = symbol_data_string.size() + 1;
+ *symbol_data = reinterpret_cast<char*>(operator new(size));
+ strcpy(*symbol_data, symbol_data_string.c_str());
+ }
+
+ return s;
+}
+
// A mock symbol supplier that always returns NOT_FOUND; one current
// use for testing the processor's caching of symbol lookups.
class MockSymbolSupplier : public SymbolSupplier {
@@ -176,6 +200,10 @@ class MockSymbolSupplier : public SymbolSupplier {
const SystemInfo*,
string*,
string*));
+ MOCK_METHOD4(GetCStringSymbolData, SymbolResult(const CodeModule*,
+ const SystemInfo*,
+ string*,
+ char**));
};
class MinidumpProcessorTest : public ::testing::Test {
@@ -217,11 +245,11 @@ TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) {
string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
"/src/processor/testdata/minidump2.dmp";
ProcessState state;
- EXPECT_CALL(supplier, GetSymbolFile(
+ EXPECT_CALL(supplier, GetCStringSymbolData(
Property(&google_breakpad::CodeModule::code_file,
"c:\\test_app.exe"),
_, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
- EXPECT_CALL(supplier, GetSymbolFile(
+ EXPECT_CALL(supplier, GetCStringSymbolData(
Property(&google_breakpad::CodeModule::code_file,
Ne("c:\\test_app.exe")),
_, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
@@ -232,11 +260,11 @@ TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) {
// We need to verify that across minidumps, the processor will refetch
// symbol files, even with the same symbol supplier.
- EXPECT_CALL(supplier, GetSymbolFile(
+ EXPECT_CALL(supplier, GetCStringSymbolData(
Property(&google_breakpad::CodeModule::code_file,
"c:\\test_app.exe"),
_, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
- EXPECT_CALL(supplier, GetSymbolFile(
+ EXPECT_CALL(supplier, GetCStringSymbolData(
Property(&google_breakpad::CodeModule::code_file,
Ne("c:\\test_app.exe")),
_, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
diff --git a/src/processor/module_factory.h b/src/processor/module_factory.h
new file mode 100644
index 00000000..6065493d
--- /dev/null
+++ b/src/processor/module_factory.h
@@ -0,0 +1,62 @@
+// 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.
+//
+// module_factory.h: ModuleFactory a factory that provides
+// an interface for creating a Module and deferring instantiation to subclasses
+// BasicModuleFactory and FastModuleFactory.
+
+// Author: Siyang Xie (lambxsy@google.com)
+
+#ifndef PROCESSOR_MODULE_FACTORY_H__
+#define PROCESSOR_MODULE_FACTORY_H__
+
+#include "processor/source_line_resolver_base_types.h"
+#include "processor/basic_source_line_resolver_types.h"
+
+namespace google_breakpad {
+
+class ModuleFactory {
+ public:
+ virtual ~ModuleFactory() { };
+ virtual SourceLineResolverBase::Module*
+ CreateModule(const string &name) const = 0;
+};
+
+class BasicModuleFactory : public ModuleFactory {
+ public:
+ virtual ~BasicModuleFactory() { }
+ virtual BasicSourceLineResolver::Module*
+ CreateModule(const string &name) const {
+ return new BasicSourceLineResolver::Module(name);
+ }
+};
+
+} // namespace google_breakpad
+
+#endif // PROCESSOR_MODULE_FACTORY_H__
diff --git a/src/processor/network_source_line_resolver.cc b/src/processor/network_source_line_resolver.cc
index f342c7a4..86c939f9 100644
--- a/src/processor/network_source_line_resolver.cc
+++ b/src/processor/network_source_line_resolver.cc
@@ -97,6 +97,13 @@ bool NetworkSourceLineResolver::LoadModuleUsingMapBuffer(
return true;
}
+bool NetworkSourceLineResolver::LoadModuleUsingMemoryBuffer(
+ const CodeModule *module,
+ char *memory_buffer) {
+ // see above
+ return true;
+}
+
void NetworkSourceLineResolver::UnloadModule(const CodeModule *module) {
// no-op
}
@@ -331,6 +338,18 @@ NetworkSourceLineResolver::GetSymbolFile(const CodeModule *module,
return GetSymbolFile(module, system_info, symbol_file);
}
+SymbolSupplier::SymbolResult
+NetworkSourceLineResolver::GetCStringSymbolData(
+ const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data) {
+ if (symbol_data)
+ delete *symbol_data;
+
+ return GetSymbolFile(module, system_info, symbol_file);
+}
+
bool NetworkSourceLineResolver::SendMessageGetResponse(
const binarystream &message,
binarystream &response) {
diff --git a/src/processor/network_source_line_server_unittest.cc b/src/processor/network_source_line_server_unittest.cc
index 5e969ccf..50eb8a04 100644
--- a/src/processor/network_source_line_server_unittest.cc
+++ b/src/processor/network_source_line_server_unittest.cc
@@ -89,6 +89,10 @@ public:
const SystemInfo *system_info,
string *symbol_file,
string *symbol_data));
+ MOCK_METHOD4(GetCStringSymbolData, SymbolResult(const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data));
};
class MockSourceLineResolver : public SourceLineResolverInterface {
@@ -100,6 +104,8 @@ class MockSourceLineResolver : public SourceLineResolverInterface {
const string &map_file));
MOCK_METHOD2(LoadModuleUsingMapBuffer, bool(const CodeModule *module,
const string &map_buffer));
+ MOCK_METHOD2(LoadModuleUsingMemoryBuffer, bool(const CodeModule *module,
+ char *memory_buffer));
MOCK_METHOD1(UnloadModule, void(const CodeModule *module));
MOCK_METHOD1(HasModule, bool(const CodeModule *module));
MOCK_METHOD1(FillSourceLineInfo, void(StackFrame *frame));
diff --git a/src/processor/simple_symbol_supplier.cc b/src/processor/simple_symbol_supplier.cc
index 544a42cb..df77d72c 100644
--- a/src/processor/simple_symbol_supplier.cc
+++ b/src/processor/simple_symbol_supplier.cc
@@ -36,6 +36,7 @@
#include "processor/simple_symbol_supplier.h"
#include <assert.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -93,6 +94,26 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
return s;
}
+SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData(
+ const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data) {
+ assert(symbol_data);
+
+ string symbol_data_string;
+ SymbolSupplier::SymbolResult s =
+ GetSymbolFile(module, system_info, symbol_file, &symbol_data_string);
+
+ if (s == FOUND) {
+ unsigned int size = symbol_data_string.size() + 1;
+ *symbol_data = reinterpret_cast<char*>(operator new(size));
+ memcpy(*symbol_data, symbol_data_string.c_str(), size - 1);
+ (*symbol_data)[size - 1] = '\0';
+ }
+ return s;
+}
+
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPathFromRoot(
const CodeModule *module, const SystemInfo *system_info,
const string &root_path, string *symbol_file) {
diff --git a/src/processor/simple_symbol_supplier.h b/src/processor/simple_symbol_supplier.h
index dff6a512..753bd0cd 100644
--- a/src/processor/simple_symbol_supplier.h
+++ b/src/processor/simple_symbol_supplier.h
@@ -110,6 +110,12 @@ class SimpleSymbolSupplier : public SymbolSupplier {
const SystemInfo *system_info,
string *symbol_file,
string *symbol_data);
+
+ virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
+ const SystemInfo *system_info,
+ string *symbol_file,
+ char **symbol_data);
+
protected:
SymbolResult GetSymbolFileAtPathFromRoot(const CodeModule *module,
const SystemInfo *system_info,
diff --git a/src/processor/source_line_resolver_base.cc b/src/processor/source_line_resolver_base.cc
new file mode 100644
index 00000000..14f6ec6d
--- /dev/null
+++ b/src/processor/source_line_resolver_base.cc
@@ -0,0 +1,283 @@
+// 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.
+//
+// source_line_resolver_base.cc: Implementation of SourceLineResolverBase.
+//
+// See source_line_resolver_base.h and source_line_resolver_base_types.h for
+// more documentation.
+//
+// Author: Siyang Xie (lambxsy@google.com)
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <map>
+#include <utility>
+
+#include "google_breakpad/processor/source_line_resolver_base.h"
+#include "processor/source_line_resolver_base_types.h"
+#include "processor/module_factory.h"
+
+using std::map;
+using std::make_pair;
+
+namespace google_breakpad {
+
+SourceLineResolverBase::SourceLineResolverBase(
+ ModuleFactory *module_factory)
+ : modules_(new ModuleMap),
+ module_factory_(module_factory) {
+}
+
+SourceLineResolverBase::~SourceLineResolverBase() {
+ ModuleMap::iterator it;
+ // Iterate through ModuleMap and delete all loaded modules.
+ for (it = modules_->begin(); it != modules_->end(); ++it) {
+ // Delete individual module.
+ delete it->second;
+ }
+ // Delete the map of modules.
+ delete modules_;
+ delete module_factory_;
+
+ // Helper method to be specified by subclasses.
+ ClearLocalMemory();
+}
+
+// Helper methods to be specified by subclasses.
+void SourceLineResolverBase::StoreDataBeforeLoad(const CodeModule *module,
+ char *symbol_data) { }
+void SourceLineResolverBase::DeleteDataAfterLoad(char *symbol_data) { }
+void SourceLineResolverBase::DeleteDataUnload(const CodeModule *module) { }
+void SourceLineResolverBase::ClearLocalMemory() { }
+
+
+bool SourceLineResolverBase::ReadSymbolFile(char **symbol_data,
+ const string &map_file) {
+ if (symbol_data == NULL) {
+ BPLOG(ERROR) << "Could not Read file into Null memory pointer";
+ return false;
+ }
+
+ struct stat buf;
+ int error_code = stat(map_file.c_str(), &buf);
+ if (error_code == -1) {
+ string error_string;
+ int error_code = ErrnoString(&error_string);
+ BPLOG(ERROR) << "Could not open " << map_file <<
+ ", error " << error_code << ": " << error_string;
+ return false;
+ }
+
+ off_t file_size = buf.st_size;
+
+ // Allocate memory for file contents, plus a null terminator
+ // since we may use strtok() on the contents.
+ *symbol_data = reinterpret_cast<char*>(operator new(file_size + 1));
+
+ if (*symbol_data == NULL) {
+ BPLOG(ERROR) << "Could not allocate memory for " << map_file;
+ return false;
+ }
+
+ BPLOG(INFO) << "Opening " << map_file;
+
+ FILE *f = fopen(map_file.c_str(), "rt");
+ if (!f) {
+ string error_string;
+ int error_code = ErrnoString(&error_string);
+ BPLOG(ERROR) << "Could not open " << map_file <<
+ ", error " << error_code << ": " << error_string;
+ delete (*symbol_data);
+ *symbol_data = NULL;
+ return false;
+ }
+
+ AutoFileCloser closer(f);
+
+ int items_read = 0;
+
+ items_read = fread(*symbol_data, 1, file_size, f);
+
+ if (items_read != file_size) {
+ string error_string;
+ int error_code = ErrnoString(&error_string);
+ BPLOG(ERROR) << "Could not slurp " << map_file <<
+ ", error " << error_code << ": " << error_string;
+ delete (*symbol_data);
+ *symbol_data = NULL;
+ return false;
+ }
+
+ (*symbol_data)[file_size] = '\0';
+ return true;
+}
+
+bool SourceLineResolverBase::LoadModule(const CodeModule *module,
+ const string &map_file) {
+ if (module == NULL)
+ return false;
+
+ // Make sure we don't already have a module with the given name.
+ if (modules_->find(module->code_file()) != modules_->end()) {
+ BPLOG(INFO) << "Symbols for module " << module->code_file()
+ << " already loaded";
+ return false;
+ }
+
+ BPLOG(INFO) << "Loading symbols for module " << module->code_file()
+ << " from " << map_file;
+
+ char *memory_buffer;
+ if (!ReadSymbolFile(&memory_buffer, map_file))
+ return false;
+
+ BPLOG(INFO) << "Read symbol file " << map_file << " succeeded";
+
+ // Invoke helper method, let the concrete subclass decides its own action.
+ StoreDataBeforeLoad(module, memory_buffer);
+
+ return LoadModuleUsingMemoryBuffer(module, memory_buffer);
+}
+
+bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
+ const CodeModule *module, const string &map_buffer) {
+ char *memory_buffer = reinterpret_cast<char*>(
+ operator new(map_buffer.size() + 1));
+ if (memory_buffer == NULL)
+ return false;
+
+ // Can't use strcpy, as the data may contain '\0's before the end.
+ memcpy(memory_buffer, map_buffer.c_str(), map_buffer.size());
+ memory_buffer[map_buffer.size()] = '\0';
+
+ // Invoke helper method, let the concrete subclass decides its own action.
+ StoreDataBeforeLoad(module, memory_buffer);
+
+ return LoadModuleUsingMemoryBuffer(module, memory_buffer);
+}
+
+bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer(
+ const CodeModule *module, char *memory_buffer) {
+ if (!module) {
+ // Invoke helper method, let the concrete subclass decides its own action.
+ DeleteDataAfterLoad(memory_buffer);
+ return false;
+ }
+
+ // Make sure we don't already have a module with the given name.
+ if (modules_->find(module->code_file()) != modules_->end()) {
+ BPLOG(INFO) << "Symbols for module " << module->code_file()
+ << " already loaded";
+ DeleteDataAfterLoad(memory_buffer);
+ return false;
+ }
+
+ BPLOG(INFO) << "Loading symbols for module " << module->code_file()
+ << " from buffer";
+
+ Module *basic_module = module_factory_->CreateModule(module->code_file());
+
+ // Ownership of memory is NOT transfered to Module::LoadMapFromMemory().
+ if (!basic_module->LoadMapFromMemory(memory_buffer)) {
+ delete basic_module;
+ DeleteDataAfterLoad(memory_buffer);
+ return false;
+ }
+
+ modules_->insert(make_pair(module->code_file(), basic_module));
+ DeleteDataAfterLoad(memory_buffer);
+ return true;
+}
+
+void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) {
+ if (!code_module)
+ return;
+
+ ModuleMap::iterator iter = modules_->find(code_module->code_file());
+ if (iter != modules_->end()) {
+ Module *symbol_module = iter->second;
+ delete symbol_module;
+ modules_->erase(iter);
+ }
+
+ DeleteDataUnload(code_module);
+}
+
+bool SourceLineResolverBase::HasModule(const CodeModule *module) {
+ if (!module)
+ return false;
+ return modules_->find(module->code_file()) != modules_->end();
+}
+
+void SourceLineResolverBase::FillSourceLineInfo(StackFrame *frame) {
+ if (frame->module) {
+ ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
+ if (it != modules_->end()) {
+ it->second->LookupAddress(frame);
+ }
+ }
+}
+
+WindowsFrameInfo *SourceLineResolverBase::FindWindowsFrameInfo(
+ const StackFrame *frame) {
+ if (frame->module) {
+ ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
+ if (it != modules_->end()) {
+ return it->second->FindWindowsFrameInfo(frame);
+ }
+ }
+ return NULL;
+}
+
+CFIFrameInfo *SourceLineResolverBase::FindCFIFrameInfo(
+ const StackFrame *frame) {
+ if (frame->module) {
+ ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
+ if (it != modules_->end()) {
+ return it->second->FindCFIFrameInfo(frame);
+ }
+ }
+ return NULL;
+}
+
+bool SourceLineResolverBase::CompareString::operator()(
+ const string &s1, const string &s2) const {
+ return strcmp(s1.c_str(), s2.c_str()) < 0;
+}
+
+bool SourceLineResolverBase::Module::ParseCFIRuleSet(
+ const string &rule_set, CFIFrameInfo *frame_info) const {
+ CFIFrameInfoParseHandler handler(frame_info);
+ CFIRuleParser parser(&handler);
+ return parser.Parse(rule_set);
+}
+
+} // namespace google_breakpad
diff --git a/src/processor/source_line_resolver_base_types.h b/src/processor/source_line_resolver_base_types.h
new file mode 100644
index 00000000..5b099f1a
--- /dev/null
+++ b/src/processor/source_line_resolver_base_types.h
@@ -0,0 +1,149 @@
+// 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.
+
+// source_line_resolver_base_types.h: definition of nested classes/structs in
+// SourceLineResolverBase. It moves the definitions out of
+// source_line_resolver_base.cc, so that other classes may have access
+// to these private nested types without including source_line_resolver_base.cc
+// In addition, Module is defined as a pure abstract class to be implemented by
+// each concrete source line resolver class.
+//
+// See source_line_resolver_base.h for more documentation.
+//
+// Author: Siyang Xie (lambxsy@google.com)
+
+#include <stdio.h>
+
+#include <map>
+#include <string>
+
+#include "google_breakpad/processor/source_line_resolver_base.h"
+#include "google_breakpad/processor/stack_frame.h"
+#include "processor/cfi_frame_info.h"
+#include "processor/windows_frame_info.h"
+
+#ifndef PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__
+#define PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__
+
+namespace google_breakpad {
+
+class SourceLineResolverBase::AutoFileCloser {
+ public:
+ explicit AutoFileCloser(FILE *file) : file_(file) {}
+ ~AutoFileCloser() {
+ if (file_)
+ fclose(file_);
+ }
+
+ private:
+ FILE *file_;
+};
+
+struct SourceLineResolverBase::Line {
+ Line() { }
+ Line(MemAddr addr, MemAddr code_size, int file_id, int source_line)
+ : address(addr)
+ , size(code_size)
+ , source_file_id(file_id)
+ , line(source_line) { }
+
+ MemAddr address;
+ MemAddr size;
+ int32_t source_file_id;
+ int32_t line;
+};
+
+struct SourceLineResolverBase::Function {
+ Function() { }
+ Function(const string &function_name,
+ MemAddr function_address,
+ MemAddr code_size,
+ int set_parameter_size)
+ : name(function_name), address(function_address), size(code_size),
+ parameter_size(set_parameter_size) { }
+
+ string name;
+ MemAddr address;
+ MemAddr size;
+
+ // The size of parameters passed to this function on the stack.
+ int32_t parameter_size;
+};
+
+struct SourceLineResolverBase::PublicSymbol {
+ PublicSymbol() { }
+ PublicSymbol(const string& set_name,
+ MemAddr set_address,
+ int set_parameter_size)
+ : name(set_name),
+ address(set_address),
+ parameter_size(set_parameter_size) {}
+
+ string name;
+ MemAddr address;
+
+ // If the public symbol is used as a function entry point, parameter_size
+ // is set to the size of the parameters passed to the funciton on the
+ // stack, if known.
+ int32_t parameter_size;
+};
+
+class SourceLineResolverBase::Module {
+ public:
+ virtual ~Module() { };
+ // Loads a map from the given buffer in char* type.
+ // Does NOT take ownership of memory_buffer (the caller, source line resolver,
+ // is the owner of memory_buffer).
+ virtual bool LoadMapFromMemory(char *memory_buffer) = 0;
+
+ // Looks up the given relative address, and fills the StackFrame struct
+ // with the result.
+ virtual void LookupAddress(StackFrame *frame) const = 0;
+
+ // If Windows stack walking information is available covering ADDRESS,
+ // return a WindowsFrameInfo structure describing it. If the information
+ // is not available, returns NULL. A NULL return value does not indicate
+ // an error. The caller takes ownership of any returned WindowsFrameInfo
+ // object.
+ virtual WindowsFrameInfo *
+ FindWindowsFrameInfo(const StackFrame *frame) const = 0;
+
+ // If CFI stack walking information is available covering ADDRESS,
+ // return a CFIFrameInfo structure describing it. If the information
+ // is not available, return NULL. The caller takes ownership of any
+ // returned CFIFrameInfo object.
+ virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const = 0;
+ protected:
+ virtual bool ParseCFIRuleSet(const string &rule_set,
+ CFIFrameInfo *frame_info) const;
+};
+
+} // namespace google_breakpad
+
+#endif // PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__
diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc
index 39eb65ec..296697cb 100644
--- a/src/processor/stackwalker.cc
+++ b/src/processor/stackwalker.cc
@@ -97,15 +97,18 @@ bool Stackwalker::Walk(CallStack *stack) {
no_symbol_modules_.find(
module->code_file()) == no_symbol_modules_.end() &&
supplier_) {
- string symbol_data, symbol_file;
+ string symbol_file;
+ char *symbol_data;
SymbolSupplier::SymbolResult symbol_result =
- supplier_->GetSymbolFile(module, system_info_,
- &symbol_file, &symbol_data);
+ supplier_->GetCStringSymbolData(module,
+ system_info_,
+ &symbol_file,
+ &symbol_data);
switch (symbol_result) {
case SymbolSupplier::FOUND:
- resolver_->LoadModuleUsingMapBuffer(frame->module,
- symbol_data);
+ resolver_->LoadModuleUsingMemoryBuffer(frame->module,
+ symbol_data);
break;
case SymbolSupplier::NOT_FOUND:
no_symbol_modules_.insert(module->code_file());
@@ -207,13 +210,14 @@ bool Stackwalker::InstructionAddressSeemsValid(u_int64_t address) {
}
if (!resolver_->HasModule(module)) {
- string symbol_data, symbol_file;
+ string symbol_file;
+ char *symbol_data;
SymbolSupplier::SymbolResult symbol_result =
- supplier_->GetSymbolFile(module, system_info_,
- &symbol_file, &symbol_data);
+ supplier_->GetCStringSymbolData(module, system_info_,
+ &symbol_file, &symbol_data);
if (symbol_result != SymbolSupplier::FOUND ||
- !resolver_->LoadModuleUsingMapBuffer(module,
+ !resolver_->LoadModuleUsingMemoryBuffer(module,
symbol_data)) {
// we don't have symbols, but we're inside a loaded module
return true;
diff --git a/src/processor/stackwalker_amd64_unittest.cc b/src/processor/stackwalker_amd64_unittest.cc
index 6fd3bea4..758c06db 100644
--- a/src/processor/stackwalker_amd64_unittest.cc
+++ b/src/processor/stackwalker_amd64_unittest.cc
@@ -85,15 +85,18 @@ class StackwalkerAMD64Fixture {
// By default, none of the modules have symbol info; call
// SetModuleSymbols to override this.
- EXPECT_CALL(supplier, GetSymbolFile(_, _, _, _))
+ EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
.WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
}
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
void SetModuleSymbols(MockCodeModule *module, const string &info) {
- EXPECT_CALL(supplier, GetSymbolFile(module, &system_info, _, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<3>(info),
+ unsigned int buffer_size = info.size() + 1;
+ char *buffer = reinterpret_cast<char*>(operator new(buffer_size));
+ strcpy(buffer, info.c_str());
+ EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
Return(MockSymbolSupplier::FOUND)));
}
diff --git a/src/processor/stackwalker_arm_unittest.cc b/src/processor/stackwalker_arm_unittest.cc
index ad7aeb31..637435b1 100644
--- a/src/processor/stackwalker_arm_unittest.cc
+++ b/src/processor/stackwalker_arm_unittest.cc
@@ -87,15 +87,18 @@ class StackwalkerARMFixture {
// By default, none of the modules have symbol info; call
// SetModuleSymbols to override this.
- EXPECT_CALL(supplier, GetSymbolFile(_, _, _, _))
+ EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
.WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
}
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
void SetModuleSymbols(MockCodeModule *module, const string &info) {
- EXPECT_CALL(supplier, GetSymbolFile(module, &system_info, _, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<3>(info),
+ unsigned int buffer_size = info.size() + 1;
+ char *buffer = reinterpret_cast<char*>(operator new(buffer_size));
+ strcpy(buffer, info.c_str());
+ EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
Return(MockSymbolSupplier::FOUND)));
}
diff --git a/src/processor/stackwalker_unittest_utils.h b/src/processor/stackwalker_unittest_utils.h
index a7bff3e8..2da71bc0 100644
--- a/src/processor/stackwalker_unittest_utils.h
+++ b/src/processor/stackwalker_unittest_utils.h
@@ -170,6 +170,10 @@ class MockSymbolSupplier: public google_breakpad::SymbolSupplier {
const SystemInfo *system_info,
std::string *symbol_file,
std::string *symbol_data));
+ MOCK_METHOD4(GetCStringSymbolData, SymbolResult(const CodeModule *module,
+ const SystemInfo *system_info,
+ std::string *symbol_file,
+ char **symbol_data));
};
#endif // PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_
diff --git a/src/processor/stackwalker_x86_unittest.cc b/src/processor/stackwalker_x86_unittest.cc
index c0890a1e..4b32cac9 100644
--- a/src/processor/stackwalker_x86_unittest.cc
+++ b/src/processor/stackwalker_x86_unittest.cc
@@ -86,15 +86,18 @@ class StackwalkerX86Fixture {
// By default, none of the modules have symbol info; call
// SetModuleSymbols to override this.
- EXPECT_CALL(supplier, GetSymbolFile(_, _, _, _))
+ EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
.WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
}
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
void SetModuleSymbols(MockCodeModule *module, const string &info) {
- EXPECT_CALL(supplier, GetSymbolFile(module, &system_info, _, _))
- .WillRepeatedly(DoAll(SetArgumentPointee<3>(info),
+ unsigned int buffer_size = info.size() + 1;
+ char *buffer = reinterpret_cast<char*>(operator new(buffer_size));
+ strcpy(buffer, info.c_str());
+ EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
Return(MockSymbolSupplier::FOUND)));
}
diff --git a/src/processor/windows_frame_info.h b/src/processor/windows_frame_info.h
index 79e74638..067f3cfd 100644
--- a/src/processor/windows_frame_info.h
+++ b/src/processor/windows_frame_info.h
@@ -39,6 +39,7 @@
#define PROCESSOR_WINDOWS_FRAME_INFO_H__
#include <string.h>
+#include <stdlib.h>
#include <string>
#include <vector>