bug 360938 - Update airbag to svn tip. r=mento

This commit is contained in:
ted.mielczarek@gmail.com 2007-07-24 18:06:07 -07:00
parent d75829f60f
commit 57f1c5a892
56 changed files with 12480 additions and 358 deletions

View File

@ -50,35 +50,39 @@ dist_doc_DATA = \
lib_LTLIBRARIES = src/libairbag.la
src_libairbag_la_SOURCES = \
src/google/airbag_types.h \
src/google/call_stack.h \
src/google/minidump_processor.h \
src/google/process_state.h \
src/google/stack_frame.h \
src/google/stack_frame_cpu.h \
src/google/symbol_supplier.h \
src/google_airbag/common/airbag_types.h \
src/google_airbag/common/minidump_format.h \
src/google_airbag/processor/call_stack.h \
src/google_airbag/processor/memory_region.h \
src/google_airbag/processor/minidump.h \
src/google_airbag/processor/minidump_processor.h \
src/google_airbag/processor/process_state.h \
src/google_airbag/processor/stack_frame.h \
src/google_airbag/processor/stack_frame_cpu.h \
src/google_airbag/processor/stackwalker.h \
src/google_airbag/processor/symbol_supplier.h \
src/processor/address_map.h \
src/processor/address_map-inl.h \
src/processor/call_stack.cc \
src/processor/contained_range_map.h \
src/processor/contained_range_map-inl.h \
src/processor/linked_ptr.h \
src/processor/memory_region.h \
src/processor/minidump.cc \
src/processor/minidump.h \
src/processor/minidump_format.h \
src/processor/minidump_processor.cc \
src/processor/pathname_stripper.cc \
src/processor/pathname_stripper.h \
src/processor/postfix_evaluator.h \
src/processor/postfix_evaluator-inl.h \
src/processor/process_state.cc \
src/processor/range_map.h \
src/processor/range_map-inl.h \
src/processor/scoped_ptr.h \
src/processor/simple_symbol_supplier.cc \
src/processor/simple_symbol_supplier.h \
src/processor/source_line_resolver.cc \
src/processor/source_line_resolver.h \
src/processor/stack_frame_info.h \
src/processor/stackwalker.cc \
src/processor/stackwalker.h \
src/processor/stackwalker_ppc.cc \
src/processor/stackwalker_ppc.h \
src/processor/stackwalker_x86.cc \
@ -96,6 +100,7 @@ check_PROGRAMS = \
src/processor/address_map_unittest \
src/processor/contained_range_map_unittest \
src/processor/minidump_processor_unittest \
src/processor/pathname_stripper_unittest \
src/processor/postfix_evaluator_unittest \
src/processor/range_map_unittest \
src/processor/source_line_resolver_unittest
@ -130,6 +135,11 @@ src_processor_minidump_processor_unittest_LDADD = \
src/processor/stackwalker_x86.lo \
src/processor/source_line_resolver.lo
src_processor_pathname_stripper_unittest_SOURCES = \
src/processor/pathname_stripper_unittest.cc
src_processor_pathname_stripper_unittest_LDADD = \
src/processor/pathname_stripper.lo
src_processor_postfix_evaluator_unittest_SOURCES = \
src/processor/postfix_evaluator_unittest.cc
@ -165,6 +175,10 @@ src_processor_minidump_stackwalk_SOURCES = \
src_processor_minidump_stackwalk_LDADD = \
src/processor/call_stack.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 \
src/processor/stackwalker.lo \
src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_x86.lo \

View File

@ -73,6 +73,7 @@ bin_PROGRAMS = src/processor/minidump_dump$(EXEEXT) \
check_PROGRAMS = src/processor/address_map_unittest$(EXEEXT) \
src/processor/contained_range_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) \
src/processor/source_line_resolver_unittest$(EXEEXT) \
@ -111,7 +112,9 @@ src_libairbag_la_LIBADD =
am__dirstamp = $(am__leading_dot)dirstamp
am_src_libairbag_la_OBJECTS = src/processor/call_stack.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 \
src/processor/source_line_resolver.lo \
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_x86.lo
@ -152,9 +155,19 @@ src_processor_minidump_stackwalk_OBJECTS = \
$(am_src_processor_minidump_stackwalk_OBJECTS)
src_processor_minidump_stackwalk_DEPENDENCIES = \
src/processor/call_stack.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 \
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_x86.lo \
src/processor/source_line_resolver.lo
am_src_processor_pathname_stripper_unittest_OBJECTS = \
src/processor/pathname_stripper_unittest.$(OBJEXT)
src_processor_pathname_stripper_unittest_OBJECTS = \
$(am_src_processor_pathname_stripper_unittest_OBJECTS)
src_processor_pathname_stripper_unittest_DEPENDENCIES = \
src/processor/pathname_stripper.lo
am_src_processor_postfix_evaluator_unittest_OBJECTS = \
src/processor/postfix_evaluator_unittest.$(OBJEXT)
src_processor_postfix_evaluator_unittest_OBJECTS = \
@ -206,6 +219,7 @@ SOURCES = $(src_libairbag_la_SOURCES) \
$(src_processor_minidump_dump_SOURCES) \
$(src_processor_minidump_processor_unittest_SOURCES) \
$(src_processor_minidump_stackwalk_SOURCES) \
$(src_processor_pathname_stripper_unittest_SOURCES) \
$(src_processor_postfix_evaluator_unittest_SOURCES) \
$(src_processor_range_map_unittest_SOURCES) \
$(src_processor_source_line_resolver_unittest_SOURCES) \
@ -216,6 +230,7 @@ DIST_SOURCES = $(src_libairbag_la_SOURCES) \
$(src_processor_minidump_dump_SOURCES) \
$(src_processor_minidump_processor_unittest_SOURCES) \
$(src_processor_minidump_stackwalk_SOURCES) \
$(src_processor_pathname_stripper_unittest_SOURCES) \
$(src_processor_postfix_evaluator_unittest_SOURCES) \
$(src_processor_range_map_unittest_SOURCES) \
$(src_processor_source_line_resolver_unittest_SOURCES) \
@ -352,35 +367,39 @@ dist_doc_DATA = \
lib_LTLIBRARIES = src/libairbag.la
src_libairbag_la_SOURCES = \
src/google/airbag_types.h \
src/google/call_stack.h \
src/google/minidump_processor.h \
src/google/process_state.h \
src/google/stack_frame.h \
src/google/stack_frame_cpu.h \
src/google/symbol_supplier.h \
src/google_airbag/common/airbag_types.h \
src/google_airbag/common/minidump_format.h \
src/google_airbag/processor/call_stack.h \
src/google_airbag/processor/memory_region.h \
src/google_airbag/processor/minidump.h \
src/google_airbag/processor/minidump_processor.h \
src/google_airbag/processor/process_state.h \
src/google_airbag/processor/stack_frame.h \
src/google_airbag/processor/stack_frame_cpu.h \
src/google_airbag/processor/stackwalker.h \
src/google_airbag/processor/symbol_supplier.h \
src/processor/address_map.h \
src/processor/address_map-inl.h \
src/processor/call_stack.cc \
src/processor/contained_range_map.h \
src/processor/contained_range_map-inl.h \
src/processor/linked_ptr.h \
src/processor/memory_region.h \
src/processor/minidump.cc \
src/processor/minidump.h \
src/processor/minidump_format.h \
src/processor/minidump_processor.cc \
src/processor/pathname_stripper.cc \
src/processor/pathname_stripper.h \
src/processor/postfix_evaluator.h \
src/processor/postfix_evaluator-inl.h \
src/processor/process_state.cc \
src/processor/range_map.h \
src/processor/range_map-inl.h \
src/processor/scoped_ptr.h \
src/processor/simple_symbol_supplier.cc \
src/processor/simple_symbol_supplier.h \
src/processor/source_line_resolver.cc \
src/processor/source_line_resolver.h \
src/processor/stack_frame_info.h \
src/processor/stackwalker.cc \
src/processor/stackwalker.h \
src/processor/stackwalker_ppc.cc \
src/processor/stackwalker_ppc.h \
src/processor/stackwalker_x86.cc \
@ -411,6 +430,12 @@ src_processor_minidump_processor_unittest_LDADD = \
src/processor/stackwalker_x86.lo \
src/processor/source_line_resolver.lo
src_processor_pathname_stripper_unittest_SOURCES = \
src/processor/pathname_stripper_unittest.cc
src_processor_pathname_stripper_unittest_LDADD = \
src/processor/pathname_stripper.lo
src_processor_postfix_evaluator_unittest_SOURCES = \
src/processor/postfix_evaluator_unittest.cc
@ -447,6 +472,10 @@ src_processor_minidump_stackwalk_SOURCES = \
src_processor_minidump_stackwalk_LDADD = \
src/processor/call_stack.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 \
src/processor/stackwalker.lo \
src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_x86.lo \
@ -556,8 +585,13 @@ src/processor/minidump.lo: src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/minidump_processor.lo: src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/pathname_stripper.lo: src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/process_state.lo: src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/simple_symbol_supplier.lo: \
src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/source_line_resolver.lo: src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/stackwalker.lo: src/processor/$(am__dirstamp) \
@ -642,6 +676,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_LDFLAGS) $(src_processor_minidump_stackwalk_OBJECTS) $(src_processor_minidump_stackwalk_LDADD) $(LIBS)
src/processor/pathname_stripper_unittest.$(OBJEXT): \
src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/pathname_stripper_unittest$(EXEEXT): $(src_processor_pathname_stripper_unittest_OBJECTS) $(src_processor_pathname_stripper_unittest_DEPENDENCIES) src/processor/$(am__dirstamp)
@rm -f src/processor/pathname_stripper_unittest$(EXEEXT)
$(CXXLINK) $(src_processor_pathname_stripper_unittest_LDFLAGS) $(src_processor_pathname_stripper_unittest_OBJECTS) $(src_processor_pathname_stripper_unittest_LDADD) $(LIBS)
src/processor/postfix_evaluator_unittest.$(OBJEXT): \
src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
@ -680,10 +720,15 @@ 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/pathname_stripper.$(OBJEXT)
-rm -f src/processor/pathname_stripper.lo
-rm -f src/processor/pathname_stripper_unittest.$(OBJEXT)
-rm -f src/processor/postfix_evaluator_unittest.$(OBJEXT)
-rm -f src/processor/process_state.$(OBJEXT)
-rm -f src/processor/process_state.lo
-rm -f src/processor/range_map_unittest.$(OBJEXT)
-rm -f src/processor/simple_symbol_supplier.$(OBJEXT)
-rm -f src/processor/simple_symbol_supplier.lo
-rm -f src/processor/source_line_resolver.$(OBJEXT)
-rm -f src/processor/source_line_resolver.lo
-rm -f src/processor/source_line_resolver_unittest.$(OBJEXT)
@ -706,9 +751,12 @@ distclean-compile:
@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)/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@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/process_state.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/range_map_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/simple_symbol_supplier.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker.Plo@am__quote@

View File

@ -0,0 +1,91 @@
// Copyright (c) 2006, 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.
// minidump_file_writer-inl.h: Minidump file writer implementation.
//
// See minidump_file_writer.h for documentation.
#ifndef CLIENT_MINIDUMP_FILE_WRITER_INL_H__
#define CLIENT_MINIDUMP_FILE_WRITER_INL_H__
#include <assert.h>
#include "client/minidump_file_writer.h"
namespace google_airbag {
template<typename MDType>
inline bool TypedMDRVA<MDType>::Allocate() {
allocation_state_ = SINGLE_OBJECT;
return UntypedMDRVA::Allocate(sizeof(MDType));
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::Allocate(size_t additional) {
allocation_state_ = SINGLE_OBJECT;
return UntypedMDRVA::Allocate(sizeof(MDType) + additional);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::AllocateArray(size_t count) {
assert(count);
allocation_state_ = ARRAY;
return UntypedMDRVA::Allocate(sizeof(MDType) * count);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::AllocateObjectAndArray(unsigned int count,
size_t size) {
assert(count && size);
allocation_state_ = SINGLE_OBJECT_WITH_ARRAY;
return UntypedMDRVA::Allocate(sizeof(MDType) + count * size);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) {
assert(allocation_state_ == ARRAY);
return writer_->Copy(position_ + index * sizeof(MDType), item,
sizeof(MDType));
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::CopyIndexAfterObject(unsigned int index,
void *src, size_t size) {
assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY);
return writer_->Copy(position_ + sizeof(MDType) + index * size, src, size);
}
template<typename MDType>
inline bool TypedMDRVA<MDType>::Flush() {
return writer_->Copy(position_, &data_, sizeof(MDType));
}
} // namespace google_airbag
#endif // CLIENT_MINIDUMP_FILE_WRITER_INL_H__

View File

@ -0,0 +1,249 @@
// Copyright (c) 2006, 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.
// minidump_file_writer.cc: Minidump file writer implementation.
//
// See minidump_file_writer.h for documentation.
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "client/minidump_file_writer-inl.h"
namespace google_airbag {
MinidumpFileWriter::MinidumpFileWriter() : file_(-1), position_(0), size_(0) {
}
MinidumpFileWriter::~MinidumpFileWriter() {
Close();
}
bool MinidumpFileWriter::Open(const std::string &path) {
assert(file_ == -1);
file_ = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
return file_ != -1;
}
bool MinidumpFileWriter::Close() {
bool result = true;
if (file_ != -1) {
ftruncate(file_, position_);
result = close(file_) == 0;
file_ = -1;
}
return result;
}
bool MinidumpFileWriter::WriteString(const wchar_t *str,
unsigned int length,
MDLocationDescriptor *location) {
assert(str);
assert(location);
// Calculate the mdstring length by either limiting to |length| as passed in
// or by finding the location of the NULL character.
if (!length)
length = INT_MAX;
unsigned int mdstring_length = 0;
for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length) {
}
// Allocate the string buffer
TypedMDRVA<MDString> mdstring(this);
if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(u_int16_t)))
return false;
// Set length excluding the NULL
mdstring.get()->length = mdstring_length * sizeof(u_int16_t);
u_int16_t ch;
bool result = true;
if (sizeof(wchar_t) == sizeof(u_int16_t)) {
// Shortcut if wchar_t is the same size as MDString's buffer
result = mdstring.Copy(str, mdstring.get()->length);
} else {
// Copy the string character by character
for (unsigned int c = 0; c < mdstring_length && result == true; c++) {
ch = str[c];
// TODO: For the UTF-32->UTF-16 conversion, it's possible that there
// are characters that will require more than one UTF-16 character to
// represent it. Fully supporting this will require a more sophisticated
// calculation of the size of the resulting string and for converting the
// UTF-32 character into the two UTF-16 characters.
result = mdstring.CopyIndexAfterObject(c, &ch, sizeof(ch));
}
}
// NULL terminate
if (result) {
ch = 0;
result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
if (result)
*location = mdstring.location();
}
return result;
}
bool MinidumpFileWriter::WriteString(const char *str, unsigned int length,
MDLocationDescriptor *location) {
assert(str);
assert(location);
// Calculate the mdstring length by either limiting to |length| as passed in
// or by finding the location of the NULL character.
if (!length)
length = INT_MAX;
unsigned int mdstring_length = 0;
for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length) {
}
// Allocate the string buffer
TypedMDRVA<MDString> mdstring(this);
if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(u_int16_t)))
return false;
// Set length excluding the NULL
mdstring.get()->length = mdstring_length * sizeof(u_int16_t);
u_int16_t ch;
bool result = true;
// Copy the string character by character
for (unsigned int c = 0; c < mdstring_length && result == true; c++) {
ch = str[c];
// TODO: For the UTF-8->UTF-16 conversion, it's possible that there are
// characters that will convert one or more UTF-8 character into a single
// UTF-16 character. Fully supporting this will require a more
// sophisticated calculation of the size of the resulting string and for
// converting the UTF-8 characters into a UTF-16 character.
result = mdstring.CopyIndexAfterObject(c, &ch, sizeof(ch));
}
// NULL terminate
if (result) {
ch = 0;
result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
if (result)
*location = mdstring.location();
}
return result;
}
bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
MDMemoryDescriptor *output) {
assert(src);
assert(output);
UntypedMDRVA mem(this);
if (!mem.Allocate(size))
return false;
if (!mem.Copy(src, mem.size()))
return false;
output->start_of_memory_range = reinterpret_cast<u_int64_t>(src);
output->memory = mem.location();
return true;
}
MDRVA MinidumpFileWriter::Allocate(size_t size) {
assert(size);
assert(file_ != -1);
size_t aligned_size = (size + 7) & ~7; // 64-bit alignment
if (position_ + aligned_size > size_) {
size_t growth = aligned_size;
size_t minimal_growth = getpagesize();
// Ensure that the file grows by at least the size of a memory page
if (growth < minimal_growth)
growth = minimal_growth;
size_t new_size = size_ + growth;
if (ftruncate(file_, new_size) != 0)
return kInvalidMDRVA;
size_ = new_size;
}
MDRVA current_position = position_;
position_ += static_cast<MDRVA>(aligned_size);
return current_position;
}
bool MinidumpFileWriter::Copy(MDRVA position, const void* src, ssize_t size) {
assert(src);
assert(size);
assert(file_ != -1);
// Ensure that the data will fit in the allocated space
if (size + position > size_)
return false;
// Seek and write the data
if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position))
if (write(file_, src, size) == size)
return true;
return false;
}
bool UntypedMDRVA::Allocate(size_t size) {
assert(size_ == 0);
size_ = size;
position_ = writer_->Allocate(size_);
return position_ != MinidumpFileWriter::kInvalidMDRVA;
}
bool UntypedMDRVA::Copy(MDRVA position, const void *src, size_t size) {
assert(src);
assert(size);
assert(position + size <= position_ + size_);
return writer_->Copy(position, src, size);
}
} // namespace google_airbag

View File

@ -0,0 +1,218 @@
// Copyright (c) 2006, 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.
// minidump_file_writer.h: Implements file-based minidump generation
#ifndef CLIENT_MINIDUMP_FILE_WRITER_H__
#define CLIENT_MINIDUMP_FILE_WRITER_H__
#include <string>
#include "google_airbag/common/minidump_format.h"
namespace google_airbag {
class MinidumpFileWriter {
public:
// Invalid MDRVA (Minidump Relative Virtual Address)
// returned on failed allocation
static const MDRVA kInvalidMDRVA = static_cast<MDRVA>(-1);
MinidumpFileWriter();
~MinidumpFileWriter();
// Open |path| as the destination of the minidump data. Any existing file
// will be overwritten.
// Return true on success, or false on failure
bool Open(const std::string &path);
// Close the current file
// Return true on success, or false on failure
bool Close();
// Write |str| to a MDString.
// |str| is expected to be either UTF-16 or UTF-32 depending on the size
// of wchar_t.
// Maximum |length| of characters to copy from |str|, or specify 0 to use the
// entire NULL terminated string. Copying will stop at the first NULL.
// |location| the allocated location
// Return true on success, or false on failure
bool WriteString(const wchar_t *str, unsigned int length,
MDLocationDescriptor *location);
// Similar to above with |str| as an UTF-8 encoded string
bool WriteString(const char *str, unsigned int length,
MDLocationDescriptor *location);
// Write |size| bytes starting at |src| into the current position.
// Return true on success and set |output| to position, or false on failure
bool WriteMemory(const void *src, size_t size, MDMemoryDescriptor *output);
// Copies |size| bytes from |src| to |position|
// Return true on success, or false on failure
bool Copy(MDRVA position, const void *src, ssize_t size);
// Return the current position for writing to the minidump
MDRVA position() const { return position_; }
private:
friend class UntypedMDRVA;
// Allocates an area of |size| bytes.
// Returns the position of the allocation, or kInvalidMDRVA if it was
// unable to allocate the bytes.
MDRVA Allocate(size_t size);
// The file descriptor for the output file
int file_;
// Current position in buffer
MDRVA position_;
// Current allocated size
size_t size_;
};
// Represents an untyped allocated chunk
class UntypedMDRVA {
public:
explicit UntypedMDRVA(MinidumpFileWriter *writer)
: writer_(writer),
position_(writer->position()),
size_(0) {}
// Allocates |size| bytes. Must not call more than once.
// Return true on success, or false on failure
bool Allocate(size_t size);
// Returns the current position or kInvalidMDRVA if allocation failed
MDRVA position() const { return position_; }
// Number of bytes allocated
size_t size() const { return size_; }
// Return size and position
MDLocationDescriptor location() const {
MDLocationDescriptor location = { size_, position_ };
return location;
}
// Copy |size| bytes starting at |src| into the minidump at |position|
// Return true on success, or false on failure
bool Copy(MDRVA position, const void *src, size_t size);
// Copy |size| bytes from |src| to the current position
bool Copy(const void *src, size_t size) {
return Copy(position_, src, size);
}
protected:
// Writer we associate with
MinidumpFileWriter *writer_;
// Position of the start of the data
MDRVA position_;
// Allocated size
size_t size_;
};
// Represents a Minidump object chunk. Additional memory can be allocated at
// the end of the object as a:
// - single allocation
// - Array of MDType objects
// - A MDType object followed by an array
template<typename MDType>
class TypedMDRVA : public UntypedMDRVA {
public:
// Constructs an unallocated MDRVA
explicit TypedMDRVA(MinidumpFileWriter *writer)
: UntypedMDRVA(writer),
data_(),
allocation_state_(UNALLOCATED) {}
~TypedMDRVA() {
// Ensure that the data_ object is written out
if (allocation_state_ != ARRAY)
Flush();
}
// Address of object data_ of MDType. This is not declared const as the
// typical usage will be to access the underlying |data_| object as to
// alter its contents.
MDType *get() { return &data_; }
// Allocates sizeof(MDType) bytes.
// Must not call more than once.
// Return true on success, or false on failure
bool Allocate();
// Allocates sizeof(MDType) + |additional| bytes.
// Must not call more than once.
// Return true on success, or false on failure
bool Allocate(size_t additional);
// Allocate an array of |count| elements of MDType.
// Must not call more than once.
// Return true on success, or false on failure
bool AllocateArray(size_t count);
// Allocate an array of |count| elements of |size| after object of MDType
// Must not call more than once.
// Return true on success, or false on failure
bool AllocateObjectAndArray(unsigned int count, size_t size);
// Copy |item| to |index|
// Must have been allocated using AllocateArray().
// Return true on success, or false on failure
bool CopyIndex(unsigned int index, MDType *item);
// Copy |size| bytes starting at |str| to |index|
// Must have been allocated using AllocateObjectAndArray().
// Return true on success, or false on failure
bool CopyIndexAfterObject(unsigned int index, void *src, size_t size);
// Write data_
bool Flush();
private:
enum AllocationState {
UNALLOCATED = 0,
SINGLE_OBJECT,
ARRAY,
SINGLE_OBJECT_WITH_ARRAY
};
MDType data_;
AllocationState allocation_state_;
};
} // namespace google_airbag
#endif // CLIENT_MINIDUMP_FILE_WRITER_H__

View File

@ -31,12 +31,23 @@
#include <cstdio>
#include "common/windows/string_utils-inl.h"
#include "client/windows/handler/exception_handler.h"
#include "common/windows/guid_string.h"
#include "google_airbag/common/minidump_format.h"
namespace google_airbag {
ExceptionHandler *ExceptionHandler::current_handler_ = NULL;
HANDLE ExceptionHandler::handler_thread_ = NULL;
CRITICAL_SECTION ExceptionHandler::handler_critical_section_;
HANDLE ExceptionHandler::handler_start_semaphore_ = NULL;
HANDLE ExceptionHandler::handler_finish_semaphore_ = NULL;
ExceptionHandler *ExceptionHandler::requesting_handler_ = NULL;
DWORD ExceptionHandler::requesting_thread_id_ = 0;
EXCEPTION_POINTERS *ExceptionHandler::exception_info_ = NULL;
bool ExceptionHandler::handler_return_value_ = false;
ExceptionHandler::ExceptionHandler(const wstring &dump_path,
MinidumpCallback callback,
@ -46,6 +57,22 @@ ExceptionHandler::ExceptionHandler(const wstring &dump_path,
dump_path_(dump_path), dbghelp_module_(NULL),
minidump_write_dump_(NULL), previous_handler_(current_handler_),
previous_filter_(NULL) {
if (!handler_thread_) {
// The first time an ExceptionHandler is created, set up the handler
// thread and the synchronization primitives.
InitializeCriticalSection(&handler_critical_section_);
handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
DWORD thread_id;
handler_thread_ = CreateThread(NULL, // lpThreadAttributes
64 * 1024, // dwStackSize
ExceptionHandlerThreadMain,
NULL, // lpParameter
0, // dwCreationFlags
&thread_id);
}
UpdateNextID();
dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
if (dbghelp_module_) {
@ -66,18 +93,72 @@ ExceptionHandler::~ExceptionHandler() {
SetUnhandledExceptionFilter(previous_filter_);
current_handler_ = previous_handler_;
}
if (previous_handler_ == NULL) {
// When destroying the last ExceptionHandler, clean up the handler thread
// and synchronization primitives.
TerminateThread(handler_thread_, 1);
handler_thread_ = NULL;
DeleteCriticalSection(&handler_critical_section_);
CloseHandle(handler_start_semaphore_);
handler_start_semaphore_ = NULL;
CloseHandle(handler_finish_semaphore_);
handler_finish_semaphore_ = NULL;
}
}
// static
DWORD ExceptionHandler::ExceptionHandlerThreadMain(void *lpParameter) {
while (true) {
if (WaitForSingleObject(handler_start_semaphore_, INFINITE) ==
WAIT_OBJECT_0) {
// Perform the requested action.
handler_return_value_ = requesting_handler_->WriteMinidumpWithException(
requesting_thread_id_, exception_info_);
// Allow the requesting thread to proceed.
ReleaseSemaphore(handler_finish_semaphore_, 1, NULL);
}
}
// Not reached. This thread will be terminated by ExceptionHandler's
// destructor.
return 0;
}
// static
LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) {
if (!current_handler_->WriteMinidumpWithException(exinfo)) {
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_EXECUTE_HANDLER;
return current_handler_->WriteMinidumpOnHandlerThread(exinfo) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
}
bool ExceptionHandler::WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS *exinfo) {
EnterCriticalSection(&handler_critical_section_);
// Set up data to be passed in to the handler thread.
requesting_handler_ = this;
requesting_thread_id_ = GetCurrentThreadId();
exception_info_ = exinfo;
// This causes the handler thread to call WriteMinidumpWithException.
ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
// Wait until WriteMinidumpWithException is done and collect its return value.
WaitForSingleObject(handler_finish_semaphore_, INFINITE);
bool status = handler_return_value_;
// Clean up.
requesting_handler_ = NULL;
requesting_thread_id_ = 0;
exception_info_ = NULL;
LeaveCriticalSection(&handler_critical_section_);
return status;
}
bool ExceptionHandler::WriteMinidump() {
bool success = WriteMinidumpWithException(NULL);
bool success = WriteMinidumpOnHandlerThread(NULL);
UpdateNextID();
return success;
}
@ -90,10 +171,12 @@ bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
return handler.WriteMinidump();
}
bool ExceptionHandler::WriteMinidumpWithException(EXCEPTION_POINTERS *exinfo) {
bool ExceptionHandler::WriteMinidumpWithException(DWORD requesting_thread_id,
EXCEPTION_POINTERS *exinfo) {
wchar_t dump_file_name[MAX_PATH];
swprintf_s(dump_file_name, MAX_PATH, L"%s\\%s.dmp",
dump_path_.c_str(), next_minidump_id_.c_str());
WindowsStringUtils::safe_swprintf(dump_file_name, MAX_PATH, L"%s\\%s.dmp",
dump_path_.c_str(),
next_minidump_id_.c_str());
bool success = false;
if (minidump_write_dump_) {
@ -106,17 +189,38 @@ bool ExceptionHandler::WriteMinidumpWithException(EXCEPTION_POINTERS *exinfo) {
NULL);
if (dump_file != INVALID_HANDLE_VALUE) {
MINIDUMP_EXCEPTION_INFORMATION except_info;
except_info.ThreadId = GetCurrentThreadId();
except_info.ThreadId = requesting_thread_id;
except_info.ExceptionPointers = exinfo;
except_info.ClientPointers = FALSE;
// Add an MDRawAirbagInfo stream to the minidump, to provide additional
// information about the exception handler to the Airbag processor. The
// information will help the processor determine which threads are
// relevant. The Airbag processor does not require this information but
// can function better with Airbag-generated dumps when it is present.
// The native debugger is not harmed by the presence of this information.
MDRawAirbagInfo airbag_info;
airbag_info.validity = MD_AIRBAG_INFO_VALID_DUMP_THREAD_ID |
MD_AIRBAG_INFO_VALID_REQUESTING_THREAD_ID;
airbag_info.dump_thread_id = GetCurrentThreadId();
airbag_info.requesting_thread_id = requesting_thread_id;
MINIDUMP_USER_STREAM airbag_info_stream;
airbag_info_stream.Type = MD_AIRBAG_INFO_STREAM;
airbag_info_stream.BufferSize = sizeof(airbag_info);
airbag_info_stream.Buffer = &airbag_info;
MINIDUMP_USER_STREAM_INFORMATION user_streams;
user_streams.UserStreamCount = 1;
user_streams.UserStreamArray = &airbag_info_stream;
// The explicit comparison to TRUE avoids a warning (C4800).
success = (minidump_write_dump_(GetCurrentProcess(),
GetCurrentProcessId(),
dump_file,
MiniDumpNormal,
&except_info,
NULL,
exinfo ? &except_info : NULL,
&user_streams,
NULL) == TRUE);
CloseHandle(dump_file);

View File

@ -63,8 +63,9 @@
#include <DbgHelp.h>
#pragma warning( push )
// disable exception handler warnings
// Disable exception handler warnings.
#pragma warning( disable : 4530 )
#include <string>
namespace google_airbag {
@ -90,7 +91,7 @@ class ExceptionHandler {
void *callback_context, bool install_handler);
~ExceptionHandler();
// Get and set the minidump path
// Get and set the minidump path.
wstring dump_path() const { return dump_path_; }
void set_dump_path(const wstring &dump_path) { dump_path_ = dump_path; }
@ -115,12 +116,30 @@ class ExceptionHandler {
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
// This function does the actual writing of a minidump.
bool WriteMinidumpWithException(EXCEPTION_POINTERS *exinfo);
// Runs the main loop for the exception handler thread.
static DWORD WINAPI ExceptionHandlerThreadMain(void *lpParameter);
// Called when an unhandled exception occurs.
// Called on the exception thread when an unhandled exception occurs.
// Signals the exception handler thread to handle the exception.
static LONG WINAPI HandleException(EXCEPTION_POINTERS *exinfo);
// This is called on the exception thread or on another thread that
// the user wishes to produce a dump from. It calls
// WriteMinidumpWithException on the handler thread, avoiding stack
// overflows and inconsistent dumps due to writing the dump from
// the exception thread. If the dump is requested as a result of an
// exception, exinfo contains exception information, otherwise, it
// is NULL.
bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS *exinfo);
// This function does the actual writing of a minidump. It is called
// on the handler thread. requesting_thread_id is the ID of the thread
// that requested the dump. If the dump is requested as a result of
// an exception, exinfo contains exception information, otherwise,
// it is NULL.
bool WriteMinidumpWithException(DWORD requesting_thread_id,
EXCEPTION_POINTERS *exinfo);
// Generates a new ID and stores it in next_minidump_id_.
void UpdateNextID();
@ -139,6 +158,41 @@ class ExceptionHandler {
// the currently-installed ExceptionHandler, of which there can be only 1
static ExceptionHandler *current_handler_;
// The exception handler thread, if one has been created.
static HANDLE handler_thread_;
// The critical section enforcing the requirement that only one exception be
// handled at a time.
static CRITICAL_SECTION handler_critical_section_;
// Semaphores used to move exception handling between the exception thread
// and the handler thread. handler_start_semaphore_ is signalled by the
// exception thread to wake up the handler thread when an exception occurs.
// handler_finish_semaphore_ is signalled by the handler thread to wake up
// the exception thread when handling is complete.
static HANDLE handler_start_semaphore_;
static HANDLE handler_finish_semaphore_;
// The next 3 fields are static data passed from the requesting thread to
// the handler thread.
// The ExceptionHandler through which a request to write a dump was routed.
// This will be the same as current_handler_ for exceptions, but
// user-requested dumps may be routed through any live ExceptionHandler.
static ExceptionHandler *requesting_handler_;
// The thread ID of the thread requesting the dump (either the exception
// thread or any other thread that called WriteMinidump directly).
static DWORD requesting_thread_id_;
// The exception info passed to the exception handler on the exception
// thread, if an exception occurred. NULL for user-requested dumps.
static EXCEPTION_POINTERS *exception_info_;
// The return value of the handler, passed from the handler thread back to
// the requesting thread.
static bool handler_return_value_;
// disallow copy ctor and operator=
explicit ExceptionHandler(const ExceptionHandler &);
void operator=(const ExceptionHandler &);
@ -147,4 +201,5 @@ class ExceptionHandler {
} // namespace google_airbag
#pragma warning( pop )
#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__

View File

@ -294,6 +294,14 @@
RelativePath="..\..\..\common\windows\guid_string.h"
>
</File>
<File
RelativePath="..\..\..\google_airbag\common\minidump_format.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\string_utils-inl.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"

View File

@ -27,7 +27,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Disable exception handler warnings.
#pragma warning( disable : 4530 )
#include "client/windows/sender/crash_report_sender.h"
#include "common/windows/http_upload.h"

View File

@ -39,7 +39,7 @@
// wininet.lib.
#pragma warning( push )
// disable exception handler warnings
// Disable exception handler warnings.
#pragma warning( disable : 4530 )
#include <map>
@ -74,4 +74,5 @@ class CrashReportSender {
} // namespace google_airbag
#pragma warning( pop )
#endif // CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__

View File

@ -33,6 +33,8 @@
#include <wchar.h>
#include "common/windows/string_utils-inl.h"
#include "common/windows/guid_string.h"
namespace google_airbag {
@ -40,12 +42,13 @@ namespace google_airbag {
// static
wstring GUIDString::GUIDToWString(GUID *guid) {
wchar_t guid_string[37];
_snwprintf_s(guid_string, sizeof(guid_string) / sizeof(wchar_t), _TRUNCATE,
L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2],
guid->Data4[3], guid->Data4[4], guid->Data4[5],
guid->Data4[6], guid->Data4[7]);
WindowsStringUtils::safe_swprintf(
guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2],
guid->Data4[3], guid->Data4[4], guid->Data4[5],
guid->Data4[6], guid->Data4[7]);
return wstring(guid_string);
}

View File

@ -31,9 +31,13 @@
#include <Windows.h>
#include <WinInet.h>
// Disable exception handler warnings.
#pragma warning( disable : 4530 )
#include <fstream>
#include "common/windows/string_utils-inl.h"
#include "common/windows/http_upload.h"
namespace google_airbag {
@ -164,7 +168,8 @@ wstring HTTPUpload::GenerateMultipartBoundary() {
int r1 = rand();
wchar_t temp[kBoundaryLength];
swprintf_s(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1);
WindowsStringUtils::safe_swprintf(temp, kBoundaryLength, L"%s%08X%08X",
kBoundaryPrefix, r0, r1);
return wstring(temp);
}
@ -230,8 +235,16 @@ bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> &parameters,
// static
void HTTPUpload::GetFileContents(const wstring &filename,
vector<char> *contents) {
// The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
// wchar_t* filename, so use _wfopen directly in that case. For VC8 and
// later, _wfopen has been deprecated in favor of _wfopen_s, which does
// not exist in earlier versions, so let the ifstream open the file itself.
#if _MSC_VER >= 1400 // MSVC 2005/8
ifstream file;
file.open(filename.c_str(), ios::binary);
#else // _MSC_VER >= 1400
ifstream file(_wfopen(filename.c_str(), L"rb"));
#endif // _MSC_VER >= 1400
if (file.is_open()) {
file.seekg(0, ios::end);
int length = file.tellg();

View File

@ -35,7 +35,7 @@
#define COMMON_WINDOWS_HTTP_UPLOAD_H__
#pragma warning( push )
// disable exception handler warnings
// Disable exception handler warnings.
#pragma warning( disable : 4530 )
#include <map>
@ -104,4 +104,5 @@ class HTTPUpload {
} // namespace google_airbag
#pragma warning( pop )
#endif // COMMON_WINDOWS_HTTP_UPLOAD_H__

View File

@ -32,6 +32,8 @@
#include <dia2.h>
#include <stdio.h>
#include "common/windows/string_utils-inl.h"
#include "common/windows/pdb_source_line_writer.h"
#include "common/windows/guid_string.h"
@ -77,6 +79,14 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
return false;
}
break;
case ANY_FILE:
if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
fprintf(stderr, "loadDataForPdb and loadDataFromExe failed\n");
return false;
}
}
break;
default:
fprintf(stderr, "Unknown file format\n");
return false;
@ -153,7 +163,7 @@ bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function) {
stack_param_size = GetFunctionStackParamSize(function);
}
fprintf(output_, "FUNC %x %llx %x %ws\n",
fprintf(output_, "FUNC %x %" WIN_STRING_FORMAT_LL "x %x %ws\n",
rva, length, stack_param_size, name);
CComPtr<IDiaEnumLineNumbers> lines;
@ -379,6 +389,18 @@ bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) {
return true;
}
bool PDBSourceLineWriter::PrintPDBInfo() {
wstring guid, filename;
int age;
if (!GetModuleInfo(&guid, &age, &filename)) {
return false;
}
fprintf(output_, "MODULE %ws %x %ws\n", guid.c_str(), age, filename.c_str());
return true;
}
// wcstol_positive_strict is sort of like wcstol, but much stricter. string
// should be a buffer pointing to a null-terminated string containing only
// decimal digits. If the entire string can be converted to an integer
@ -441,6 +463,11 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
// If a name comes from get_name because no undecorated form existed,
// it's already formatted properly to be used as output. Don't do any
// additional processing.
//
// MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's.
// This will result in calling get_name for some C++ symbols, so
// all of the parameter and return type information may not be included in
// the name string.
} else {
// C++ uses a bogus "void" argument for functions and methods that don't
// take any parameters. Take it out of the undecorated name because it's
@ -452,7 +479,8 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
if (length >= replace_length) {
wchar_t *name_end = *name + length - replace_length;
if (wcscmp(name_end, replace_string) == 0) {
wcscpy_s(name_end, replace_length, replacement_string);
WindowsStringUtils::safe_wcscpy(name_end, replace_length,
replacement_string);
length = wcslen(*name);
}
}
@ -481,13 +509,14 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
// Undecorate the name by moving it one character to the left in its
// buffer, and terminating it where the last '@' had been.
wcsncpy_s(*name, length, *name + 1, last_at - *name - 1);
} else if (*name[0] == '_') {
WindowsStringUtils::safe_wcsncpy(*name, length,
*name + 1, last_at - *name - 1);
} else if (*name[0] == '_') {
// This symbol's name is encoded according to the cdecl rules. The
// name doesn't end in a '@' character followed by a decimal positive
// integer, so it's not a stdcall name. Strip off the leading
// underscore.
wcsncpy_s(*name, length, *name + 1, length - 1);
WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length);
}
}
}
@ -608,11 +637,12 @@ next_child:
}
bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
bool ret = false;
output_ = map_file;
if (PrintSourceFiles() && PrintFunctions() && PrintFrameData()) {
ret = true;
}
bool ret = PrintPDBInfo() &&
PrintSourceFiles() &&
PrintFunctions() &&
PrintFrameData();
output_ = NULL;
return ret;
@ -622,18 +652,47 @@ void PDBSourceLineWriter::Close() {
session_.Release();
}
wstring PDBSourceLineWriter::GetModuleGUID() {
// static
wstring PDBSourceLineWriter::GetBaseName(const wstring &filename) {
wstring base_name(filename);
size_t slash_pos = base_name.find_last_of(L"/\\");
if (slash_pos != wstring::npos) {
base_name.erase(0, slash_pos + 1);
}
return base_name;
}
bool PDBSourceLineWriter::GetModuleInfo(wstring *guid, int *age,
wstring *filename) {
guid->clear();
*age = 0;
filename->clear();
CComPtr<IDiaSymbol> global;
if (FAILED(session_->get_globalScope(&global))) {
return L"";
return false;
}
GUID guid;
if (FAILED(global->get_guid(&guid))) {
return L"";
GUID guid_number;
if (FAILED(global->get_guid(&guid_number))) {
return false;
}
*guid = GUIDString::GUIDToWString(&guid_number);
return GUIDString::GUIDToWString(&guid);
// DWORD* and int* are not compatible. This is clean and avoids a cast.
DWORD age_dword;
if (FAILED(global->get_age(&age_dword))) {
return false;
}
*age = age_dword;
CComBSTR filename_string;
if (FAILED(global->get_symbolsFileName(&filename_string))) {
return false;
}
*filename = GetBaseName(wstring(filename_string));
return true;
}
} // namespace google_airbag

View File

@ -50,6 +50,7 @@ class PDBSourceLineWriter {
enum FileFormat {
PDB_FILE, // a .pdb file containing debug symbols
EXE_FILE, // a .exe or .dll file
ANY_FILE // try PDB_FILE and then EXE_FILE
};
explicit PDBSourceLineWriter();
@ -73,9 +74,11 @@ class PDBSourceLineWriter {
// Closes the current pdb file and its associated resources.
void Close();
// Returns the GUID for the module, as a string,
// e.g. "11111111-2222-3333-4444-555555555555".
wstring GetModuleGUID();
// Sets guid to the GUID for the module, as a string,
// e.g. "11111111-2222-3333-4444-555555555555". age will be set to the
// age of the pdb file, and filename will be set to the basename of the
// PDB's file name. Returns true on success and false on failure.
bool GetModuleInfo(wstring *guid, int *age, wstring *filename);
private:
// Outputs the line/address pairs for each line in the enumerator.
@ -102,6 +105,13 @@ class PDBSourceLineWriter {
// correspond to code, returns true without outputting anything.
bool PrintCodePublicSymbol(IDiaSymbol *symbol);
// Outputs a line identifying the PDB file that is being dumped, along with
// its uuid and age.
bool PrintPDBInfo();
// Returns the base name of a file, e.g. strips off the path.
static wstring GetBaseName(const wstring &filename);
// Returns the function name for a symbol. If possible, the name is
// undecorated. If the symbol's decorated form indicates the size of
// parameters on the stack, this information is returned in stack_param_size.

View File

@ -0,0 +1,132 @@
// Copyright (c) 2006, 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.
// string_utils-inl.h: Safer string manipulation on Windows, supporting
// pre-MSVC8 environments.
#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H__
#define COMMON_WINDOWS_STRING_UTILS_INL_H__
#include <stdarg.h>
#include <wchar.h>
// The "ll" printf format size specifier corresponding to |long long| was
// intrudced in MSVC8. Earlier versions did not provide this size specifier,
// but "I64" can be used to print 64-bit types. Don't use "I64" where "ll"
// is available, in the event of oddball systems where |long long| is not
// 64 bits wide.
#if _MSC_VER >= 1400 // MSVC 2005/8
#define WIN_STRING_FORMAT_LL "ll"
#else // MSC_VER >= 1400
#define WIN_STRING_FORMAT_LL "I64"
#endif // MSC_VER >= 1400
namespace google_airbag {
class WindowsStringUtils {
public:
// Equivalent to MSVC8's swprintf, which always 0-terminates buffer.
static void safe_swprintf(wchar_t *buffer, size_t count,
const wchar_t *format, ...);
// Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does
// not fail if source is longer than destination_size. The destination
// buffer is always 0-terminated.
static void safe_wcscpy(wchar_t *destination, size_t destination_size,
const wchar_t *source);
// Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot
// be passed directly, and pre-MSVC8, this will not fail if source or count
// are longer than destination_size. The destination buffer is always
// 0-terminated.
static void safe_wcsncpy(wchar_t *destination, size_t destination_size,
const wchar_t *source, size_t count);
private:
// Disallow instantiation and other object-based operations.
WindowsStringUtils();
WindowsStringUtils(const WindowsStringUtils&);
~WindowsStringUtils();
void operator=(const WindowsStringUtils&);
};
// static
inline void WindowsStringUtils::safe_swprintf(wchar_t *buffer, size_t count,
const wchar_t *format, ...) {
va_list args;
va_start(args, format);
vswprintf(buffer, count, format, args);
#if _MSC_VER < 1400 // MSVC 2005/8
// Pre-MSVC 2005/8 doesn't 0-terminate the buffer if the formatted string
// is larger than the buffer. Ensure that the string is 0-terminated.
if (buffer && count)
buffer[count - 1] = 0;
#endif // _MSC_VER < 1400
}
// static
inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination,
size_t destination_size,
const wchar_t *source) {
#if _MSC_VER >= 1400 // MSVC 2005/8
wcscpy_s(destination, destination_size, source);
#else // _MSC_VER >= 1400
// Pre-MSVC 2005/8 doesn't have wcscpy_s. Simulate it with wcsncpy.
// wcsncpy doesn't 0-terminate the destination buffer if the source string
// is longer than size. Ensure that the destination is 0-terminated.
wcsncpy(destination, source, destination_size);
if (destination && destination_size)
destination[destination_size - 1] = 0;
#endif // _MSC_VER >= 1400
}
// static
inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination,
size_t destination_size,
const wchar_t *source,
size_t count) {
#if _MSC_VER >= 1400 // MSVC 2005/8
wcsncpy_s(destination, destination_size, source, count);
#else // _MSC_VER >= 1400
// Pre-MSVC 2005/8 doesn't have wcsncpy_s. Simulate it with wcsncpy.
// wcsncpy doesn't 0-terminate the destination buffer if the source string
// is longer than size. Ensure that the destination is 0-terminated.
if (destination_size < count)
count = destination_size;
wcsncpy(destination, source, count);
if (destination && count)
destination[count - 1] = 0;
#endif // _MSC_VER >= 1400
}
} // namespace google_airbag
#endif // COMMON_WINDOWS_STRING_UTILS_INL_H__

View File

@ -47,6 +47,8 @@
#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
namespace {
using google_airbag::AddressMap;
using google_airbag::linked_ptr;
@ -185,6 +187,8 @@ static bool RunTests() {
return true;
}
} // namespace
int main(int argc, char **argv) {
return RunTests() ? 0 : 1;
}

View File

@ -33,8 +33,8 @@
//
// Author: Mark Mentovai
#include "google/call_stack.h"
#include "google/stack_frame.h"
#include "google_airbag/processor/call_stack.h"
#include "google_airbag/processor/stack_frame.h"
namespace google_airbag {

View File

@ -45,6 +45,9 @@
#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition))
namespace {
using google_airbag::ContainedRangeMap;
@ -248,6 +251,9 @@ static bool RunTests() {
}
} // namespace
int main(int argc, char **argv) {
return RunTests() ? 0 : 1;
}

View File

@ -53,7 +53,7 @@ typedef SSIZE_T ssize_t;
#include "processor/range_map-inl.h"
#include "processor/minidump.h"
#include "google_airbag/processor/minidump.h"
#include "processor/scoped_ptr.h"
@ -462,13 +462,13 @@ void MinidumpContext::FreeContext() {
bool MinidumpContext::CheckAgainstSystemInfo(u_int32_t context_cpu_type) {
// It's OK if the minidump doesn't contain a SYSTEM_INFO_STREAM,
// It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
// as this function just implements a sanity check.
MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
if (!system_info)
return true;
// If there is a SYSTEM_INFO_STREAM, it should contain valid system info.
// If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info.
const MDRawSystemInfo* raw_system_info = system_info->system_info();
if (!raw_system_info)
return false;
@ -661,7 +661,8 @@ const u_int8_t* MinidumpMemoryRegion::GetMemory() {
u_int64_t MinidumpMemoryRegion::GetBase() {
return valid_ ? descriptor_->start_of_memory_range : (u_int64_t)-1;
return valid_ ?
descriptor_->start_of_memory_range : static_cast<u_int64_t>(-1);
}
@ -829,8 +830,12 @@ MinidumpContext* MinidumpThread::GetContext() {
}
u_int32_t MinidumpThread::GetThreadID() {
return valid_ ? thread_.thread_id : (u_int32_t)-1;
bool MinidumpThread::GetThreadID(u_int32_t *thread_id) const {
if (!thread_id || !valid_)
return false;
*thread_id = thread_.thread_id;
return true;
}
@ -928,7 +933,10 @@ bool MinidumpThreadList::Read(u_int32_t expected_size) {
if (!thread->Read())
return false;
u_int32_t thread_id = thread->GetThreadID();
u_int32_t thread_id;
if (!thread->GetThreadID(&thread_id))
return false;
if (GetThreadByID(thread_id)) {
// Another thread with this ID is already in the list. Data error.
return false;
@ -1408,20 +1416,21 @@ void MinidumpModule::Print() {
MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
: MinidumpStream(minidump),
range_map_(),
range_map_(new RangeMap<u_int64_t, unsigned int>()),
modules_(NULL),
module_count_(0) {
}
MinidumpModuleList::~MinidumpModuleList() {
delete range_map_;
delete modules_;
}
bool MinidumpModuleList::Read(u_int32_t expected_size) {
// Invalidate cached data.
range_map_.Clear();
range_map_->Clear();
delete modules_;
modules_ = NULL;
module_count_ = 0;
@ -1460,7 +1469,7 @@ bool MinidumpModuleList::Read(u_int32_t expected_size) {
if (base_address == (u_int64_t)-1)
return false;
if (!range_map_.StoreRange(base_address, module_size, module_index))
if (!range_map_->StoreRange(base_address, module_size, module_index))
return false;
}
@ -1486,7 +1495,7 @@ MinidumpModule* MinidumpModuleList::GetModuleForAddress(u_int64_t address) {
return NULL;
unsigned int module_index;
if (!range_map_.RetrieveRange(address, &module_index, NULL, NULL))
if (!range_map_->RetrieveRange(address, &module_index, NULL, NULL))
return NULL;
return GetModuleAtIndex(module_index);
@ -1518,7 +1527,7 @@ void MinidumpModuleList::Print() {
MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
: MinidumpStream(minidump),
range_map_(),
range_map_(new RangeMap<u_int64_t, unsigned int>()),
descriptors_(NULL),
regions_(NULL),
region_count_(0) {
@ -1526,6 +1535,7 @@ MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
MinidumpMemoryList::~MinidumpMemoryList() {
delete range_map_;
delete descriptors_;
delete regions_;
}
@ -1537,7 +1547,7 @@ bool MinidumpMemoryList::Read(u_int32_t expected_size) {
descriptors_ = NULL;
delete regions_;
regions_ = NULL;
range_map_.Clear();
range_map_->Clear();
region_count_ = 0;
valid_ = false;
@ -1587,7 +1597,7 @@ bool MinidumpMemoryList::Read(u_int32_t expected_size) {
if (region_size == 0 || high_address < base_address)
return false;
if (!range_map_.StoreRange(base_address, region_size, region_index))
if (!range_map_->StoreRange(base_address, region_size, region_index))
return false;
(*regions)[region_index].SetDescriptor(descriptor);
@ -1617,7 +1627,7 @@ MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
return NULL;
unsigned int region_index;
if (!range_map_.RetrieveRange(address, &region_index, NULL, NULL))
if (!range_map_->RetrieveRange(address, &region_index, NULL, NULL))
return NULL;
return GetMemoryRegionAtIndex(region_index);
@ -1708,8 +1718,12 @@ bool MinidumpException::Read(u_int32_t expected_size) {
}
u_int32_t MinidumpException::GetThreadID() {
return valid_ ? exception_.thread_id : 0;
bool MinidumpException::GetThreadID(u_int32_t *thread_id) const {
if (!thread_id || !valid_)
return false;
*thread_id = exception_.thread_id;
return true;
}
@ -2006,6 +2020,85 @@ void MinidumpMiscInfo::Print() {
printf(" processor_current_idle_state = 0x%x\n",
misc_info_.processor_current_idle_state);
}
printf("\n");
}
//
// MinidumpAirbagInfo
//
MinidumpAirbagInfo::MinidumpAirbagInfo(Minidump* minidump)
: MinidumpStream(minidump),
airbag_info_() {
}
bool MinidumpAirbagInfo::Read(u_int32_t expected_size) {
valid_ = false;
if (expected_size != sizeof(airbag_info_))
return false;
if (!minidump_->ReadBytes(&airbag_info_, sizeof(airbag_info_)))
return false;
if (minidump_->swap()) {
Swap(&airbag_info_.validity);
Swap(&airbag_info_.dump_thread_id);
Swap(&airbag_info_.requesting_thread_id);
}
valid_ = true;
return true;
}
bool MinidumpAirbagInfo::GetDumpThreadID(u_int32_t *thread_id) const {
if (!thread_id || !valid_ ||
!(airbag_info_.validity & MD_AIRBAG_INFO_VALID_DUMP_THREAD_ID)) {
return false;
}
*thread_id = airbag_info_.dump_thread_id;
return true;
}
bool MinidumpAirbagInfo::GetRequestingThreadID(u_int32_t *thread_id)
const {
if (!thread_id || !valid_ ||
!(airbag_info_.validity & MD_AIRBAG_INFO_VALID_REQUESTING_THREAD_ID)) {
return false;
}
*thread_id = airbag_info_.requesting_thread_id;
return true;
}
void MinidumpAirbagInfo::Print() {
if (!valid_)
return;
printf("MDRawAirbagInfo\n");
printf(" validity = 0x%x\n", airbag_info_.validity);
if (airbag_info_.validity & MD_AIRBAG_INFO_VALID_DUMP_THREAD_ID) {
printf(" dump_thread_id = 0x%x\n", airbag_info_.dump_thread_id);
} else {
printf(" dump_thread_id = (invalid)\n");
}
if (airbag_info_.validity & MD_AIRBAG_INFO_VALID_DUMP_THREAD_ID) {
printf(" requesting_thread_id = 0x%x\n",
airbag_info_.requesting_thread_id);
} else {
printf(" requesting_thread_id = (invalid)\n");
}
printf("\n");
}
@ -2128,12 +2221,13 @@ bool Minidump::Read() {
// type.
unsigned int stream_type = directory_entry->stream_type;
switch (stream_type) {
case THREAD_LIST_STREAM:
case MODULE_LIST_STREAM:
case MEMORY_LIST_STREAM:
case EXCEPTION_STREAM:
case SYSTEM_INFO_STREAM:
case MISC_INFO_STREAM: {
case MD_THREAD_LIST_STREAM:
case MD_MODULE_LIST_STREAM:
case MD_MEMORY_LIST_STREAM:
case MD_EXCEPTION_STREAM:
case MD_SYSTEM_INFO_STREAM:
case MD_MISC_INFO_STREAM:
case MD_AIRBAG_INFO_STREAM: {
if (stream_map->find(stream_type) != stream_map->end()) {
// Another stream with this type was already found. A minidump
// file should contain at most one of each of these stream types.
@ -2194,6 +2288,12 @@ MinidumpMiscInfo* Minidump::GetMiscInfo() {
}
MinidumpAirbagInfo* Minidump::GetAirbagInfo() {
MinidumpAirbagInfo* airbag_info;
return GetStream(&airbag_info);
}
void Minidump::Print() {
if (!valid_)
return;
@ -2233,7 +2333,7 @@ void Minidump::Print() {
++iterator) {
u_int32_t stream_type = iterator->first;
MinidumpStreamInfo info = iterator->second;
printf(" stream type %2d at index %d\n", stream_type, info.stream_index);
printf(" stream type 0x%x at index %d\n", stream_type, info.stream_index);
}
printf("\n");
}

View File

@ -32,81 +32,97 @@
//
// Author: Mark Mentovai
#include <stdlib.h>
#include <stdio.h>
#include <cstdio>
#include <string>
#include "google_airbag/processor/minidump.h"
#include "processor/minidump.h"
namespace {
using google_airbag::Minidump;
using google_airbag::MinidumpThreadList;
using google_airbag::MinidumpModuleList;
using google_airbag::MinidumpMemoryList;
using google_airbag::MinidumpException;
using google_airbag::MinidumpSystemInfo;
using google_airbag::MinidumpMiscInfo;
using google_airbag::MinidumpAirbagInfo;
using std::string;
using namespace google_airbag;
int main(int argc, char** argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
exit(1);
}
Minidump minidump(argv[1]);
static bool PrintMinidumpDump(const char *minidump_file) {
Minidump minidump(minidump_file);
if (!minidump.Read()) {
printf("minidump.Read() failed\n");
exit(1);
fprintf(stderr, "minidump.Read() failed\n");
return false;
}
minidump.Print();
int error = 0;
int errors = 0;
MinidumpThreadList* threadList = minidump.GetThreadList();
if (!threadList) {
error |= 1 << 2;
MinidumpThreadList *thread_list = minidump.GetThreadList();
if (!thread_list) {
++errors;
printf("minidump.GetThreadList() failed\n");
} else {
threadList->Print();
thread_list->Print();
}
MinidumpModuleList* moduleList = minidump.GetModuleList();
if (!moduleList) {
error |= 1 << 3;
MinidumpModuleList *module_list = minidump.GetModuleList();
if (!module_list) {
++errors;
printf("minidump.GetModuleList() failed\n");
} else {
moduleList->Print();
module_list->Print();
}
MinidumpMemoryList* memoryList = minidump.GetMemoryList();
if (!memoryList) {
error |= 1 << 4;
MinidumpMemoryList *memory_list = minidump.GetMemoryList();
if (!memory_list) {
++errors;
printf("minidump.GetMemoryList() failed\n");
} else {
memoryList->Print();
memory_list->Print();
}
MinidumpException* exception = minidump.GetException();
MinidumpException *exception = minidump.GetException();
if (!exception) {
error |= 1 << 5;
// Exception info is optional, so don't treat this as an error.
printf("minidump.GetException() failed\n");
} else {
exception->Print();
}
MinidumpSystemInfo* systemInfo = minidump.GetSystemInfo();
if (!systemInfo) {
error |= 1 << 6;
MinidumpSystemInfo *system_info = minidump.GetSystemInfo();
if (!system_info) {
++errors;
printf("minidump.GetSystemInfo() failed\n");
} else {
systemInfo->Print();
system_info->Print();
}
MinidumpMiscInfo* miscInfo = minidump.GetMiscInfo();
if (!miscInfo) {
error |= 1 << 7;
MinidumpMiscInfo *misc_info = minidump.GetMiscInfo();
if (!misc_info) {
++errors;
printf("minidump.GetMiscInfo() failed\n");
} else {
miscInfo->Print();
misc_info->Print();
}
// Use return instead of exit to allow destructors to run.
return(error);
MinidumpAirbagInfo *airbag_info = minidump.GetAirbagInfo();
if (!airbag_info) {
// Airbag info is optional, so don't treat this as an error.
printf("minidump.GetAirbagInfo() failed\n");
} else {
airbag_info->Print();
}
return errors == 0;
}
} // namespace
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
return PrintMinidumpDump(argv[1]) ? 0 : 1;
}

View File

@ -30,7 +30,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
testdata_dir=$srcdir/src/processor/testdata
./src/processor/minidump_dump $testdata_dir/minidump1.dmp | \
tr -s '\015' '\012' | \
diff -u $testdata_dir/minidump1.out -
./src/processor/minidump_dump $testdata_dir/minidump2.dmp | \
tr -d '\015' | \
diff -u $testdata_dir/minidump2.dump.out -
exit $?

View File

@ -27,10 +27,10 @@
// (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 "google/minidump_processor.h"
#include "google/call_stack.h"
#include "google/process_state.h"
#include "processor/minidump.h"
#include "google_airbag/processor/minidump_processor.h"
#include "google_airbag/processor/call_stack.h"
#include "google_airbag/processor/minidump.h"
#include "google_airbag/processor/process_state.h"
#include "processor/scoped_ptr.h"
#include "processor/stackwalker_x86.h"
@ -54,11 +54,22 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
process_state->cpu_ = GetCPUInfo(&dump, &process_state->cpu_info_);
process_state->os_ = GetOSInfo(&dump, &process_state->os_version_);
u_int32_t exception_thread_id = 0;
u_int32_t dump_thread_id = 0;
bool has_dump_thread = false;
u_int32_t requesting_thread_id = 0;
bool has_requesting_thread = false;
MinidumpAirbagInfo *airbag_info = dump.GetAirbagInfo();
if (airbag_info) {
has_dump_thread = airbag_info->GetDumpThreadID(&dump_thread_id);
has_requesting_thread =
airbag_info->GetRequestingThreadID(&requesting_thread_id);
}
MinidumpException *exception = dump.GetException();
if (exception) {
process_state->crashed_ = true;
exception_thread_id = exception->GetThreadID();
has_requesting_thread = exception->GetThreadID(&requesting_thread_id);
process_state->crash_reason_ = GetCrashReason(
&dump, &process_state->crash_address_);
@ -69,7 +80,7 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
return NULL;
}
bool found_crash_thread = false;
bool found_requesting_thread = false;
unsigned int thread_count = threads->thread_count();
for (unsigned int thread_index = 0;
thread_index < thread_count;
@ -79,15 +90,46 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
return NULL;
}
if (process_state->crashed_ &&
thread->GetThreadID() == exception_thread_id) {
if (found_crash_thread) {
// There can't be more than one crash thread.
u_int32_t thread_id;
if (!thread->GetThreadID(&thread_id)) {
return NULL;
}
// If this thread is the thread that produced the minidump, don't process
// it. Because of the problems associated with a thread producing a
// dump of itself (when both its context and its stack are in flux),
// processing that stack wouldn't provide much useful data.
if (has_dump_thread && thread_id == dump_thread_id) {
continue;
}
MinidumpContext *context = thread->GetContext();
if (has_requesting_thread && thread_id == requesting_thread_id) {
if (found_requesting_thread) {
// There can't be more than one requesting thread.
return NULL;
}
process_state->crash_thread_ = thread_index;
found_crash_thread = true;
// Use processed_state->threads_.size() instead of thread_index.
// thread_index points to the thread index in the minidump, which
// might be greater than the thread index in the threads vector if
// any of the minidump's threads are skipped and not placed into the
// processed threads vector. The thread vector's current size will
// be the index of the current thread when it's pushed into the
// vector.
process_state->requesting_thread_ = process_state->threads_.size();
found_requesting_thread = true;
if (process_state->crashed_) {
// Use the exception record's context for the crashed thread, instead
// of the thread's own context. For the crashed thread, the thread's
// own context is the state inside the exception handler. Using it
// would not result in the expected stack trace from the time of the
// crash.
context = exception->GetContext();
}
}
MinidumpMemoryRegion *thread_memory = thread->GetMemory();
@ -96,7 +138,7 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
}
scoped_ptr<Stackwalker> stackwalker(
Stackwalker::StackwalkerForCPU(exception->GetContext(),
Stackwalker::StackwalkerForCPU(context,
thread_memory,
dump.GetModuleList(),
supplier_));
@ -112,8 +154,8 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
process_state->threads_.push_back(stack.release());
}
// If the process crashed, there must be a crash thread.
if (process_state->crashed_ && !found_crash_thread) {
// If a requesting thread was indicated, it must be present.
if (has_requesting_thread && !found_requesting_thread) {
return NULL;
}

View File

@ -31,19 +31,23 @@
// corresponding symbol file, and checks the stack frames for correctness.
#include <string>
#include "google/call_stack.h"
#include "google/minidump_processor.h"
#include "google/process_state.h"
#include "google/stack_frame.h"
#include "google/symbol_supplier.h"
#include "processor/minidump.h"
#include "google_airbag/processor/call_stack.h"
#include "google_airbag/processor/minidump.h"
#include "google_airbag/processor/minidump_processor.h"
#include "google_airbag/processor/process_state.h"
#include "google_airbag/processor/stack_frame.h"
#include "google_airbag/processor/symbol_supplier.h"
#include "processor/scoped_ptr.h"
namespace {
using std::string;
using google_airbag::CallStack;
using google_airbag::MinidumpModule;
using google_airbag::MinidumpProcessor;
using google_airbag::ProcessState;
using google_airbag::scoped_ptr;
using google_airbag::SymbolSupplier;
#define ASSERT_TRUE(cond) \
if (!(cond)) { \
@ -53,8 +57,6 @@ using google_airbag::scoped_ptr;
#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
namespace google_airbag {
class TestSymbolSupplier : public SymbolSupplier {
public:
virtual string GetSymbolFile(MinidumpModule *module);
@ -62,17 +64,16 @@ class TestSymbolSupplier : public SymbolSupplier {
string TestSymbolSupplier::GetSymbolFile(MinidumpModule *module) {
if (*(module->GetName()) == "c:\\test_app.exe") {
// The funny-looking pathname is so that the symbol file can also be
// reached by a SimpleSymbolSupplier.
return string(getenv("srcdir") ? getenv("srcdir") : ".") +
"/src/processor/testdata/minidump2.sym";
"/src/processor/testdata/symbols/"
"test_app.pdb/8DDB7E9A365748938D6EB08B1DCA31AA1/test_app.sym";
}
return "";
}
} // namespace google_airbag
using google_airbag::TestSymbolSupplier;
static bool RunTests() {
TestSymbolSupplier supplier;
MinidumpProcessor processor(&supplier);
@ -88,9 +89,9 @@ static bool RunTests() {
ASSERT_EQ(state->os_version(), "5.1.2600 Service Pack 2");
ASSERT_TRUE(state->crashed());
ASSERT_EQ(state->crash_reason(), "EXCEPTION_ACCESS_VIOLATION");
ASSERT_EQ(state->crash_address(), 0);
ASSERT_EQ(state->crash_address(), 0x45);
ASSERT_EQ(state->threads()->size(), 1);
ASSERT_EQ(state->crash_thread(), 0);
ASSERT_EQ(state->requesting_thread(), 0);
CallStack *stack = state->threads()->at(0);
ASSERT_TRUE(stack);
ASSERT_EQ(stack->frames()->size(), 4);
@ -99,13 +100,13 @@ static bool RunTests() {
ASSERT_EQ(stack->frames()->at(0)->module_name, "c:\\test_app.exe");
ASSERT_EQ(stack->frames()->at(0)->function_name, "CrashFunction()");
ASSERT_EQ(stack->frames()->at(0)->source_file_name, "c:\\test_app.cc");
ASSERT_EQ(stack->frames()->at(0)->source_line, 65);
ASSERT_EQ(stack->frames()->at(0)->source_line, 51);
ASSERT_EQ(stack->frames()->at(1)->module_base, 0x400000);
ASSERT_EQ(stack->frames()->at(1)->module_name, "c:\\test_app.exe");
ASSERT_EQ(stack->frames()->at(1)->function_name, "main");
ASSERT_EQ(stack->frames()->at(1)->source_file_name, "c:\\test_app.cc");
ASSERT_EQ(stack->frames()->at(1)->source_line, 70);
ASSERT_EQ(stack->frames()->at(1)->source_line, 56);
// This comes from the CRT
ASSERT_EQ(stack->frames()->at(2)->module_base, 0x400000);
@ -126,6 +127,8 @@ static bool RunTests() {
return true;
}
} // namespace
int main(int argc, char *argv[]) {
if (!RunTests()) {
return 1;

View File

@ -27,104 +27,212 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// minidump_stackwalk.cc: Print the stack of the exception thread from a
// minidump.
// minidump_stackwalk.cc: Process a minidump with MinidumpProcessor, printing
// the results, including stack traces.
//
// Author: Mark Mentovai
#include <stdlib.h>
#include <stdio.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include "google/call_stack.h"
#include "google/stack_frame.h"
#include "processor/minidump.h"
#include "google_airbag/processor/call_stack.h"
#include "google_airbag/processor/minidump.h"
#include "google_airbag/processor/minidump_processor.h"
#include "google_airbag/processor/process_state.h"
#include "google_airbag/processor/stack_frame_cpu.h"
#include "processor/pathname_stripper.h"
#include "processor/scoped_ptr.h"
#include "processor/stackwalker_x86.h"
#include "processor/simple_symbol_supplier.h"
namespace {
using std::string;
using google_airbag::CallStack;
using google_airbag::MemoryRegion;
using google_airbag::Minidump;
using google_airbag::MinidumpContext;
using google_airbag::MinidumpException;
using google_airbag::MinidumpModuleList;
using google_airbag::MinidumpThread;
using google_airbag::MinidumpThreadList;
using google_airbag::MinidumpModule;
using google_airbag::MinidumpProcessor;
using google_airbag::PathnameStripper;
using google_airbag::ProcessState;
using google_airbag::scoped_ptr;
using google_airbag::SimpleSymbolSupplier;
using google_airbag::StackFrame;
using google_airbag::Stackwalker;
using google_airbag::StackFramePPC;
using google_airbag::StackFrameX86;
// PrintRegister prints a register's name and value to stdout. It will
// print four registers on a line. For the first register in a set,
// pass 0 for |sequence|. For registers in a set, pass the most recent
// return value of PrintRegister. Note that PrintRegister will print a
// newline before the first register (with |sequence| set to 0) is printed.
// The caller is responsible for printing the final newline after a set
// of registers is completely printed, regardless of the number of calls
// to PrintRegister.
static int PrintRegister(const char *name, u_int32_t value, int sequence) {
if (sequence % 4 == 0) {
printf("\n ");
}
printf(" %5s = 0x%08x", name, value);
return ++sequence;
}
// PrintStack prints the call stack in |stack| to stdout, in a reasonably
// useful form. Module, function, and source file names are displayed if
// they are available. The code offset to the base code address of the
// source line, function, or module is printed, preferring them in that
// order. If no source line, function, or module information is available,
// an absolute code offset is printed.
//
// If |cpu| is a recognized CPU name, relevant register state for each stack
// frame printed is also output, if available.
static void PrintStack(const CallStack *stack, const string &cpu) {
int frame_count = stack->frames()->size();
for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
const StackFrame *frame = stack->frames()->at(frame_index);
printf("%2d ", frame_index);
if (!frame->module_name.empty()) {
printf("%s", PathnameStripper::File(frame->module_name).c_str());
if (!frame->function_name.empty()) {
printf("!%s", frame->function_name.c_str());
if (!frame->source_file_name.empty()) {
string source_file = PathnameStripper::File(frame->source_file_name);
printf(" [%s : %d + 0x%llx]", source_file.c_str(),
frame->source_line,
frame->instruction -
frame->source_line_base);
} else {
printf(" + 0x%llx", frame->instruction - frame->function_base);
}
} else {
printf(" + 0x%llx", frame->instruction - frame->module_base);
}
} else {
printf("0x%llx", frame->instruction);
}
int sequence = 0;
if (cpu == "x86") {
const StackFrameX86 *frame_x86 =
reinterpret_cast<const StackFrameX86*>(frame);
if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP)
sequence = PrintRegister("eip", frame_x86->context.eip, sequence);
if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)
sequence = PrintRegister("esp", frame_x86->context.esp, sequence);
if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP)
sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence);
if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX)
sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence);
if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI)
sequence = PrintRegister("esi", frame_x86->context.esi, sequence);
if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI)
sequence = PrintRegister("edi", frame_x86->context.edi, sequence);
if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) {
sequence = PrintRegister("eax", frame_x86->context.eax, sequence);
sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence);
sequence = PrintRegister("edx", frame_x86->context.edx, sequence);
sequence = PrintRegister("efl", frame_x86->context.eflags, sequence);
}
} else if (cpu == "ppc") {
const StackFramePPC *frame_ppc =
reinterpret_cast<const StackFramePPC*>(frame);
if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0)
sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
}
printf("\n");
}
}
// Processes |minidump_file| using MinidumpProcessor. |symbol_path|, if
// non-empty, is the base directory of a symbol storage area, laid out in
// the format required by SimpleSymbolSupplier. If such a storage area
// is specified, it is made available for use by the MinidumpProcessor.
//
// Returns the value of MinidumpProcessor::Process. If processing succeeds,
// prints identifying OS and CPU information from the minidump, crash
// information if the minidump was produced as a result of a crash, and
// call stacks for each thread contained in the minidump. All information
// is printed to stdout.
static bool PrintMinidumpProcess(const string &minidump_file,
const string &symbol_path) {
scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
if (!symbol_path.empty()) {
// TODO(mmentovai): check existence of symbol_path if specified?
symbol_supplier.reset(new SimpleSymbolSupplier(symbol_path));
}
MinidumpProcessor minidump_processor(symbol_supplier.get());
// Process the minidump.
scoped_ptr<ProcessState> process_state(
minidump_processor.Process(minidump_file));
if (!process_state.get()) {
fprintf(stderr, "MinidumpProcessor::Process failed\n");
return false;
}
// Print OS and CPU information.
string cpu = process_state->cpu();
string cpu_info = process_state->cpu_info();
printf("Operating system: %s\n", process_state->os().c_str());
printf(" %s\n", process_state->os_version().c_str());
printf("CPU: %s\n", cpu.c_str());
if (!cpu_info.empty()) {
// This field is optional.
printf(" %s\n", cpu_info.c_str());
}
printf("\n");
// Print crash information.
if (process_state->crashed()) {
printf("Crash reason: %s\n", process_state->crash_reason().c_str());
printf("Crash address: 0x%llx\n", process_state->crash_address());
} else {
printf("No crash\n");
}
// If the thread that requested the dump is known, print it first.
int requesting_thread = process_state->requesting_thread();
if (requesting_thread != -1) {
printf("\n");
printf("Thread %d (%s)\n",
requesting_thread,
process_state->crashed() ? "crashed" :
"requested dump, did not crash");
PrintStack(process_state->threads()->at(requesting_thread), cpu);
}
// Print all of the threads in the dump.
int thread_count = process_state->threads()->size();
for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
if (thread_index != requesting_thread) {
// Don't print the crash thread again, it was already printed.
printf("\n");
printf("Thread %d\n", thread_index);
PrintStack(process_state->threads()->at(thread_index), cpu);
}
}
return true;
}
} // namespace
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
exit(1);
if (argc < 2 || argc > 3) {
fprintf(stderr, "usage: %s <minidump-file> [symbol-path]\n", argv[0]);
return 1;
}
Minidump minidump(argv[1]);
if (!minidump.Read()) {
fprintf(stderr, "minidump.Read() failed\n");
exit(1);
const char *minidump_file = argv[1];
const char *symbol_path = "";
if (argc == 3) {
symbol_path = argv[2];
}
MinidumpException *exception = minidump.GetException();
if (!exception) {
fprintf(stderr, "minidump.GetException() failed\n");
exit(1);
}
MinidumpThreadList *thread_list = minidump.GetThreadList();
if (!thread_list) {
fprintf(stderr, "minidump.GetThreadList() failed\n");
exit(1);
}
MinidumpThread *exception_thread =
thread_list->GetThreadByID(exception->GetThreadID());
if (!exception_thread) {
fprintf(stderr, "thread_list->GetThreadByID() failed\n");
exit(1);
}
MemoryRegion *stack_memory = exception_thread->GetMemory();
if (!stack_memory) {
fprintf(stderr, "exception_thread->GetStackMemory() failed\n");
exit(1);
}
MinidumpContext *context = exception->GetContext();
if (!context) {
fprintf(stderr, "exception->GetContext() failed\n");
exit(1);
}
MinidumpModuleList *modules = minidump.GetModuleList();
if (!modules) {
fprintf(stderr, "minidump.GetModuleList() failed\n");
exit(1);
}
scoped_ptr<Stackwalker> stackwalker(
Stackwalker::StackwalkerForCPU(context, stack_memory, modules, NULL));
if (!stackwalker.get()) {
fprintf(stderr, "Stackwalker::StackwalkerForCPU failed\n");
exit(1);
}
scoped_ptr<CallStack> stack(stackwalker->Walk());
unsigned int index;
for (index = 0; index < stack->frames()->size(); ++index) {
StackFrame *frame = stack->frames()->at(index);
printf("[%2d] instruction = 0x%08llx \"%s\" + 0x%08llx\n",
index,
frame->instruction,
frame->module_base ? frame->module_name.c_str() : "0x0",
frame->instruction - frame->module_base);
}
return 0;
return PrintMinidumpProcess(minidump_file, symbol_path) ? 0 : 1;
}

View File

@ -30,7 +30,8 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
testdata_dir=$srcdir/src/processor/testdata
./src/processor/minidump_stackwalk $testdata_dir/minidump1.dmp | \
tr -s '\015' '\012' | \
diff -u $testdata_dir/minidump1.stack.out -
./src/processor/minidump_stackwalk $testdata_dir/minidump2.dmp \
$testdata_dir/symbols | \
tr -d '\015' | \
diff -u $testdata_dir/minidump2.stackwalk.out -
exit $?

View File

@ -0,0 +1,56 @@
// Copyright (c) 2006, 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.
// pathname_stripper.cc: Manipulates pathnames into their component parts.
//
// See pathname_stripper.h for documentation.
//
// Author: Mark Mentovai
#include "processor/pathname_stripper.h"
namespace google_airbag {
// static
string PathnameStripper::File(const string &path) {
string::size_type slash = path.rfind('/');
string::size_type backslash = path.rfind('\\');
string::size_type file_start = 0;
if (slash != string::npos &&
(backslash == string::npos || slash > backslash)) {
file_start = slash + 1;
} else if (backslash != string::npos) {
file_start = backslash + 1;
}
return path.substr(file_start);
}
} // namespace google_airbag

View File

@ -0,0 +1,53 @@
// Copyright (c) 2006, 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.
// pathname_stripper.h: Manipulates pathnames into their component parts.
//
// Author: Mark Mentovai
#ifndef PROCESSOR_PATHNAME_STRIPPER_H__
#define PROCESSOR_PATHNAME_STRIPPER_H__
#include <string>
namespace google_airbag {
using std::string;
class PathnameStripper {
public:
// Given path, a pathname with components separated by slashes (/) or
// backslashes (\), returns the trailing component, without any separator.
// If path ends in a separator character, returns an empty string.
static string File(const string &path);
};
} // namespace google_airbag
#endif // PROCESSOR_PATHNAME_STRIPPER_H__

View File

@ -0,0 +1,82 @@
// Copyright (c) 2006, 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 "processor/pathname_stripper.h"
#define ASSERT_TRUE(condition) \
if (!(condition)) { \
fprintf(stderr, "FAIL: %s @ %s:%d\n", #condition, __FILE__, __LINE__); \
return false; \
}
#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
namespace {
using google_airbag::PathnameStripper;
static bool RunTests() {
ASSERT_EQ(PathnameStripper::File("/dir/file"), "file");
ASSERT_EQ(PathnameStripper::File("\\dir\\file"), "file");
ASSERT_EQ(PathnameStripper::File("/dir\\file"), "file");
ASSERT_EQ(PathnameStripper::File("\\dir/file"), "file");
ASSERT_EQ(PathnameStripper::File("dir/file"), "file");
ASSERT_EQ(PathnameStripper::File("dir\\file"), "file");
ASSERT_EQ(PathnameStripper::File("dir/\\file"), "file");
ASSERT_EQ(PathnameStripper::File("dir\\/file"), "file");
ASSERT_EQ(PathnameStripper::File("file"), "file");
ASSERT_EQ(PathnameStripper::File("dir/"), "");
ASSERT_EQ(PathnameStripper::File("dir\\"), "");
ASSERT_EQ(PathnameStripper::File("dir/dir/"), "");
ASSERT_EQ(PathnameStripper::File("dir\\dir\\"), "");
ASSERT_EQ(PathnameStripper::File("dir1/dir2/file"), "file");
ASSERT_EQ(PathnameStripper::File("dir1\\dir2\\file"), "file");
ASSERT_EQ(PathnameStripper::File("dir1/dir2\\file"), "file");
ASSERT_EQ(PathnameStripper::File("dir1\\dir2/file"), "file");
ASSERT_EQ(PathnameStripper::File(""), "");
ASSERT_EQ(PathnameStripper::File("1"), "1");
ASSERT_EQ(PathnameStripper::File("1/2"), "2");
ASSERT_EQ(PathnameStripper::File("1\\2"), "2");
ASSERT_EQ(PathnameStripper::File("/1/2"), "2");
ASSERT_EQ(PathnameStripper::File("\\1\\2"), "2");
ASSERT_EQ(PathnameStripper::File("dir//file"), "file");
ASSERT_EQ(PathnameStripper::File("dir\\\\file"), "file");
ASSERT_EQ(PathnameStripper::File("/dir//file"), "file");
ASSERT_EQ(PathnameStripper::File("\\dir\\\\file"), "file");
ASSERT_EQ(PathnameStripper::File("c:\\dir\\file"), "file");
ASSERT_EQ(PathnameStripper::File("c:\\dir\\file.ext"), "file.ext");
return true;
}
} // namespace
int main(int argc, char **argv) {
return RunTests() ? 0 : 1;
}

View File

@ -26,7 +26,7 @@
#include <sstream>
#include "processor/postfix_evaluator.h"
#include "processor/memory_region.h"
#include "google_airbag/processor/memory_region.h"
namespace google_airbag {

View File

@ -55,8 +55,6 @@
#include <string>
#include <vector>
#include "processor/memory_region.h"
namespace google_airbag {
using std::map;

View File

@ -22,8 +22,11 @@
#include "processor/postfix_evaluator-inl.h"
#include "google/airbag_types.h"
#include "processor/memory_region.h"
#include "google_airbag/common/airbag_types.h"
#include "google_airbag/processor/memory_region.h"
namespace {
using std::map;
@ -84,7 +87,7 @@ struct EvaluateTestSet {
};
bool RunTests() {
static bool RunTests() {
// The first test set checks the basic operations and failure modes.
PostfixEvaluator<unsigned int>::DictionaryType dictionary_0;
const EvaluateTest evaluate_tests_0[] = {
@ -274,6 +277,9 @@ bool RunTests() {
}
} // namespace
int main(int argc, char **argv) {
return RunTests() ? 0 : 1;
}

View File

@ -33,8 +33,8 @@
//
// Author: Mark Mentovai
#include "google/process_state.h"
#include "google/call_stack.h"
#include "google_airbag/processor/process_state.h"
#include "google_airbag/processor/call_stack.h"
namespace google_airbag {

View File

@ -41,6 +41,9 @@
#include "processor/scoped_ptr.h"
namespace {
using google_airbag::linked_ptr;
using google_airbag::scoped_ptr;
using google_airbag::RangeMap;
@ -99,7 +102,7 @@ struct RangeTestSet {
// StoreTest uses the data in a RangeTest and calls StoreRange on the
// test RangeMap. It returns true if the expected result occurred, and
// false if something else happened.
bool StoreTest(TestMap *range_map, const RangeTest *range_test) {
static bool StoreTest(TestMap *range_map, const RangeTest *range_test) {
linked_ptr<CountedObject> object(new CountedObject(range_test->id));
bool stored = range_map->StoreRange(range_test->address,
range_test->size,
@ -123,7 +126,7 @@ bool StoreTest(TestMap *range_map, const RangeTest *range_test) {
// map entry at the specified range,) it returns true, otherwise, it returns
// false. RetrieveTest will check the values around the base address and
// the high address of a range to guard against off-by-one errors.
bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) {
static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) {
for (unsigned int side = 0; side <= 1; ++side) {
// When side == 0, check the low side (base address) of each range.
// When side == 1, check the high side (base + size) of each range.
@ -241,7 +244,7 @@ bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) {
// RunTests runs a series of test sets.
bool RunTests() {
static bool RunTests() {
// These tests will be run sequentially. The first set of tests exercises
// most functions of RangeTest, and verifies all of the bounds-checking.
const RangeTest range_tests_0[] = {
@ -402,6 +405,10 @@ bool RunTests() {
return true;
}
} // namespace
int main(int argc, char **argv) {
return RunTests() ? 0 : 1;
}

View File

@ -0,0 +1,98 @@
// Copyright (c) 2006, 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.
// simple_symbol_supplier.cc: A simple SymbolSupplier implementation
//
// See simple_symbol_supplier.h for documentation.
//
// Author: Mark Mentovai
#include "processor/simple_symbol_supplier.h"
#include "google_airbag/processor/minidump.h"
#include "processor/pathname_stripper.h"
namespace google_airbag {
string SimpleSymbolSupplier::GetSymbolFileAtPath(MinidumpModule *module,
const string &root_path) {
// For now, only support modules that have GUIDs - which means
// MDCVInfoPDB70.
if (!module)
return "";
const MDCVInfoPDB70 *cv_record =
reinterpret_cast<const MDCVInfoPDB70*>(module->GetCVRecord());
if (!cv_record)
return "";
if (cv_record->cv_signature != MD_CVINFOPDB70_SIGNATURE)
return "";
// Start with the base path.
string path = root_path;
// Append the pdb file name as a directory name.
path.append("/");
string pdb_file_name = PathnameStripper::File(
reinterpret_cast<const char *>(cv_record->pdb_file_name));
path.append(pdb_file_name);
// Append the uuid and age as a directory name.
path.append("/");
char uuid_age_string[43];
snprintf(uuid_age_string, sizeof(uuid_age_string),
"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%X",
cv_record->signature.data1, cv_record->signature.data2,
cv_record->signature.data3,
cv_record->signature.data4[0], cv_record->signature.data4[1],
cv_record->signature.data4[2], cv_record->signature.data4[3],
cv_record->signature.data4[4], cv_record->signature.data4[5],
cv_record->signature.data4[6], cv_record->signature.data4[7],
cv_record->age);
path.append(uuid_age_string);
// Transform the pdb file name into one ending in .sym. If the existing
// name ends in .pdb, strip the .pdb. Otherwise, add .sym to the non-.pdb
// name.
path.append("/");
string pdb_file_extension = pdb_file_name.substr(pdb_file_name.size() - 4);
transform(pdb_file_extension.begin(), pdb_file_extension.end(),
pdb_file_extension.begin(), tolower);
if (pdb_file_extension == ".pdb") {
path.append(pdb_file_name.substr(0, pdb_file_name.size() - 4));
} else {
path.append(pdb_file_name);
}
path.append(".sym");
return path;
}
} // namespace google_airbag

View File

@ -0,0 +1,104 @@
// Copyright (c) 2006, 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.
// simple_symbol_supplier.h: A simple SymbolSupplier implementation
//
// SimpleSymbolSupplier is a straightforward implementation of SymbolSupplier
// that stores symbol files in a filesystem tree. A SimpleSymbolSupplier is
// created with a base directory, which is the root for all symbol files.
// Each symbol file contained therien has a directory entry in the base
// directory with a name identical to the corresponding pdb file. Within
// each of these directories, there are subdirectories named for the uuid and
// age of each pdb file. The uuid is presented in hexadecimal form, with
// uppercase characters and no dashes. The age is appended to it in
// hexadecimal form, without any separators. Within that subdirectory,
// SimpleSymbolSupplier expects to find the symbol file, which is named
// identically to the pdb file, but with a .sym extension. This sample
// hierarchy is rooted at the "symbols" base directory:
//
// symbols
// symbols/test_app.pdb
// symbols/test_app.pdb/63FE4780728D49379B9D7BB6460CB42A1
// symbols/test_app.pdb/63FE4780728D49379B9D7BB6460CB42A1/test_app.sym
// symbols/kernel32.pdb
// symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542
// symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542/kernel32.sym
//
// In this case, the uuid of test_app.pdb is
// 63fe4780-728d-4937-9b9d-7bb6460cb42a and its age is 1.
//
// This scheme was chosen to be roughly analogous to the way that
// symbol files may be accessed from Microsoft Symbol Server. A hierarchy
// used for Microsoft Symbol Server storage is usable as a hierarchy for
// SimpleSymbolServer, provided that the pdb files are transformed to dumped
// format using a tool such as dump_syms, and given a .sym extension.
//
// SimpleSymbolSupplier presently only supports symbol files that have
// the MSVC 7.0 CodeView record format. See MDCVInfoPDB70 in
// minidump_format.h.
//
// Author: Mark Mentovai
#ifndef PROCESSOR_SIMPLE_SYMBOL_SUPPLIER_H__
#define PROCESSOR_SIMPLE_SYMBOL_SUPPLIER_H__
#include <string>
#include "google_airbag/processor/symbol_supplier.h"
namespace google_airbag {
using std::string;
class MinidumpModule;
class SimpleSymbolSupplier : public SymbolSupplier {
public:
// Creates a new SimpleSymbolSupplier, using path as the root path where
// symbols are stored.
explicit SimpleSymbolSupplier(const string &path) : path_(path) {}
virtual ~SimpleSymbolSupplier() {}
// Returns the path to the symbol file for the given module. See the
// description above.
virtual string GetSymbolFile(MinidumpModule *module) {
return GetSymbolFileAtPath(module, path_);
}
protected:
string GetSymbolFileAtPath(MinidumpModule *module, const string &root_path);
private:
string path_;
};
} // namespace google_airbag
#endif // PROCESSOR_SIMPLE_SYMBOL_SUPPLIER_H__

View File

@ -40,7 +40,7 @@
#include <string>
#include "google/airbag_types.h"
#include "google_airbag/common/airbag_types.h"
namespace google_airbag {

View File

@ -34,12 +34,12 @@
// Author: Mark Mentovai
#include "processor/stackwalker.h"
#include "google/call_stack.h"
#include "google/stack_frame.h"
#include "google/symbol_supplier.h"
#include "google_airbag/processor/stackwalker.h"
#include "google_airbag/processor/call_stack.h"
#include "google_airbag/processor/minidump.h"
#include "google_airbag/processor/stack_frame.h"
#include "google_airbag/processor/symbol_supplier.h"
#include "processor/linked_ptr.h"
#include "processor/minidump.h"
#include "processor/scoped_ptr.h"
#include "processor/source_line_resolver.h"
#include "processor/stack_frame_info.h"

View File

@ -35,9 +35,9 @@
#include "processor/stackwalker_ppc.h"
#include "google/call_stack.h"
#include "google/stack_frame_cpu.h"
#include "processor/minidump.h"
#include "google_airbag/processor/call_stack.h"
#include "google_airbag/processor/minidump.h"
#include "google_airbag/processor/stack_frame_cpu.h"
namespace google_airbag {

View File

@ -39,9 +39,9 @@
#define PROCESSOR_STACKWALKER_PPC_H__
#include "google/airbag_types.h"
#include "processor/stackwalker.h"
#include "processor/minidump_format.h"
#include "google_airbag/common/airbag_types.h"
#include "google_airbag/common/minidump_format.h"
#include "google_airbag/processor/stackwalker.h"
namespace google_airbag {

View File

@ -39,12 +39,12 @@
#include <cstdio>
#include "google/airbag_types.h"
#include "google/call_stack.h"
#include "google/stack_frame.h"
#include "google/stack_frame_cpu.h"
#include "processor/memory_region.h"
#include "processor/minidump_format.h"
#include "google_airbag/common/airbag_types.h"
#include "google_airbag/common/minidump_format.h"
#include "google_airbag/processor/call_stack.h"
#include "google_airbag/processor/memory_region.h"
#include "google_airbag/processor/stack_frame.h"
#include "google_airbag/processor/stack_frame_cpu.h"
#include "processor/scoped_ptr.h"
using google_airbag::CallStack;

View File

@ -37,10 +37,10 @@
#include "processor/postfix_evaluator-inl.h"
#include "processor/stackwalker_x86.h"
#include "google/call_stack.h"
#include "google/stack_frame_cpu.h"
#include "google_airbag/processor/call_stack.h"
#include "google_airbag/processor/minidump.h"
#include "google_airbag/processor/stack_frame_cpu.h"
#include "processor/linked_ptr.h"
#include "processor/minidump.h"
#include "processor/stack_frame_info.h"
namespace google_airbag {
@ -283,15 +283,15 @@ StackFrame* StackwalkerX86::GetCallerFrame(
// These are nonvolatile (callee-save) registers, and the program string
// may have filled them in.
if (dictionary_validity.find("$ebx") == dictionary_validity.end()) {
if (dictionary_validity.find("$ebx") != dictionary_validity.end()) {
frame->context.ebx = dictionary["$ebx"];
frame->context_validity |= StackFrameX86::CONTEXT_VALID_EBX;
}
if (dictionary_validity.find("$esi") == dictionary_validity.end()) {
if (dictionary_validity.find("$esi") != dictionary_validity.end()) {
frame->context.esi = dictionary["$esi"];
frame->context_validity |= StackFrameX86::CONTEXT_VALID_ESI;
}
if (dictionary_validity.find("$edi") == dictionary_validity.end()) {
if (dictionary_validity.find("$edi") != dictionary_validity.end()) {
frame->context.edi = dictionary["$edi"];
frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI;
}

View File

@ -39,9 +39,9 @@
#define PROCESSOR_STACKWALKER_X86_H__
#include "google/airbag_types.h"
#include "processor/stackwalker.h"
#include "processor/minidump_format.h"
#include "google_airbag/common/airbag_types.h"
#include "google_airbag/common/minidump_format.h"
#include "google_airbag/processor/stackwalker.h"
namespace google_airbag {

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,19 @@
Operating system: Windows NT
5.1.2600 Service Pack 2
CPU: x86
GenuineIntel family 6 model 13 stepping 8
Crash reason: EXCEPTION_ACCESS_VIOLATION
Crash address: 0x45
Thread 0 (crashed)
0 test_app.exe!CrashFunction() [test_app.cc : 51 + 0x3]
eip = 0x0040208e esp = 0x0012feec ebp = 0x0012fef0 ebx = 0x7c80abc1
esi = 0x00000002 edi = 0x00000a28 eax = 0x00000045 ecx = 0x0012fefc
edx = 0x7c90eb94 efl = 0x00010246
1 test_app.exe!main [test_app.cc : 56 + 0x4]
eip = 0x004020df esp = 0x0012fef8 ebp = 0x0012ff70
2 test_app.exe!__tmainCRTStartup [crt0.c : 318 + 0x11]
eip = 0x0040395c esp = 0x0012ff78 ebp = 0x0012ffc0
3 kernel32.dll!BaseProcessStart + 0x22
eip = 0x7c816fd7 esp = 0x0012ffc8 ebp = 0x0012fff0

View File

@ -1,3 +1,4 @@
MODULE 11111111-1111-1111-1111-111111111111 1 module1.pdb
FILE 1 file1_1.cc
FILE 2 file1_2.cc
FILE 3 file1_3.cc

View File

@ -1,3 +1,4 @@
MODULE 22222222-2222-2222-2222-222222222222 2 module2.pdb
FILE 1 file2_1.cc
FILE 2 file2_2.cc
FILE 3 file2_3.cc

View File

@ -1,2 +1,3 @@
MODULE 33333333-3333-3333-3333-333333333333 3 module3.pdb
FILE 1 file1.cc
FUNC 1000

View File

@ -28,47 +28,32 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file is used to generate minidump2.dmp and minidump2.sym.
// cl /Zi /Fetest_app.exe test_app.cc dbghelp.lib
// cl /Zi test_app.cc /Fetest_app.exe /I airbag/src \
// airbag/src/client/windows/releasestaticcrt/exception_handler.lib \
// ole32.lib
// Then run test_app to generate a dump, and dump_syms to create the .sym file.
#include <windows.h>
#include <dbghelp.h>
#include <cstdio>
static LONG HandleException(EXCEPTION_POINTERS *exinfo) {
HANDLE dump_file = CreateFile("dump.dmp",
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
#include "client/windows/handler/exception_handler.h"
MINIDUMP_EXCEPTION_INFORMATION except_info;
except_info.ThreadId = GetCurrentThreadId();
except_info.ExceptionPointers = exinfo;
except_info.ClientPointers = false;
MiniDumpWriteDump(GetCurrentProcess(),
GetCurrentProcessId(),
dump_file,
MiniDumpNormal,
&except_info,
NULL,
NULL);
CloseHandle(dump_file);
return EXCEPTION_EXECUTE_HANDLER;
void callback(const std::wstring &id, void *context, bool succeeded) {
if (succeeded) {
printf("dump guid is %ws\n", id.c_str());
} else {
printf("dump failed\n");
}
exit(1);
}
void CrashFunction() {
int *i = NULL;
int *i = reinterpret_cast<int*>(0x45);
*i = 5; // crash!
}
int main(int argc, char *argv[]) {
__try {
CrashFunction();
} __except(HandleException(GetExceptionInformation())) {
}
int main(int argc, char **argv) {
google_airbag::ExceptionHandler eh(L".", callback, NULL, true);
CrashFunction();
printf("did not crash?\n");
return 0;
}

View File

@ -39,20 +39,14 @@
using std::wstring;
using google_airbag::PDBSourceLineWriter;
int main(int argc, char **argv) {
int wmain(int argc, wchar_t **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <pdb file>\n", argv[0]);
return 1;
}
wchar_t filename[_MAX_PATH];
if (mbstowcs_s(NULL, filename, argv[1], _MAX_PATH) == -1) {
fprintf(stderr, "invalid multibyte character in %s\n", argv[1]);
fprintf(stderr, "Usage: %ws <pdb file>\n", argv[0]);
return 1;
}
PDBSourceLineWriter writer;
if (!writer.Open(wstring(filename), PDBSourceLineWriter::PDB_FILE)) {
if (!writer.Open(wstring(argv[1]), PDBSourceLineWriter::ANY_FILE)) {
fprintf(stderr, "Open failed\n");
return 1;
}

View File

@ -183,6 +183,10 @@
RelativePath="..\..\..\common\windows\pdb_source_line_writer.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\string_utils-inl.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"

View File

@ -29,10 +29,25 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Release/dump_syms.exe testdata/dump_syms_regtest.pdb > testdata/dump_syms_regtest.new
if diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.out >& testdata/dump_syms_regtest.diff; then
Release/dump_syms.exe testdata/dump_syms_regtest.pdb | \
tr -d '\015' > \
testdata/dump_syms_regtest.new
status=$?
if [ $status -ne 0 ] ; then
echo "FAIL, dump_syms.exe failed"
exit $status
fi
diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.out > \
testdata/dump_syms_regtest.diff
status=$?
if [ $status -eq 0 ] ; then
rm testdata/dump_syms_regtest.diff testdata/dump_syms_regtest.new
echo "PASS"
else
echo "FAIL, see testdata/dump_syms_regtest.[new|diff]"
fi
exit $status

View File

@ -46,6 +46,8 @@
#include <string>
#include <vector>
#include "common/windows/string_utils-inl.h"
#include "common/windows/http_upload.h"
#include "common/windows/pdb_source_line_writer.h"
@ -55,6 +57,7 @@ using std::vector;
using std::map;
using google_airbag::HTTPUpload;
using google_airbag::PDBSourceLineWriter;
using google_airbag::WindowsStringUtils;
// Extracts the file version information for the given filename,
// as a string, for example, "1.2.3.4". Returns true on success.
@ -82,12 +85,13 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) {
wchar_t ver_string[24];
VS_FIXEDFILEINFO *file_info =
reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer);
_snwprintf_s(ver_string, sizeof(ver_string) / sizeof(wchar_t), _TRUNCATE,
L"%d.%d.%d.%d",
file_info->dwFileVersionMS >> 16,
file_info->dwFileVersionMS & 0xffff,
file_info->dwFileVersionLS >> 16,
file_info->dwFileVersionLS & 0xffff);
WindowsStringUtils::safe_swprintf(
ver_string, sizeof(ver_string) / sizeof(ver_string[0]),
L"%d.%d.%d.%d",
file_info->dwFileVersionMS >> 16,
file_info->dwFileVersionMS & 0xffff,
file_info->dwFileVersionLS >> 16,
file_info->dwFileVersionLS & 0xffff);
*version = ver_string;
return true;
}
@ -95,11 +99,13 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) {
// Creates a new temporary file and writes the symbol data from the given
// exe/dll file to it. Returns the path to the temp file in temp_file_path,
// and the unique identifier (GUID) for the pdb in module_guid.
static bool DumpSymbolsToTempFile(const wchar_t *exe_file,
static bool DumpSymbolsToTempFile(const wchar_t *file,
wstring *temp_file_path,
wstring *module_guid) {
wstring *module_guid,
int *module_age,
wstring *module_filename) {
google_airbag::PDBSourceLineWriter writer;
if (!writer.Open(exe_file, PDBSourceLineWriter::EXE_FILE)) {
if (!writer.Open(file, PDBSourceLineWriter::ANY_FILE)) {
return false;
}
@ -114,7 +120,13 @@ static bool DumpSymbolsToTempFile(const wchar_t *exe_file,
}
FILE *temp_file = NULL;
#if _MSC_VER >= 1400 // MSVC 2005/8
if (_wfopen_s(&temp_file, temp_filename, L"w") != 0) {
#else // _MSC_VER >= 1400
// _wfopen_s was introduced in MSVC8. Use _wfopen for earlier environments.
// Don't use it with MSVC8 and later, because it's deprecated.
if (!(temp_file = _wfopen(temp_filename, L"w"))) {
#endif // _MSC_VER >= 1400
return false;
}
@ -126,37 +138,35 @@ static bool DumpSymbolsToTempFile(const wchar_t *exe_file,
}
*temp_file_path = temp_filename;
*module_guid = writer.GetModuleGUID();
return true;
}
// Returns the base name of a file, e.g. strips off the path.
static wstring GetBaseName(const wstring &filename) {
wstring base_name(filename);
size_t slash_pos = base_name.find_last_of(L"/\\");
if (slash_pos != string::npos) {
base_name.erase(0, slash_pos + 1);
}
return base_name;
return writer.GetModuleInfo(module_guid, module_age, module_filename);
}
int wmain(int argc, wchar_t *argv[]) {
if (argc < 3) {
wprintf(L"Usage: %s file.[exe|dll] <symbol upload URL>\n", argv[0]);
wprintf(L"Usage: %s file.[pdb|exe|dll] <symbol upload URL>\n", argv[0]);
return 0;
}
const wchar_t *module = argv[1], *url = argv[2];
wstring module_basename = GetBaseName(module);
wstring symbol_file, module_guid;
if (!DumpSymbolsToTempFile(module, &symbol_file, &module_guid)) {
wstring symbol_file, module_guid, module_basename;
int module_age;
if (!DumpSymbolsToTempFile(module, &symbol_file,
&module_guid, &module_age, &module_basename)) {
fwprintf(stderr, L"Could not get symbol data from %s\n", module);
return 1;
}
wchar_t module_age_string[11];
WindowsStringUtils::safe_swprintf(
module_age_string,
sizeof(module_age_string) / sizeof(module_age_string[0]),
L"0x%x", module_age);
map<wstring, wstring> parameters;
parameters[L"module"] = module_basename;
parameters[L"guid"] = module_guid;
parameters[L"age"] = module_age_string;
// Don't make a missing version a hard error. Issue a warning, and let the
// server decide whether to reject files without versions.

View File

@ -188,6 +188,10 @@
RelativePath="..\..\..\common\windows\pdb_source_line_writer.h"
>
</File>
<File
RelativePath="..\..\..\common\windows\string_utils-inl.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"