Compare commits

...

4 Commits

Author SHA1 Message Date
ted.mielczarek
1b114d00ad properly null terminate temp file template names, add some extra logging to DiskModuleCache
git-svn-id: http://google-breakpad.googlecode.com/svn/branches/processor-symbol-cache@408 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-07 18:02:59 +00:00
ted.mielczarek
eeae662157 add some tempfile goo to avoid race conditions in cache file creation
git-svn-id: http://google-breakpad.googlecode.com/svn/branches/processor-symbol-cache@406 4c0a9323-5329-0410-9bdc-e9ce6186880e
2009-10-01 22:40:28 +00:00
ted.mielczarek
b8af9814ba issue 230 - cache binary symbol maps on disk
git-svn-id: http://google-breakpad.googlecode.com/svn/branches/processor-symbol-cache@246 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-03-10 19:27:00 +00:00
ted.mielczarek
37e2d8391e creating a branch for work on issue 230
git-svn-id: http://google-breakpad.googlecode.com/svn/branches/processor-symbol-cache@245 4c0a9323-5329-0410-9bdc-e9ce6186880e
2008-03-10 19:24:07 +00:00
19 changed files with 1290 additions and 34 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

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

View File

@ -36,6 +36,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifdef _WIN32

View File

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

View 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;
}

View File

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

View File

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

View File

@ -36,6 +36,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <algorithm>
#include <cassert>
#include "processor/simple_symbol_supplier.h"

View File

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