Refactor source line resolver, add interface in supplier and resolver.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@711 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
SiyangXie@gmail.com 2010-10-07 20:31:36 +00:00
parent d35f113d02
commit 5b117cf53a
24 changed files with 1021 additions and 418 deletions

View file

@ -90,6 +90,7 @@ src_libbreakpad_a_SOURCES = \
src/google_breakpad/processor/minidump_processor.h \
src/google-breakpad/processor/network_source_line_resolver.h \
src/google_breakpad/processor/process_state.h \
src/google_breakpad/processor/source_line_resolver_base.h \
src/google_breakpad/processor/source_line_resolver_interface.h \
src/google_breakpad/processor/stack_frame.h \
src/google_breakpad/processor/stack_frame_cpu.h \
@ -101,6 +102,7 @@ src_libbreakpad_a_SOURCES = \
src/processor/basic_code_module.h \
src/processor/basic_code_modules.cc \
src/processor/basic_code_modules.h \
src/processor/basic_source_line_resolver_types.h \
src/processor/basic_source_line_resolver.cc \
src/processor/binarystream.h \
src/processor/binarystream.cc \
@ -134,6 +136,8 @@ src_libbreakpad_a_SOURCES = \
src/processor/simple_symbol_supplier.cc \
src/processor/simple_symbol_supplier.h \
src/processor/windows_frame_info.h \
src/processor/source_line_resolver_base_types.h \
src/processor/source_line_resolver_base.cc \
src/processor/stackwalker.cc \
src/processor/stackwalker_amd64.cc \
src/processor/stackwalker_amd64.h \
@ -322,6 +326,7 @@ src_processor_basic_source_line_resolver_unittest_LDADD = \
src/processor/cfi_frame_info.o \
src/processor/pathname_stripper.o \
src/processor/logging.o \
src/processor/source_line_resolver_base.o \
src/processor/tokenize.o
src_processor_cfi_frame_info_unittest_SOURCES = \
@ -370,6 +375,7 @@ src_processor_exploitability_unittest_LDADD = \
src/processor/logging.o \
src/processor/minidump.o \
src/processor/pathname_stripper.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
@ -417,6 +423,7 @@ src_processor_minidump_processor_unittest_LDADD = \
src/processor/minidump.o \
src/processor/pathname_stripper.o \
src/processor/process_state.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
@ -492,6 +499,7 @@ src_processor_network_source_line_resolver_server_unittest_LDADD = \
src/processor/pathname_stripper.o \
src/processor/process_state.o \
src/processor/simple_symbol_supplier.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
@ -563,6 +571,7 @@ src_processor_stackwalker_selftest_LDADD = \
src/processor/logging.o \
src/processor/minidump.o \
src/processor/pathname_stripper.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
@ -676,6 +685,7 @@ src_processor_minidump_stackwalk_LDADD = \
src/processor/process_state.o \
src/processor/network_source_line_resolver.o \
src/processor/simple_symbol_supplier.o \
src/processor/source_line_resolver_base.o \
src/processor/stackwalker.o \
src/processor/stackwalker_amd64.o \
src/processor/stackwalker_arm.o \
@ -697,6 +707,7 @@ src_processor_source_daemon_LDADD = \
src/processor/network_source_line_server.o \
src/processor/pathname_stripper.o \
src/processor/simple_symbol_supplier.o \
src/processor/source_line_resolver_base.o \
src/processor/tokenize.o \
src/processor/udp_network.o
endif !DISABLE_PROCESSOR

View file

@ -192,6 +192,7 @@ am__src_libbreakpad_a_SOURCES_DIST = \
src/google_breakpad/processor/minidump_processor.h \
src/google-breakpad/processor/network_source_line_resolver.h \
src/google_breakpad/processor/process_state.h \
src/google_breakpad/processor/source_line_resolver_base.h \
src/google_breakpad/processor/source_line_resolver_interface.h \
src/google_breakpad/processor/stack_frame.h \
src/google_breakpad/processor/stack_frame_cpu.h \
@ -202,6 +203,7 @@ am__src_libbreakpad_a_SOURCES_DIST = \
src/processor/basic_code_module.h \
src/processor/basic_code_modules.cc \
src/processor/basic_code_modules.h \
src/processor/basic_source_line_resolver_types.h \
src/processor/basic_source_line_resolver.cc \
src/processor/binarystream.h src/processor/binarystream.cc \
src/processor/call_stack.cc src/processor/cfi_frame_info.cc \
@ -228,6 +230,8 @@ am__src_libbreakpad_a_SOURCES_DIST = \
src/processor/simple_symbol_supplier.cc \
src/processor/simple_symbol_supplier.h \
src/processor/windows_frame_info.h \
src/processor/source_line_resolver_base_types.h \
src/processor/source_line_resolver_base.cc \
src/processor/stackwalker.cc \
src/processor/stackwalker_amd64.cc \
src/processor/stackwalker_amd64.h \
@ -260,6 +264,7 @@ am__src_libbreakpad_a_SOURCES_DIST = \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.$(OBJEXT) \
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.$(OBJEXT) \
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.$(OBJEXT) \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.$(OBJEXT) \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.$(OBJEXT) \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.$(OBJEXT) \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.$(OBJEXT) \
@ -414,6 +419,7 @@ src_processor_basic_source_line_resolver_unittest_OBJECTS = $(am_src_processor_b
@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o
am__src_processor_binarystream_unittest_SOURCES_DIST = \
src/processor/binarystream_unittest.cc \
@ -487,6 +493,7 @@ src_processor_exploitability_unittest_OBJECTS = \
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -527,6 +534,7 @@ src_processor_minidump_processor_unittest_OBJECTS = \
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -556,6 +564,7 @@ src_processor_minidump_stackwalk_OBJECTS = \
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/network_source_line_resolver.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -610,6 +619,7 @@ src_processor_network_source_line_resolver_server_unittest_OBJECTS = $(am_src_pr
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -688,6 +698,7 @@ src_processor_source_daemon_OBJECTS = \
@DISABLE_PROCESSOR_FALSE@ src/processor/network_source_line_server.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/udp_network.o
am__src_processor_stackwalker_amd64_unittest_SOURCES_DIST = \
@ -735,6 +746,7 @@ src_processor_stackwalker_selftest_OBJECTS = \
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -1021,6 +1033,7 @@ lib_LIBRARIES = $(am__append_1) $(am__append_3)
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/minidump_processor.h \
@DISABLE_PROCESSOR_FALSE@ src/google-breakpad/processor/network_source_line_resolver.h \
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/process_state.h \
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/source_line_resolver_base.h \
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/source_line_resolver_interface.h \
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame.h \
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame_cpu.h \
@ -1032,6 +1045,7 @@ lib_LIBRARIES = $(am__append_1) $(am__append_3)
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_module.h \
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.cc \
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.h \
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_types.h \
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.cc \
@DISABLE_PROCESSOR_FALSE@ src/processor/binarystream.h \
@DISABLE_PROCESSOR_FALSE@ src/processor/binarystream.cc \
@ -1065,6 +1079,8 @@ lib_LIBRARIES = $(am__append_1) $(am__append_3)
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.cc \
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.h \
@DISABLE_PROCESSOR_FALSE@ src/processor/windows_frame_info.h \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base_types.h \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.cc \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.cc \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.cc \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.h \
@ -1201,6 +1217,7 @@ TESTS_ENVIRONMENT =
@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o
@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_SOURCES = \
@ -1254,6 +1271,7 @@ TESTS_ENVIRONMENT =
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -1305,6 +1323,7 @@ TESTS_ENVIRONMENT =
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -1386,6 +1405,7 @@ TESTS_ENVIRONMENT =
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -1465,6 +1485,7 @@ TESTS_ENVIRONMENT =
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -1585,6 +1606,7 @@ TESTS_ENVIRONMENT =
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/network_source_line_resolver.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
@ -1607,6 +1629,7 @@ TESTS_ENVIRONMENT =
@DISABLE_PROCESSOR_FALSE@ src/processor/network_source_line_server.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \
@DISABLE_PROCESSOR_FALSE@ src/processor/udp_network.o
@ -1946,6 +1969,9 @@ src/processor/process_state.$(OBJEXT): src/processor/$(am__dirstamp) \
src/processor/simple_symbol_supplier.$(OBJEXT): \
src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/source_line_resolver_base.$(OBJEXT): \
src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/stackwalker.$(OBJEXT): src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/stackwalker_amd64.$(OBJEXT): \
@ -2475,6 +2501,7 @@ mostlyclean-compile:
-rm -f src/processor/range_map_unittest.$(OBJEXT)
-rm -f src/processor/simple_symbol_supplier.$(OBJEXT)
-rm -f src/processor/source_daemon.$(OBJEXT)
-rm -f src/processor/source_line_resolver_base.$(OBJEXT)
-rm -f src/processor/src_client_linux_linux_client_unittest-basic_code_modules.$(OBJEXT)
-rm -f src/processor/src_client_linux_linux_client_unittest-logging.$(OBJEXT)
-rm -f src/processor/src_client_linux_linux_client_unittest-minidump.$(OBJEXT)
@ -2615,6 +2642,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/range_map_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/simple_symbol_supplier.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_daemon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver_base.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest-basic_code_modules.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest-logging.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest-minidump.Po@am__quote@

View file

@ -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();
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);
// 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&);

View file

@ -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__

View file

@ -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__

View file

@ -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;

View file

@ -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

View file

@ -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) { }
BasicSourceLineResolver::BasicSourceLineResolver() :
SourceLineResolverBase(new BasicModuleFactory) { }
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) {
void BasicSourceLineResolver::DeleteDataAfterLoad(char *symbol_data) {
// Always delete allocated memory after loading symbol.
delete symbol_data;
}
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;
}
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;
}
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

View file

@ -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__

View file

@ -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,

View file

@ -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));

View file

@ -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__

View file

@ -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) {

View file

@ -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));

View file

@ -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) {

View file

@ -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,

View file

@ -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

View file

@ -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__

View file

@ -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;

View file

@ -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)));
}

View file

@ -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)));
}

View file

@ -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_

View file

@ -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)));
}

View file

@ -39,6 +39,7 @@
#define PROCESSOR_WINDOWS_FRAME_INFO_H__
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>