mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
bug 360938 - Update airbag to svn tip. r=mento
This commit is contained in:
parent
d75829f60f
commit
57f1c5a892
@ -50,35 +50,39 @@ dist_doc_DATA = \
|
|||||||
lib_LTLIBRARIES = src/libairbag.la
|
lib_LTLIBRARIES = src/libairbag.la
|
||||||
|
|
||||||
src_libairbag_la_SOURCES = \
|
src_libairbag_la_SOURCES = \
|
||||||
src/google/airbag_types.h \
|
src/google_airbag/common/airbag_types.h \
|
||||||
src/google/call_stack.h \
|
src/google_airbag/common/minidump_format.h \
|
||||||
src/google/minidump_processor.h \
|
src/google_airbag/processor/call_stack.h \
|
||||||
src/google/process_state.h \
|
src/google_airbag/processor/memory_region.h \
|
||||||
src/google/stack_frame.h \
|
src/google_airbag/processor/minidump.h \
|
||||||
src/google/stack_frame_cpu.h \
|
src/google_airbag/processor/minidump_processor.h \
|
||||||
src/google/symbol_supplier.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.h \
|
||||||
src/processor/address_map-inl.h \
|
src/processor/address_map-inl.h \
|
||||||
src/processor/call_stack.cc \
|
src/processor/call_stack.cc \
|
||||||
src/processor/contained_range_map.h \
|
src/processor/contained_range_map.h \
|
||||||
src/processor/contained_range_map-inl.h \
|
src/processor/contained_range_map-inl.h \
|
||||||
src/processor/linked_ptr.h \
|
src/processor/linked_ptr.h \
|
||||||
src/processor/memory_region.h \
|
|
||||||
src/processor/minidump.cc \
|
src/processor/minidump.cc \
|
||||||
src/processor/minidump.h \
|
|
||||||
src/processor/minidump_format.h \
|
|
||||||
src/processor/minidump_processor.cc \
|
src/processor/minidump_processor.cc \
|
||||||
|
src/processor/pathname_stripper.cc \
|
||||||
|
src/processor/pathname_stripper.h \
|
||||||
src/processor/postfix_evaluator.h \
|
src/processor/postfix_evaluator.h \
|
||||||
src/processor/postfix_evaluator-inl.h \
|
src/processor/postfix_evaluator-inl.h \
|
||||||
src/processor/process_state.cc \
|
src/processor/process_state.cc \
|
||||||
src/processor/range_map.h \
|
src/processor/range_map.h \
|
||||||
src/processor/range_map-inl.h \
|
src/processor/range_map-inl.h \
|
||||||
src/processor/scoped_ptr.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.cc \
|
||||||
src/processor/source_line_resolver.h \
|
src/processor/source_line_resolver.h \
|
||||||
src/processor/stack_frame_info.h \
|
src/processor/stack_frame_info.h \
|
||||||
src/processor/stackwalker.cc \
|
src/processor/stackwalker.cc \
|
||||||
src/processor/stackwalker.h \
|
|
||||||
src/processor/stackwalker_ppc.cc \
|
src/processor/stackwalker_ppc.cc \
|
||||||
src/processor/stackwalker_ppc.h \
|
src/processor/stackwalker_ppc.h \
|
||||||
src/processor/stackwalker_x86.cc \
|
src/processor/stackwalker_x86.cc \
|
||||||
@ -96,6 +100,7 @@ check_PROGRAMS = \
|
|||||||
src/processor/address_map_unittest \
|
src/processor/address_map_unittest \
|
||||||
src/processor/contained_range_map_unittest \
|
src/processor/contained_range_map_unittest \
|
||||||
src/processor/minidump_processor_unittest \
|
src/processor/minidump_processor_unittest \
|
||||||
|
src/processor/pathname_stripper_unittest \
|
||||||
src/processor/postfix_evaluator_unittest \
|
src/processor/postfix_evaluator_unittest \
|
||||||
src/processor/range_map_unittest \
|
src/processor/range_map_unittest \
|
||||||
src/processor/source_line_resolver_unittest
|
src/processor/source_line_resolver_unittest
|
||||||
@ -130,6 +135,11 @@ src_processor_minidump_processor_unittest_LDADD = \
|
|||||||
src/processor/stackwalker_x86.lo \
|
src/processor/stackwalker_x86.lo \
|
||||||
src/processor/source_line_resolver.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_SOURCES = \
|
||||||
src/processor/postfix_evaluator_unittest.cc
|
src/processor/postfix_evaluator_unittest.cc
|
||||||
|
|
||||||
@ -165,6 +175,10 @@ src_processor_minidump_stackwalk_SOURCES = \
|
|||||||
src_processor_minidump_stackwalk_LDADD = \
|
src_processor_minidump_stackwalk_LDADD = \
|
||||||
src/processor/call_stack.lo \
|
src/processor/call_stack.lo \
|
||||||
src/processor/minidump.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.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_x86.lo \
|
src/processor/stackwalker_x86.lo \
|
||||||
|
@ -73,6 +73,7 @@ bin_PROGRAMS = src/processor/minidump_dump$(EXEEXT) \
|
|||||||
check_PROGRAMS = src/processor/address_map_unittest$(EXEEXT) \
|
check_PROGRAMS = src/processor/address_map_unittest$(EXEEXT) \
|
||||||
src/processor/contained_range_map_unittest$(EXEEXT) \
|
src/processor/contained_range_map_unittest$(EXEEXT) \
|
||||||
src/processor/minidump_processor_unittest$(EXEEXT) \
|
src/processor/minidump_processor_unittest$(EXEEXT) \
|
||||||
|
src/processor/pathname_stripper_unittest$(EXEEXT) \
|
||||||
src/processor/postfix_evaluator_unittest$(EXEEXT) \
|
src/processor/postfix_evaluator_unittest$(EXEEXT) \
|
||||||
src/processor/range_map_unittest$(EXEEXT) \
|
src/processor/range_map_unittest$(EXEEXT) \
|
||||||
src/processor/source_line_resolver_unittest$(EXEEXT) \
|
src/processor/source_line_resolver_unittest$(EXEEXT) \
|
||||||
@ -111,7 +112,9 @@ src_libairbag_la_LIBADD =
|
|||||||
am__dirstamp = $(am__leading_dot)dirstamp
|
am__dirstamp = $(am__leading_dot)dirstamp
|
||||||
am_src_libairbag_la_OBJECTS = src/processor/call_stack.lo \
|
am_src_libairbag_la_OBJECTS = src/processor/call_stack.lo \
|
||||||
src/processor/minidump.lo src/processor/minidump_processor.lo \
|
src/processor/minidump.lo src/processor/minidump_processor.lo \
|
||||||
|
src/processor/pathname_stripper.lo \
|
||||||
src/processor/process_state.lo \
|
src/processor/process_state.lo \
|
||||||
|
src/processor/simple_symbol_supplier.lo \
|
||||||
src/processor/source_line_resolver.lo \
|
src/processor/source_line_resolver.lo \
|
||||||
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_x86.lo
|
src/processor/stackwalker_x86.lo
|
||||||
@ -152,9 +155,19 @@ src_processor_minidump_stackwalk_OBJECTS = \
|
|||||||
$(am_src_processor_minidump_stackwalk_OBJECTS)
|
$(am_src_processor_minidump_stackwalk_OBJECTS)
|
||||||
src_processor_minidump_stackwalk_DEPENDENCIES = \
|
src_processor_minidump_stackwalk_DEPENDENCIES = \
|
||||||
src/processor/call_stack.lo src/processor/minidump.lo \
|
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.lo src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_x86.lo \
|
src/processor/stackwalker_x86.lo \
|
||||||
src/processor/source_line_resolver.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 = \
|
am_src_processor_postfix_evaluator_unittest_OBJECTS = \
|
||||||
src/processor/postfix_evaluator_unittest.$(OBJEXT)
|
src/processor/postfix_evaluator_unittest.$(OBJEXT)
|
||||||
src_processor_postfix_evaluator_unittest_OBJECTS = \
|
src_processor_postfix_evaluator_unittest_OBJECTS = \
|
||||||
@ -206,6 +219,7 @@ SOURCES = $(src_libairbag_la_SOURCES) \
|
|||||||
$(src_processor_minidump_dump_SOURCES) \
|
$(src_processor_minidump_dump_SOURCES) \
|
||||||
$(src_processor_minidump_processor_unittest_SOURCES) \
|
$(src_processor_minidump_processor_unittest_SOURCES) \
|
||||||
$(src_processor_minidump_stackwalk_SOURCES) \
|
$(src_processor_minidump_stackwalk_SOURCES) \
|
||||||
|
$(src_processor_pathname_stripper_unittest_SOURCES) \
|
||||||
$(src_processor_postfix_evaluator_unittest_SOURCES) \
|
$(src_processor_postfix_evaluator_unittest_SOURCES) \
|
||||||
$(src_processor_range_map_unittest_SOURCES) \
|
$(src_processor_range_map_unittest_SOURCES) \
|
||||||
$(src_processor_source_line_resolver_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_dump_SOURCES) \
|
||||||
$(src_processor_minidump_processor_unittest_SOURCES) \
|
$(src_processor_minidump_processor_unittest_SOURCES) \
|
||||||
$(src_processor_minidump_stackwalk_SOURCES) \
|
$(src_processor_minidump_stackwalk_SOURCES) \
|
||||||
|
$(src_processor_pathname_stripper_unittest_SOURCES) \
|
||||||
$(src_processor_postfix_evaluator_unittest_SOURCES) \
|
$(src_processor_postfix_evaluator_unittest_SOURCES) \
|
||||||
$(src_processor_range_map_unittest_SOURCES) \
|
$(src_processor_range_map_unittest_SOURCES) \
|
||||||
$(src_processor_source_line_resolver_unittest_SOURCES) \
|
$(src_processor_source_line_resolver_unittest_SOURCES) \
|
||||||
@ -352,35 +367,39 @@ dist_doc_DATA = \
|
|||||||
|
|
||||||
lib_LTLIBRARIES = src/libairbag.la
|
lib_LTLIBRARIES = src/libairbag.la
|
||||||
src_libairbag_la_SOURCES = \
|
src_libairbag_la_SOURCES = \
|
||||||
src/google/airbag_types.h \
|
src/google_airbag/common/airbag_types.h \
|
||||||
src/google/call_stack.h \
|
src/google_airbag/common/minidump_format.h \
|
||||||
src/google/minidump_processor.h \
|
src/google_airbag/processor/call_stack.h \
|
||||||
src/google/process_state.h \
|
src/google_airbag/processor/memory_region.h \
|
||||||
src/google/stack_frame.h \
|
src/google_airbag/processor/minidump.h \
|
||||||
src/google/stack_frame_cpu.h \
|
src/google_airbag/processor/minidump_processor.h \
|
||||||
src/google/symbol_supplier.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.h \
|
||||||
src/processor/address_map-inl.h \
|
src/processor/address_map-inl.h \
|
||||||
src/processor/call_stack.cc \
|
src/processor/call_stack.cc \
|
||||||
src/processor/contained_range_map.h \
|
src/processor/contained_range_map.h \
|
||||||
src/processor/contained_range_map-inl.h \
|
src/processor/contained_range_map-inl.h \
|
||||||
src/processor/linked_ptr.h \
|
src/processor/linked_ptr.h \
|
||||||
src/processor/memory_region.h \
|
|
||||||
src/processor/minidump.cc \
|
src/processor/minidump.cc \
|
||||||
src/processor/minidump.h \
|
|
||||||
src/processor/minidump_format.h \
|
|
||||||
src/processor/minidump_processor.cc \
|
src/processor/minidump_processor.cc \
|
||||||
|
src/processor/pathname_stripper.cc \
|
||||||
|
src/processor/pathname_stripper.h \
|
||||||
src/processor/postfix_evaluator.h \
|
src/processor/postfix_evaluator.h \
|
||||||
src/processor/postfix_evaluator-inl.h \
|
src/processor/postfix_evaluator-inl.h \
|
||||||
src/processor/process_state.cc \
|
src/processor/process_state.cc \
|
||||||
src/processor/range_map.h \
|
src/processor/range_map.h \
|
||||||
src/processor/range_map-inl.h \
|
src/processor/range_map-inl.h \
|
||||||
src/processor/scoped_ptr.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.cc \
|
||||||
src/processor/source_line_resolver.h \
|
src/processor/source_line_resolver.h \
|
||||||
src/processor/stack_frame_info.h \
|
src/processor/stack_frame_info.h \
|
||||||
src/processor/stackwalker.cc \
|
src/processor/stackwalker.cc \
|
||||||
src/processor/stackwalker.h \
|
|
||||||
src/processor/stackwalker_ppc.cc \
|
src/processor/stackwalker_ppc.cc \
|
||||||
src/processor/stackwalker_ppc.h \
|
src/processor/stackwalker_ppc.h \
|
||||||
src/processor/stackwalker_x86.cc \
|
src/processor/stackwalker_x86.cc \
|
||||||
@ -411,6 +430,12 @@ src_processor_minidump_processor_unittest_LDADD = \
|
|||||||
src/processor/stackwalker_x86.lo \
|
src/processor/stackwalker_x86.lo \
|
||||||
src/processor/source_line_resolver.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_SOURCES = \
|
||||||
src/processor/postfix_evaluator_unittest.cc
|
src/processor/postfix_evaluator_unittest.cc
|
||||||
|
|
||||||
@ -447,6 +472,10 @@ src_processor_minidump_stackwalk_SOURCES = \
|
|||||||
src_processor_minidump_stackwalk_LDADD = \
|
src_processor_minidump_stackwalk_LDADD = \
|
||||||
src/processor/call_stack.lo \
|
src/processor/call_stack.lo \
|
||||||
src/processor/minidump.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.lo \
|
||||||
src/processor/stackwalker_ppc.lo \
|
src/processor/stackwalker_ppc.lo \
|
||||||
src/processor/stackwalker_x86.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/$(DEPDIR)/$(am__dirstamp)
|
||||||
src/processor/minidump_processor.lo: src/processor/$(am__dirstamp) \
|
src/processor/minidump_processor.lo: src/processor/$(am__dirstamp) \
|
||||||
src/processor/$(DEPDIR)/$(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/process_state.lo: src/processor/$(am__dirstamp) \
|
||||||
src/processor/$(DEPDIR)/$(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/source_line_resolver.lo: src/processor/$(am__dirstamp) \
|
||||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||||
src/processor/stackwalker.lo: src/processor/$(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)
|
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)
|
@rm -f src/processor/minidump_stackwalk$(EXEEXT)
|
||||||
$(CXXLINK) $(src_processor_minidump_stackwalk_LDFLAGS) $(src_processor_minidump_stackwalk_OBJECTS) $(src_processor_minidump_stackwalk_LDADD) $(LIBS)
|
$(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/postfix_evaluator_unittest.$(OBJEXT): \
|
||||||
src/processor/$(am__dirstamp) \
|
src/processor/$(am__dirstamp) \
|
||||||
src/processor/$(DEPDIR)/$(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.lo
|
||||||
-rm -f src/processor/minidump_processor_unittest.$(OBJEXT)
|
-rm -f src/processor/minidump_processor_unittest.$(OBJEXT)
|
||||||
-rm -f src/processor/minidump_stackwalk.$(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/postfix_evaluator_unittest.$(OBJEXT)
|
||||||
-rm -f src/processor/process_state.$(OBJEXT)
|
-rm -f src/processor/process_state.$(OBJEXT)
|
||||||
-rm -f src/processor/process_state.lo
|
-rm -f src/processor/process_state.lo
|
||||||
-rm -f src/processor/range_map_unittest.$(OBJEXT)
|
-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.$(OBJEXT)
|
||||||
-rm -f src/processor/source_line_resolver.lo
|
-rm -f src/processor/source_line_resolver.lo
|
||||||
-rm -f src/processor/source_line_resolver_unittest.$(OBJEXT)
|
-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.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_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)/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)/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)/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)/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.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)/source_line_resolver_unittest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker.Plo@am__quote@
|
||||||
|
91
toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer-inl.h
Executable file
91
toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer-inl.h
Executable 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__
|
249
toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer.cc
Executable file
249
toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer.cc
Executable 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
|
218
toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer.h
Executable file
218
toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer.h
Executable 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__
|
@ -31,12 +31,23 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "common/windows/string_utils-inl.h"
|
||||||
|
|
||||||
#include "client/windows/handler/exception_handler.h"
|
#include "client/windows/handler/exception_handler.h"
|
||||||
#include "common/windows/guid_string.h"
|
#include "common/windows/guid_string.h"
|
||||||
|
#include "google_airbag/common/minidump_format.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
ExceptionHandler *ExceptionHandler::current_handler_ = NULL;
|
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,
|
ExceptionHandler::ExceptionHandler(const wstring &dump_path,
|
||||||
MinidumpCallback callback,
|
MinidumpCallback callback,
|
||||||
@ -46,6 +57,22 @@ ExceptionHandler::ExceptionHandler(const wstring &dump_path,
|
|||||||
dump_path_(dump_path), dbghelp_module_(NULL),
|
dump_path_(dump_path), dbghelp_module_(NULL),
|
||||||
minidump_write_dump_(NULL), previous_handler_(current_handler_),
|
minidump_write_dump_(NULL), previous_handler_(current_handler_),
|
||||||
previous_filter_(NULL) {
|
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();
|
UpdateNextID();
|
||||||
dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
|
dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
|
||||||
if (dbghelp_module_) {
|
if (dbghelp_module_) {
|
||||||
@ -66,18 +93,72 @@ ExceptionHandler::~ExceptionHandler() {
|
|||||||
SetUnhandledExceptionFilter(previous_filter_);
|
SetUnhandledExceptionFilter(previous_filter_);
|
||||||
current_handler_ = previous_handler_;
|
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
|
// static
|
||||||
LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) {
|
LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) {
|
||||||
if (!current_handler_->WriteMinidumpWithException(exinfo)) {
|
return current_handler_->WriteMinidumpOnHandlerThread(exinfo) ?
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
|
||||||
|
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 ExceptionHandler::WriteMinidump() {
|
||||||
bool success = WriteMinidumpWithException(NULL);
|
bool success = WriteMinidumpOnHandlerThread(NULL);
|
||||||
UpdateNextID();
|
UpdateNextID();
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@ -90,10 +171,12 @@ bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
|
|||||||
return handler.WriteMinidump();
|
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];
|
wchar_t dump_file_name[MAX_PATH];
|
||||||
swprintf_s(dump_file_name, MAX_PATH, L"%s\\%s.dmp",
|
WindowsStringUtils::safe_swprintf(dump_file_name, MAX_PATH, L"%s\\%s.dmp",
|
||||||
dump_path_.c_str(), next_minidump_id_.c_str());
|
dump_path_.c_str(),
|
||||||
|
next_minidump_id_.c_str());
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (minidump_write_dump_) {
|
if (minidump_write_dump_) {
|
||||||
@ -106,17 +189,38 @@ bool ExceptionHandler::WriteMinidumpWithException(EXCEPTION_POINTERS *exinfo) {
|
|||||||
NULL);
|
NULL);
|
||||||
if (dump_file != INVALID_HANDLE_VALUE) {
|
if (dump_file != INVALID_HANDLE_VALUE) {
|
||||||
MINIDUMP_EXCEPTION_INFORMATION except_info;
|
MINIDUMP_EXCEPTION_INFORMATION except_info;
|
||||||
except_info.ThreadId = GetCurrentThreadId();
|
except_info.ThreadId = requesting_thread_id;
|
||||||
except_info.ExceptionPointers = exinfo;
|
except_info.ExceptionPointers = exinfo;
|
||||||
except_info.ClientPointers = FALSE;
|
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).
|
// The explicit comparison to TRUE avoids a warning (C4800).
|
||||||
success = (minidump_write_dump_(GetCurrentProcess(),
|
success = (minidump_write_dump_(GetCurrentProcess(),
|
||||||
GetCurrentProcessId(),
|
GetCurrentProcessId(),
|
||||||
dump_file,
|
dump_file,
|
||||||
MiniDumpNormal,
|
MiniDumpNormal,
|
||||||
&except_info,
|
exinfo ? &except_info : NULL,
|
||||||
NULL,
|
&user_streams,
|
||||||
NULL) == TRUE);
|
NULL) == TRUE);
|
||||||
|
|
||||||
CloseHandle(dump_file);
|
CloseHandle(dump_file);
|
||||||
|
@ -63,8 +63,9 @@
|
|||||||
#include <DbgHelp.h>
|
#include <DbgHelp.h>
|
||||||
|
|
||||||
#pragma warning( push )
|
#pragma warning( push )
|
||||||
// disable exception handler warnings
|
// Disable exception handler warnings.
|
||||||
#pragma warning( disable : 4530 )
|
#pragma warning( disable : 4530 )
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
@ -90,7 +91,7 @@ class ExceptionHandler {
|
|||||||
void *callback_context, bool install_handler);
|
void *callback_context, bool install_handler);
|
||||||
~ExceptionHandler();
|
~ExceptionHandler();
|
||||||
|
|
||||||
// Get and set the minidump path
|
// Get and set the minidump path.
|
||||||
wstring dump_path() const { return dump_path_; }
|
wstring dump_path() const { return dump_path_; }
|
||||||
void set_dump_path(const wstring &dump_path) { dump_path_ = 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_USER_STREAM_INFORMATION UserStreamParam,
|
||||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||||
|
|
||||||
// This function does the actual writing of a minidump.
|
// Runs the main loop for the exception handler thread.
|
||||||
bool WriteMinidumpWithException(EXCEPTION_POINTERS *exinfo);
|
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);
|
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_.
|
// Generates a new ID and stores it in next_minidump_id_.
|
||||||
void UpdateNextID();
|
void UpdateNextID();
|
||||||
|
|
||||||
@ -139,6 +158,41 @@ class ExceptionHandler {
|
|||||||
// the currently-installed ExceptionHandler, of which there can be only 1
|
// the currently-installed ExceptionHandler, of which there can be only 1
|
||||||
static ExceptionHandler *current_handler_;
|
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=
|
// disallow copy ctor and operator=
|
||||||
explicit ExceptionHandler(const ExceptionHandler &);
|
explicit ExceptionHandler(const ExceptionHandler &);
|
||||||
void operator=(const ExceptionHandler &);
|
void operator=(const ExceptionHandler &);
|
||||||
@ -147,4 +201,5 @@ class ExceptionHandler {
|
|||||||
} // namespace google_airbag
|
} // namespace google_airbag
|
||||||
|
|
||||||
#pragma warning( pop )
|
#pragma warning( pop )
|
||||||
|
|
||||||
#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
|
#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
|
||||||
|
@ -294,6 +294,14 @@
|
|||||||
RelativePath="..\..\..\common\windows\guid_string.h"
|
RelativePath="..\..\..\common\windows\guid_string.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\google_airbag\common\minidump_format.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\common\windows\string_utils-inl.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Resource Files"
|
Name="Resource Files"
|
||||||
|
@ -27,7 +27,9 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Disable exception handler warnings.
|
||||||
#pragma warning( disable : 4530 )
|
#pragma warning( disable : 4530 )
|
||||||
|
|
||||||
#include "client/windows/sender/crash_report_sender.h"
|
#include "client/windows/sender/crash_report_sender.h"
|
||||||
#include "common/windows/http_upload.h"
|
#include "common/windows/http_upload.h"
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
// wininet.lib.
|
// wininet.lib.
|
||||||
|
|
||||||
#pragma warning( push )
|
#pragma warning( push )
|
||||||
// disable exception handler warnings
|
// Disable exception handler warnings.
|
||||||
#pragma warning( disable : 4530 )
|
#pragma warning( disable : 4530 )
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -74,4 +74,5 @@ class CrashReportSender {
|
|||||||
} // namespace google_airbag
|
} // namespace google_airbag
|
||||||
|
|
||||||
#pragma warning( pop )
|
#pragma warning( pop )
|
||||||
|
|
||||||
#endif // CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__
|
#endif // CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__
|
||||||
|
@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include "common/windows/string_utils-inl.h"
|
||||||
|
|
||||||
#include "common/windows/guid_string.h"
|
#include "common/windows/guid_string.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
@ -40,12 +42,13 @@ namespace google_airbag {
|
|||||||
// static
|
// static
|
||||||
wstring GUIDString::GUIDToWString(GUID *guid) {
|
wstring GUIDString::GUIDToWString(GUID *guid) {
|
||||||
wchar_t guid_string[37];
|
wchar_t guid_string[37];
|
||||||
_snwprintf_s(guid_string, sizeof(guid_string) / sizeof(wchar_t), _TRUNCATE,
|
WindowsStringUtils::safe_swprintf(
|
||||||
L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
|
||||||
guid->Data1, guid->Data2, guid->Data3,
|
L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||||
guid->Data4[0], guid->Data4[1], guid->Data4[2],
|
guid->Data1, guid->Data2, guid->Data3,
|
||||||
guid->Data4[3], guid->Data4[4], guid->Data4[5],
|
guid->Data4[0], guid->Data4[1], guid->Data4[2],
|
||||||
guid->Data4[6], guid->Data4[7]);
|
guid->Data4[3], guid->Data4[4], guid->Data4[5],
|
||||||
|
guid->Data4[6], guid->Data4[7]);
|
||||||
return wstring(guid_string);
|
return wstring(guid_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,13 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <WinInet.h>
|
#include <WinInet.h>
|
||||||
|
|
||||||
|
// Disable exception handler warnings.
|
||||||
#pragma warning( disable : 4530 )
|
#pragma warning( disable : 4530 )
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "common/windows/string_utils-inl.h"
|
||||||
|
|
||||||
#include "common/windows/http_upload.h"
|
#include "common/windows/http_upload.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
@ -164,7 +168,8 @@ wstring HTTPUpload::GenerateMultipartBoundary() {
|
|||||||
int r1 = rand();
|
int r1 = rand();
|
||||||
|
|
||||||
wchar_t temp[kBoundaryLength];
|
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);
|
return wstring(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,8 +235,16 @@ bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> ¶meters,
|
|||||||
// static
|
// static
|
||||||
void HTTPUpload::GetFileContents(const wstring &filename,
|
void HTTPUpload::GetFileContents(const wstring &filename,
|
||||||
vector<char> *contents) {
|
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;
|
ifstream file;
|
||||||
file.open(filename.c_str(), ios::binary);
|
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()) {
|
if (file.is_open()) {
|
||||||
file.seekg(0, ios::end);
|
file.seekg(0, ios::end);
|
||||||
int length = file.tellg();
|
int length = file.tellg();
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#define COMMON_WINDOWS_HTTP_UPLOAD_H__
|
#define COMMON_WINDOWS_HTTP_UPLOAD_H__
|
||||||
|
|
||||||
#pragma warning( push )
|
#pragma warning( push )
|
||||||
// disable exception handler warnings
|
// Disable exception handler warnings.
|
||||||
#pragma warning( disable : 4530 )
|
#pragma warning( disable : 4530 )
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -104,4 +104,5 @@ class HTTPUpload {
|
|||||||
} // namespace google_airbag
|
} // namespace google_airbag
|
||||||
|
|
||||||
#pragma warning( pop )
|
#pragma warning( pop )
|
||||||
|
|
||||||
#endif // COMMON_WINDOWS_HTTP_UPLOAD_H__
|
#endif // COMMON_WINDOWS_HTTP_UPLOAD_H__
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include <dia2.h>
|
#include <dia2.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "common/windows/string_utils-inl.h"
|
||||||
|
|
||||||
#include "common/windows/pdb_source_line_writer.h"
|
#include "common/windows/pdb_source_line_writer.h"
|
||||||
#include "common/windows/guid_string.h"
|
#include "common/windows/guid_string.h"
|
||||||
|
|
||||||
@ -77,6 +79,14 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
fprintf(stderr, "Unknown file format\n");
|
fprintf(stderr, "Unknown file format\n");
|
||||||
return false;
|
return false;
|
||||||
@ -153,7 +163,7 @@ bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function) {
|
|||||||
stack_param_size = GetFunctionStackParamSize(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);
|
rva, length, stack_param_size, name);
|
||||||
|
|
||||||
CComPtr<IDiaEnumLineNumbers> lines;
|
CComPtr<IDiaEnumLineNumbers> lines;
|
||||||
@ -379,6 +389,18 @@ bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) {
|
|||||||
return true;
|
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
|
// wcstol_positive_strict is sort of like wcstol, but much stricter. string
|
||||||
// should be a buffer pointing to a null-terminated string containing only
|
// should be a buffer pointing to a null-terminated string containing only
|
||||||
// decimal digits. If the entire string can be converted to an integer
|
// 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,
|
// 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
|
// it's already formatted properly to be used as output. Don't do any
|
||||||
// additional processing.
|
// 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 {
|
} else {
|
||||||
// C++ uses a bogus "void" argument for functions and methods that don't
|
// 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
|
// 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) {
|
if (length >= replace_length) {
|
||||||
wchar_t *name_end = *name + length - replace_length;
|
wchar_t *name_end = *name + length - replace_length;
|
||||||
if (wcscmp(name_end, replace_string) == 0) {
|
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);
|
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
|
// Undecorate the name by moving it one character to the left in its
|
||||||
// buffer, and terminating it where the last '@' had been.
|
// buffer, and terminating it where the last '@' had been.
|
||||||
wcsncpy_s(*name, length, *name + 1, last_at - *name - 1);
|
WindowsStringUtils::safe_wcsncpy(*name, length,
|
||||||
} else if (*name[0] == '_') {
|
*name + 1, last_at - *name - 1);
|
||||||
|
} else if (*name[0] == '_') {
|
||||||
// This symbol's name is encoded according to the cdecl rules. The
|
// This symbol's name is encoded according to the cdecl rules. The
|
||||||
// name doesn't end in a '@' character followed by a decimal positive
|
// name doesn't end in a '@' character followed by a decimal positive
|
||||||
// integer, so it's not a stdcall name. Strip off the leading
|
// integer, so it's not a stdcall name. Strip off the leading
|
||||||
// underscore.
|
// 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 PDBSourceLineWriter::WriteMap(FILE *map_file) {
|
||||||
bool ret = false;
|
|
||||||
output_ = map_file;
|
output_ = map_file;
|
||||||
if (PrintSourceFiles() && PrintFunctions() && PrintFrameData()) {
|
|
||||||
ret = true;
|
bool ret = PrintPDBInfo() &&
|
||||||
}
|
PrintSourceFiles() &&
|
||||||
|
PrintFunctions() &&
|
||||||
|
PrintFrameData();
|
||||||
|
|
||||||
output_ = NULL;
|
output_ = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
@ -622,18 +652,47 @@ void PDBSourceLineWriter::Close() {
|
|||||||
session_.Release();
|
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;
|
CComPtr<IDiaSymbol> global;
|
||||||
if (FAILED(session_->get_globalScope(&global))) {
|
if (FAILED(session_->get_globalScope(&global))) {
|
||||||
return L"";
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUID guid;
|
GUID guid_number;
|
||||||
if (FAILED(global->get_guid(&guid))) {
|
if (FAILED(global->get_guid(&guid_number))) {
|
||||||
return L"";
|
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
|
} // namespace google_airbag
|
||||||
|
@ -50,6 +50,7 @@ class PDBSourceLineWriter {
|
|||||||
enum FileFormat {
|
enum FileFormat {
|
||||||
PDB_FILE, // a .pdb file containing debug symbols
|
PDB_FILE, // a .pdb file containing debug symbols
|
||||||
EXE_FILE, // a .exe or .dll file
|
EXE_FILE, // a .exe or .dll file
|
||||||
|
ANY_FILE // try PDB_FILE and then EXE_FILE
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit PDBSourceLineWriter();
|
explicit PDBSourceLineWriter();
|
||||||
@ -73,9 +74,11 @@ class PDBSourceLineWriter {
|
|||||||
// Closes the current pdb file and its associated resources.
|
// Closes the current pdb file and its associated resources.
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
// Returns the GUID for the module, as a string,
|
// Sets guid to the GUID for the module, as a string,
|
||||||
// e.g. "11111111-2222-3333-4444-555555555555".
|
// e.g. "11111111-2222-3333-4444-555555555555". age will be set to the
|
||||||
wstring GetModuleGUID();
|
// 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:
|
private:
|
||||||
// Outputs the line/address pairs for each line in the enumerator.
|
// 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.
|
// correspond to code, returns true without outputting anything.
|
||||||
bool PrintCodePublicSymbol(IDiaSymbol *symbol);
|
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
|
// Returns the function name for a symbol. If possible, the name is
|
||||||
// undecorated. If the symbol's decorated form indicates the size of
|
// undecorated. If the symbol's decorated form indicates the size of
|
||||||
// parameters on the stack, this information is returned in stack_param_size.
|
// parameters on the stack, this information is returned in stack_param_size.
|
||||||
|
132
toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h
Executable file
132
toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h
Executable 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__
|
@ -47,6 +47,8 @@
|
|||||||
|
|
||||||
#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
|
#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
using google_airbag::AddressMap;
|
using google_airbag::AddressMap;
|
||||||
using google_airbag::linked_ptr;
|
using google_airbag::linked_ptr;
|
||||||
|
|
||||||
@ -185,6 +187,8 @@ static bool RunTests() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
return RunTests() ? 0 : 1;
|
return RunTests() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,8 @@
|
|||||||
//
|
//
|
||||||
// Author: Mark Mentovai
|
// Author: Mark Mentovai
|
||||||
|
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
#include "google/stack_frame.h"
|
#include "google_airbag/processor/stack_frame.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
|
@ -45,6 +45,9 @@
|
|||||||
#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition))
|
#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition))
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
using google_airbag::ContainedRangeMap;
|
using google_airbag::ContainedRangeMap;
|
||||||
|
|
||||||
|
|
||||||
@ -248,6 +251,9 @@ static bool RunTests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
return RunTests() ? 0 : 1;
|
return RunTests() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ typedef SSIZE_T ssize_t;
|
|||||||
|
|
||||||
#include "processor/range_map-inl.h"
|
#include "processor/range_map-inl.h"
|
||||||
|
|
||||||
#include "processor/minidump.h"
|
#include "google_airbag/processor/minidump.h"
|
||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
|
|
||||||
|
|
||||||
@ -462,13 +462,13 @@ void MinidumpContext::FreeContext() {
|
|||||||
|
|
||||||
|
|
||||||
bool MinidumpContext::CheckAgainstSystemInfo(u_int32_t context_cpu_type) {
|
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.
|
// as this function just implements a sanity check.
|
||||||
MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
|
MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
|
||||||
if (!system_info)
|
if (!system_info)
|
||||||
return true;
|
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();
|
const MDRawSystemInfo* raw_system_info = system_info->system_info();
|
||||||
if (!raw_system_info)
|
if (!raw_system_info)
|
||||||
return false;
|
return false;
|
||||||
@ -661,7 +661,8 @@ const u_int8_t* MinidumpMemoryRegion::GetMemory() {
|
|||||||
|
|
||||||
|
|
||||||
u_int64_t MinidumpMemoryRegion::GetBase() {
|
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() {
|
bool MinidumpThread::GetThreadID(u_int32_t *thread_id) const {
|
||||||
return valid_ ? thread_.thread_id : (u_int32_t)-1;
|
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())
|
if (!thread->Read())
|
||||||
return false;
|
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)) {
|
if (GetThreadByID(thread_id)) {
|
||||||
// Another thread with this ID is already in the list. Data error.
|
// Another thread with this ID is already in the list. Data error.
|
||||||
return false;
|
return false;
|
||||||
@ -1408,20 +1416,21 @@ void MinidumpModule::Print() {
|
|||||||
|
|
||||||
MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
|
MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
|
||||||
: MinidumpStream(minidump),
|
: MinidumpStream(minidump),
|
||||||
range_map_(),
|
range_map_(new RangeMap<u_int64_t, unsigned int>()),
|
||||||
modules_(NULL),
|
modules_(NULL),
|
||||||
module_count_(0) {
|
module_count_(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MinidumpModuleList::~MinidumpModuleList() {
|
MinidumpModuleList::~MinidumpModuleList() {
|
||||||
|
delete range_map_;
|
||||||
delete modules_;
|
delete modules_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MinidumpModuleList::Read(u_int32_t expected_size) {
|
bool MinidumpModuleList::Read(u_int32_t expected_size) {
|
||||||
// Invalidate cached data.
|
// Invalidate cached data.
|
||||||
range_map_.Clear();
|
range_map_->Clear();
|
||||||
delete modules_;
|
delete modules_;
|
||||||
modules_ = NULL;
|
modules_ = NULL;
|
||||||
module_count_ = 0;
|
module_count_ = 0;
|
||||||
@ -1460,7 +1469,7 @@ bool MinidumpModuleList::Read(u_int32_t expected_size) {
|
|||||||
if (base_address == (u_int64_t)-1)
|
if (base_address == (u_int64_t)-1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!range_map_.StoreRange(base_address, module_size, module_index))
|
if (!range_map_->StoreRange(base_address, module_size, module_index))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1486,7 +1495,7 @@ MinidumpModule* MinidumpModuleList::GetModuleForAddress(u_int64_t address) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
unsigned int module_index;
|
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 NULL;
|
||||||
|
|
||||||
return GetModuleAtIndex(module_index);
|
return GetModuleAtIndex(module_index);
|
||||||
@ -1518,7 +1527,7 @@ void MinidumpModuleList::Print() {
|
|||||||
|
|
||||||
MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
|
MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
|
||||||
: MinidumpStream(minidump),
|
: MinidumpStream(minidump),
|
||||||
range_map_(),
|
range_map_(new RangeMap<u_int64_t, unsigned int>()),
|
||||||
descriptors_(NULL),
|
descriptors_(NULL),
|
||||||
regions_(NULL),
|
regions_(NULL),
|
||||||
region_count_(0) {
|
region_count_(0) {
|
||||||
@ -1526,6 +1535,7 @@ MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
|
|||||||
|
|
||||||
|
|
||||||
MinidumpMemoryList::~MinidumpMemoryList() {
|
MinidumpMemoryList::~MinidumpMemoryList() {
|
||||||
|
delete range_map_;
|
||||||
delete descriptors_;
|
delete descriptors_;
|
||||||
delete regions_;
|
delete regions_;
|
||||||
}
|
}
|
||||||
@ -1537,7 +1547,7 @@ bool MinidumpMemoryList::Read(u_int32_t expected_size) {
|
|||||||
descriptors_ = NULL;
|
descriptors_ = NULL;
|
||||||
delete regions_;
|
delete regions_;
|
||||||
regions_ = NULL;
|
regions_ = NULL;
|
||||||
range_map_.Clear();
|
range_map_->Clear();
|
||||||
region_count_ = 0;
|
region_count_ = 0;
|
||||||
|
|
||||||
valid_ = false;
|
valid_ = false;
|
||||||
@ -1587,7 +1597,7 @@ bool MinidumpMemoryList::Read(u_int32_t expected_size) {
|
|||||||
if (region_size == 0 || high_address < base_address)
|
if (region_size == 0 || high_address < base_address)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!range_map_.StoreRange(base_address, region_size, region_index))
|
if (!range_map_->StoreRange(base_address, region_size, region_index))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
(*regions)[region_index].SetDescriptor(descriptor);
|
(*regions)[region_index].SetDescriptor(descriptor);
|
||||||
@ -1617,7 +1627,7 @@ MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
unsigned int region_index;
|
unsigned int region_index;
|
||||||
if (!range_map_.RetrieveRange(address, ®ion_index, NULL, NULL))
|
if (!range_map_->RetrieveRange(address, ®ion_index, NULL, NULL))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return GetMemoryRegionAtIndex(region_index);
|
return GetMemoryRegionAtIndex(region_index);
|
||||||
@ -1708,8 +1718,12 @@ bool MinidumpException::Read(u_int32_t expected_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u_int32_t MinidumpException::GetThreadID() {
|
bool MinidumpException::GetThreadID(u_int32_t *thread_id) const {
|
||||||
return valid_ ? exception_.thread_id : 0;
|
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",
|
printf(" processor_current_idle_state = 0x%x\n",
|
||||||
misc_info_.processor_current_idle_state);
|
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.
|
// type.
|
||||||
unsigned int stream_type = directory_entry->stream_type;
|
unsigned int stream_type = directory_entry->stream_type;
|
||||||
switch (stream_type) {
|
switch (stream_type) {
|
||||||
case THREAD_LIST_STREAM:
|
case MD_THREAD_LIST_STREAM:
|
||||||
case MODULE_LIST_STREAM:
|
case MD_MODULE_LIST_STREAM:
|
||||||
case MEMORY_LIST_STREAM:
|
case MD_MEMORY_LIST_STREAM:
|
||||||
case EXCEPTION_STREAM:
|
case MD_EXCEPTION_STREAM:
|
||||||
case SYSTEM_INFO_STREAM:
|
case MD_SYSTEM_INFO_STREAM:
|
||||||
case MISC_INFO_STREAM: {
|
case MD_MISC_INFO_STREAM:
|
||||||
|
case MD_AIRBAG_INFO_STREAM: {
|
||||||
if (stream_map->find(stream_type) != stream_map->end()) {
|
if (stream_map->find(stream_type) != stream_map->end()) {
|
||||||
// Another stream with this type was already found. A minidump
|
// Another stream with this type was already found. A minidump
|
||||||
// file should contain at most one of each of these stream types.
|
// 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() {
|
void Minidump::Print() {
|
||||||
if (!valid_)
|
if (!valid_)
|
||||||
return;
|
return;
|
||||||
@ -2233,7 +2333,7 @@ void Minidump::Print() {
|
|||||||
++iterator) {
|
++iterator) {
|
||||||
u_int32_t stream_type = iterator->first;
|
u_int32_t stream_type = iterator->first;
|
||||||
MinidumpStreamInfo info = iterator->second;
|
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");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
@ -32,81 +32,97 @@
|
|||||||
//
|
//
|
||||||
// Author: Mark Mentovai
|
// Author: Mark Mentovai
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <cstdio>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#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;
|
static bool PrintMinidumpDump(const char *minidump_file) {
|
||||||
using namespace google_airbag;
|
Minidump minidump(minidump_file);
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
if (argc != 2) {
|
|
||||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Minidump minidump(argv[1]);
|
|
||||||
if (!minidump.Read()) {
|
if (!minidump.Read()) {
|
||||||
printf("minidump.Read() failed\n");
|
fprintf(stderr, "minidump.Read() failed\n");
|
||||||
exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
minidump.Print();
|
minidump.Print();
|
||||||
|
|
||||||
int error = 0;
|
int errors = 0;
|
||||||
|
|
||||||
MinidumpThreadList* threadList = minidump.GetThreadList();
|
MinidumpThreadList *thread_list = minidump.GetThreadList();
|
||||||
if (!threadList) {
|
if (!thread_list) {
|
||||||
error |= 1 << 2;
|
++errors;
|
||||||
printf("minidump.GetThreadList() failed\n");
|
printf("minidump.GetThreadList() failed\n");
|
||||||
} else {
|
} else {
|
||||||
threadList->Print();
|
thread_list->Print();
|
||||||
}
|
}
|
||||||
|
|
||||||
MinidumpModuleList* moduleList = minidump.GetModuleList();
|
MinidumpModuleList *module_list = minidump.GetModuleList();
|
||||||
if (!moduleList) {
|
if (!module_list) {
|
||||||
error |= 1 << 3;
|
++errors;
|
||||||
printf("minidump.GetModuleList() failed\n");
|
printf("minidump.GetModuleList() failed\n");
|
||||||
} else {
|
} else {
|
||||||
moduleList->Print();
|
module_list->Print();
|
||||||
}
|
}
|
||||||
|
|
||||||
MinidumpMemoryList* memoryList = minidump.GetMemoryList();
|
MinidumpMemoryList *memory_list = minidump.GetMemoryList();
|
||||||
if (!memoryList) {
|
if (!memory_list) {
|
||||||
error |= 1 << 4;
|
++errors;
|
||||||
printf("minidump.GetMemoryList() failed\n");
|
printf("minidump.GetMemoryList() failed\n");
|
||||||
} else {
|
} else {
|
||||||
memoryList->Print();
|
memory_list->Print();
|
||||||
}
|
}
|
||||||
|
|
||||||
MinidumpException* exception = minidump.GetException();
|
MinidumpException *exception = minidump.GetException();
|
||||||
if (!exception) {
|
if (!exception) {
|
||||||
error |= 1 << 5;
|
// Exception info is optional, so don't treat this as an error.
|
||||||
printf("minidump.GetException() failed\n");
|
printf("minidump.GetException() failed\n");
|
||||||
} else {
|
} else {
|
||||||
exception->Print();
|
exception->Print();
|
||||||
}
|
}
|
||||||
|
|
||||||
MinidumpSystemInfo* systemInfo = minidump.GetSystemInfo();
|
MinidumpSystemInfo *system_info = minidump.GetSystemInfo();
|
||||||
if (!systemInfo) {
|
if (!system_info) {
|
||||||
error |= 1 << 6;
|
++errors;
|
||||||
printf("minidump.GetSystemInfo() failed\n");
|
printf("minidump.GetSystemInfo() failed\n");
|
||||||
} else {
|
} else {
|
||||||
systemInfo->Print();
|
system_info->Print();
|
||||||
}
|
}
|
||||||
|
|
||||||
MinidumpMiscInfo* miscInfo = minidump.GetMiscInfo();
|
MinidumpMiscInfo *misc_info = minidump.GetMiscInfo();
|
||||||
if (!miscInfo) {
|
if (!misc_info) {
|
||||||
error |= 1 << 7;
|
++errors;
|
||||||
printf("minidump.GetMiscInfo() failed\n");
|
printf("minidump.GetMiscInfo() failed\n");
|
||||||
} else {
|
} else {
|
||||||
miscInfo->Print();
|
misc_info->Print();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use return instead of exit to allow destructors to run.
|
MinidumpAirbagInfo *airbag_info = minidump.GetAirbagInfo();
|
||||||
return(error);
|
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;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
testdata_dir=$srcdir/src/processor/testdata
|
testdata_dir=$srcdir/src/processor/testdata
|
||||||
./src/processor/minidump_dump $testdata_dir/minidump1.dmp | \
|
./src/processor/minidump_dump $testdata_dir/minidump2.dmp | \
|
||||||
tr -s '\015' '\012' | \
|
tr -d '\015' | \
|
||||||
diff -u $testdata_dir/minidump1.out -
|
diff -u $testdata_dir/minidump2.dump.out -
|
||||||
exit $?
|
exit $?
|
||||||
|
@ -27,10 +27,10 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "google/minidump_processor.h"
|
#include "google_airbag/processor/minidump_processor.h"
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
#include "google/process_state.h"
|
#include "google_airbag/processor/minidump.h"
|
||||||
#include "processor/minidump.h"
|
#include "google_airbag/processor/process_state.h"
|
||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
#include "processor/stackwalker_x86.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->cpu_ = GetCPUInfo(&dump, &process_state->cpu_info_);
|
||||||
process_state->os_ = GetOSInfo(&dump, &process_state->os_version_);
|
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();
|
MinidumpException *exception = dump.GetException();
|
||||||
if (exception) {
|
if (exception) {
|
||||||
process_state->crashed_ = true;
|
process_state->crashed_ = true;
|
||||||
exception_thread_id = exception->GetThreadID();
|
has_requesting_thread = exception->GetThreadID(&requesting_thread_id);
|
||||||
|
|
||||||
process_state->crash_reason_ = GetCrashReason(
|
process_state->crash_reason_ = GetCrashReason(
|
||||||
&dump, &process_state->crash_address_);
|
&dump, &process_state->crash_address_);
|
||||||
@ -69,7 +80,7 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool found_crash_thread = false;
|
bool found_requesting_thread = false;
|
||||||
unsigned int thread_count = threads->thread_count();
|
unsigned int thread_count = threads->thread_count();
|
||||||
for (unsigned int thread_index = 0;
|
for (unsigned int thread_index = 0;
|
||||||
thread_index < thread_count;
|
thread_index < thread_count;
|
||||||
@ -79,15 +90,46 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_state->crashed_ &&
|
u_int32_t thread_id;
|
||||||
thread->GetThreadID() == exception_thread_id) {
|
if (!thread->GetThreadID(&thread_id)) {
|
||||||
if (found_crash_thread) {
|
return NULL;
|
||||||
// There can't be more than one crash thread.
|
}
|
||||||
|
|
||||||
|
// 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_state->crash_thread_ = thread_index;
|
// Use processed_state->threads_.size() instead of thread_index.
|
||||||
found_crash_thread = true;
|
// 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();
|
MinidumpMemoryRegion *thread_memory = thread->GetMemory();
|
||||||
@ -96,7 +138,7 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scoped_ptr<Stackwalker> stackwalker(
|
scoped_ptr<Stackwalker> stackwalker(
|
||||||
Stackwalker::StackwalkerForCPU(exception->GetContext(),
|
Stackwalker::StackwalkerForCPU(context,
|
||||||
thread_memory,
|
thread_memory,
|
||||||
dump.GetModuleList(),
|
dump.GetModuleList(),
|
||||||
supplier_));
|
supplier_));
|
||||||
@ -112,8 +154,8 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
|
|||||||
process_state->threads_.push_back(stack.release());
|
process_state->threads_.push_back(stack.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the process crashed, there must be a crash thread.
|
// If a requesting thread was indicated, it must be present.
|
||||||
if (process_state->crashed_ && !found_crash_thread) {
|
if (has_requesting_thread && !found_requesting_thread) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,19 +31,23 @@
|
|||||||
// corresponding symbol file, and checks the stack frames for correctness.
|
// corresponding symbol file, and checks the stack frames for correctness.
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
#include "google/minidump_processor.h"
|
#include "google_airbag/processor/minidump.h"
|
||||||
#include "google/process_state.h"
|
#include "google_airbag/processor/minidump_processor.h"
|
||||||
#include "google/stack_frame.h"
|
#include "google_airbag/processor/process_state.h"
|
||||||
#include "google/symbol_supplier.h"
|
#include "google_airbag/processor/stack_frame.h"
|
||||||
#include "processor/minidump.h"
|
#include "google_airbag/processor/symbol_supplier.h"
|
||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using google_airbag::CallStack;
|
using google_airbag::CallStack;
|
||||||
|
using google_airbag::MinidumpModule;
|
||||||
using google_airbag::MinidumpProcessor;
|
using google_airbag::MinidumpProcessor;
|
||||||
using google_airbag::ProcessState;
|
using google_airbag::ProcessState;
|
||||||
using google_airbag::scoped_ptr;
|
using google_airbag::scoped_ptr;
|
||||||
|
using google_airbag::SymbolSupplier;
|
||||||
|
|
||||||
#define ASSERT_TRUE(cond) \
|
#define ASSERT_TRUE(cond) \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
@ -53,8 +57,6 @@ using google_airbag::scoped_ptr;
|
|||||||
|
|
||||||
#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
|
#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
|
||||||
|
|
||||||
namespace google_airbag {
|
|
||||||
|
|
||||||
class TestSymbolSupplier : public SymbolSupplier {
|
class TestSymbolSupplier : public SymbolSupplier {
|
||||||
public:
|
public:
|
||||||
virtual string GetSymbolFile(MinidumpModule *module);
|
virtual string GetSymbolFile(MinidumpModule *module);
|
||||||
@ -62,17 +64,16 @@ class TestSymbolSupplier : public SymbolSupplier {
|
|||||||
|
|
||||||
string TestSymbolSupplier::GetSymbolFile(MinidumpModule *module) {
|
string TestSymbolSupplier::GetSymbolFile(MinidumpModule *module) {
|
||||||
if (*(module->GetName()) == "c:\\test_app.exe") {
|
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") : ".") +
|
return string(getenv("srcdir") ? getenv("srcdir") : ".") +
|
||||||
"/src/processor/testdata/minidump2.sym";
|
"/src/processor/testdata/symbols/"
|
||||||
|
"test_app.pdb/8DDB7E9A365748938D6EB08B1DCA31AA1/test_app.sym";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google_airbag
|
|
||||||
|
|
||||||
using google_airbag::TestSymbolSupplier;
|
|
||||||
|
|
||||||
static bool RunTests() {
|
static bool RunTests() {
|
||||||
TestSymbolSupplier supplier;
|
TestSymbolSupplier supplier;
|
||||||
MinidumpProcessor processor(&supplier);
|
MinidumpProcessor processor(&supplier);
|
||||||
@ -88,9 +89,9 @@ static bool RunTests() {
|
|||||||
ASSERT_EQ(state->os_version(), "5.1.2600 Service Pack 2");
|
ASSERT_EQ(state->os_version(), "5.1.2600 Service Pack 2");
|
||||||
ASSERT_TRUE(state->crashed());
|
ASSERT_TRUE(state->crashed());
|
||||||
ASSERT_EQ(state->crash_reason(), "EXCEPTION_ACCESS_VIOLATION");
|
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->threads()->size(), 1);
|
||||||
ASSERT_EQ(state->crash_thread(), 0);
|
ASSERT_EQ(state->requesting_thread(), 0);
|
||||||
CallStack *stack = state->threads()->at(0);
|
CallStack *stack = state->threads()->at(0);
|
||||||
ASSERT_TRUE(stack);
|
ASSERT_TRUE(stack);
|
||||||
ASSERT_EQ(stack->frames()->size(), 4);
|
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)->module_name, "c:\\test_app.exe");
|
||||||
ASSERT_EQ(stack->frames()->at(0)->function_name, "CrashFunction()");
|
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_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_base, 0x400000);
|
||||||
ASSERT_EQ(stack->frames()->at(1)->module_name, "c:\\test_app.exe");
|
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)->function_name, "main");
|
||||||
ASSERT_EQ(stack->frames()->at(1)->source_file_name, "c:\\test_app.cc");
|
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
|
// This comes from the CRT
|
||||||
ASSERT_EQ(stack->frames()->at(2)->module_base, 0x400000);
|
ASSERT_EQ(stack->frames()->at(2)->module_base, 0x400000);
|
||||||
@ -126,6 +127,8 @@ static bool RunTests() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (!RunTests()) {
|
if (!RunTests()) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -27,104 +27,212 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// 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_stackwalk.cc: Process a minidump with MinidumpProcessor, printing
|
||||||
// minidump.
|
// the results, including stack traces.
|
||||||
//
|
//
|
||||||
// Author: Mark Mentovai
|
// Author: Mark Mentovai
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <cstdio>
|
||||||
#include <stdio.h>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
#include "google/stack_frame.h"
|
#include "google_airbag/processor/minidump.h"
|
||||||
#include "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/scoped_ptr.h"
|
||||||
#include "processor/stackwalker_x86.h"
|
#include "processor/simple_symbol_supplier.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using google_airbag::CallStack;
|
using google_airbag::CallStack;
|
||||||
using google_airbag::MemoryRegion;
|
using google_airbag::MinidumpModule;
|
||||||
using google_airbag::Minidump;
|
using google_airbag::MinidumpProcessor;
|
||||||
using google_airbag::MinidumpContext;
|
using google_airbag::PathnameStripper;
|
||||||
using google_airbag::MinidumpException;
|
using google_airbag::ProcessState;
|
||||||
using google_airbag::MinidumpModuleList;
|
|
||||||
using google_airbag::MinidumpThread;
|
|
||||||
using google_airbag::MinidumpThreadList;
|
|
||||||
using google_airbag::scoped_ptr;
|
using google_airbag::scoped_ptr;
|
||||||
|
using google_airbag::SimpleSymbolSupplier;
|
||||||
using google_airbag::StackFrame;
|
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) {
|
int main(int argc, char **argv) {
|
||||||
if (argc != 2) {
|
if (argc < 2 || argc > 3) {
|
||||||
fprintf(stderr, "usage: %s <file>\n", argv[0]);
|
fprintf(stderr, "usage: %s <minidump-file> [symbol-path]\n", argv[0]);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Minidump minidump(argv[1]);
|
const char *minidump_file = argv[1];
|
||||||
if (!minidump.Read()) {
|
const char *symbol_path = "";
|
||||||
fprintf(stderr, "minidump.Read() failed\n");
|
if (argc == 3) {
|
||||||
exit(1);
|
symbol_path = argv[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
MinidumpException *exception = minidump.GetException();
|
return PrintMinidumpProcess(minidump_file, symbol_path) ? 0 : 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,8 @@
|
|||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
testdata_dir=$srcdir/src/processor/testdata
|
testdata_dir=$srcdir/src/processor/testdata
|
||||||
./src/processor/minidump_stackwalk $testdata_dir/minidump1.dmp | \
|
./src/processor/minidump_stackwalk $testdata_dir/minidump2.dmp \
|
||||||
tr -s '\015' '\012' | \
|
$testdata_dir/symbols | \
|
||||||
diff -u $testdata_dir/minidump1.stack.out -
|
tr -d '\015' | \
|
||||||
|
diff -u $testdata_dir/minidump2.stackwalk.out -
|
||||||
exit $?
|
exit $?
|
||||||
|
56
toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.cc
Executable file
56
toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.cc
Executable 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
|
53
toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.h
Executable file
53
toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.h
Executable 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__
|
@ -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;
|
||||||
|
}
|
@ -26,7 +26,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "processor/postfix_evaluator.h"
|
#include "processor/postfix_evaluator.h"
|
||||||
#include "processor/memory_region.h"
|
#include "google_airbag/processor/memory_region.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
|
@ -55,8 +55,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "processor/memory_region.h"
|
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
|
@ -22,8 +22,11 @@
|
|||||||
|
|
||||||
#include "processor/postfix_evaluator-inl.h"
|
#include "processor/postfix_evaluator-inl.h"
|
||||||
|
|
||||||
#include "google/airbag_types.h"
|
#include "google_airbag/common/airbag_types.h"
|
||||||
#include "processor/memory_region.h"
|
#include "google_airbag/processor/memory_region.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
using std::map;
|
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.
|
// The first test set checks the basic operations and failure modes.
|
||||||
PostfixEvaluator<unsigned int>::DictionaryType dictionary_0;
|
PostfixEvaluator<unsigned int>::DictionaryType dictionary_0;
|
||||||
const EvaluateTest evaluate_tests_0[] = {
|
const EvaluateTest evaluate_tests_0[] = {
|
||||||
@ -274,6 +277,9 @@ bool RunTests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
return RunTests() ? 0 : 1;
|
return RunTests() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,8 @@
|
|||||||
//
|
//
|
||||||
// Author: Mark Mentovai
|
// Author: Mark Mentovai
|
||||||
|
|
||||||
#include "google/process_state.h"
|
#include "google_airbag/processor/process_state.h"
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
|
@ -41,6 +41,9 @@
|
|||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
using google_airbag::linked_ptr;
|
using google_airbag::linked_ptr;
|
||||||
using google_airbag::scoped_ptr;
|
using google_airbag::scoped_ptr;
|
||||||
using google_airbag::RangeMap;
|
using google_airbag::RangeMap;
|
||||||
@ -99,7 +102,7 @@ struct RangeTestSet {
|
|||||||
// StoreTest uses the data in a RangeTest and calls StoreRange on the
|
// StoreTest uses the data in a RangeTest and calls StoreRange on the
|
||||||
// test RangeMap. It returns true if the expected result occurred, and
|
// test RangeMap. It returns true if the expected result occurred, and
|
||||||
// false if something else happened.
|
// 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));
|
linked_ptr<CountedObject> object(new CountedObject(range_test->id));
|
||||||
bool stored = range_map->StoreRange(range_test->address,
|
bool stored = range_map->StoreRange(range_test->address,
|
||||||
range_test->size,
|
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
|
// map entry at the specified range,) it returns true, otherwise, it returns
|
||||||
// false. RetrieveTest will check the values around the base address and
|
// false. RetrieveTest will check the values around the base address and
|
||||||
// the high address of a range to guard against off-by-one errors.
|
// 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) {
|
for (unsigned int side = 0; side <= 1; ++side) {
|
||||||
// When side == 0, check the low side (base address) of each range.
|
// When side == 0, check the low side (base address) of each range.
|
||||||
// When side == 1, check the high side (base + size) 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.
|
// RunTests runs a series of test sets.
|
||||||
bool RunTests() {
|
static bool RunTests() {
|
||||||
// These tests will be run sequentially. The first set of tests exercises
|
// These tests will be run sequentially. The first set of tests exercises
|
||||||
// most functions of RangeTest, and verifies all of the bounds-checking.
|
// most functions of RangeTest, and verifies all of the bounds-checking.
|
||||||
const RangeTest range_tests_0[] = {
|
const RangeTest range_tests_0[] = {
|
||||||
@ -402,6 +405,10 @@ bool RunTests() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
return RunTests() ? 0 : 1;
|
return RunTests() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -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
|
104
toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.h
Executable file
104
toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.h
Executable 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__
|
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "google/airbag_types.h"
|
#include "google_airbag/common/airbag_types.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
|
@ -34,12 +34,12 @@
|
|||||||
// Author: Mark Mentovai
|
// Author: Mark Mentovai
|
||||||
|
|
||||||
|
|
||||||
#include "processor/stackwalker.h"
|
#include "google_airbag/processor/stackwalker.h"
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
#include "google/stack_frame.h"
|
#include "google_airbag/processor/minidump.h"
|
||||||
#include "google/symbol_supplier.h"
|
#include "google_airbag/processor/stack_frame.h"
|
||||||
|
#include "google_airbag/processor/symbol_supplier.h"
|
||||||
#include "processor/linked_ptr.h"
|
#include "processor/linked_ptr.h"
|
||||||
#include "processor/minidump.h"
|
|
||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
#include "processor/source_line_resolver.h"
|
#include "processor/source_line_resolver.h"
|
||||||
#include "processor/stack_frame_info.h"
|
#include "processor/stack_frame_info.h"
|
||||||
|
@ -35,9 +35,9 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "processor/stackwalker_ppc.h"
|
#include "processor/stackwalker_ppc.h"
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
#include "google/stack_frame_cpu.h"
|
#include "google_airbag/processor/minidump.h"
|
||||||
#include "processor/minidump.h"
|
#include "google_airbag/processor/stack_frame_cpu.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
|
@ -39,9 +39,9 @@
|
|||||||
#define PROCESSOR_STACKWALKER_PPC_H__
|
#define PROCESSOR_STACKWALKER_PPC_H__
|
||||||
|
|
||||||
|
|
||||||
#include "google/airbag_types.h"
|
#include "google_airbag/common/airbag_types.h"
|
||||||
#include "processor/stackwalker.h"
|
#include "google_airbag/common/minidump_format.h"
|
||||||
#include "processor/minidump_format.h"
|
#include "google_airbag/processor/stackwalker.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
|
@ -39,12 +39,12 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "google/airbag_types.h"
|
#include "google_airbag/common/airbag_types.h"
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/common/minidump_format.h"
|
||||||
#include "google/stack_frame.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
#include "google/stack_frame_cpu.h"
|
#include "google_airbag/processor/memory_region.h"
|
||||||
#include "processor/memory_region.h"
|
#include "google_airbag/processor/stack_frame.h"
|
||||||
#include "processor/minidump_format.h"
|
#include "google_airbag/processor/stack_frame_cpu.h"
|
||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
|
|
||||||
using google_airbag::CallStack;
|
using google_airbag::CallStack;
|
||||||
|
@ -37,10 +37,10 @@
|
|||||||
#include "processor/postfix_evaluator-inl.h"
|
#include "processor/postfix_evaluator-inl.h"
|
||||||
|
|
||||||
#include "processor/stackwalker_x86.h"
|
#include "processor/stackwalker_x86.h"
|
||||||
#include "google/call_stack.h"
|
#include "google_airbag/processor/call_stack.h"
|
||||||
#include "google/stack_frame_cpu.h"
|
#include "google_airbag/processor/minidump.h"
|
||||||
|
#include "google_airbag/processor/stack_frame_cpu.h"
|
||||||
#include "processor/linked_ptr.h"
|
#include "processor/linked_ptr.h"
|
||||||
#include "processor/minidump.h"
|
|
||||||
#include "processor/stack_frame_info.h"
|
#include "processor/stack_frame_info.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
@ -283,15 +283,15 @@ StackFrame* StackwalkerX86::GetCallerFrame(
|
|||||||
|
|
||||||
// These are nonvolatile (callee-save) registers, and the program string
|
// These are nonvolatile (callee-save) registers, and the program string
|
||||||
// may have filled them in.
|
// 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.ebx = dictionary["$ebx"];
|
||||||
frame->context_validity |= StackFrameX86::CONTEXT_VALID_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.esi = dictionary["$esi"];
|
||||||
frame->context_validity |= StackFrameX86::CONTEXT_VALID_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.edi = dictionary["$edi"];
|
||||||
frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI;
|
frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI;
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,9 @@
|
|||||||
#define PROCESSOR_STACKWALKER_X86_H__
|
#define PROCESSOR_STACKWALKER_X86_H__
|
||||||
|
|
||||||
|
|
||||||
#include "google/airbag_types.h"
|
#include "google_airbag/common/airbag_types.h"
|
||||||
#include "processor/stackwalker.h"
|
#include "google_airbag/common/minidump_format.h"
|
||||||
#include "processor/minidump_format.h"
|
#include "google_airbag/processor/stackwalker.h"
|
||||||
|
|
||||||
namespace google_airbag {
|
namespace google_airbag {
|
||||||
|
|
||||||
|
Binary file not shown.
666
toolkit/crashreporter/google-breakpad/src/processor/testdata/minidump2.dump.out
vendored
Executable file
666
toolkit/crashreporter/google-breakpad/src/processor/testdata/minidump2.dump.out
vendored
Executable file
File diff suppressed because one or more lines are too long
19
toolkit/crashreporter/google-breakpad/src/processor/testdata/minidump2.stackwalk.out
vendored
Executable file
19
toolkit/crashreporter/google-breakpad/src/processor/testdata/minidump2.stackwalk.out
vendored
Executable 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
|
@ -1,3 +1,4 @@
|
|||||||
|
MODULE 11111111-1111-1111-1111-111111111111 1 module1.pdb
|
||||||
FILE 1 file1_1.cc
|
FILE 1 file1_1.cc
|
||||||
FILE 2 file1_2.cc
|
FILE 2 file1_2.cc
|
||||||
FILE 3 file1_3.cc
|
FILE 3 file1_3.cc
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
MODULE 22222222-2222-2222-2222-222222222222 2 module2.pdb
|
||||||
FILE 1 file2_1.cc
|
FILE 1 file2_1.cc
|
||||||
FILE 2 file2_2.cc
|
FILE 2 file2_2.cc
|
||||||
FILE 3 file2_3.cc
|
FILE 3 file2_3.cc
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
|
MODULE 33333333-3333-3333-3333-333333333333 3 module3.pdb
|
||||||
FILE 1 file1.cc
|
FILE 1 file1.cc
|
||||||
FUNC 1000
|
FUNC 1000
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -28,47 +28,32 @@
|
|||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// This file is used to generate minidump2.dmp and minidump2.sym.
|
// 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.
|
// Then run test_app to generate a dump, and dump_syms to create the .sym file.
|
||||||
|
|
||||||
#include <windows.h>
|
#include <cstdio>
|
||||||
#include <dbghelp.h>
|
|
||||||
|
|
||||||
static LONG HandleException(EXCEPTION_POINTERS *exinfo) {
|
#include "client/windows/handler/exception_handler.h"
|
||||||
HANDLE dump_file = CreateFile("dump.dmp",
|
|
||||||
GENERIC_WRITE,
|
|
||||||
FILE_SHARE_WRITE,
|
|
||||||
NULL,
|
|
||||||
CREATE_ALWAYS,
|
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
MINIDUMP_EXCEPTION_INFORMATION except_info;
|
void callback(const std::wstring &id, void *context, bool succeeded) {
|
||||||
except_info.ThreadId = GetCurrentThreadId();
|
if (succeeded) {
|
||||||
except_info.ExceptionPointers = exinfo;
|
printf("dump guid is %ws\n", id.c_str());
|
||||||
except_info.ClientPointers = false;
|
} else {
|
||||||
|
printf("dump failed\n");
|
||||||
MiniDumpWriteDump(GetCurrentProcess(),
|
}
|
||||||
GetCurrentProcessId(),
|
exit(1);
|
||||||
dump_file,
|
|
||||||
MiniDumpNormal,
|
|
||||||
&except_info,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
CloseHandle(dump_file);
|
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashFunction() {
|
void CrashFunction() {
|
||||||
int *i = NULL;
|
int *i = reinterpret_cast<int*>(0x45);
|
||||||
*i = 5; // crash!
|
*i = 5; // crash!
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char **argv) {
|
||||||
__try {
|
google_airbag::ExceptionHandler eh(L".", callback, NULL, true);
|
||||||
CrashFunction();
|
CrashFunction();
|
||||||
} __except(HandleException(GetExceptionInformation())) {
|
printf("did not crash?\n");
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -39,20 +39,14 @@
|
|||||||
using std::wstring;
|
using std::wstring;
|
||||||
using google_airbag::PDBSourceLineWriter;
|
using google_airbag::PDBSourceLineWriter;
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int wmain(int argc, wchar_t **argv) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
fprintf(stderr, "Usage: %s <pdb file>\n", argv[0]);
|
fprintf(stderr, "Usage: %ws <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]);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PDBSourceLineWriter writer;
|
PDBSourceLineWriter writer;
|
||||||
if (!writer.Open(wstring(filename), PDBSourceLineWriter::PDB_FILE)) {
|
if (!writer.Open(wstring(argv[1]), PDBSourceLineWriter::ANY_FILE)) {
|
||||||
fprintf(stderr, "Open failed\n");
|
fprintf(stderr, "Open failed\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +183,10 @@
|
|||||||
RelativePath="..\..\..\common\windows\pdb_source_line_writer.h"
|
RelativePath="..\..\..\common\windows\pdb_source_line_writer.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\common\windows\string_utils-inl.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Resource Files"
|
Name="Resource Files"
|
||||||
|
@ -29,10 +29,25 @@
|
|||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# 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
|
Release/dump_syms.exe testdata/dump_syms_regtest.pdb | \
|
||||||
if diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.out >& testdata/dump_syms_regtest.diff; then
|
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
|
rm testdata/dump_syms_regtest.diff testdata/dump_syms_regtest.new
|
||||||
echo "PASS"
|
echo "PASS"
|
||||||
else
|
else
|
||||||
echo "FAIL, see testdata/dump_syms_regtest.[new|diff]"
|
echo "FAIL, see testdata/dump_syms_regtest.[new|diff]"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
exit $status
|
||||||
|
@ -46,6 +46,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/windows/string_utils-inl.h"
|
||||||
|
|
||||||
#include "common/windows/http_upload.h"
|
#include "common/windows/http_upload.h"
|
||||||
#include "common/windows/pdb_source_line_writer.h"
|
#include "common/windows/pdb_source_line_writer.h"
|
||||||
|
|
||||||
@ -55,6 +57,7 @@ using std::vector;
|
|||||||
using std::map;
|
using std::map;
|
||||||
using google_airbag::HTTPUpload;
|
using google_airbag::HTTPUpload;
|
||||||
using google_airbag::PDBSourceLineWriter;
|
using google_airbag::PDBSourceLineWriter;
|
||||||
|
using google_airbag::WindowsStringUtils;
|
||||||
|
|
||||||
// Extracts the file version information for the given filename,
|
// Extracts the file version information for the given filename,
|
||||||
// as a string, for example, "1.2.3.4". Returns true on success.
|
// 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];
|
wchar_t ver_string[24];
|
||||||
VS_FIXEDFILEINFO *file_info =
|
VS_FIXEDFILEINFO *file_info =
|
||||||
reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer);
|
reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer);
|
||||||
_snwprintf_s(ver_string, sizeof(ver_string) / sizeof(wchar_t), _TRUNCATE,
|
WindowsStringUtils::safe_swprintf(
|
||||||
L"%d.%d.%d.%d",
|
ver_string, sizeof(ver_string) / sizeof(ver_string[0]),
|
||||||
file_info->dwFileVersionMS >> 16,
|
L"%d.%d.%d.%d",
|
||||||
file_info->dwFileVersionMS & 0xffff,
|
file_info->dwFileVersionMS >> 16,
|
||||||
file_info->dwFileVersionLS >> 16,
|
file_info->dwFileVersionMS & 0xffff,
|
||||||
file_info->dwFileVersionLS & 0xffff);
|
file_info->dwFileVersionLS >> 16,
|
||||||
|
file_info->dwFileVersionLS & 0xffff);
|
||||||
*version = ver_string;
|
*version = ver_string;
|
||||||
return true;
|
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
|
// 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,
|
// 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.
|
// 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 *temp_file_path,
|
||||||
wstring *module_guid) {
|
wstring *module_guid,
|
||||||
|
int *module_age,
|
||||||
|
wstring *module_filename) {
|
||||||
google_airbag::PDBSourceLineWriter writer;
|
google_airbag::PDBSourceLineWriter writer;
|
||||||
if (!writer.Open(exe_file, PDBSourceLineWriter::EXE_FILE)) {
|
if (!writer.Open(file, PDBSourceLineWriter::ANY_FILE)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +120,13 @@ static bool DumpSymbolsToTempFile(const wchar_t *exe_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILE *temp_file = NULL;
|
FILE *temp_file = NULL;
|
||||||
|
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||||
if (_wfopen_s(&temp_file, temp_filename, L"w") != 0) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,37 +138,35 @@ static bool DumpSymbolsToTempFile(const wchar_t *exe_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*temp_file_path = temp_filename;
|
*temp_file_path = temp_filename;
|
||||||
*module_guid = writer.GetModuleGUID();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the base name of a file, e.g. strips off the path.
|
return writer.GetModuleInfo(module_guid, module_age, module_filename);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wmain(int argc, wchar_t *argv[]) {
|
int wmain(int argc, wchar_t *argv[]) {
|
||||||
if (argc < 3) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
const wchar_t *module = argv[1], *url = argv[2];
|
const wchar_t *module = argv[1], *url = argv[2];
|
||||||
wstring module_basename = GetBaseName(module);
|
|
||||||
|
|
||||||
wstring symbol_file, module_guid;
|
wstring symbol_file, module_guid, module_basename;
|
||||||
if (!DumpSymbolsToTempFile(module, &symbol_file, &module_guid)) {
|
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);
|
fwprintf(stderr, L"Could not get symbol data from %s\n", module);
|
||||||
return 1;
|
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;
|
map<wstring, wstring> parameters;
|
||||||
parameters[L"module"] = module_basename;
|
parameters[L"module"] = module_basename;
|
||||||
parameters[L"guid"] = module_guid;
|
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
|
// Don't make a missing version a hard error. Issue a warning, and let the
|
||||||
// server decide whether to reject files without versions.
|
// server decide whether to reject files without versions.
|
||||||
|
@ -188,6 +188,10 @@
|
|||||||
RelativePath="..\..\..\common\windows\pdb_source_line_writer.h"
|
RelativePath="..\..\..\common\windows\pdb_source_line_writer.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\common\windows\string_utils-inl.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Resource Files"
|
Name="Resource Files"
|
||||||
|
Loading…
Reference in New Issue
Block a user