Compare commits
4 Commits
main
...
processor-
Author | SHA1 | Date | |
---|---|---|---|
|
1b114d00ad | ||
|
eeae662157 | ||
|
b8af9814ba | ||
|
37e2d8391e |
16
Makefile.am
16
Makefile.am
@ -62,6 +62,7 @@ src_libbreakpad_la_SOURCES = \
|
||||
src/google_breakpad/processor/minidump_processor.h \
|
||||
src/google_breakpad/processor/process_state.h \
|
||||
src/google_breakpad/processor/source_line_resolver_interface.h \
|
||||
src/google_breakpad/processor/source_line_resolver_module_cache_interface.h \
|
||||
src/google_breakpad/processor/stack_frame.h \
|
||||
src/google_breakpad/processor/stack_frame_cpu.h \
|
||||
src/google_breakpad/processor/stackwalker.h \
|
||||
@ -76,6 +77,8 @@ src_libbreakpad_la_SOURCES = \
|
||||
src/processor/call_stack.cc \
|
||||
src/processor/contained_range_map-inl.h \
|
||||
src/processor/contained_range_map.h \
|
||||
src/processor/disk_module_cache.cc \
|
||||
src/processor/disk_module_cache.h \
|
||||
src/processor/linked_ptr.h \
|
||||
src/processor/logging.h \
|
||||
src/processor/logging.cc \
|
||||
@ -117,7 +120,8 @@ check_PROGRAMS = \
|
||||
src/processor/minidump_processor_unittest \
|
||||
src/processor/pathname_stripper_unittest \
|
||||
src/processor/postfix_evaluator_unittest \
|
||||
src/processor/range_map_unittest
|
||||
src/processor/range_map_unittest \
|
||||
src/processor/module_serialize_unittest
|
||||
|
||||
if SELFTEST
|
||||
check_PROGRAMS += \
|
||||
@ -185,6 +189,15 @@ src_processor_range_map_unittest_LDADD = \
|
||||
src/processor/logging.lo \
|
||||
src/processor/pathname_stripper.lo
|
||||
|
||||
src_processor_module_serialize_unittest_SOURCES = \
|
||||
src/processor/module_serialize_unittest.cc
|
||||
src_processor_module_serialize_unittest_LDADD = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/call_stack.lo \
|
||||
src/processor/logging.lo \
|
||||
src/processor/pathname_stripper.lo
|
||||
|
||||
src_processor_stackwalker_selftest_SOURCES = \
|
||||
src/processor/stackwalker_selftest.cc
|
||||
src_processor_stackwalker_selftest_LDADD = \
|
||||
@ -218,6 +231,7 @@ src_processor_minidump_stackwalk_LDADD = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/call_stack.lo \
|
||||
src/processor/disk_module_cache.lo \
|
||||
src/processor/logging.lo \
|
||||
src/processor/minidump.lo \
|
||||
src/processor/minidump_processor.lo \
|
||||
|
52
Makefile.in
52
Makefile.in
@ -72,7 +72,9 @@ check_PROGRAMS = src/processor/address_map_unittest$(EXEEXT) \
|
||||
src/processor/minidump_processor_unittest$(EXEEXT) \
|
||||
src/processor/pathname_stripper_unittest$(EXEEXT) \
|
||||
src/processor/postfix_evaluator_unittest$(EXEEXT) \
|
||||
src/processor/range_map_unittest$(EXEEXT) $(am__EXEEXT_1)
|
||||
src/processor/range_map_unittest$(EXEEXT) \
|
||||
src/processor/module_serialize_unittest$(EXEEXT) \
|
||||
$(am__EXEEXT_1)
|
||||
@SELFTEST_TRUE@am__append_1 = \
|
||||
@SELFTEST_TRUE@ src/processor/stackwalker_selftest
|
||||
|
||||
@ -107,8 +109,9 @@ src_libbreakpad_la_LIBADD =
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
am_src_libbreakpad_la_OBJECTS = src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/call_stack.lo src/processor/logging.lo \
|
||||
src/processor/minidump.lo src/processor/minidump_processor.lo \
|
||||
src/processor/call_stack.lo src/processor/disk_module_cache.lo \
|
||||
src/processor/logging.lo src/processor/minidump.lo \
|
||||
src/processor/minidump_processor.lo \
|
||||
src/processor/pathname_stripper.lo \
|
||||
src/processor/process_state.lo \
|
||||
src/processor/simple_symbol_supplier.lo \
|
||||
@ -169,8 +172,9 @@ src_processor_minidump_stackwalk_OBJECTS = \
|
||||
src_processor_minidump_stackwalk_DEPENDENCIES = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/call_stack.lo src/processor/logging.lo \
|
||||
src/processor/minidump.lo src/processor/minidump_processor.lo \
|
||||
src/processor/call_stack.lo src/processor/disk_module_cache.lo \
|
||||
src/processor/logging.lo src/processor/minidump.lo \
|
||||
src/processor/minidump_processor.lo \
|
||||
src/processor/pathname_stripper.lo \
|
||||
src/processor/process_state.lo \
|
||||
src/processor/simple_symbol_supplier.lo \
|
||||
@ -179,6 +183,15 @@ src_processor_minidump_stackwalk_DEPENDENCIES = \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
am_src_processor_module_serialize_unittest_OBJECTS = \
|
||||
src/processor/module_serialize_unittest.$(OBJEXT)
|
||||
src_processor_module_serialize_unittest_OBJECTS = \
|
||||
$(am_src_processor_module_serialize_unittest_OBJECTS)
|
||||
src_processor_module_serialize_unittest_DEPENDENCIES = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/call_stack.lo src/processor/logging.lo \
|
||||
src/processor/pathname_stripper.lo
|
||||
am_src_processor_pathname_stripper_unittest_OBJECTS = \
|
||||
src/processor/pathname_stripper_unittest.$(OBJEXT)
|
||||
src_processor_pathname_stripper_unittest_OBJECTS = \
|
||||
@ -240,6 +253,7 @@ SOURCES = $(src_libbreakpad_la_SOURCES) \
|
||||
$(src_processor_minidump_dump_SOURCES) \
|
||||
$(src_processor_minidump_processor_unittest_SOURCES) \
|
||||
$(src_processor_minidump_stackwalk_SOURCES) \
|
||||
$(src_processor_module_serialize_unittest_SOURCES) \
|
||||
$(src_processor_pathname_stripper_unittest_SOURCES) \
|
||||
$(src_processor_postfix_evaluator_unittest_SOURCES) \
|
||||
$(src_processor_range_map_unittest_SOURCES) \
|
||||
@ -251,6 +265,7 @@ DIST_SOURCES = $(src_libbreakpad_la_SOURCES) \
|
||||
$(src_processor_minidump_dump_SOURCES) \
|
||||
$(src_processor_minidump_processor_unittest_SOURCES) \
|
||||
$(src_processor_minidump_stackwalk_SOURCES) \
|
||||
$(src_processor_module_serialize_unittest_SOURCES) \
|
||||
$(src_processor_pathname_stripper_unittest_SOURCES) \
|
||||
$(src_processor_postfix_evaluator_unittest_SOURCES) \
|
||||
$(src_processor_range_map_unittest_SOURCES) \
|
||||
@ -401,6 +416,7 @@ src_libbreakpad_la_SOURCES = \
|
||||
src/google_breakpad/processor/minidump_processor.h \
|
||||
src/google_breakpad/processor/process_state.h \
|
||||
src/google_breakpad/processor/source_line_resolver_interface.h \
|
||||
src/google_breakpad/processor/source_line_resolver_module_cache_interface.h \
|
||||
src/google_breakpad/processor/stack_frame.h \
|
||||
src/google_breakpad/processor/stack_frame_cpu.h \
|
||||
src/google_breakpad/processor/stackwalker.h \
|
||||
@ -415,6 +431,8 @@ src_libbreakpad_la_SOURCES = \
|
||||
src/processor/call_stack.cc \
|
||||
src/processor/contained_range_map-inl.h \
|
||||
src/processor/contained_range_map.h \
|
||||
src/processor/disk_module_cache.cc \
|
||||
src/processor/disk_module_cache.h \
|
||||
src/processor/linked_ptr.h \
|
||||
src/processor/logging.h \
|
||||
src/processor/logging.cc \
|
||||
@ -508,6 +526,16 @@ src_processor_range_map_unittest_LDADD = \
|
||||
src/processor/logging.lo \
|
||||
src/processor/pathname_stripper.lo
|
||||
|
||||
src_processor_module_serialize_unittest_SOURCES = \
|
||||
src/processor/module_serialize_unittest.cc
|
||||
|
||||
src_processor_module_serialize_unittest_LDADD = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/call_stack.lo \
|
||||
src/processor/logging.lo \
|
||||
src/processor/pathname_stripper.lo
|
||||
|
||||
src_processor_stackwalker_selftest_SOURCES = \
|
||||
src/processor/stackwalker_selftest.cc
|
||||
|
||||
@ -541,6 +569,7 @@ src_processor_minidump_stackwalk_LDADD = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/call_stack.lo \
|
||||
src/processor/disk_module_cache.lo \
|
||||
src/processor/logging.lo \
|
||||
src/processor/minidump.lo \
|
||||
src/processor/minidump_processor.lo \
|
||||
@ -778,6 +807,8 @@ src/processor/basic_source_line_resolver.lo: \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/call_stack.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/disk_module_cache.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/logging.lo: src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/minidump.lo: src/processor/$(am__dirstamp) \
|
||||
@ -883,6 +914,12 @@ src/processor/minidump_stackwalk.$(OBJEXT): \
|
||||
src/processor/minidump_stackwalk$(EXEEXT): $(src_processor_minidump_stackwalk_OBJECTS) $(src_processor_minidump_stackwalk_DEPENDENCIES) src/processor/$(am__dirstamp)
|
||||
@rm -f src/processor/minidump_stackwalk$(EXEEXT)
|
||||
$(CXXLINK) $(src_processor_minidump_stackwalk_OBJECTS) $(src_processor_minidump_stackwalk_LDADD) $(LIBS)
|
||||
src/processor/module_serialize_unittest.$(OBJEXT): \
|
||||
src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/module_serialize_unittest$(EXEEXT): $(src_processor_module_serialize_unittest_OBJECTS) $(src_processor_module_serialize_unittest_DEPENDENCIES) src/processor/$(am__dirstamp)
|
||||
@rm -f src/processor/module_serialize_unittest$(EXEEXT)
|
||||
$(CXXLINK) $(src_processor_module_serialize_unittest_OBJECTS) $(src_processor_module_serialize_unittest_LDADD) $(LIBS)
|
||||
src/processor/pathname_stripper_unittest.$(OBJEXT): \
|
||||
src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
@ -919,6 +956,8 @@ mostlyclean-compile:
|
||||
-rm -f src/processor/call_stack.$(OBJEXT)
|
||||
-rm -f src/processor/call_stack.lo
|
||||
-rm -f src/processor/contained_range_map_unittest.$(OBJEXT)
|
||||
-rm -f src/processor/disk_module_cache.$(OBJEXT)
|
||||
-rm -f src/processor/disk_module_cache.lo
|
||||
-rm -f src/processor/logging.$(OBJEXT)
|
||||
-rm -f src/processor/logging.lo
|
||||
-rm -f src/processor/minidump.$(OBJEXT)
|
||||
@ -928,6 +967,7 @@ mostlyclean-compile:
|
||||
-rm -f src/processor/minidump_processor.lo
|
||||
-rm -f src/processor/minidump_processor_unittest.$(OBJEXT)
|
||||
-rm -f src/processor/minidump_stackwalk.$(OBJEXT)
|
||||
-rm -f src/processor/module_serialize_unittest.$(OBJEXT)
|
||||
-rm -f src/processor/pathname_stripper.$(OBJEXT)
|
||||
-rm -f src/processor/pathname_stripper.lo
|
||||
-rm -f src/processor/pathname_stripper_unittest.$(OBJEXT)
|
||||
@ -958,12 +998,14 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/basic_source_line_resolver_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/call_stack.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/contained_range_map_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/disk_module_cache.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/logging.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_dump.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_processor.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_processor_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_stackwalk.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/module_serialize_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/pathname_stripper.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/pathname_stripper_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/postfix_evaluator_unittest.Po@am__quote@
|
||||
|
@ -46,6 +46,7 @@
|
||||
#endif // BSLR_NO_HASH_MAP
|
||||
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_module_cache_interface.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
@ -56,9 +57,11 @@ using std::map;
|
||||
using __gnu_cxx::hash_map;
|
||||
#endif // BSLR_NO_HASH_MAP
|
||||
|
||||
|
||||
class BasicSourceLineResolver : public SourceLineResolverInterface {
|
||||
public:
|
||||
BasicSourceLineResolver();
|
||||
BasicSourceLineResolver(SourceLineResolverModuleCacheInterface *);
|
||||
virtual ~BasicSourceLineResolver();
|
||||
|
||||
// SourceLineResolverInterface methods, see source_line_resolver_interface.h
|
||||
@ -73,6 +76,8 @@ class BasicSourceLineResolver : public SourceLineResolverInterface {
|
||||
|
||||
virtual StackFrameInfo* FillSourceLineInfo(StackFrame *frame) const;
|
||||
|
||||
static bool ModuleRoundTripTest(const string &map_file);
|
||||
|
||||
private:
|
||||
template<class T> class MemAddrMap;
|
||||
struct Line;
|
||||
@ -97,10 +102,16 @@ class BasicSourceLineResolver : public SourceLineResolverInterface {
|
||||
typedef hash_map<string, Module*, HashString> ModuleMap;
|
||||
#endif // BSLR_NO_HASH_MAP
|
||||
ModuleMap *modules_;
|
||||
SourceLineResolverModuleCacheInterface *module_cache_;
|
||||
|
||||
// Disallow unwanted copy ctor and assignment operator
|
||||
BasicSourceLineResolver(const BasicSourceLineResolver&);
|
||||
void operator=(const BasicSourceLineResolver&);
|
||||
|
||||
friend bool Equals(const BasicSourceLineResolver::Function &a,
|
||||
const BasicSourceLineResolver::Function &b);
|
||||
|
||||
friend class ModuleSerializer;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
// Abstract interface to store and retrieve cached data for module
|
||||
// symbols.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_MODULE_CACHE_INTERFACE_H__
|
||||
#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_MODULE_CACHE_INTERFACE_H__
|
||||
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
|
||||
class SourceLineResolverModuleCacheInterface {
|
||||
public:
|
||||
virtual ~SourceLineResolverModuleCacheInterface() {}
|
||||
|
||||
// Retrieve the symbol data associated with a module
|
||||
virtual bool GetModuleData(const string &symbol_file,
|
||||
istream **data_stream) = 0;
|
||||
|
||||
// Get a stream to which the data associated with a module
|
||||
// can be stored
|
||||
virtual bool BeginSetModuleData(const string &symbol_file,
|
||||
ostream **data_stream) = 0;
|
||||
// Finish setting the data associated with this module,
|
||||
// data should already have been written to the stream
|
||||
virtual bool EndSetModuleData(const string &symbol_file,
|
||||
ostream **data_stream) = 0;
|
||||
|
||||
protected:
|
||||
// SourceLineResolverModuleCacheInterface cannot be instantiated
|
||||
// except by subclasses
|
||||
SourceLineResolverModuleCacheInterface() {}
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_MODULE_CACHE_INTERFACE_H__
|
@ -39,6 +39,7 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "processor/address_map.h"
|
||||
#include "processor/equals.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
@ -87,6 +88,12 @@ void AddressMap<AddressType, EntryType>::Clear() {
|
||||
map_.clear();
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
bool AddressMap<AddressType, EntryType>::Equals(
|
||||
const AddressMap<AddressType, EntryType> &other) const {
|
||||
return google_breakpad::Equals(map_, other.map_);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_ADDRESS_MAP_INL_H__
|
||||
|
@ -64,6 +64,8 @@ class AddressMap {
|
||||
// initially created.
|
||||
void Clear();
|
||||
|
||||
bool Equals(const AddressMap<AddressType, EntryType> &other) const;
|
||||
|
||||
private:
|
||||
// Convenience types.
|
||||
typedef std::map<AddressType, EntryType> AddressToEntryMap;
|
||||
@ -72,6 +74,8 @@ class AddressMap {
|
||||
|
||||
// Maps the address of each entry to an EntryType.
|
||||
AddressToEntryMap map_;
|
||||
|
||||
friend class ModuleSerializer;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
@ -33,7 +33,9 @@
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include "processor/equals.h"
|
||||
#include "processor/address_map-inl.h"
|
||||
#include "processor/contained_range_map-inl.h"
|
||||
#include "processor/range_map-inl.h"
|
||||
@ -61,10 +63,17 @@ struct BasicSourceLineResolver::Line {
|
||||
, source_file_id(file_id)
|
||||
, line(source_line) { }
|
||||
|
||||
bool operator==(const Line &other) const {
|
||||
return address == other.address &&
|
||||
size == other.size &&
|
||||
source_file_id == other.source_file_id &&
|
||||
line == other.line;
|
||||
}
|
||||
|
||||
MemAddr address;
|
||||
MemAddr size;
|
||||
int source_file_id;
|
||||
int line;
|
||||
u_int32_t source_file_id;
|
||||
u_int32_t line;
|
||||
};
|
||||
|
||||
struct BasicSourceLineResolver::Function {
|
||||
@ -80,11 +89,21 @@ struct BasicSourceLineResolver::Function {
|
||||
MemAddr size;
|
||||
|
||||
// The size of parameters passed to this function on the stack.
|
||||
int parameter_size;
|
||||
u_int32_t parameter_size;
|
||||
|
||||
RangeMap< MemAddr, linked_ptr<Line> > lines;
|
||||
};
|
||||
|
||||
// doesn't really belong here, but I can't put it anywhere else...
|
||||
inline bool Equals(const BasicSourceLineResolver::Function &a,
|
||||
const BasicSourceLineResolver::Function &b)
|
||||
{
|
||||
return a.name == b.name &&
|
||||
a.address == b.address &&
|
||||
a.size == b.size &&
|
||||
Equals(a.lines, b.lines);
|
||||
}
|
||||
|
||||
struct BasicSourceLineResolver::PublicSymbol {
|
||||
PublicSymbol(const string& set_name,
|
||||
MemAddr set_address,
|
||||
@ -93,13 +112,19 @@ struct BasicSourceLineResolver::PublicSymbol {
|
||||
address(set_address),
|
||||
parameter_size(set_parameter_size) {}
|
||||
|
||||
bool operator==(const PublicSymbol &other) const {
|
||||
return name == other.name &&
|
||||
address == other.address &&
|
||||
parameter_size == other.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
|
||||
// is set to the size of the parameters passed to the function on the
|
||||
// stack, if known.
|
||||
int parameter_size;
|
||||
u_int32_t parameter_size;
|
||||
};
|
||||
|
||||
class BasicSourceLineResolver::Module {
|
||||
@ -116,12 +141,15 @@ class BasicSourceLineResolver::Module {
|
||||
// any returned StackFrameInfo object.
|
||||
StackFrameInfo* LookupAddress(StackFrame *frame) const;
|
||||
|
||||
bool Equals(const Module &other) const;
|
||||
|
||||
private:
|
||||
friend class BasicSourceLineResolver;
|
||||
|
||||
#ifdef BSLR_NO_HASH_MAP
|
||||
typedef map<int, string> FileMap;
|
||||
typedef map<u_int32_t, string> FileMap;
|
||||
#else // BSLR_NO_HASH_MAP
|
||||
typedef hash_map<int, string> FileMap;
|
||||
typedef hash_map<u_int32_t, string> FileMap;
|
||||
#endif // BSLR_NO_HASH_MAP
|
||||
|
||||
// The types for stack_info_. This is equivalent to MS DIA's
|
||||
@ -177,9 +205,391 @@ class BasicSourceLineResolver::Module {
|
||||
// as certain types.
|
||||
ContainedRangeMap< MemAddr, linked_ptr<StackFrameInfo> >
|
||||
stack_info_[STACK_INFO_LAST];
|
||||
|
||||
friend class ModuleSerializer;
|
||||
};
|
||||
|
||||
BasicSourceLineResolver::BasicSourceLineResolver() : modules_(new ModuleMap) {
|
||||
|
||||
class ModuleSerializer {
|
||||
public:
|
||||
ModuleSerializer(std::istream *stream) : instream_(stream),
|
||||
outstream_(NULL) {}
|
||||
ModuleSerializer(std::ostream *stream) : instream_(NULL),
|
||||
outstream_(stream) {}
|
||||
|
||||
bool Serialize(const BasicSourceLineResolver::Module &module) {
|
||||
if (!outstream_)
|
||||
return false;
|
||||
|
||||
outstream_->seekp(0, std::ios_base::beg);
|
||||
Write(SERIALIZE_FORMAT);
|
||||
Write(module.files_);
|
||||
Write(module.functions_);
|
||||
Write(module.public_symbols_);
|
||||
for (int i = BasicSourceLineResolver::Module::STACK_INFO_FPO;
|
||||
i < BasicSourceLineResolver::Module::STACK_INFO_LAST; i++)
|
||||
Write(module.stack_info_[i]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Deserialize(BasicSourceLineResolver::Module &module) {
|
||||
if (!instream_)
|
||||
return false;
|
||||
|
||||
instream_->seekg(0, std::ios_base::beg);
|
||||
u_int32_t format;
|
||||
Read(format);
|
||||
if (format != SERIALIZE_FORMAT)
|
||||
return false;
|
||||
|
||||
Read(module.files_);
|
||||
Read(module.functions_);
|
||||
Read(module.public_symbols_);
|
||||
for (int i = BasicSourceLineResolver::Module::STACK_INFO_FPO;
|
||||
i < BasicSourceLineResolver::Module::STACK_INFO_LAST; i++)
|
||||
Read(module.stack_info_[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Increment this if changing the serializing format
|
||||
static const u_int32_t SERIALIZE_FORMAT = 1;
|
||||
|
||||
void Write(const u_int32_t data) {
|
||||
outstream_->write(reinterpret_cast<const char*>(&data), sizeof(u_int32_t));
|
||||
}
|
||||
|
||||
void Write(const u_int64_t data) {
|
||||
outstream_->write(reinterpret_cast<const char*>(&data), sizeof(u_int64_t));
|
||||
}
|
||||
|
||||
void Read(u_int32_t &data) {
|
||||
instream_->read(reinterpret_cast<char*>(&data), sizeof(u_int32_t));
|
||||
}
|
||||
|
||||
void Read(u_int64_t &data) {
|
||||
instream_->read(reinterpret_cast<char*>(&data), sizeof(u_int64_t));
|
||||
}
|
||||
|
||||
// Serialize strings as a length + character array (not null terminated)
|
||||
// pad out to sizeof(int)
|
||||
void Write(const string &data) {
|
||||
if (data.empty()) {
|
||||
Write((u_int32_t)0);
|
||||
return;
|
||||
}
|
||||
|
||||
u_int32_t extra = sizeof(u_int32_t) - (data.size() % sizeof(u_int32_t));
|
||||
Write((u_int32_t)data.size() + extra);
|
||||
outstream_->write(data.c_str(), data.size());
|
||||
char c = '\0';
|
||||
for (int i=0; i<extra; i++)
|
||||
outstream_->write(&c, 1);
|
||||
}
|
||||
|
||||
void Read(string &data) {
|
||||
u_int32_t length;
|
||||
Read(length);
|
||||
|
||||
if (length > 0) {
|
||||
vector<char> string_bytes(length);
|
||||
instream_->read(&string_bytes[0], length);
|
||||
data = &string_bytes[0];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename k, typename d>
|
||||
void Write(const map<k, d> &data) {
|
||||
Write((u_int32_t)data.size());
|
||||
for (typename map<k,d>::const_iterator it = data.begin();
|
||||
it != data.end(); it++) {
|
||||
Write(it->first);
|
||||
Write(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename k, typename v>
|
||||
void Read(map<k, v> &data) {
|
||||
u_int32_t length;
|
||||
Read(length);
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
for (int i=0; i<length; i++) {
|
||||
k key;
|
||||
v value;
|
||||
Read(key);
|
||||
Read(value);
|
||||
data.insert(make_pair(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BSLR_NO_HASH_MAP
|
||||
template<typename k, typename d>
|
||||
void Write(const hash_map<k, d> &data) {
|
||||
Write((u_int32_t)data.size());
|
||||
for (typename hash_map<k,d>::const_iterator it = data.begin();
|
||||
it != data.end(); it++) {
|
||||
Write(it->first);
|
||||
Write(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename k, typename v>
|
||||
void Read(hash_map<k, v> &data) {
|
||||
u_int32_t length;
|
||||
Read(length);
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
data.resize(length);
|
||||
|
||||
for (int i=0; i<length; i++) {
|
||||
k key;
|
||||
v value;
|
||||
Read(key);
|
||||
Read(value);
|
||||
data.insert(make_pair(key, value));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Write(const RangeMap<AddressType, EntryType> &data) {
|
||||
Write((u_int32_t)data.map_.size());
|
||||
for (typename RangeMap<AddressType, EntryType>::MapConstIterator it =
|
||||
data.map_.begin(); it != data.map_.end(); it++) {
|
||||
Write(it->first);
|
||||
Write<AddressType, EntryType>(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Read(RangeMap<AddressType, EntryType> &data) {
|
||||
// Can't instantiate Range(), so manually read in the
|
||||
// AddressMap here.
|
||||
u_int32_t length;
|
||||
Read(length);
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
for (int i=0; i<length; i++) {
|
||||
AddressType address, range_address;
|
||||
EntryType entry;
|
||||
// map key
|
||||
Read(address);
|
||||
// Range values
|
||||
Read(range_address);
|
||||
Read(entry);
|
||||
data.map_.insert(make_pair(address,
|
||||
typename RangeMap<AddressType, EntryType>::Range(range_address, entry)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Write(const typename RangeMap<AddressType, EntryType>::Range &data) {
|
||||
Write(data.base_);
|
||||
Write(data.entry_);
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Write(const AddressMap<AddressType, EntryType> &data) {
|
||||
Write(data.map_);
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Read(AddressMap<AddressType, EntryType> &data) {
|
||||
Read(data.map_);
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Write(const ContainedRangeMap<AddressType, EntryType> &data) {
|
||||
Write(data.base_);
|
||||
Write(data.entry_);
|
||||
if (data.map_) {
|
||||
// write this as a marker
|
||||
Write((u_int32_t)1);
|
||||
Write(*data.map_);
|
||||
}
|
||||
else {
|
||||
Write((u_int32_t)0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Read(ContainedRangeMap<AddressType, EntryType> &data) {
|
||||
// sort of evil, but that's ok
|
||||
AddressType *base_ptr = const_cast<AddressType*>(&data.base_);
|
||||
Read(*base_ptr);
|
||||
EntryType *entry_ptr = const_cast<EntryType*>(&data.entry_);
|
||||
Read(*entry_ptr);
|
||||
|
||||
u_int32_t marker;
|
||||
Read(marker);
|
||||
if (marker == 1) {
|
||||
data.map_ = new typename ContainedRangeMap<AddressType, EntryType>::AddressToRangeMap();
|
||||
Read(*data.map_);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Write(const ContainedRangeMap<AddressType, EntryType> * const &data) {
|
||||
if (data) {
|
||||
// write this as a marker
|
||||
Write((u_int32_t)1);
|
||||
Write<AddressType, EntryType>(*data);
|
||||
}
|
||||
else {
|
||||
Write((u_int32_t)0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
void Read(ContainedRangeMap<AddressType, EntryType> *&data) {
|
||||
u_int32_t marker;
|
||||
Read(marker);
|
||||
if (marker == 1) {
|
||||
data = new ContainedRangeMap<AddressType, EntryType>();
|
||||
Read<AddressType, EntryType>(*data);
|
||||
}
|
||||
else {
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Write(const BasicSourceLineResolver::Function &data) {
|
||||
Write(data.name);
|
||||
Write(data.address);
|
||||
Write(data.size);
|
||||
Write(data.parameter_size);
|
||||
Write(data.lines);
|
||||
}
|
||||
|
||||
// Read this as a pointer because there's no zero-argument
|
||||
// constructor.
|
||||
void Read(BasicSourceLineResolver::Function *&data) {
|
||||
string name;
|
||||
SourceLineResolverInterface::MemAddr address;
|
||||
SourceLineResolverInterface::MemAddr size;
|
||||
u_int32_t parameter_size;
|
||||
|
||||
Read(name);
|
||||
Read(address);
|
||||
Read(size);
|
||||
Read(parameter_size);
|
||||
data = new BasicSourceLineResolver::Function(name, address, size,
|
||||
parameter_size);
|
||||
Read(data->lines);
|
||||
}
|
||||
|
||||
void Write(const BasicSourceLineResolver::PublicSymbol &data) {
|
||||
Write(data.name);
|
||||
Write(data.address);
|
||||
Write(data.parameter_size);
|
||||
}
|
||||
|
||||
// Read this as a pointer because there's no zero-argument
|
||||
// constructor.
|
||||
void Read(BasicSourceLineResolver::PublicSymbol *&data) {
|
||||
string name;
|
||||
SourceLineResolverInterface::MemAddr address;
|
||||
u_int32_t parameter_size;
|
||||
Read(name);
|
||||
Read(address);
|
||||
Read(parameter_size);
|
||||
data = new BasicSourceLineResolver::PublicSymbol(name, address,
|
||||
parameter_size);
|
||||
}
|
||||
|
||||
void Write(const BasicSourceLineResolver::Line &data) {
|
||||
Write(data.address);
|
||||
Write(data.size);
|
||||
Write(data.source_file_id);
|
||||
Write(data.line);
|
||||
}
|
||||
|
||||
// Read this as a pointer because there's no zero-argument
|
||||
// constructor.
|
||||
void Read(BasicSourceLineResolver::Line *&data) {
|
||||
SourceLineResolverInterface::MemAddr address;
|
||||
SourceLineResolverInterface::MemAddr size;
|
||||
u_int32_t source_file_id;
|
||||
u_int32_t line;
|
||||
|
||||
Read(address);
|
||||
Read(size);
|
||||
Read(source_file_id);
|
||||
Read(line);
|
||||
|
||||
data = new BasicSourceLineResolver::Line(address, size, source_file_id,
|
||||
line);
|
||||
}
|
||||
|
||||
void Write(const StackFrameInfo &data) {
|
||||
Write(data.valid);
|
||||
Write(data.prolog_size);
|
||||
Write(data.epilog_size);
|
||||
Write(data.parameter_size);
|
||||
Write(data.saved_register_size);
|
||||
Write(data.local_size);
|
||||
Write(data.max_stack_size);
|
||||
Write((u_int32_t)data.allocates_base_pointer);
|
||||
Write(data.program_string);
|
||||
}
|
||||
|
||||
// Just for consistency with the above methods.
|
||||
void Read(StackFrameInfo *&data) {
|
||||
data = new StackFrameInfo();
|
||||
Read(data->valid);
|
||||
Read(data->prolog_size);
|
||||
Read(data->epilog_size);
|
||||
Read(data->parameter_size);
|
||||
Read(data->saved_register_size);
|
||||
Read(data->local_size);
|
||||
Read(data->max_stack_size);
|
||||
u_int32_t allocates_base_pointer;
|
||||
Read(allocates_base_pointer);
|
||||
data->allocates_base_pointer = (allocates_base_pointer != 0);
|
||||
Read(data->program_string);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Write(const linked_ptr<T> &data) {
|
||||
if (data.get()) {
|
||||
// write this as a marker
|
||||
Write((u_int32_t)1);
|
||||
Write(*data);
|
||||
}
|
||||
else {
|
||||
Write((u_int32_t)0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Read(linked_ptr<T> &data) {
|
||||
u_int32_t marker;
|
||||
Read(marker);
|
||||
if (marker == 1) {
|
||||
T *thing;
|
||||
// Read will allocate the pointer
|
||||
Read(thing);
|
||||
data.reset(thing);
|
||||
}
|
||||
}
|
||||
|
||||
std::istream *instream_;
|
||||
std::ostream *outstream_;
|
||||
};
|
||||
|
||||
BasicSourceLineResolver::BasicSourceLineResolver() :
|
||||
modules_(new ModuleMap),
|
||||
module_cache_(NULL) {
|
||||
}
|
||||
|
||||
BasicSourceLineResolver::BasicSourceLineResolver(SourceLineResolverModuleCacheInterface *module_cache) :
|
||||
modules_(new ModuleMap),
|
||||
module_cache_(module_cache) {
|
||||
}
|
||||
|
||||
BasicSourceLineResolver::~BasicSourceLineResolver() {
|
||||
@ -202,9 +612,32 @@ bool BasicSourceLineResolver::LoadModule(const string &module_name,
|
||||
map_file;
|
||||
|
||||
Module *module = new Module(module_name);
|
||||
if (!module->LoadMap(map_file)) {
|
||||
delete module;
|
||||
return false;
|
||||
|
||||
// First see if we have a cache, and if so,
|
||||
// if the cache contains this module
|
||||
istream *instream;
|
||||
if (module_cache_ &&
|
||||
module_cache_->GetModuleData(map_file, &instream)) {
|
||||
ModuleSerializer serializer(instream);
|
||||
serializer.Deserialize(*module);
|
||||
delete instream;
|
||||
}
|
||||
else {
|
||||
// Otherwise load from file
|
||||
if (!module->LoadMap(map_file)) {
|
||||
delete module;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have a cache, then store the result
|
||||
ostream *outstream;
|
||||
if (module_cache_ &&
|
||||
module_cache_->BeginSetModuleData(map_file, &outstream)) {
|
||||
ModuleSerializer serializer(outstream);
|
||||
serializer.Serialize(*module);
|
||||
module_cache_->EndSetModuleData(map_file, &outstream);
|
||||
delete outstream;
|
||||
}
|
||||
}
|
||||
|
||||
modules_->insert(make_pair(module_name, module));
|
||||
@ -402,6 +835,23 @@ StackFrameInfo* BasicSourceLineResolver::Module::LookupAddress(
|
||||
return frame_info.release();
|
||||
}
|
||||
|
||||
bool BasicSourceLineResolver::Module::Equals(const Module &other) const {
|
||||
return
|
||||
google_breakpad::Equals(files_, other.files_) &&
|
||||
google_breakpad::Equals(functions_, other.functions_) &&
|
||||
google_breakpad::Equals(public_symbols_, other.public_symbols_) &&
|
||||
google_breakpad::Equals(stack_info_[STACK_INFO_FPO],
|
||||
other.stack_info_[STACK_INFO_FPO]) &&
|
||||
google_breakpad::Equals(stack_info_[STACK_INFO_TRAP],
|
||||
other.stack_info_[STACK_INFO_TRAP]) &&
|
||||
google_breakpad::Equals(stack_info_[STACK_INFO_TSS],
|
||||
other.stack_info_[STACK_INFO_TSS]) &&
|
||||
google_breakpad::Equals(stack_info_[STACK_INFO_STANDARD],
|
||||
other.stack_info_[STACK_INFO_STANDARD]) &&
|
||||
google_breakpad::Equals(stack_info_[STACK_INFO_FRAME_DATA],
|
||||
other.stack_info_[STACK_INFO_FRAME_DATA]);
|
||||
}
|
||||
|
||||
// static
|
||||
bool BasicSourceLineResolver::Module::Tokenize(char *line, int max_tokens,
|
||||
vector<char*> *tokens) {
|
||||
@ -611,4 +1061,44 @@ size_t BasicSourceLineResolver::HashString::operator()(const string &s) const {
|
||||
}
|
||||
#endif // BSLR_NO_HASH_MAP
|
||||
|
||||
// static
|
||||
bool BasicSourceLineResolver::ModuleRoundTripTest(const string &map_file) {
|
||||
Module *module = new Module("test");
|
||||
if (!module->LoadMap(map_file)) {
|
||||
BPLOG(ERROR) << "Failed to load map file!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!module->Equals(*module)) { // sanity check
|
||||
BPLOG(ERROR) << "Failed sanity check!";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::stringstream memory_stream(std::ios::in | std::ios::out |
|
||||
std::ios::binary);
|
||||
memory_stream.exceptions(std::ios::eofbit | std::ios::failbit |
|
||||
std::ios::badbit);
|
||||
ModuleSerializer serializer(static_cast<ostream*>(&memory_stream));
|
||||
if (!serializer.Serialize(*module)) {
|
||||
BPLOG(ERROR) << "Failed to serialize Module!";
|
||||
return false;
|
||||
}
|
||||
|
||||
BPLOG(INFO) << "Serialized " << memory_stream.tellp() << " bytes.";
|
||||
|
||||
Module *new_module = new Module("test");
|
||||
ModuleSerializer deserializer(static_cast<istream*>(&memory_stream));
|
||||
if (!deserializer.Deserialize(*new_module)) {
|
||||
BPLOG(ERROR) << "Failed to deserialize Module!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!module->Equals(*new_module)) {
|
||||
BPLOG(ERROR) << "Deserialized module not equivalent to original!";
|
||||
return false;
|
||||
}
|
||||
BPLOG(INFO) << "Round trip successful!";
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "processor/contained_range_map.h"
|
||||
#include "processor/equals.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
|
||||
@ -185,6 +186,23 @@ void ContainedRangeMap<AddressType, EntryType>::Clear() {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
bool ContainedRangeMap<AddressType, EntryType>::Equals(
|
||||
const ContainedRangeMap<AddressType, EntryType> &other) const
|
||||
{
|
||||
bool equal;
|
||||
if (map_ && other.map_) {
|
||||
equal = google_breakpad::Equals(*map_, *other.map_);
|
||||
}
|
||||
else {
|
||||
// otherwise if they're both NULL they're equal
|
||||
equal = map_ == other.map_;
|
||||
}
|
||||
|
||||
return equal &&
|
||||
google_breakpad::Equals(base_, other.base_) &&
|
||||
google_breakpad::Equals(entry_, other.entry_);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
@ -102,6 +102,8 @@ class ContainedRangeMap {
|
||||
// empty state when called on the root node.
|
||||
void Clear();
|
||||
|
||||
bool Equals(const ContainedRangeMap<AddressType, EntryType> &other) const;
|
||||
|
||||
private:
|
||||
// AddressToRangeMap stores pointers. This makes reparenting simpler in
|
||||
// StoreRange, because it doesn't need to copy entire objects.
|
||||
@ -136,6 +138,8 @@ class ContainedRangeMap {
|
||||
// address. This is a pointer to avoid allocating map structures for
|
||||
// leaf nodes, where they are not needed.
|
||||
AddressToRangeMap *map_;
|
||||
|
||||
friend class ModuleSerializer;
|
||||
};
|
||||
|
||||
|
||||
|
218
src/processor/disk_module_cache.cc
Normal file
218
src/processor/disk_module_cache.cc
Normal file
@ -0,0 +1,218 @@
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <vector>
|
||||
|
||||
#include "processor/disk_module_cache.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
using std::string;
|
||||
using std::ostream;
|
||||
using std::ofstream;
|
||||
using std::istream;
|
||||
using std::ifstream;
|
||||
using std::ios;
|
||||
using std::vector;
|
||||
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// tempofstream writes data to a temporary file in the same
|
||||
// directory as the file passed to the constructor.
|
||||
// when closed, it renames the temporary file to the given filename.
|
||||
class tempofstream : public ofstream
|
||||
{
|
||||
public:
|
||||
tempofstream(const char * filename, ios_base::openmode mode = ios_base::out);
|
||||
void close();
|
||||
|
||||
private:
|
||||
string tempname_;
|
||||
string filename_;
|
||||
};
|
||||
|
||||
tempofstream::tempofstream(const char * filename,
|
||||
ios_base::openmode mode) : tempname_(""),
|
||||
filename_(filename)
|
||||
{
|
||||
string name_template_s = filename_ + "XXXXXX";
|
||||
vector<char> name_template(name_template_s.length() + 1);
|
||||
std::copy(name_template_s.begin(), name_template_s.end(),
|
||||
name_template.begin());
|
||||
name_template[name_template.size() - 1] = '\0';
|
||||
tempname_ = mktemp(&name_template[0]);
|
||||
open(tempname_.c_str(), mode);
|
||||
}
|
||||
|
||||
void tempofstream::close()
|
||||
{
|
||||
ofstream::close();
|
||||
rename(tempname_.c_str(), filename_.c_str());
|
||||
}
|
||||
|
||||
DiskModuleCache::DiskModuleCache(string cache_directory) :
|
||||
cache_directory_(cache_directory)
|
||||
{
|
||||
// ensure trailing slash in cache directory
|
||||
if (cache_directory_[cache_directory_.length()] != '/')
|
||||
cache_directory.append("/");
|
||||
}
|
||||
|
||||
bool DiskModuleCache::GetModuleData(const string &symbol_file,
|
||||
istream **data_stream)
|
||||
{
|
||||
if (!data_stream)
|
||||
return false;
|
||||
|
||||
string cache_file = MapToCacheEntry(symbol_file);
|
||||
if (cache_file.empty())
|
||||
return false;
|
||||
|
||||
*data_stream = new ifstream(cache_file.c_str(),
|
||||
ios::in | ios::binary);
|
||||
if (!**data_stream) {
|
||||
delete *data_stream;
|
||||
*data_stream = NULL;
|
||||
|
||||
BPLOG(INFO) << "Symbol file " << symbol_file << " not cached";
|
||||
return false;
|
||||
}
|
||||
BPLOG(INFO) << "Loading cached copy of symbol file " << symbol_file
|
||||
<< " from " << cache_file;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskModuleCache::BeginSetModuleData(const string &symbol_file,
|
||||
ostream **data_stream)
|
||||
{
|
||||
if (!data_stream)
|
||||
return false;
|
||||
|
||||
string cache_file = MapToCacheEntry(symbol_file);
|
||||
BPLOG(INFO) << "Writing cache entry " << cache_file;
|
||||
if (!EnsurePathExists(cache_file.substr(0, cache_file.rfind('/'))))
|
||||
return false;
|
||||
|
||||
*data_stream = new tempofstream(cache_file.c_str(),
|
||||
ios::out | ios::binary | ios::trunc);
|
||||
if (!**data_stream) {
|
||||
delete *data_stream;
|
||||
*data_stream = NULL;
|
||||
|
||||
BPLOG(INFO) << "Failed writing cache entry " << cache_file;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskModuleCache::EndSetModuleData(const string &symbol_file,
|
||||
ostream **data_stream)
|
||||
{
|
||||
tempofstream *file_stream = dynamic_cast<tempofstream*>(*data_stream);
|
||||
if (!file_stream) {
|
||||
BPLOG(INFO) << "Error writing cache entry for " << symbol_file;
|
||||
return false;
|
||||
}
|
||||
|
||||
BPLOG(INFO) << "Finished writing cache entry for " << symbol_file;
|
||||
file_stream->close();
|
||||
return true;
|
||||
}
|
||||
|
||||
// We assume that symbol_file is in the Microsoft Symbol Server
|
||||
// format, /path/debug_file/IDENTIFIER/debug_file.sym. We map
|
||||
// this to /cache/path/debug_file/IDENTIFIER/debug_file.symcache.
|
||||
// NOTE: this assumes unix style paths!
|
||||
string DiskModuleCache::MapToCacheEntry(const string &symbol_file)
|
||||
{
|
||||
string::size_type pos = string::npos;
|
||||
|
||||
// we want the last three components in the path
|
||||
for (int i=0; i<3; i++) {
|
||||
pos = symbol_file.rfind('/', pos);
|
||||
if (pos == string::npos)
|
||||
return "";
|
||||
// back up one character so we don't find this slash again
|
||||
pos--;
|
||||
}
|
||||
|
||||
string cache_file(cache_directory_ +
|
||||
symbol_file.substr(pos + 2));
|
||||
pos = cache_file.length() - 4;
|
||||
if (cache_file.compare(pos, 4, ".sym") == 0)
|
||||
cache_file.replace(pos, 4, ".symcache");
|
||||
|
||||
return cache_file;
|
||||
}
|
||||
|
||||
bool DiskModuleCache::EnsurePathExists(const string &path)
|
||||
{
|
||||
if (IsDir(path))
|
||||
return true;
|
||||
|
||||
if (mkdir(path.c_str(), 0755) == -1) {
|
||||
// we handle ENOENT here
|
||||
if (errno != ENOENT)
|
||||
return false;
|
||||
|
||||
string::size_type pos = path.rfind('/');
|
||||
if (pos == string::npos)
|
||||
// not enough path left?
|
||||
return false;
|
||||
|
||||
if (!EnsurePathExists(path.substr(0, pos)))
|
||||
return false;
|
||||
|
||||
// all previous directories should exist at this point
|
||||
return mkdir(path.c_str(), 0755) != -1;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskModuleCache::IsDir(const string &path)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(path.c_str(), &st) != 0)
|
||||
return false;
|
||||
|
||||
return (st.st_mode & S_IFDIR) == S_IFDIR;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
74
src/processor/disk_module_cache.h
Normal file
74
src/processor/disk_module_cache.h
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
// DiskModuleCache implements SourceLineResolverModuleCacheInterface,
|
||||
// storing the cached objects on disk.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_DISK_MODULE_CACHE_H__
|
||||
#define GOOGLE_BREAKPAD_PROCESSOR_DISK_MODULE_CACHE_H__
|
||||
|
||||
#include "google_breakpad/processor/source_line_resolver_module_cache_interface.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
|
||||
class DiskModuleCache : public SourceLineResolverModuleCacheInterface {
|
||||
public:
|
||||
DiskModuleCache(string cache_directory);
|
||||
virtual ~DiskModuleCache() {}
|
||||
|
||||
// Retrieve the symbol data associated with a module
|
||||
virtual bool GetModuleData(const string &symbol_file,
|
||||
istream **data_stream);
|
||||
|
||||
// Get a stream to which the data associated with a module
|
||||
// can be stored
|
||||
virtual bool BeginSetModuleData(const string &symbol_file,
|
||||
ostream **data_stream);
|
||||
// Finish setting the data associated with this module,
|
||||
// data should already have been written to the stream
|
||||
virtual bool EndSetModuleData(const string &symbol_file,
|
||||
ostream **data_stream);
|
||||
|
||||
private:
|
||||
string cache_directory_;
|
||||
// Given a symbol file, map to a cache entry on disk
|
||||
string MapToCacheEntry(const string &symbol_file);
|
||||
// Given a file path, ensure that all directories in the path exist.
|
||||
bool EnsurePathExists(const string &cache_entry);
|
||||
// determine if this path is a directory
|
||||
bool IsDir(const string &path);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_DISK_MODULE_CACHE_H__
|
178
src/processor/equals.h
Normal file
178
src/processor/equals.h
Normal file
@ -0,0 +1,178 @@
|
||||
// Copyright (c) 2007, 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.
|
||||
|
||||
// equals.h: Templatized functions for checking equivalence.
|
||||
//
|
||||
// Use these instead of operator== so that we can check for equivalence
|
||||
// of objects stored as pointers inside linked_ptrs. Equals knows
|
||||
// how to compare certain objects (RangeMap, AddressMap, ContainedRangeMap),
|
||||
// and special-cases linked_ptr as well. It defaults to operator== for
|
||||
// everything else.
|
||||
//
|
||||
// Author: Ted Mielczarek
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_EQUALS_H_
|
||||
#define GOOGLE_BREAKPAD_EQUALS_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#ifdef __SUNPRO_CC
|
||||
#define BSLR_NO_HASH_MAP
|
||||
#endif // __SUNPRO_CC
|
||||
|
||||
#ifndef BSLR_NO_HASH_MAP
|
||||
#include <ext/hash_map>
|
||||
#endif
|
||||
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "processor/linked_ptr.h"
|
||||
#include "processor/range_map.h"
|
||||
#include "processor/address_map.h"
|
||||
#include "processor/contained_range_map.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::map;
|
||||
#ifndef BSLR_NO_HASH_MAP
|
||||
using __gnu_cxx::hash_map;
|
||||
#endif
|
||||
|
||||
// In the general case, just use operator==
|
||||
// This should handle base types.
|
||||
template<typename T>
|
||||
inline bool Equals(const T &a, const T &b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
// for linked_ptr, we want to compare the objects
|
||||
// pointed at, not the raw pointers
|
||||
template<typename U>
|
||||
bool Equals(const linked_ptr<U> &a, const linked_ptr<U> &b)
|
||||
{
|
||||
if (a.get() && b.get())
|
||||
return Equals(*a, *b);
|
||||
|
||||
// if one is NULL, just compare pointers
|
||||
return a == b;
|
||||
}
|
||||
|
||||
// for std::map/hash_map, we want to call Equals on each component of
|
||||
// each pair
|
||||
#ifndef BSLR_NO_HASH_MAP
|
||||
template<typename k, typename v>
|
||||
bool Equals(const hash_map<k, v> &a, const hash_map<k, v> &b)
|
||||
{
|
||||
// simple check for equivalent size first
|
||||
if (a.size() != b.size())
|
||||
return false;
|
||||
|
||||
typename hash_map<k,v>::const_iterator it, found;
|
||||
for (it = a.begin(); it != a.end(); it++) {
|
||||
// if b doesn't contain this entry, then
|
||||
// just get out
|
||||
found = b.find(it->first);
|
||||
if (found == b.end())
|
||||
return false;
|
||||
|
||||
if (!Equals(it->second, found->second))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // BSLR_NO_HASH_MAP
|
||||
|
||||
template<typename k, typename v>
|
||||
bool Equals(const map<k, v> &a, const map<k, v> &b)
|
||||
{
|
||||
// simple check for equivalent size first
|
||||
if (a.size() != b.size())
|
||||
return false;
|
||||
|
||||
typename map<k,v>::const_iterator it, found;
|
||||
for (it = a.begin(); it != a.end(); it++) {
|
||||
// if b doesn't contain this entry, then
|
||||
// just get out
|
||||
found = b.find(it->first);
|
||||
if (found == b.end())
|
||||
return false;
|
||||
|
||||
if (!Equals(it->second, found->second))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// For certain classes we know about, use their Equals method.
|
||||
// Note: a few variations of this are in other places:
|
||||
// processor/basic_source_line_resolver.cc
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
inline bool Equals(const RangeMap<AddressType, EntryType> &a,
|
||||
const RangeMap<AddressType, EntryType> &b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
inline bool Equals(const typename RangeMap<AddressType, EntryType>::Range &a,
|
||||
const typename RangeMap<AddressType, EntryType>::Range &b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
inline bool Equals(const AddressMap<AddressType, EntryType> &a,
|
||||
const AddressMap<AddressType, EntryType> &b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
inline bool Equals(const ContainedRangeMap<AddressType, EntryType> &a,
|
||||
const ContainedRangeMap<AddressType, EntryType> &b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
inline bool Equals(ContainedRangeMap<AddressType, EntryType> * const &a,
|
||||
ContainedRangeMap<AddressType, EntryType> * const &b)
|
||||
{
|
||||
if (a && b)
|
||||
return a->Equals(*b);
|
||||
|
||||
// if one is NULL, just compare pointer values
|
||||
return a == b;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_EQUALS_H_
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#ifdef _WIN32
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
@ -45,6 +46,7 @@
|
||||
#include "google_breakpad/processor/minidump_processor.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/disk_module_cache.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/pathname_stripper.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
@ -55,6 +57,7 @@ namespace {
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::DiskModuleCache;
|
||||
using google_breakpad::CallStack;
|
||||
using google_breakpad::CodeModule;
|
||||
using google_breakpad::CodeModules;
|
||||
@ -433,6 +436,7 @@ static void PrintProcessStateMachineReadable(const ProcessState& process_state)
|
||||
// is printed to stdout.
|
||||
static bool PrintMinidumpProcess(const string &minidump_file,
|
||||
const vector<string> &symbol_paths,
|
||||
const string &symbol_cache_path,
|
||||
bool machine_readable) {
|
||||
scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
|
||||
if (!symbol_paths.empty()) {
|
||||
@ -440,7 +444,11 @@ static bool PrintMinidumpProcess(const string &minidump_file,
|
||||
symbol_supplier.reset(new SimpleSymbolSupplier(symbol_paths));
|
||||
}
|
||||
|
||||
BasicSourceLineResolver resolver;
|
||||
scoped_ptr<DiskModuleCache> disk_cache;
|
||||
if (!symbol_cache_path.empty()) {
|
||||
disk_cache.reset(new DiskModuleCache(symbol_cache_path));
|
||||
}
|
||||
BasicSourceLineResolver resolver(disk_cache.get());
|
||||
MinidumpProcessor minidump_processor(symbol_supplier.get(), &resolver);
|
||||
|
||||
// Process the minidump.
|
||||
@ -463,8 +471,9 @@ static bool PrintMinidumpProcess(const string &minidump_file,
|
||||
} // namespace
|
||||
|
||||
static void usage(const char *program_name) {
|
||||
fprintf(stderr, "usage: %s [-m] <minidump-file> [symbol-path ...]\n"
|
||||
" -m : Output in machine-readable format\n",
|
||||
fprintf(stderr, "usage: %s [-m] [-c path] <minidump-file> [symbol-path ...]\n"
|
||||
" -m : Output in machine-readable format\n",
|
||||
" -c <path> : Cache symbol files to this path\n",
|
||||
program_name);
|
||||
}
|
||||
|
||||
@ -477,32 +486,48 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
const char *minidump_file;
|
||||
bool machine_readable;
|
||||
bool machine_readable = false;
|
||||
int symbol_path_arg;
|
||||
string symbol_cache_path;
|
||||
|
||||
if (strcmp(argv[1], "-m") == 0) {
|
||||
if (argc < 3) {
|
||||
// handle switches
|
||||
int option;
|
||||
opterr = 0;
|
||||
while ((option = getopt(argc, argv, "mc:")) != -1) {
|
||||
switch (option) {
|
||||
case 'm':
|
||||
machine_readable = true;
|
||||
break;
|
||||
case 'c':
|
||||
symbol_cache_path = optarg;
|
||||
break;
|
||||
case '?':
|
||||
if (optopt == 'c')
|
||||
fprintf(stderr, "Error: -c requires an argument.\n");
|
||||
else
|
||||
fprintf(stderr, "Error: unknown option '-%c'.\n", optopt);
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
machine_readable = true;
|
||||
minidump_file = argv[2];
|
||||
symbol_path_arg = 3;
|
||||
} else {
|
||||
machine_readable = false;
|
||||
minidump_file = argv[1];
|
||||
symbol_path_arg = 2;
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
minidump_file = argv[optind];
|
||||
optind++;
|
||||
|
||||
// extra arguments are symbol paths
|
||||
std::vector<std::string> symbol_paths;
|
||||
if (argc > symbol_path_arg) {
|
||||
for (int argi = symbol_path_arg; argi < argc; ++argi)
|
||||
if (argc > optind) {
|
||||
for (int argi = optind; argi < argc; ++argi)
|
||||
symbol_paths.push_back(argv[argi]);
|
||||
}
|
||||
|
||||
return PrintMinidumpProcess(minidump_file,
|
||||
symbol_paths,
|
||||
symbol_cache_path,
|
||||
machine_readable) ? 0 : 1;
|
||||
}
|
||||
|
61
src/processor/module_serialize_unittest.cc
Normal file
61
src/processor/module_serialize_unittest.cc
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2007, 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_serialize_unittest.cc: Unit tests for
|
||||
// BasicSourceLineResolver::Module serialization.
|
||||
//
|
||||
// Author: Ted Mielczarek
|
||||
|
||||
#include <fstream>
|
||||
#include "stdio.h"
|
||||
|
||||
#include "processor/logging.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
char symbol_test_files[][1024] = {
|
||||
"src/processor/testdata/symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542/kernel32.sym",
|
||||
"src/processor/testdata/symbols/test_app.pdb/5A9832E5287241C1838ED98914E9B7FF1/test_app.sym"
|
||||
};
|
||||
|
||||
for (int i=0; i < sizeof(symbol_test_files) / sizeof(symbol_test_files[0]);
|
||||
i++) {
|
||||
BPLOG(INFO) << "Testing round trip serialize for symbol file "
|
||||
<< symbol_test_files[i];
|
||||
if (!google_breakpad::BasicSourceLineResolver::ModuleRoundTripTest(symbol_test_files[i])) {
|
||||
BPLOG(ERROR) << "FAILED: module round trip test for symbol file "
|
||||
<< symbol_test_files[i];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -40,6 +40,7 @@
|
||||
#include <cassert>
|
||||
|
||||
#include "processor/range_map.h"
|
||||
#include "processor/equals.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
|
||||
@ -203,6 +204,17 @@ void RangeMap<AddressType, EntryType>::Clear() {
|
||||
map_.clear();
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
bool RangeMap<AddressType, EntryType>::Equals(
|
||||
const RangeMap<AddressType, EntryType> &other) const {
|
||||
return google_breakpad::Equals(map_, other.map_);
|
||||
}
|
||||
|
||||
template<typename AddressType, typename EntryType>
|
||||
bool RangeMap<AddressType, EntryType>::Range::operator==(const Range &other) const {
|
||||
return google_breakpad::Equals(base_, other.base_) &&
|
||||
google_breakpad::Equals(entry_, other.entry_);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
@ -92,6 +92,8 @@ class RangeMap {
|
||||
// initially created.
|
||||
void Clear();
|
||||
|
||||
bool Equals(const RangeMap<AddressType, EntryType> &other) const;
|
||||
|
||||
private:
|
||||
class Range {
|
||||
public:
|
||||
@ -101,6 +103,10 @@ class RangeMap {
|
||||
AddressType base() const { return base_; }
|
||||
EntryType entry() const { return entry_; }
|
||||
|
||||
//XXX: I really wanted this to be Equals, but
|
||||
// I can't seem to get that to work properly.
|
||||
bool operator==(const Range &other) const;
|
||||
|
||||
private:
|
||||
// The base address of the range. The high address does not need to
|
||||
// be stored, because RangeMap uses it as the key to the map.
|
||||
@ -108,6 +114,8 @@ class RangeMap {
|
||||
|
||||
// The entry corresponding to a range.
|
||||
const EntryType entry_;
|
||||
|
||||
friend class ModuleSerializer;
|
||||
};
|
||||
|
||||
// Convenience types.
|
||||
@ -117,6 +125,11 @@ class RangeMap {
|
||||
|
||||
// Maps the high address of each range to a EntryType.
|
||||
AddressToRangeMap map_;
|
||||
|
||||
friend class ModuleSerializer;
|
||||
|
||||
//template<typename T>
|
||||
//friend bool Equals(const T &a, const T &b);
|
||||
};
|
||||
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include "processor/simple_symbol_supplier.h"
|
||||
|
@ -100,11 +100,23 @@ struct StackFrameInfo {
|
||||
program_string.erase();
|
||||
}
|
||||
|
||||
bool operator==(const StackFrameInfo &other) const {
|
||||
return valid == other.valid &&
|
||||
prolog_size == other.prolog_size &&
|
||||
epilog_size == other.epilog_size &&
|
||||
parameter_size == other.parameter_size &&
|
||||
saved_register_size == other.saved_register_size &&
|
||||
local_size == other.local_size &&
|
||||
max_stack_size == other.max_stack_size &&
|
||||
allocates_base_pointer == other.allocates_base_pointer &&
|
||||
program_string == other.program_string;
|
||||
}
|
||||
|
||||
// Identifies which fields in the structure are valid. This is of
|
||||
// type Validity, but it is defined as an int because it's not
|
||||
// possible to OR values into an enumerated type. Users must check
|
||||
// this field before using any other.
|
||||
int valid;
|
||||
u_int32_t valid;
|
||||
|
||||
// These values come from IDiaFrameData.
|
||||
u_int32_t prolog_size;
|
||||
|
Loading…
Reference in New Issue
Block a user