Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c86860f5e2 | ||
|
ef04c53283 | ||
|
897c1bb4d6 | ||
|
7ac616335d | ||
|
5b47d9d474 | ||
|
622588226d | ||
|
be470f3a11 | ||
|
eb81077a4f | ||
|
8ba5453573 | ||
|
b0fbff302a | ||
|
43b75f42a7 | ||
|
8ca937a3a7 | ||
|
2b7360217e | ||
|
4aeb452cdd | ||
|
19a35ba066 | ||
|
5bf649f336 | ||
|
41f858a4d7 | ||
|
54d899d631 | ||
|
16ab317dfc | ||
|
d6eb7fa1b8 | ||
|
d2904bb421 | ||
|
7c7366dd6d | ||
|
55f879151c | ||
|
a4eb2e302c | ||
|
ccc06f4798 | ||
|
acb33ed38f | ||
|
2f77d4e41c | ||
|
0a5700b594 | ||
|
e0d5189f74 | ||
|
c32b7ad535 | ||
|
aad5d66fa5 | ||
|
e9df0305d3 | ||
|
a4283fc4cf | ||
|
259512f933 | ||
|
725a5dff8a | ||
|
63f4e5f479 | ||
|
7de07eed33 |
77
Makefile.am
77
Makefile.am
@ -168,6 +168,7 @@ src_libbreakpad_a_SOURCES = \
|
||||
src/google_breakpad/processor/exploitability.h \
|
||||
src/google_breakpad/processor/fast_source_line_resolver.h \
|
||||
src/google_breakpad/processor/memory_region.h \
|
||||
src/google_breakpad/processor/microdump.h \
|
||||
src/google_breakpad/processor/microdump_processor.h \
|
||||
src/google_breakpad/processor/minidump.h \
|
||||
src/google_breakpad/processor/minidump_processor.h \
|
||||
@ -211,6 +212,7 @@ src_libbreakpad_a_SOURCES = \
|
||||
src/processor/logging.cc \
|
||||
src/processor/map_serializers-inl.h \
|
||||
src/processor/map_serializers.h \
|
||||
src/processor/microdump.cc \
|
||||
src/processor/microdump_processor.cc \
|
||||
src/processor/minidump.cc \
|
||||
src/processor/minidump_processor.cc \
|
||||
@ -299,6 +301,7 @@ src_third_party_libdisasm_libdisasm_a_SOURCES = \
|
||||
|
||||
## Programs
|
||||
bin_PROGRAMS += \
|
||||
src/processor/microdump_stackwalk \
|
||||
src/processor/minidump_dump \
|
||||
src/processor/minidump_stackwalk
|
||||
endif !DISABLE_PROCESSOR
|
||||
@ -373,6 +376,8 @@ endif !DISABLE_PROCESSOR
|
||||
|
||||
if !DISABLE_PROCESSOR
|
||||
check_SCRIPTS = \
|
||||
src/processor/microdump_stackwalk_test \
|
||||
src/processor/microdump_stackwalk_machine_readable_test \
|
||||
src/processor/minidump_dump_test \
|
||||
src/processor/minidump_stackwalk_test \
|
||||
src/processor/minidump_stackwalk_machine_readable_test
|
||||
@ -433,6 +438,10 @@ if ANDROID_HOST
|
||||
src_client_linux_linux_client_unittest_shlib_SOURCES += \
|
||||
src/common/android/breakpad_getcontext.S
|
||||
endif
|
||||
if LINUX_HOST
|
||||
src_client_linux_linux_client_unittest_shlib_SOURCES += \
|
||||
src/client/linux/microdump_writer/microdump_writer_unittest.cc
|
||||
endif
|
||||
|
||||
src_client_linux_linux_client_unittest_shlib_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
@ -704,10 +713,10 @@ src_processor_exploitability_unittest_LDADD = \
|
||||
src/processor/stack_frame_cpu.o \
|
||||
src/processor/stack_frame_symbolizer.o \
|
||||
src/processor/stackwalker.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_amd64.o \
|
||||
src/processor/stackwalker_arm.o \
|
||||
src/processor/stackwalker_arm64.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_mips.o \
|
||||
src/processor/stackwalker_ppc.o \
|
||||
src/processor/stackwalker_ppc64.o \
|
||||
@ -781,6 +790,31 @@ src_processor_microdump_processor_unittest_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
-I$(top_srcdir)/src/testing
|
||||
src_processor_microdump_processor_unittest_LDADD = \
|
||||
src/processor/basic_code_modules.o \
|
||||
src/processor/basic_source_line_resolver.o \
|
||||
src/processor/call_stack.o \
|
||||
src/processor/cfi_frame_info.o \
|
||||
src/processor/dump_context.o \
|
||||
src/processor/dump_object.o \
|
||||
src/processor/logging.o \
|
||||
src/processor/microdump.o \
|
||||
src/processor/microdump_processor.o \
|
||||
src/processor/pathname_stripper.o \
|
||||
src/processor/process_state.o \
|
||||
src/processor/simple_symbol_supplier.o \
|
||||
src/processor/source_line_resolver_base.o \
|
||||
src/processor/stack_frame_symbolizer.o \
|
||||
src/processor/stackwalker.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_amd64.o \
|
||||
src/processor/stackwalker_arm.o \
|
||||
src/processor/stackwalker_arm64.o \
|
||||
src/processor/stackwalker_mips.o \
|
||||
src/processor/stackwalker_ppc.o \
|
||||
src/processor/stackwalker_ppc64.o \
|
||||
src/processor/stackwalker_sparc.o \
|
||||
src/processor/stackwalker_x86.o \
|
||||
src/processor/tokenize.o \
|
||||
$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
|
||||
|
||||
src_processor_minidump_processor_unittest_SOURCES = \
|
||||
@ -813,10 +847,10 @@ src_processor_minidump_processor_unittest_LDADD = \
|
||||
src/processor/stack_frame_cpu.o \
|
||||
src/processor/stack_frame_symbolizer.o \
|
||||
src/processor/stackwalker.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_amd64.o \
|
||||
src/processor/stackwalker_arm.o \
|
||||
src/processor/stackwalker_arm64.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_mips.o \
|
||||
src/processor/stackwalker_ppc.o \
|
||||
src/processor/stackwalker_ppc64.o \
|
||||
@ -945,10 +979,10 @@ src_processor_stackwalker_selftest_LDADD = \
|
||||
src/processor/stack_frame_cpu.o \
|
||||
src/processor/stack_frame_symbolizer.o \
|
||||
src/processor/stackwalker.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_amd64.o \
|
||||
src/processor/stackwalker_arm.o \
|
||||
src/processor/stackwalker_arm64.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_mips.o \
|
||||
src/processor/stackwalker_ppc.o \
|
||||
src/processor/stackwalker_ppc64.o \
|
||||
@ -1099,6 +1133,40 @@ src_processor_minidump_dump_LDADD = \
|
||||
src/processor/minidump.o \
|
||||
src/processor/pathname_stripper.o
|
||||
|
||||
src_processor_microdump_stackwalk_SOURCES = \
|
||||
src/processor/microdump_stackwalk.cc
|
||||
src_processor_microdump_stackwalk_LDADD = \
|
||||
src/processor/basic_code_modules.o \
|
||||
src/processor/basic_source_line_resolver.o \
|
||||
src/processor/binarystream.o \
|
||||
src/processor/call_stack.o \
|
||||
src/processor/cfi_frame_info.o \
|
||||
src/processor/disassembler_x86.o \
|
||||
src/processor/dump_context.o \
|
||||
src/processor/dump_object.o \
|
||||
src/processor/logging.o \
|
||||
src/processor/microdump.o \
|
||||
src/processor/microdump_processor.o \
|
||||
src/processor/pathname_stripper.o \
|
||||
src/processor/process_state.o \
|
||||
src/processor/simple_symbol_supplier.o \
|
||||
src/processor/source_line_resolver_base.o \
|
||||
src/processor/stack_frame_cpu.o \
|
||||
src/processor/stack_frame_symbolizer.o \
|
||||
src/processor/stackwalk_common.o \
|
||||
src/processor/stackwalker.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_amd64.o \
|
||||
src/processor/stackwalker_arm.o \
|
||||
src/processor/stackwalker_arm64.o \
|
||||
src/processor/stackwalker_mips.o \
|
||||
src/processor/stackwalker_ppc.o \
|
||||
src/processor/stackwalker_ppc64.o \
|
||||
src/processor/stackwalker_sparc.o \
|
||||
src/processor/stackwalker_x86.o \
|
||||
src/processor/tokenize.o \
|
||||
src/third_party/libdisasm/libdisasm.a
|
||||
|
||||
src_processor_minidump_stackwalk_SOURCES = \
|
||||
src/processor/minidump_stackwalk.cc
|
||||
src_processor_minidump_stackwalk_LDADD = \
|
||||
@ -1122,11 +1190,12 @@ src_processor_minidump_stackwalk_LDADD = \
|
||||
src/processor/source_line_resolver_base.o \
|
||||
src/processor/stack_frame_cpu.o \
|
||||
src/processor/stack_frame_symbolizer.o \
|
||||
src/processor/stackwalk_common.o \
|
||||
src/processor/stackwalker.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_amd64.o \
|
||||
src/processor/stackwalker_arm.o \
|
||||
src/processor/stackwalker_arm64.o \
|
||||
src/processor/stackwalker_address_list.o \
|
||||
src/processor/stackwalker_mips.o \
|
||||
src/processor/stackwalker_ppc.o \
|
||||
src/processor/stackwalker_ppc64.o \
|
||||
|
222
Makefile.in
222
Makefile.in
@ -145,6 +145,7 @@ check_PROGRAMS = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ src/common/android/breakpad_getcontext.S
|
||||
|
||||
@DISABLE_PROCESSOR_FALSE@am__append_11 = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk
|
||||
|
||||
@ -198,12 +199,16 @@ check_PROGRAMS = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
|
||||
@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__append_17 = \
|
||||
@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@ src/processor/stackwalker_selftest
|
||||
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_18 = src/common/android/breakpad_getcontext.S \
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ src/common/android/breakpad_getcontext_unittest.cc
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_18 = \
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ src/common/android/breakpad_getcontext.S
|
||||
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_19 = \
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ -llog -lm
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ src/common/android/breakpad_getcontext_unittest.cc
|
||||
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_20 = \
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ -llog -lm
|
||||
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_21 = \
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ -llog
|
||||
|
||||
noinst_PROGRAMS =
|
||||
@ -342,6 +347,7 @@ am__src_libbreakpad_a_SOURCES_DIST = \
|
||||
src/google_breakpad/processor/exploitability.h \
|
||||
src/google_breakpad/processor/fast_source_line_resolver.h \
|
||||
src/google_breakpad/processor/memory_region.h \
|
||||
src/google_breakpad/processor/microdump.h \
|
||||
src/google_breakpad/processor/microdump_processor.h \
|
||||
src/google_breakpad/processor/minidump.h \
|
||||
src/google_breakpad/processor/minidump_processor.h \
|
||||
@ -378,7 +384,7 @@ am__src_libbreakpad_a_SOURCES_DIST = \
|
||||
src/processor/fast_source_line_resolver.cc \
|
||||
src/processor/linked_ptr.h src/processor/logging.h \
|
||||
src/processor/logging.cc src/processor/map_serializers-inl.h \
|
||||
src/processor/map_serializers.h \
|
||||
src/processor/map_serializers.h src/processor/microdump.cc \
|
||||
src/processor/microdump_processor.cc src/processor/minidump.cc \
|
||||
src/processor/minidump_processor.cc \
|
||||
src/processor/module_comparer.cc \
|
||||
@ -442,6 +448,7 @@ am__src_libbreakpad_a_SOURCES_DIST = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.$(OBJEXT) \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.$(OBJEXT) \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.$(OBJEXT) \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.$(OBJEXT) \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.$(OBJEXT) \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.$(OBJEXT) \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.$(OBJEXT) \
|
||||
@ -510,7 +517,7 @@ am__src_third_party_libdisasm_libdisasm_a_SOURCES_DIST = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_operand_list.$(OBJEXT)
|
||||
src_third_party_libdisasm_libdisasm_a_OBJECTS = \
|
||||
$(am_src_third_party_libdisasm_libdisasm_a_OBJECTS)
|
||||
@DISABLE_PROCESSOR_FALSE@am__EXEEXT_1 = \
|
||||
@DISABLE_PROCESSOR_FALSE@am__EXEEXT_1 = src/processor/microdump_stackwalk$(EXEEXT) \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump$(EXEEXT) \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk$(EXEEXT)
|
||||
@LINUX_HOST_TRUE@am__EXEEXT_2 = src/client/linux/linux_dumper_unittest_helper$(EXEEXT)
|
||||
@ -580,9 +587,10 @@ am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST = \
|
||||
src/processor/logging.cc src/processor/minidump.cc \
|
||||
src/processor/pathname_stripper.cc \
|
||||
src/common/android/breakpad_getcontext.S \
|
||||
src/client/linux/microdump_writer/microdump_writer_unittest.cc \
|
||||
src/common/android/breakpad_getcontext_unittest.cc
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__objects_2 = src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.$(OBJEXT) \
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.$(OBJEXT)
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__objects_2 = src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.$(OBJEXT)
|
||||
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__objects_3 = src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.$(OBJEXT)
|
||||
@LINUX_HOST_TRUE@am_src_client_linux_linux_client_unittest_shlib_OBJECTS = src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.$(OBJEXT) \
|
||||
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.$(OBJEXT) \
|
||||
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.$(OBJEXT) \
|
||||
@ -607,7 +615,9 @@ am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST = \
|
||||
@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-logging.$(OBJEXT) \
|
||||
@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-minidump.$(OBJEXT) \
|
||||
@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.$(OBJEXT) \
|
||||
@LINUX_HOST_TRUE@ $(am__objects_2)
|
||||
@LINUX_HOST_TRUE@ $(am__objects_2) \
|
||||
@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.$(OBJEXT) \
|
||||
@LINUX_HOST_TRUE@ $(am__objects_3)
|
||||
src_client_linux_linux_client_unittest_shlib_OBJECTS = \
|
||||
$(am_src_client_linux_linux_client_unittest_shlib_OBJECTS)
|
||||
am__DEPENDENCIES_1 =
|
||||
@ -843,10 +853,10 @@ src_processor_exploitability_unittest_OBJECTS = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@ -899,8 +909,69 @@ am__src_processor_microdump_processor_unittest_SOURCES_DIST = \
|
||||
src_processor_microdump_processor_unittest_OBJECTS = \
|
||||
$(am_src_processor_microdump_processor_unittest_OBJECTS)
|
||||
@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_DEPENDENCIES = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \
|
||||
@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1)
|
||||
am__src_processor_microdump_stackwalk_SOURCES_DIST = \
|
||||
src/processor/microdump_stackwalk.cc
|
||||
@DISABLE_PROCESSOR_FALSE@am_src_processor_microdump_stackwalk_OBJECTS = src/processor/microdump_stackwalk.$(OBJEXT)
|
||||
src_processor_microdump_stackwalk_OBJECTS = \
|
||||
$(am_src_processor_microdump_stackwalk_OBJECTS)
|
||||
@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_DEPENDENCIES = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/binarystream.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a
|
||||
am__src_processor_minidump_dump_SOURCES_DIST = \
|
||||
src/processor/minidump_dump.cc
|
||||
@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_dump_OBJECTS = src/processor/minidump_dump.$(OBJEXT)
|
||||
@ -942,10 +1013,10 @@ src_processor_minidump_processor_unittest_OBJECTS = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@ -981,11 +1052,12 @@ src_processor_minidump_stackwalk_OBJECTS = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@ -1151,10 +1223,10 @@ src_processor_stackwalker_selftest_OBJECTS = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@ -1406,6 +1478,7 @@ SOURCES = $(src_client_linux_libbreakpad_client_a_SOURCES) \
|
||||
$(src_processor_fast_source_line_resolver_unittest_SOURCES) \
|
||||
$(src_processor_map_serializers_unittest_SOURCES) \
|
||||
$(src_processor_microdump_processor_unittest_SOURCES) \
|
||||
$(src_processor_microdump_stackwalk_SOURCES) \
|
||||
$(src_processor_minidump_dump_SOURCES) \
|
||||
$(src_processor_minidump_processor_unittest_SOURCES) \
|
||||
$(src_processor_minidump_stackwalk_SOURCES) \
|
||||
@ -1450,6 +1523,7 @@ DIST_SOURCES = \
|
||||
$(am__src_processor_fast_source_line_resolver_unittest_SOURCES_DIST) \
|
||||
$(am__src_processor_map_serializers_unittest_SOURCES_DIST) \
|
||||
$(am__src_processor_microdump_processor_unittest_SOURCES_DIST) \
|
||||
$(am__src_processor_microdump_stackwalk_SOURCES_DIST) \
|
||||
$(am__src_processor_minidump_dump_SOURCES_DIST) \
|
||||
$(am__src_processor_minidump_processor_unittest_SOURCES_DIST) \
|
||||
$(am__src_processor_minidump_stackwalk_SOURCES_DIST) \
|
||||
@ -1888,6 +1962,7 @@ lib_LIBRARIES = $(am__append_5) $(am__append_8)
|
||||
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/exploitability.h \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/fast_source_line_resolver.h \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/memory_region.h \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/microdump.h \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/microdump_processor.h \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/minidump.h \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/minidump_processor.h \
|
||||
@ -1931,6 +2006,7 @@ lib_LIBRARIES = $(am__append_5) $(am__append_8)
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.cc \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers-inl.h \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers.h \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.cc \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.cc \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.cc \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.cc \
|
||||
@ -2017,6 +2093,8 @@ lib_LIBRARIES = $(am__append_5) $(am__append_8)
|
||||
@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_operand_list.h
|
||||
|
||||
@DISABLE_PROCESSOR_FALSE@check_SCRIPTS = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk_test \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk_machine_readable_test \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump_test \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk_test \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk_machine_readable_test
|
||||
@ -2063,7 +2141,9 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@LINUX_HOST_TRUE@ src/processor/logging.cc \
|
||||
@LINUX_HOST_TRUE@ src/processor/minidump.cc \
|
||||
@LINUX_HOST_TRUE@ src/processor/pathname_stripper.cc \
|
||||
@LINUX_HOST_TRUE@ $(am__append_18)
|
||||
@LINUX_HOST_TRUE@ $(am__append_18) \
|
||||
@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer_unittest.cc \
|
||||
@LINUX_HOST_TRUE@ $(am__append_19)
|
||||
@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_CPPFLAGS = \
|
||||
@LINUX_HOST_TRUE@ -I$(top_srcdir)/src \
|
||||
@LINUX_HOST_TRUE@ -I$(top_srcdir)/src/testing/include \
|
||||
@ -2073,7 +2153,7 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
|
||||
@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_LDFLAGS = \
|
||||
@LINUX_HOST_TRUE@ -shared -Wl,-h,linux_client_unittest_shlib \
|
||||
@LINUX_HOST_TRUE@ $(am__append_19)
|
||||
@LINUX_HOST_TRUE@ $(am__append_20)
|
||||
@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_LDADD = \
|
||||
@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_client.o \
|
||||
@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/seccomp_unwinder.o \
|
||||
@ -2105,7 +2185,7 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
|
||||
@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_SOURCES =
|
||||
@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_LDFLAGS = \
|
||||
@LINUX_HOST_TRUE@ -Wl,-rpath,'$$ORIGIN' $(am__append_20)
|
||||
@LINUX_HOST_TRUE@ -Wl,-rpath,'$$ORIGIN' $(am__append_21)
|
||||
@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_LDADD = \
|
||||
@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib
|
||||
|
||||
@ -2332,10 +2412,10 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@ -2417,6 +2497,31 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing
|
||||
|
||||
@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_LDADD = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
|
||||
|
||||
@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_SOURCES = \
|
||||
@ -2451,10 +2556,10 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@ -2597,10 +2702,10 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@ -2763,6 +2868,41 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o
|
||||
|
||||
@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_SOURCES = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk.cc
|
||||
|
||||
@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_LDADD = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/binarystream.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a
|
||||
|
||||
@DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_SOURCES = \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk.cc
|
||||
|
||||
@ -2787,11 +2927,12 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \
|
||||
@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \
|
||||
@ -3199,6 +3340,8 @@ src/processor/fast_source_line_resolver.$(OBJEXT): \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/logging.$(OBJEXT): src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/microdump.$(OBJEXT): src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
src/processor/microdump_processor.$(OBJEXT): \
|
||||
src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
@ -3473,6 +3616,9 @@ src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.$(O
|
||||
src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.$(OBJEXT): \
|
||||
src/common/android/$(am__dirstamp) \
|
||||
src/common/android/$(DEPDIR)/$(am__dirstamp)
|
||||
src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.$(OBJEXT): \
|
||||
src/client/linux/microdump_writer/$(am__dirstamp) \
|
||||
src/client/linux/microdump_writer/$(DEPDIR)/$(am__dirstamp)
|
||||
src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.$(OBJEXT): \
|
||||
src/common/android/$(am__dirstamp) \
|
||||
src/common/android/$(DEPDIR)/$(am__dirstamp)
|
||||
@ -3781,6 +3927,13 @@ src/testing/src/src_processor_microdump_processor_unittest-gmock-all.$(OBJEXT):
|
||||
src/processor/microdump_processor_unittest$(EXEEXT): $(src_processor_microdump_processor_unittest_OBJECTS) $(src_processor_microdump_processor_unittest_DEPENDENCIES) $(EXTRA_src_processor_microdump_processor_unittest_DEPENDENCIES) src/processor/$(am__dirstamp)
|
||||
@rm -f src/processor/microdump_processor_unittest$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(src_processor_microdump_processor_unittest_OBJECTS) $(src_processor_microdump_processor_unittest_LDADD) $(LIBS)
|
||||
src/processor/microdump_stackwalk.$(OBJEXT): \
|
||||
src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
|
||||
src/processor/microdump_stackwalk$(EXEEXT): $(src_processor_microdump_stackwalk_OBJECTS) $(src_processor_microdump_stackwalk_DEPENDENCIES) $(EXTRA_src_processor_microdump_stackwalk_DEPENDENCIES) src/processor/$(am__dirstamp)
|
||||
@rm -f src/processor/microdump_stackwalk$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(src_processor_microdump_stackwalk_OBJECTS) $(src_processor_microdump_stackwalk_LDADD) $(LIBS)
|
||||
src/processor/minidump_dump.$(OBJEXT): src/processor/$(am__dirstamp) \
|
||||
src/processor/$(DEPDIR)/$(am__dirstamp)
|
||||
|
||||
@ -4199,6 +4352,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/log/$(DEPDIR)/log.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/microdump_writer/$(DEPDIR)/microdump_writer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po@am__quote@
|
||||
@ -4313,7 +4467,9 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/exploitability_win.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/fast_source_line_resolver.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/logging.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/microdump.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/microdump_processor.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/microdump_stackwalk.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_dump.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_processor.Po@am__quote@
|
||||
@ -4854,6 +5010,20 @@ src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.obj
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.obj `if test -f 'src/processor/pathname_stripper.cc'; then $(CYGPATH_W) 'src/processor/pathname_stripper.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/pathname_stripper.cc'; fi`
|
||||
|
||||
src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o: src/client/linux/microdump_writer/microdump_writer_unittest.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o -MD -MP -MF src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Tpo -c -o src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o `test -f 'src/client/linux/microdump_writer/microdump_writer_unittest.cc' || echo '$(srcdir)/'`src/client/linux/microdump_writer/microdump_writer_unittest.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Tpo src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/microdump_writer/microdump_writer_unittest.cc' object='src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o `test -f 'src/client/linux/microdump_writer/microdump_writer_unittest.cc' || echo '$(srcdir)/'`src/client/linux/microdump_writer/microdump_writer_unittest.cc
|
||||
|
||||
src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj: src/client/linux/microdump_writer/microdump_writer_unittest.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj -MD -MP -MF src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Tpo -c -o src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj `if test -f 'src/client/linux/microdump_writer/microdump_writer_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/microdump_writer/microdump_writer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/microdump_writer/microdump_writer_unittest.cc'; fi`
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Tpo src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/microdump_writer/microdump_writer_unittest.cc' object='src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj `if test -f 'src/client/linux/microdump_writer/microdump_writer_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/microdump_writer/microdump_writer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/microdump_writer/microdump_writer_unittest.cc'; fi`
|
||||
|
||||
src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.o: src/common/android/breakpad_getcontext_unittest.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.o -MD -MP -MF src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Tpo -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.o `test -f 'src/common/android/breakpad_getcontext_unittest.cc' || echo '$(srcdir)/'`src/common/android/breakpad_getcontext_unittest.cc
|
||||
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Tpo src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po
|
||||
@ -7455,6 +7625,20 @@ src/processor/stackwalker_selftest.log: src/processor/stackwalker_selftest$(EXEE
|
||||
--log-file $$b.log --trs-file $$b.trs \
|
||||
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
|
||||
"$$tst" $(AM_TESTS_FD_REDIRECT)
|
||||
src/processor/microdump_stackwalk_test.log: src/processor/microdump_stackwalk_test
|
||||
@p='src/processor/microdump_stackwalk_test'; \
|
||||
b='src/processor/microdump_stackwalk_test'; \
|
||||
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
|
||||
--log-file $$b.log --trs-file $$b.trs \
|
||||
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
|
||||
"$$tst" $(AM_TESTS_FD_REDIRECT)
|
||||
src/processor/microdump_stackwalk_machine_readable_test.log: src/processor/microdump_stackwalk_machine_readable_test
|
||||
@p='src/processor/microdump_stackwalk_machine_readable_test'; \
|
||||
b='src/processor/microdump_stackwalk_machine_readable_test'; \
|
||||
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
|
||||
--log-file $$b.log --trs-file $$b.trs \
|
||||
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
|
||||
"$$tst" $(AM_TESTS_FD_REDIRECT)
|
||||
src/processor/minidump_dump_test.log: src/processor/minidump_dump_test
|
||||
@p='src/processor/minidump_dump_test'; \
|
||||
b='src/processor/minidump_dump_test'; \
|
||||
|
@ -45,7 +45,7 @@
|
||||
#import "client/mac/handler/protected_memory_allocator.h"
|
||||
#import "common/simple_string_dictionary.h"
|
||||
|
||||
#ifndef __EXCEPTIONS
|
||||
#if !defined(__EXCEPTIONS) || (__clang__ && !__has_feature(cxx_exceptions))
|
||||
// This file uses C++ try/catch (but shouldn't). Duplicate the macros from
|
||||
// <c++/4.2.1/exception_defines.h> allowing this file to work properly with
|
||||
// exceptions disabled even when other C++ libraries are used. #undef the try
|
||||
|
@ -44,8 +44,8 @@ void SeccompUnwinder::PopSeccompStackFrame(RawContextCPU* cpu,
|
||||
uint64_t top = thread.stack.start_of_memory_range;
|
||||
for (int i = 4; i--; ) {
|
||||
if (bp < top ||
|
||||
bp + sizeof(bp) > thread.stack.start_of_memory_range +
|
||||
thread.stack.memory.data_size ||
|
||||
bp > thread.stack.start_of_memory_range +
|
||||
thread.stack.memory.data_size - sizeof(bp) ||
|
||||
bp & 1) {
|
||||
break;
|
||||
}
|
||||
@ -107,8 +107,8 @@ void SeccompUnwinder::PopSeccompStackFrame(RawContextCPU* cpu,
|
||||
uint32_t top = thread.stack.start_of_memory_range;
|
||||
for (int i = 4; i--; ) {
|
||||
if (bp < top ||
|
||||
bp + sizeof(bp) > thread.stack.start_of_memory_range +
|
||||
thread.stack.memory.data_size ||
|
||||
bp > thread.stack.start_of_memory_range +
|
||||
thread.stack.memory.data_size - sizeof(bp) ||
|
||||
bp & 1) {
|
||||
break;
|
||||
}
|
||||
|
@ -178,12 +178,8 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
||||
out->flt_save.data_offset = fpregs.rdp;
|
||||
out->flt_save.data_selector = 0; // We don't have this.
|
||||
out->flt_save.mx_csr = fpregs.mxcsr;
|
||||
#if defined (__ANDROID__)
|
||||
// Internal bug b/18097559
|
||||
out->flt_save.mx_csr_mask = fpregs.mxcsr_mask;
|
||||
#else
|
||||
out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
|
||||
#endif
|
||||
|
||||
my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
|
||||
my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
|
||||
}
|
||||
|
@ -188,6 +188,24 @@ void RestoreAlternateStackLocked() {
|
||||
stack_installed = false;
|
||||
}
|
||||
|
||||
void InstallDefaultHandler(int sig) {
|
||||
#if defined(__ANDROID__)
|
||||
// Android L+ expose signal and sigaction symbols that override the system
|
||||
// ones. There is a bug in these functions where a request to set the handler
|
||||
// to SIG_DFL is ignored. In that case, an infinite loop is entered as the
|
||||
// signal is repeatedly sent to breakpad's signal handler.
|
||||
// To work around this, directly call the system's sigaction.
|
||||
struct kernel_sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sys_sigemptyset(&sa.sa_mask);
|
||||
sa.sa_handler_ = SIG_DFL;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sys_rt_sigaction(sig, &sa, NULL, sizeof(kernel_sigset_t));
|
||||
#else
|
||||
signal(sig, SIG_DFL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The global exception handler stack. This is needed because there may exist
|
||||
// multiple ExceptionHandler instances in a process. Each will have itself
|
||||
// registered in this stack.
|
||||
@ -283,7 +301,7 @@ void ExceptionHandler::RestoreHandlersLocked() {
|
||||
|
||||
for (int i = 0; i < kNumHandledSignals; ++i) {
|
||||
if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) {
|
||||
signal(kExceptionSignals[i], SIG_DFL);
|
||||
InstallDefaultHandler(kExceptionSignals[i]);
|
||||
}
|
||||
}
|
||||
handlers_installed = false;
|
||||
@ -323,7 +341,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
|
||||
if (sigaction(sig, &cur_handler, NULL) == -1) {
|
||||
// When resetting the handler fails, try to reset the
|
||||
// default one to avoid an infinite loop here.
|
||||
signal(sig, SIG_DFL);
|
||||
InstallDefaultHandler(sig);
|
||||
}
|
||||
pthread_mutex_unlock(&g_handler_stack_mutex_);
|
||||
return;
|
||||
@ -340,14 +358,15 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
|
||||
// previously installed handler. Then, when the signal is retriggered, it will
|
||||
// be delivered to the appropriate handler.
|
||||
if (handled) {
|
||||
signal(sig, SIG_DFL);
|
||||
InstallDefaultHandler(sig);
|
||||
} else {
|
||||
RestoreHandlersLocked();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_handler_stack_mutex_);
|
||||
|
||||
if (info->si_pid || sig == SIGABRT) {
|
||||
// info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise).
|
||||
if (info->si_code <= 0 || sig == SIGABRT) {
|
||||
// This signal was triggered by somebody sending us the signal with kill().
|
||||
// In order to retrigger it, we have to queue a new signal by calling
|
||||
// kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is
|
||||
|
@ -36,7 +36,8 @@
|
||||
namespace google_breakpad {
|
||||
|
||||
//static
|
||||
const MinidumpDescriptor::MicrodumpOnConsole kMicrodumpOnConsole = {};
|
||||
const MinidumpDescriptor::MicrodumpOnConsole
|
||||
MinidumpDescriptor::kMicrodumpOnConsole = {};
|
||||
|
||||
MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor)
|
||||
: mode_(descriptor.mode_),
|
||||
|
@ -38,9 +38,9 @@
|
||||
#include "client/linux/dump_writer_common/thread_info.h"
|
||||
#include "client/linux/dump_writer_common/ucontext_reader.h"
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#include "client/linux/log/log.h"
|
||||
#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "client/linux/log/log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -54,6 +54,8 @@ using google_breakpad::SeccompUnwinder;
|
||||
using google_breakpad::ThreadInfo;
|
||||
using google_breakpad::UContextReader;
|
||||
|
||||
const size_t kLineBufferSize = 2048;
|
||||
|
||||
class MicrodumpWriter {
|
||||
public:
|
||||
MicrodumpWriter(const ExceptionHandler::CrashContext* context,
|
||||
@ -64,12 +66,21 @@ class MicrodumpWriter {
|
||||
float_state_(context ? &context->float_state : NULL),
|
||||
#endif
|
||||
dumper_(dumper),
|
||||
mapping_list_(mappings) { }
|
||||
mapping_list_(mappings),
|
||||
log_line_(NULL) {
|
||||
log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize));
|
||||
if (log_line_)
|
||||
log_line_[0] = '\0'; // Clear out the log line buffer.
|
||||
}
|
||||
|
||||
~MicrodumpWriter() { dumper_->ThreadsResume(); }
|
||||
|
||||
bool Init() {
|
||||
if (!dumper_->Init())
|
||||
// In the exceptional case where the system was out of memory and there
|
||||
// wasn't even room to allocate the line buffer, bail out. There is nothing
|
||||
// useful we can possibly achieve without the ability to Log. At least let's
|
||||
// try to not crash.
|
||||
if (!dumper_->Init() || !log_line_)
|
||||
return false;
|
||||
return dumper_->ThreadsSuspend();
|
||||
}
|
||||
@ -91,11 +102,14 @@ class MicrodumpWriter {
|
||||
// Writes one line to the system log.
|
||||
void LogLine(const char* msg) {
|
||||
logger::write(msg, my_strlen(msg));
|
||||
#if !defined(__ANDROID__)
|
||||
logger::write("\n", 1); // Android logger appends the \n. Linux's doesn't.
|
||||
#endif
|
||||
}
|
||||
|
||||
// Stages the given string in the current line buffer.
|
||||
void LogAppend(const char* str) {
|
||||
my_strlcat(log_line_, str, sizeof(log_line_));
|
||||
my_strlcat(log_line_, str, kLineBufferSize);
|
||||
}
|
||||
|
||||
// As above (required to take precedence over template specialization below).
|
||||
@ -125,14 +139,15 @@ class MicrodumpWriter {
|
||||
|
||||
// Writes out the current line buffer on the system log.
|
||||
void LogCommitLine() {
|
||||
logger::write(log_line_, my_strlen(log_line_));
|
||||
my_strlcpy(log_line_, "", sizeof(log_line_));
|
||||
LogLine(log_line_);
|
||||
my_strlcpy(log_line_, "", kLineBufferSize);
|
||||
}
|
||||
|
||||
bool DumpOSInformation() {
|
||||
struct utsname uts;
|
||||
if (uname(&uts))
|
||||
return false;
|
||||
const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF));
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
const char kOSId[] = "A";
|
||||
@ -140,15 +155,34 @@ class MicrodumpWriter {
|
||||
const char kOSId[] = "L";
|
||||
#endif
|
||||
|
||||
// We cannot depend on uts.machine. On multiarch devices it always returns the
|
||||
// primary arch, not the one that match the executable being run.
|
||||
#if defined(__aarch64__)
|
||||
const char kArch[] = "arm64";
|
||||
#elif defined(__ARMEL__)
|
||||
const char kArch[] = "arm";
|
||||
#elif defined(__x86_64__)
|
||||
const char kArch[] = "x86_64";
|
||||
#elif defined(__i386__)
|
||||
const char kArch[] = "x86";
|
||||
#elif defined(__mips__)
|
||||
const char kArch[] = "mips";
|
||||
#else
|
||||
#error "This code has not been ported to your platform yet"
|
||||
#endif
|
||||
|
||||
LogAppend("O ");
|
||||
LogAppend(kOSId);
|
||||
LogAppend(" \"");
|
||||
LogAppend(" ");
|
||||
LogAppend(kArch);
|
||||
LogAppend(" ");
|
||||
LogAppend(n_cpus);
|
||||
LogAppend(" ");
|
||||
LogAppend(uts.machine);
|
||||
LogAppend("\" \"");
|
||||
LogAppend(" ");
|
||||
LogAppend(uts.release);
|
||||
LogAppend(" \"");
|
||||
LogAppend(" ");
|
||||
LogAppend(uts.version);
|
||||
LogAppend("\"");
|
||||
LogCommitLine();
|
||||
return true;
|
||||
}
|
||||
@ -162,8 +196,9 @@ class MicrodumpWriter {
|
||||
size_t stack_len;
|
||||
|
||||
if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
|
||||
assert(false);
|
||||
return false;
|
||||
// The stack pointer might not be available. In this case we don't hard
|
||||
// fail, just produce a (almost useless) microdump w/o a stack section.
|
||||
return true;
|
||||
}
|
||||
|
||||
LogAppend("S 0 ");
|
||||
@ -296,7 +331,7 @@ class MicrodumpWriter {
|
||||
LogAppend(module_identifier.data4[5]);
|
||||
LogAppend(module_identifier.data4[6]);
|
||||
LogAppend(module_identifier.data4[7]);
|
||||
LogAppend(" ");
|
||||
LogAppend("0 "); // Age is always 0 on Linux.
|
||||
LogAppend(file_name);
|
||||
LogCommitLine();
|
||||
}
|
||||
@ -306,15 +341,13 @@ class MicrodumpWriter {
|
||||
// First write all the mappings from the dumper
|
||||
for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
|
||||
const MappingInfo& mapping = *dumper_->mappings()[i];
|
||||
// Skip mappings which don't look like libraries.
|
||||
if (!strstr(mapping.name, ".so") || // dump only libs (skip fonts, apks).
|
||||
mapping.size < 4096) { // too small to get a signature for.
|
||||
if (mapping.name[0] == 0 || // only want modules with filenames.
|
||||
!mapping.exec || // only want executable mappings.
|
||||
mapping.size < 4096 || // too small to get a signature for.
|
||||
HaveMappingInfo(mapping)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HaveMappingInfo(mapping))
|
||||
continue;
|
||||
|
||||
DumpModule(mapping, true, i, NULL);
|
||||
}
|
||||
// Next write all the mappings provided by the caller
|
||||
@ -334,7 +367,7 @@ class MicrodumpWriter {
|
||||
#endif
|
||||
LinuxDumper* dumper_;
|
||||
const MappingList& mapping_list_;
|
||||
char log_line_[512];
|
||||
char* log_line_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
133
src/client/linux/microdump_writer/microdump_writer_unittest.cc
Normal file
133
src/client/linux/microdump_writer/microdump_writer_unittest.cc
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2014 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#include "client/linux/microdump_writer/microdump_writer.h"
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/linux/ignore_ret.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef testing::Test MicrodumpWriterTest;
|
||||
|
||||
TEST(MicrodumpWriterTest, Setup) {
|
||||
int fds[2];
|
||||
ASSERT_NE(-1, pipe(fds));
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string stderr_file = temp_dir.path() + "/stderr.log";
|
||||
int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
ASSERT_NE(-1, err_fd);
|
||||
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
close(fds[1]);
|
||||
char b;
|
||||
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
ExceptionHandler::CrashContext context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
|
||||
// Set a non-zero tid to avoid tripping asserts.
|
||||
context.tid = child;
|
||||
|
||||
// Push some extra mapping to check the MappingList logic.
|
||||
const uint32_t memory_size = sysconf(_SC_PAGESIZE);
|
||||
const char* kMemoryName = "libfoo.so";
|
||||
const uint8_t kModuleGUID[sizeof(MDGUID)] = {
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
|
||||
};
|
||||
|
||||
MappingInfo info;
|
||||
info.start_addr = memory_size;
|
||||
info.size = memory_size;
|
||||
info.offset = 42;
|
||||
strcpy(info.name, kMemoryName);
|
||||
|
||||
MappingList mappings;
|
||||
MappingEntry mapping;
|
||||
mapping.first = info;
|
||||
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
|
||||
mappings.push_back(mapping);
|
||||
|
||||
// Redirect temporarily stderr to the stderr.log file.
|
||||
int save_err = dup(STDERR_FILENO);
|
||||
ASSERT_NE(-1, save_err);
|
||||
ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO));
|
||||
|
||||
ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings));
|
||||
|
||||
// Revert stderr back to the console.
|
||||
dup2(save_err, STDERR_FILENO);
|
||||
close(save_err);
|
||||
|
||||
// Read back the stderr file and check for the microdump marker.
|
||||
fsync(err_fd);
|
||||
lseek(err_fd, 0, SEEK_SET);
|
||||
const size_t kBufSize = 64 * 1024;
|
||||
scoped_array<char> buf(new char[kBufSize]);
|
||||
ASSERT_GT(read(err_fd, buf.get(), kBufSize), 0);
|
||||
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "-----BEGIN BREAKPAD MICRODUMP-----"));
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "-----END BREAKPAD MICRODUMP-----"));
|
||||
|
||||
#ifdef __LP64__
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 "
|
||||
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
|
||||
#else
|
||||
ASSERT_NE(static_cast<char*>(0), strstr(
|
||||
buf.get(), "M 00001000 0000002A 00001000 "
|
||||
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
|
||||
#endif
|
||||
|
||||
close(err_fd);
|
||||
close(fds[1]);
|
||||
}
|
||||
|
||||
} // namespace
|
@ -74,7 +74,7 @@ bool LinuxCoreDumper::BuildProcPath(char* path, pid_t pid,
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
|
||||
bool LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
|
||||
const void* src, size_t length) {
|
||||
ElfCoreDump::Addr virtual_address = reinterpret_cast<ElfCoreDump::Addr>(src);
|
||||
// TODO(benchan): Investigate whether the data to be copied could span
|
||||
@ -84,7 +84,9 @@ void LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
|
||||
// If the data segment is not found in the core dump, fill the result
|
||||
// with marker characters.
|
||||
memset(dest, 0xab, length);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
|
||||
|
@ -68,8 +68,9 @@ class LinuxCoreDumper : public LinuxDumper {
|
||||
// Copies content of |length| bytes from a given process |child|,
|
||||
// starting from |src|, into |dest|. This method extracts the content
|
||||
// the core dump and fills |dest| with a sequence of marker bytes
|
||||
// if the expected data is not found in the core dump.
|
||||
virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
|
||||
// if the expected data is not found in the core dump. Returns true if
|
||||
// the expected data is found in the core dump.
|
||||
virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
|
||||
size_t length);
|
||||
|
||||
// Implements LinuxDumper::GetThreadInfoByIndex().
|
||||
|
@ -100,8 +100,8 @@ class LinuxDumper {
|
||||
PageAllocator* allocator() { return &allocator_; }
|
||||
|
||||
// Copy content of |length| bytes from a given process |child|,
|
||||
// starting from |src|, into |dest|.
|
||||
virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
|
||||
// starting from |src|, into |dest|. Returns true on success.
|
||||
virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
|
||||
size_t length) = 0;
|
||||
|
||||
// Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
|
||||
|
@ -130,7 +130,7 @@ bool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid,
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
|
||||
bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
|
||||
const void* src, size_t length) {
|
||||
unsigned long tmp = 55;
|
||||
size_t done = 0;
|
||||
@ -146,6 +146,7 @@ void LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
|
||||
my_memcpy(local + done, &tmp, l);
|
||||
done += l;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read thread info from /proc/$pid/status.
|
||||
@ -282,8 +283,10 @@ bool LinuxPtraceDumper::ThreadsSuspend() {
|
||||
// If the thread either disappeared before we could attach to it, or if
|
||||
// it was part of the seccomp sandbox's trusted code, it is OK to
|
||||
// silently drop it from the minidump.
|
||||
my_memmove(&threads_[i], &threads_[i+1],
|
||||
if (i < threads_.size() - 1) {
|
||||
my_memmove(&threads_[i], &threads_[i + 1],
|
||||
(threads_.size() - i - 1) * sizeof(threads_[i]));
|
||||
}
|
||||
threads_.resize(threads_.size() - 1);
|
||||
--i;
|
||||
}
|
||||
|
@ -55,8 +55,8 @@ class LinuxPtraceDumper : public LinuxDumper {
|
||||
// Implements LinuxDumper::CopyFromProcess().
|
||||
// Copies content of |length| bytes from a given process |child|,
|
||||
// starting from |src|, into |dest|. This method uses ptrace to extract
|
||||
// the content from the target process.
|
||||
virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
|
||||
// the content from the target process. Always returns true.
|
||||
virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
|
||||
size_t length);
|
||||
|
||||
// Implements LinuxDumper::GetThreadInfoByIndex().
|
||||
|
@ -75,6 +75,7 @@
|
||||
#include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
|
||||
#include "client/minidump_file_writer.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/minidump_type_helper.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
@ -86,6 +87,7 @@ using google_breakpad::CpuSet;
|
||||
using google_breakpad::LineReader;
|
||||
using google_breakpad::LinuxDumper;
|
||||
using google_breakpad::LinuxPtraceDumper;
|
||||
using google_breakpad::MDTypeHelper;
|
||||
using google_breakpad::MappingEntry;
|
||||
using google_breakpad::MappingInfo;
|
||||
using google_breakpad::MappingList;
|
||||
@ -100,6 +102,8 @@ using google_breakpad::UContextReader;
|
||||
using google_breakpad::UntypedMDRVA;
|
||||
using google_breakpad::wasteful_vector;
|
||||
|
||||
typedef MDTypeHelper<sizeof(void*)>::MDRawDebug MDRawDebug;
|
||||
typedef MDTypeHelper<sizeof(void*)>::MDRawLinkMap MDRawLinkMap;
|
||||
|
||||
class MinidumpWriter {
|
||||
public:
|
||||
@ -654,7 +658,9 @@ class MinidumpWriter {
|
||||
ElfW(Addr) dyn_addr = 0;
|
||||
for (; phnum >= 0; phnum--, phdr++) {
|
||||
ElfW(Phdr) ph;
|
||||
dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph));
|
||||
if (!dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph)))
|
||||
return false;
|
||||
|
||||
// Adjust base address with the virtual address of the PT_LOAD segment
|
||||
// corresponding to offset 0
|
||||
if (ph.p_type == PT_LOAD && ph.p_offset == 0) {
|
||||
@ -675,11 +681,14 @@ class MinidumpWriter {
|
||||
struct r_debug* r_debug = NULL;
|
||||
uint32_t dynamic_length = 0;
|
||||
|
||||
for (int i = 0;;) {
|
||||
for (int i = 0; ; ++i) {
|
||||
ElfW(Dyn) dyn;
|
||||
dynamic_length += sizeof(dyn);
|
||||
dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic+i++,
|
||||
sizeof(dyn));
|
||||
if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i,
|
||||
sizeof(dyn))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dyn.d_tag == DT_DEBUG) {
|
||||
r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
|
||||
continue;
|
||||
@ -699,11 +708,15 @@ class MinidumpWriter {
|
||||
// Count the number of loaded DSOs
|
||||
int dso_count = 0;
|
||||
struct r_debug debug_entry;
|
||||
dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
|
||||
sizeof(debug_entry));
|
||||
if (!dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
|
||||
sizeof(debug_entry))) {
|
||||
return false;
|
||||
}
|
||||
for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
|
||||
struct link_map map;
|
||||
dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
|
||||
if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
|
||||
return false;
|
||||
|
||||
ptr = map.l_next;
|
||||
dso_count++;
|
||||
}
|
||||
@ -721,7 +734,9 @@ class MinidumpWriter {
|
||||
// Iterate over DSOs and write their information to mini dump
|
||||
for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
|
||||
struct link_map map;
|
||||
dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
|
||||
if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
|
||||
return false;
|
||||
|
||||
ptr = map.l_next;
|
||||
char filename[257] = { 0 };
|
||||
if (map.l_name) {
|
||||
@ -733,8 +748,8 @@ class MinidumpWriter {
|
||||
return false;
|
||||
MDRawLinkMap entry;
|
||||
entry.name = location.rva;
|
||||
entry.addr = reinterpret_cast<void*>(map.l_addr);
|
||||
entry.ld = reinterpret_cast<void*>(map.l_ld);
|
||||
entry.addr = map.l_addr;
|
||||
entry.ld = reinterpret_cast<uintptr_t>(map.l_ld);
|
||||
linkmap.CopyIndex(idx++, &entry);
|
||||
}
|
||||
}
|
||||
@ -750,9 +765,9 @@ class MinidumpWriter {
|
||||
debug.get()->version = debug_entry.r_version;
|
||||
debug.get()->map = linkmap_rva;
|
||||
debug.get()->dso_count = dso_count;
|
||||
debug.get()->brk = reinterpret_cast<void*>(debug_entry.r_brk);
|
||||
debug.get()->ldbase = reinterpret_cast<void*>(debug_entry.r_ldbase);
|
||||
debug.get()->dynamic = dynamic;
|
||||
debug.get()->brk = debug_entry.r_brk;
|
||||
debug.get()->ldbase = debug_entry.r_ldbase;
|
||||
debug.get()->dynamic = reinterpret_cast<uintptr_t>(dynamic);
|
||||
|
||||
wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length);
|
||||
// The passed-in size to the constructor (above) is only a hint.
|
||||
|
@ -48,7 +48,7 @@
|
||||
#import "common/mac/MachIPC.h"
|
||||
#import "common/simple_string_dictionary.h"
|
||||
|
||||
#ifndef __EXCEPTIONS
|
||||
#if !defined(__EXCEPTIONS) || (__clang__ && !__has_feature(cxx_exceptions))
|
||||
// This file uses C++ try/catch (but shouldn't). Duplicate the macros from
|
||||
// <c++/4.2.1/exception_defines.h> allowing this file to work properly with
|
||||
// exceptions disabled even when other C++ libraries are used. #undef the try
|
||||
|
@ -174,6 +174,7 @@ void ExceptionHandler::Initialize(
|
||||
assertion_ = NULL;
|
||||
handler_return_value_ = false;
|
||||
handle_debug_exceptions_ = false;
|
||||
consume_invalid_handle_exceptions_ = false;
|
||||
|
||||
// Attempt to use out-of-process if user has specified a pipe or a
|
||||
// crash generation client.
|
||||
@ -481,6 +482,11 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
|
||||
bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
|
||||
(code == EXCEPTION_SINGLE_STEP);
|
||||
|
||||
if (code == EXCEPTION_INVALID_HANDLE &&
|
||||
current_handler->consume_invalid_handle_exceptions_) {
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (!is_debug_exception ||
|
||||
|
@ -263,6 +263,15 @@ class ExceptionHandler {
|
||||
handle_debug_exceptions_ = handle_debug_exceptions;
|
||||
}
|
||||
|
||||
// Controls behavior of EXCEPTION_INVALID_HANDLE.
|
||||
bool get_consume_invalid_handle_exceptions() const {
|
||||
return consume_invalid_handle_exceptions_;
|
||||
}
|
||||
void set_consume_invalid_handle_exceptions(
|
||||
bool consume_invalid_handle_exceptions) {
|
||||
consume_invalid_handle_exceptions_ = consume_invalid_handle_exceptions;
|
||||
}
|
||||
|
||||
// Returns whether out-of-process dump generation is used or not.
|
||||
bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; }
|
||||
|
||||
@ -472,6 +481,10 @@ class ExceptionHandler {
|
||||
// to not interfere with debuggers.
|
||||
bool handle_debug_exceptions_;
|
||||
|
||||
// If true, the handler will consume any EXCEPTION_INVALID_HANDLE exceptions.
|
||||
// Leave this false (the default) to handle these exceptions as normal.
|
||||
bool consume_invalid_handle_exceptions_;
|
||||
|
||||
// Callers can request additional memory regions to be included in
|
||||
// the dump.
|
||||
AppMemoryList app_memory_info_;
|
||||
|
@ -34,9 +34,11 @@
|
||||
// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code.
|
||||
// The following quirks are currently handled by this file:
|
||||
// - MIPS: Keep using forked definitions of user.h structs. The definition in
|
||||
// the NDK is completely different.
|
||||
// Internal bug b/18097715
|
||||
// the NDK is completely different. Internal bug b/18097715
|
||||
// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct.
|
||||
// - x86_64: Override a typo in user_fpregs_struct (mxcsr_mask -> mxcr_mask).
|
||||
// The typo has been fixed in NDK r10d, but a preprocessor workaround is
|
||||
// required to make breakpad build with r10c and lower (more details below).
|
||||
// - Other platforms: Just use the Android NDK unchanged.
|
||||
|
||||
#ifdef __mips__
|
||||
@ -113,8 +115,24 @@ struct user_fpregs_struct {
|
||||
|
||||
#else // __mips__
|
||||
|
||||
// TODO(primiano): remove this after Chromium has stably rolled to NDK r10d.
|
||||
// Historical context: NDK releases < r10d had a typo in sys/user.h (mxcsr_mask
|
||||
// instead of mxcr_mask), which is fixed in r10d. However, just switching to use
|
||||
// the correct one (mxcr_mask) would put Breakpad in a state where it can be
|
||||
// rolled in chromium only atomically with the r10d NDK. A revert of either
|
||||
// project (android_tools, breakpad) would make the other one unrollable.
|
||||
// This hack makes breakpad code compatible with both r10c and r10d NDKs,
|
||||
// reducing the dependency entangling with android_tools.
|
||||
#if defined(__x86_64__)
|
||||
#define mxcsr_mask mxcr_mask
|
||||
#endif
|
||||
|
||||
#include_next <sys/user.h>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#undef mxcsr_mask
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -1,23 +1,39 @@
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
|
||||
* Distributed under the Terms of Use in
|
||||
* http://www.unicode.org/copyright.html.
|
||||
*
|
||||
* Disclaimer
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of the Unicode data files and any associated documentation
|
||||
* (the "Data Files") or Unicode software and any associated documentation
|
||||
* (the "Software") to deal in the Data Files or Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
* the Data Files or Software, and to permit persons to whom the Data Files
|
||||
* or Software are furnished to do so, provided that
|
||||
* (a) this copyright and permission notice appear with all copies
|
||||
* of the Data Files or Software,
|
||||
* (b) this copyright and permission notice appear in associated
|
||||
* documentation, and
|
||||
* (c) there is clear notice in each modified Data File or in the Software
|
||||
* as well as in the documentation associated with the Data File(s) or
|
||||
* Software that the data or software has been modified.
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
* THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
* Except as contained in this notice, the name of a copyright holder
|
||||
* shall not be used in advertising or otherwise to promote the sale,
|
||||
* use or other dealings in these Data Files or Software without prior
|
||||
* written authorization of the copyright holder.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
@ -1,23 +1,39 @@
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
|
||||
* Distributed under the Terms of Use in
|
||||
* http://www.unicode.org/copyright.html.
|
||||
*
|
||||
* Disclaimer
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of the Unicode data files and any associated documentation
|
||||
* (the "Data Files") or Unicode software and any associated documentation
|
||||
* (the "Software") to deal in the Data Files or Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
* the Data Files or Software, and to permit persons to whom the Data Files
|
||||
* or Software are furnished to do so, provided that
|
||||
* (a) this copyright and permission notice appear with all copies
|
||||
* of the Data Files or Software,
|
||||
* (b) this copyright and permission notice appear in associated
|
||||
* documentation, and
|
||||
* (c) there is clear notice in each modified Data File or in the Software
|
||||
* as well as in the documentation associated with the Data File(s) or
|
||||
* Software that the data or software has been modified.
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
* THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
* Except as contained in this notice, the name of a copyright holder
|
||||
* shall not be used in advertising or otherwise to promote the sale,
|
||||
* use or other dealings in these Data Files or Software without prior
|
||||
* written authorization of the copyright holder.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_CONVERT_UTF_H_
|
||||
|
@ -183,14 +183,15 @@ const char* CompilationUnit::SkipAttribute(const char* start,
|
||||
case DW_FORM_addr:
|
||||
return start + reader_->AddressSize();
|
||||
case DW_FORM_ref_addr:
|
||||
// DWARF2 and 3 differ on whether ref_addr is address size or
|
||||
// DWARF2 and 3/4 differ on whether ref_addr is address size or
|
||||
// offset size.
|
||||
assert(header_.version == 2 || header_.version == 3);
|
||||
assert(header_.version >= 2);
|
||||
if (header_.version == 2) {
|
||||
return start + reader_->AddressSize();
|
||||
} else if (header_.version == 3) {
|
||||
} else if (header_.version >= 3) {
|
||||
return start + reader_->OffsetSize();
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_FORM_block1:
|
||||
return start + 1 + reader_->ReadOneByte(start);
|
||||
@ -390,14 +391,14 @@ const char* CompilationUnit::ProcessAttribute(
|
||||
+ offset_from_section_start_);
|
||||
return start + len;
|
||||
case DW_FORM_ref_addr:
|
||||
// DWARF2 and 3 differ on whether ref_addr is address size or
|
||||
// DWARF2 and 3/4 differ on whether ref_addr is address size or
|
||||
// offset size.
|
||||
assert(header_.version == 2 || header_.version == 3);
|
||||
assert(header_.version >= 2);
|
||||
if (header_.version == 2) {
|
||||
handler_->ProcessAttributeReference(dieoffset, attr, form,
|
||||
reader_->ReadAddress(start));
|
||||
return start + reader_->AddressSize();
|
||||
} else if (header_.version == 3) {
|
||||
} else if (header_.version >= 3) {
|
||||
handler_->ProcessAttributeReference(dieoffset, attr, form,
|
||||
reader_->ReadOffset(start));
|
||||
return start + reader_->OffsetSize();
|
||||
|
@ -351,9 +351,15 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
|
||||
break;
|
||||
case dwarf2reader::DW_AT_MIPS_linkage_name: {
|
||||
char* demangled = NULL;
|
||||
#if !defined(__ANDROID__)
|
||||
demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL);
|
||||
int status = -1;
|
||||
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
|
||||
demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, &status);
|
||||
#endif
|
||||
if (status != 0) {
|
||||
cu_context_->reporter->DemangleError(data, status);
|
||||
demangled_name_ = "";
|
||||
break;
|
||||
}
|
||||
if (demangled) {
|
||||
demangled_name_ = AddStringToPool(demangled);
|
||||
free(reinterpret_cast<void*>(demangled));
|
||||
@ -396,6 +402,18 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
|
||||
enclosing_name = &parent_context_->name;
|
||||
}
|
||||
|
||||
// Prepare the return value before upcoming mutations possibly invalidate the
|
||||
// existing pointers.
|
||||
string return_value;
|
||||
if (qualified_name) {
|
||||
return_value = *qualified_name;
|
||||
} else {
|
||||
// Combine the enclosing name and unqualified name to produce our
|
||||
// own fully-qualified name.
|
||||
return_value = cu_context_->language->MakeQualifiedName(*enclosing_name,
|
||||
*unqualified_name);
|
||||
}
|
||||
|
||||
// If this DIE was marked as a declaration, record its names in the
|
||||
// specification table.
|
||||
if (declaration_) {
|
||||
@ -409,13 +427,7 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
|
||||
cu_context_->file_context->file_private_->specifications[offset_] = spec;
|
||||
}
|
||||
|
||||
if (qualified_name)
|
||||
return *qualified_name;
|
||||
|
||||
// Combine the enclosing name and unqualified name to produce our
|
||||
// own fully-qualified name.
|
||||
return cu_context_->language->MakeQualifiedName(*enclosing_name,
|
||||
*unqualified_name);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// A handler class for DW_TAG_subprogram DIEs.
|
||||
@ -528,18 +540,19 @@ void DwarfCUToModule::FuncHandler::Finish() {
|
||||
// functions that were never used), but all the ones we're
|
||||
// interested in cover a non-empty range of bytes.
|
||||
if (low_pc_ < high_pc_) {
|
||||
// Create a Module::Function based on the data we've gathered, and
|
||||
// add it to the functions_ list.
|
||||
scoped_ptr<Module::Function> func(new Module::Function);
|
||||
// Malformed DWARF may omit the name, but all Module::Functions must
|
||||
// have names.
|
||||
string name;
|
||||
if (!name_.empty()) {
|
||||
func->name = name_;
|
||||
name = name_;
|
||||
} else {
|
||||
cu_context_->reporter->UnnamedFunction(offset_);
|
||||
func->name = "<name omitted>";
|
||||
name = "<name omitted>";
|
||||
}
|
||||
func->address = low_pc_;
|
||||
|
||||
// Create a Module::Function based on the data we've gathered, and
|
||||
// add it to the functions_ list.
|
||||
scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
|
||||
func->size = high_pc_ - low_pc_;
|
||||
func->parameter_size = 0;
|
||||
if (func->address) {
|
||||
@ -661,6 +674,13 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
|
||||
filename_.c_str(), offset);
|
||||
}
|
||||
|
||||
void DwarfCUToModule::WarningReporter::DemangleError(
|
||||
const string &input, int error) {
|
||||
CUHeading();
|
||||
fprintf(stderr, "%s: warning: failed to demangle %s with error %d\n",
|
||||
filename_.c_str(), input.c_str(), error);
|
||||
}
|
||||
|
||||
void DwarfCUToModule::WarningReporter::UnhandledInterCUReference(
|
||||
uint64 offset, uint64 target) {
|
||||
CUHeading();
|
||||
|
@ -199,6 +199,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
// link.
|
||||
virtual void UnnamedFunction(uint64 offset);
|
||||
|
||||
// __cxa_demangle() failed to demangle INPUT.
|
||||
virtual void DemangleError(const string &input, int error);
|
||||
|
||||
// The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
|
||||
// FilePrivate did not retain the inter-CU specification data.
|
||||
virtual void UnhandledInterCUReference(uint64 offset, uint64 target);
|
||||
|
@ -81,6 +81,7 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter {
|
||||
MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
|
||||
MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
|
||||
MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
|
||||
MOCK_METHOD2(DemangleError, void(const string &input, int error));
|
||||
MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target));
|
||||
};
|
||||
|
||||
@ -1712,16 +1713,14 @@ TEST_F(CUErrors, BadCURootDIETag) {
|
||||
// produce) output, so their results need to be checked by hand.
|
||||
struct Reporter: public Test {
|
||||
Reporter()
|
||||
: reporter("filename", 0x123456789abcdef0ULL) {
|
||||
: reporter("filename", 0x123456789abcdef0ULL),
|
||||
function("function name", 0x19c45c30770c1eb0ULL),
|
||||
file("source file name") {
|
||||
reporter.SetCUName("compilation-unit-name");
|
||||
|
||||
function.name = "function name";
|
||||
function.address = 0x19c45c30770c1eb0ULL;
|
||||
function.size = 0x89808a5bdfa0a6a3ULL;
|
||||
function.parameter_size = 0x6a329f18683dcd51ULL;
|
||||
|
||||
file.name = "source file name";
|
||||
|
||||
line.address = 0x3606ac6267aebeccULL;
|
||||
line.size = 0x5de482229f32556aULL;
|
||||
line.file = &file;
|
||||
|
@ -413,6 +413,15 @@ bool ElfEndianness(const typename ElfClass::Ehdr* elf_header,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Given |left_abspath|, find the absolute path for |right_path| and see if the
|
||||
// two absolute paths are the same.
|
||||
bool IsSameFile(const char* left_abspath, const string& right_path) {
|
||||
char right_abspath[PATH_MAX];
|
||||
if (!realpath(right_path.c_str(), right_abspath))
|
||||
return false;
|
||||
return strcmp(left_abspath, right_abspath) == 0;
|
||||
}
|
||||
|
||||
// Read the .gnu_debuglink and get the debug file name. If anything goes
|
||||
// wrong, return an empty string.
|
||||
string ReadDebugLink(const char* debuglink,
|
||||
@ -430,14 +439,27 @@ string ReadDebugLink(const char* debuglink,
|
||||
return string();
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
int debuglink_fd = -1;
|
||||
char obj_file_abspath[PATH_MAX];
|
||||
if (!realpath(obj_file.c_str(), obj_file_abspath)) {
|
||||
fprintf(stderr, "Cannot resolve absolute path for %s\n", obj_file.c_str());
|
||||
return string();
|
||||
}
|
||||
|
||||
std::vector<string> searched_paths;
|
||||
string debuglink_path;
|
||||
std::vector<string>::const_iterator it;
|
||||
for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) {
|
||||
const string& debug_dir = *it;
|
||||
debuglink_path = debug_dir + "/" + debuglink;
|
||||
debuglink_fd = open(debuglink_path.c_str(), O_RDONLY);
|
||||
|
||||
// There is the annoying case of /path/to/foo.so having foo.so as the
|
||||
// debug link file name. Thus this may end up opening /path/to/foo.so again,
|
||||
// and there is a small chance of the two files having the same CRC.
|
||||
if (IsSameFile(obj_file_abspath, debuglink_path))
|
||||
continue;
|
||||
|
||||
searched_paths.push_back(debug_dir);
|
||||
int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY);
|
||||
if (debuglink_fd < 0)
|
||||
continue;
|
||||
|
||||
@ -469,21 +491,19 @@ string ReadDebugLink(const char* debuglink,
|
||||
debuglink_path.c_str());
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
|
||||
// Found debug file.
|
||||
return debuglink_path;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// Not found case.
|
||||
fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n",
|
||||
obj_file.c_str());
|
||||
for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) {
|
||||
const string debug_dir = *it;
|
||||
for (it = searched_paths.begin(); it < searched_paths.end(); ++it) {
|
||||
const string& debug_dir = *it;
|
||||
fprintf(stderr, " %s/%s\n", debug_dir.c_str(), debuglink);
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
return debuglink_path;
|
||||
}
|
||||
|
||||
//
|
||||
@ -628,6 +648,35 @@ bool LoadSymbols(const string& obj_file,
|
||||
"DWARF debugging information\n", obj_file.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// See if there are export symbols available.
|
||||
const Shdr* dynsym_section =
|
||||
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
const Shdr* dynstr_section =
|
||||
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
if (dynsym_section && dynstr_section) {
|
||||
info->LoadedSection(".dynsym");
|
||||
|
||||
const uint8_t* dynsyms =
|
||||
GetOffset<ElfClass, uint8_t>(elf_header,
|
||||
dynsym_section->sh_offset);
|
||||
const uint8_t* dynstrs =
|
||||
GetOffset<ElfClass, uint8_t>(elf_header,
|
||||
dynstr_section->sh_offset);
|
||||
bool result =
|
||||
ELFSymbolsToModule(dynsyms,
|
||||
dynsym_section->sh_size,
|
||||
dynstrs,
|
||||
dynstr_section->sh_size,
|
||||
big_endian,
|
||||
ElfClass::kAddrSize,
|
||||
module);
|
||||
found_usable_info = found_usable_info || result;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.symbol_data != NO_CFI) {
|
||||
@ -689,8 +738,6 @@ bool LoadSymbols(const string& obj_file,
|
||||
names_end, elf_header->e_shnum);
|
||||
if (gnu_debuglink_section) {
|
||||
if (!info->debug_dirs().empty()) {
|
||||
found_debug_info_section = true;
|
||||
|
||||
const char* debuglink_contents =
|
||||
GetOffset<ElfClass, char>(elf_header,
|
||||
gnu_debuglink_section->sh_offset);
|
||||
@ -709,45 +756,18 @@ bool LoadSymbols(const string& obj_file,
|
||||
fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n",
|
||||
obj_file.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.symbol_data != ONLY_CFI) {
|
||||
const Shdr* dynsym_section =
|
||||
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
const Shdr* dynstr_section =
|
||||
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
if (dynsym_section && dynstr_section) {
|
||||
info->LoadedSection(".dynsym");
|
||||
|
||||
const uint8_t* dynsyms =
|
||||
GetOffset<ElfClass, uint8_t>(elf_header,
|
||||
dynsym_section->sh_offset);
|
||||
const uint8_t* dynstrs =
|
||||
GetOffset<ElfClass, uint8_t>(elf_header,
|
||||
dynstr_section->sh_offset);
|
||||
bool result =
|
||||
ELFSymbolsToModule(dynsyms,
|
||||
dynsym_section->sh_size,
|
||||
dynstrs,
|
||||
dynstr_section->sh_size,
|
||||
big_endian,
|
||||
ElfClass::kAddrSize,
|
||||
module);
|
||||
found_usable_info = found_usable_info || result;
|
||||
}
|
||||
}
|
||||
|
||||
if (read_gnu_debug_link) {
|
||||
return found_debug_info_section;
|
||||
}
|
||||
|
||||
// Return true if some usable information was found
|
||||
} else {
|
||||
// Return true if some usable information was found, since the caller
|
||||
// doesn't want to use .gnu_debuglink.
|
||||
return found_usable_info;
|
||||
}
|
||||
|
||||
// No debug info was found, let the user try again with .gnu_debuglink
|
||||
// if present.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the breakpad symbol file identifier for the architecture of
|
||||
@ -800,6 +820,37 @@ string BaseFileName(const string &filename) {
|
||||
return base;
|
||||
}
|
||||
|
||||
template<typename ElfClass>
|
||||
bool SanitizeDebugFile(const typename ElfClass::Ehdr* debug_elf_header,
|
||||
const string& debuglink_file,
|
||||
const string& obj_filename,
|
||||
const char* obj_file_architecture,
|
||||
const bool obj_file_is_big_endian) {
|
||||
const char* debug_architecture =
|
||||
ElfArchitecture<ElfClass>(debug_elf_header);
|
||||
if (!debug_architecture) {
|
||||
fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
|
||||
debuglink_file.c_str(), debug_elf_header->e_machine);
|
||||
return false;
|
||||
}
|
||||
if (strcmp(obj_file_architecture, debug_architecture)) {
|
||||
fprintf(stderr, "%s with ELF machine architecture %s does not match "
|
||||
"%s with ELF architecture %s\n",
|
||||
debuglink_file.c_str(), debug_architecture,
|
||||
obj_filename.c_str(), obj_file_architecture);
|
||||
return false;
|
||||
}
|
||||
bool debug_big_endian;
|
||||
if (!ElfEndianness<ElfClass>(debug_elf_header, &debug_big_endian))
|
||||
return false;
|
||||
if (debug_big_endian != obj_file_is_big_endian) {
|
||||
fprintf(stderr, "%s and %s does not match in endianness\n",
|
||||
obj_filename.c_str(), debuglink_file.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename ElfClass>
|
||||
bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||
const string& obj_filename,
|
||||
@ -849,34 +900,13 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
|
||||
MmapWrapper debug_map_wrapper;
|
||||
Ehdr* debug_elf_header = NULL;
|
||||
if (!LoadELF(debuglink_file, &debug_map_wrapper,
|
||||
reinterpret_cast<void**>(&debug_elf_header)))
|
||||
return false;
|
||||
// Sanity checks to make sure everything matches up.
|
||||
const char *debug_architecture =
|
||||
ElfArchitecture<ElfClass>(debug_elf_header);
|
||||
if (!debug_architecture) {
|
||||
fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
|
||||
debuglink_file.c_str(), debug_elf_header->e_machine);
|
||||
return false;
|
||||
}
|
||||
if (strcmp(architecture, debug_architecture)) {
|
||||
fprintf(stderr, "%s with ELF machine architecture %s does not match "
|
||||
"%s with ELF architecture %s\n",
|
||||
debuglink_file.c_str(), debug_architecture,
|
||||
obj_filename.c_str(), architecture);
|
||||
reinterpret_cast<void**>(&debug_elf_header)) ||
|
||||
!SanitizeDebugFile<ElfClass>(debug_elf_header, debuglink_file,
|
||||
obj_filename, architecture, big_endian)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool debug_big_endian;
|
||||
if (!ElfEndianness<ElfClass>(debug_elf_header, &debug_big_endian))
|
||||
return false;
|
||||
if (debug_big_endian != big_endian) {
|
||||
fprintf(stderr, "%s and %s does not match in endianness\n",
|
||||
obj_filename.c_str(), debuglink_file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian,
|
||||
if (!LoadSymbols<ElfClass>(debuglink_file, big_endian,
|
||||
debug_elf_header, false, &info,
|
||||
options, module.get())) {
|
||||
return false;
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include "common/linux/elf_symbols_to_module.h"
|
||||
|
||||
#include <cxxabi.h>
|
||||
#include <elf.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -155,9 +156,18 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section,
|
||||
while(!iterator->at_end) {
|
||||
if (ELF32_ST_TYPE(iterator->info) == STT_FUNC &&
|
||||
iterator->shndx != SHN_UNDEF) {
|
||||
Module::Extern *ext = new Module::Extern;
|
||||
Module::Extern *ext = new Module::Extern(iterator->value);
|
||||
ext->name = SymbolString(iterator->name_offset, strings);
|
||||
ext->address = iterator->value;
|
||||
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
|
||||
int status = 0;
|
||||
char* demangled =
|
||||
abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status);
|
||||
if (demangled) {
|
||||
if (status == 0)
|
||||
ext->name = demangled;
|
||||
free(demangled);
|
||||
}
|
||||
#endif
|
||||
module->AddExtern(ext);
|
||||
}
|
||||
++iterator;
|
||||
|
56
src/common/minidump_type_helper.h
Normal file
56
src/common/minidump_type_helper.h
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2014, 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.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
template <size_t>
|
||||
struct MDTypeHelper;
|
||||
|
||||
template <>
|
||||
struct MDTypeHelper<sizeof(uint32_t)> {
|
||||
typedef MDRawDebug32 MDRawDebug;
|
||||
typedef MDRawLinkMap32 MDRawLinkMap;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MDTypeHelper<sizeof(uint64_t)> {
|
||||
typedef MDRawDebug64 MDRawDebug;
|
||||
typedef MDRawLinkMap64 MDRawLinkMap;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_
|
@ -79,8 +79,34 @@ void Module::AddFunction(Function *function) {
|
||||
// FUNC lines must not hold an empty name, so catch the problem early if
|
||||
// callers try to add one.
|
||||
assert(!function->name.empty());
|
||||
|
||||
// FUNCs are better than PUBLICs as they come with sizes, so remove an extern
|
||||
// with the same address if present.
|
||||
Extern ext(function->address);
|
||||
ExternSet::iterator it_ext = externs_.find(&ext);
|
||||
if (it_ext == externs_.end() &&
|
||||
architecture_ == "arm" &&
|
||||
(function->address & 0x1) == 0) {
|
||||
// ARM THUMB functions have bit 0 set. ARM64 does not have THUMB.
|
||||
Extern arm_thumb_ext(function->address | 0x1);
|
||||
it_ext = externs_.find(&arm_thumb_ext);
|
||||
}
|
||||
if (it_ext != externs_.end()) {
|
||||
delete *it_ext;
|
||||
externs_.erase(it_ext);
|
||||
}
|
||||
#if _DEBUG
|
||||
{
|
||||
// There should be no other PUBLIC symbols that overlap with the function.
|
||||
Extern debug_ext(function->address);
|
||||
ExternSet::iterator it_debug = externs_.lower_bound(&ext);
|
||||
assert(it_debug == externs_.end() ||
|
||||
(*it_debug)->address >= function->address + function->size);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
|
||||
if (!ret.second) {
|
||||
if (!ret.second && (*ret.first != function)) {
|
||||
// Free the duplicate that was not inserted because this Module
|
||||
// now owns it.
|
||||
delete function;
|
||||
@ -98,23 +124,12 @@ void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) {
|
||||
}
|
||||
|
||||
void Module::AddExtern(Extern *ext) {
|
||||
Function func;
|
||||
func.name = ext->name;
|
||||
func.address = ext->address;
|
||||
|
||||
// Since parsing debug section and public info are not necessarily
|
||||
// mutually exclusive, check if the symbol has already been read
|
||||
// as a function to avoid duplicates.
|
||||
if (functions_.find(&func) == functions_.end()) {
|
||||
std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
|
||||
if (!ret.second) {
|
||||
// Free the duplicate that was not inserted because this Module
|
||||
// now owns it.
|
||||
delete ext;
|
||||
}
|
||||
} else {
|
||||
delete ext;
|
||||
}
|
||||
}
|
||||
|
||||
void Module::GetFunctions(vector<Function *> *vec,
|
||||
@ -141,8 +156,7 @@ Module::File *Module::FindFile(const string &name) {
|
||||
FileByNameMap::iterator destiny = files_.lower_bound(&name);
|
||||
if (destiny == files_.end()
|
||||
|| *destiny->first != name) { // Repeated string comparison, boo hoo.
|
||||
File *file = new File;
|
||||
file->name = name;
|
||||
File *file = new File(name);
|
||||
file->source_id = -1;
|
||||
destiny = files_.insert(destiny,
|
||||
FileByNameMap::value_type(&file->name, file));
|
||||
|
@ -74,8 +74,10 @@ class Module {
|
||||
|
||||
// A source file.
|
||||
struct File {
|
||||
explicit File(const string &name_input) : name(name_input), source_id(0) {}
|
||||
|
||||
// The name of the source file.
|
||||
string name;
|
||||
const string name;
|
||||
|
||||
// The file's source id. The Write member function clears this
|
||||
// field and assigns source ids a fresh, so any value placed here
|
||||
@ -85,6 +87,9 @@ class Module {
|
||||
|
||||
// A function.
|
||||
struct Function {
|
||||
Function(const string &name_input, const Address &address_input) :
|
||||
name(name_input), address(address_input), size(0), parameter_size(0) {}
|
||||
|
||||
// For sorting by address. (Not style-guide compliant, but it's
|
||||
// stupid not to put this in the struct.)
|
||||
static bool CompareByAddress(const Function *x, const Function *y) {
|
||||
@ -92,10 +97,11 @@ class Module {
|
||||
}
|
||||
|
||||
// The function's name.
|
||||
string name;
|
||||
const string name;
|
||||
|
||||
// The start address and length of the function's code.
|
||||
Address address, size;
|
||||
const Address address;
|
||||
Address size;
|
||||
|
||||
// The function's parameter size.
|
||||
Address parameter_size;
|
||||
@ -120,7 +126,8 @@ class Module {
|
||||
|
||||
// An exported symbol.
|
||||
struct Extern {
|
||||
Address address;
|
||||
explicit Extern(const Address &address_input) : address(address_input) {}
|
||||
const Address address;
|
||||
string name;
|
||||
};
|
||||
|
||||
|
@ -54,9 +54,7 @@ static Module::Function *generate_duplicate_function(const string &name) {
|
||||
const Module::Address DUP_SIZE = 0x200b26e605f99071LL;
|
||||
const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL;
|
||||
|
||||
Module::Function *function = new(Module::Function);
|
||||
function->name = name;
|
||||
function->address = DUP_ADDRESS;
|
||||
Module::Function *function = new Module::Function(name, DUP_ADDRESS);
|
||||
function->size = DUP_SIZE;
|
||||
function->parameter_size = DUP_PARAMETER_SIZE;
|
||||
return function;
|
||||
@ -81,9 +79,8 @@ TEST(Write, OneLineFunc) {
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
Module::File *file = m.FindFile("file_name.cc");
|
||||
Module::Function *function = new(Module::Function);
|
||||
function->name = "function_name";
|
||||
function->address = 0xe165bf8023b9d9abLL;
|
||||
Module::Function *function = new Module::Function(
|
||||
"function_name", 0xe165bf8023b9d9abLL);
|
||||
function->size = 0x1e4bb0eb1cbf5b09LL;
|
||||
function->parameter_size = 0x772beee89114358aLL;
|
||||
Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL,
|
||||
@ -110,9 +107,8 @@ TEST(Write, RelativeLoadAddress) {
|
||||
Module::File *file2 = m.FindFile("filename-a.cc");
|
||||
|
||||
// A function.
|
||||
Module::Function *function = new(Module::Function);
|
||||
function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)";
|
||||
function->address = 0xbec774ea5dd935f3LL;
|
||||
Module::Function *function = new Module::Function(
|
||||
"A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL);
|
||||
function->size = 0x2922088f98d3f6fcLL;
|
||||
function->parameter_size = 0xe5e9aa008bd5f0d0LL;
|
||||
|
||||
@ -168,9 +164,8 @@ TEST(Write, OmitUnusedFiles) {
|
||||
Module::File *file3 = m.FindFile("filename3");
|
||||
|
||||
// Create a function.
|
||||
Module::Function *function = new(Module::Function);
|
||||
function->name = "function_name";
|
||||
function->address = 0x9b926d464f0b9384LL;
|
||||
Module::Function *function = new Module::Function(
|
||||
"function_name", 0x9b926d464f0b9384LL);
|
||||
function->size = 0x4f524a4ba795e6a6LL;
|
||||
function->parameter_size = 0xbbe8133a6641c9b7LL;
|
||||
|
||||
@ -217,9 +212,8 @@ TEST(Write, NoCFI) {
|
||||
Module::File *file1 = m.FindFile("filename.cc");
|
||||
|
||||
// A function.
|
||||
Module::Function *function = new(Module::Function);
|
||||
function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)";
|
||||
function->address = 0xbec774ea5dd935f3LL;
|
||||
Module::Function *function = new Module::Function(
|
||||
"A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL);
|
||||
function->size = 0x2922088f98d3f6fcLL;
|
||||
function->parameter_size = 0xe5e9aa008bd5f0d0LL;
|
||||
|
||||
@ -260,15 +254,13 @@ TEST(Construct, AddFunctions) {
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two functions.
|
||||
Module::Function *function1 = new(Module::Function);
|
||||
function1->name = "_without_form";
|
||||
function1->address = 0xd35024aa7ca7da5cLL;
|
||||
Module::Function *function1 = new Module::Function(
|
||||
"_without_form", 0xd35024aa7ca7da5cLL);
|
||||
function1->size = 0x200b26e605f99071LL;
|
||||
function1->parameter_size = 0xf14ac4fed48c4a99LL;
|
||||
|
||||
Module::Function *function2 = new(Module::Function);
|
||||
function2->name = "_and_void";
|
||||
function2->address = 0x2987743d0b35b13fLL;
|
||||
Module::Function *function2 = new Module::Function(
|
||||
"_and_void", 0x2987743d0b35b13fLL);
|
||||
function2->size = 0xb369db048deb3010LL;
|
||||
function2->parameter_size = 0x938e556cb5a79988LL;
|
||||
|
||||
@ -443,11 +435,9 @@ TEST(Construct, Externs) {
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two externs.
|
||||
Module::Extern *extern1 = new(Module::Extern);
|
||||
extern1->address = 0xffff;
|
||||
Module::Extern *extern1 = new Module::Extern(0xffff);
|
||||
extern1->name = "_abc";
|
||||
Module::Extern *extern2 = new(Module::Extern);
|
||||
extern2->address = 0xaaaa;
|
||||
Module::Extern *extern2 = new Module::Extern(0xaaaa);
|
||||
extern2->name = "_xyz";
|
||||
|
||||
m.AddExtern(extern1);
|
||||
@ -470,11 +460,9 @@ TEST(Construct, DuplicateExterns) {
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two externs.
|
||||
Module::Extern *extern1 = new(Module::Extern);
|
||||
extern1->address = 0xffff;
|
||||
Module::Extern *extern1 = new Module::Extern(0xffff);
|
||||
extern1->name = "_xyz";
|
||||
Module::Extern *extern2 = new(Module::Extern);
|
||||
extern2->address = 0xffff;
|
||||
Module::Extern *extern2 = new Module::Extern(0xffff);
|
||||
extern2->name = "_abc";
|
||||
|
||||
m.AddExtern(extern1);
|
||||
@ -488,3 +476,71 @@ TEST(Construct, DuplicateExterns) {
|
||||
"PUBLIC ffff 0 _xyz\n",
|
||||
contents.c_str());
|
||||
}
|
||||
|
||||
// If there exists an extern and a function at the same address, only write
|
||||
// out the FUNC entry.
|
||||
TEST(Construct, FunctionsAndExternsWithSameAddress) {
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two externs.
|
||||
Module::Extern* extern1 = new Module::Extern(0xabc0);
|
||||
extern1->name = "abc";
|
||||
Module::Extern* extern2 = new Module::Extern(0xfff0);
|
||||
extern2->name = "xyz";
|
||||
|
||||
m.AddExtern(extern1);
|
||||
m.AddExtern(extern2);
|
||||
|
||||
Module::Function* function = new Module::Function("_xyz", 0xfff0);
|
||||
function->size = 0x10;
|
||||
function->parameter_size = 0;
|
||||
m.AddFunction(function);
|
||||
|
||||
m.Write(s, ALL_SYMBOL_DATA);
|
||||
string contents = s.str();
|
||||
|
||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||
MODULE_ID " " MODULE_NAME "\n"
|
||||
"FUNC fff0 10 0 _xyz\n"
|
||||
"PUBLIC abc0 0 abc\n",
|
||||
contents.c_str());
|
||||
}
|
||||
|
||||
// If there exists an extern and a function at the same address, only write
|
||||
// out the FUNC entry. For ARM THUMB, the extern that comes from the ELF
|
||||
// symbol section has bit 0 set.
|
||||
TEST(Construct, FunctionsAndThumbExternsWithSameAddress) {
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, "arm", MODULE_ID);
|
||||
|
||||
// Two THUMB externs.
|
||||
Module::Extern* thumb_extern1 = new Module::Extern(0xabc1);
|
||||
thumb_extern1->name = "thumb_abc";
|
||||
Module::Extern* thumb_extern2 = new Module::Extern(0xfff1);
|
||||
thumb_extern2->name = "thumb_xyz";
|
||||
|
||||
Module::Extern* arm_extern1 = new Module::Extern(0xcc00);
|
||||
arm_extern1->name = "arm_func";
|
||||
|
||||
m.AddExtern(thumb_extern1);
|
||||
m.AddExtern(thumb_extern2);
|
||||
m.AddExtern(arm_extern1);
|
||||
|
||||
// The corresponding function from the DWARF debug data have the actual
|
||||
// address.
|
||||
Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0);
|
||||
function->size = 0x10;
|
||||
function->parameter_size = 0;
|
||||
m.AddFunction(function);
|
||||
|
||||
m.Write(s, ALL_SYMBOL_DATA);
|
||||
string contents = s.str();
|
||||
|
||||
EXPECT_STREQ("MODULE " MODULE_OS " arm "
|
||||
MODULE_ID " " MODULE_NAME "\n"
|
||||
"FUNC fff0 10 0 _thumb_xyz\n"
|
||||
"PUBLIC abc1 0 thumb_abc\n"
|
||||
"PUBLIC cc00 0 arm_func\n",
|
||||
contents.c_str());
|
||||
}
|
||||
|
@ -90,9 +90,7 @@ bool StabsToModule::EndCompilationUnit(uint64_t address) {
|
||||
bool StabsToModule::StartFunction(const string &name,
|
||||
uint64_t address) {
|
||||
assert(!current_function_);
|
||||
Module::Function *f = new Module::Function;
|
||||
f->name = Demangle(name);
|
||||
f->address = address;
|
||||
Module::Function *f = new Module::Function(Demangle(name), address);
|
||||
f->size = 0; // We compute this in StabsToModule::Finalize().
|
||||
f->parameter_size = 0; // We don't provide this information.
|
||||
current_function_ = f;
|
||||
@ -133,7 +131,7 @@ bool StabsToModule::Line(uint64_t address, const char *name, int number) {
|
||||
}
|
||||
|
||||
bool StabsToModule::Extern(const string &name, uint64_t address) {
|
||||
Module::Extern *ext = new Module::Extern;
|
||||
Module::Extern *ext = new Module::Extern(address);
|
||||
// Older libstdc++ demangle implementations can crash on unexpected
|
||||
// input, so be careful about what gets passed in.
|
||||
if (name.compare(0, 3, "__Z") == 0) {
|
||||
@ -143,7 +141,6 @@ bool StabsToModule::Extern(const string &name, uint64_t address) {
|
||||
} else {
|
||||
ext->name = name;
|
||||
}
|
||||
ext->address = address;
|
||||
module_->AddExtern(ext);
|
||||
return true;
|
||||
}
|
||||
|
@ -37,16 +37,34 @@
|
||||
'all_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(DEPTH)',
|
||||
'$(VSInstallDir)\DIA SDK\include',
|
||||
'$(VSInstallDir)/DIA SDK/include',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
'AdditionalDependencies': [
|
||||
'$(VSInstallDir)\DIA SDK\lib\diaguids.lib',
|
||||
'diaguids.lib',
|
||||
'imagehlp.lib',
|
||||
],
|
||||
},
|
||||
},
|
||||
'configurations': {
|
||||
'x86_Base': {
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
'AdditionalLibraryDirectories':
|
||||
['$(VSInstallDir)/DIA SDK/lib'],
|
||||
},
|
||||
},
|
||||
},
|
||||
'x64_Base': {
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
'AdditionalLibraryDirectories':
|
||||
['$(VSInstallDir)/DIA SDK/lib/amd64'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
#include <atlcomcli.h>
|
||||
|
||||
#include <hash_map>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
#include "common/windows/omap.h"
|
||||
@ -47,7 +47,7 @@ struct IDiaSymbol;
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::wstring;
|
||||
using stdext::hash_map;
|
||||
using std::unordered_map;
|
||||
|
||||
// A structure that carries information that identifies a pdb file.
|
||||
struct PDBModuleInfo {
|
||||
@ -192,7 +192,7 @@ class PDBSourceLineWriter {
|
||||
|
||||
// Store this ID in the cache as a duplicate for this filename.
|
||||
void StoreDuplicateFileID(const wstring &file, DWORD id) {
|
||||
hash_map<wstring, DWORD>::iterator iter = unique_files_.find(file);
|
||||
unordered_map<wstring, DWORD>::iterator iter = unique_files_.find(file);
|
||||
if (iter != unique_files_.end()) {
|
||||
// map this id to the previously seen one
|
||||
file_ids_[id] = iter->second;
|
||||
@ -204,7 +204,7 @@ class PDBSourceLineWriter {
|
||||
// but different unique IDs. The cache attempts to coalesce these into
|
||||
// one ID per unique filename.
|
||||
DWORD GetRealFileID(DWORD id) {
|
||||
hash_map<DWORD, DWORD>::iterator iter = file_ids_.find(id);
|
||||
unordered_map<DWORD, DWORD>::iterator iter = file_ids_.find(id);
|
||||
if (iter == file_ids_.end())
|
||||
return id;
|
||||
return iter->second;
|
||||
@ -240,9 +240,9 @@ class PDBSourceLineWriter {
|
||||
// There may be many duplicate filenames with different IDs.
|
||||
// This maps from the DIA "unique ID" to a single ID per unique
|
||||
// filename.
|
||||
hash_map<DWORD, DWORD> file_ids_;
|
||||
unordered_map<DWORD, DWORD> file_ids_;
|
||||
// This maps unique filenames to file IDs.
|
||||
hash_map<wstring, DWORD> unique_files_;
|
||||
unordered_map<wstring, DWORD> unique_files_;
|
||||
|
||||
// This is used for calculating post-transform symbol addresses and lengths.
|
||||
ImageMap image_map_;
|
||||
|
@ -342,7 +342,7 @@ typedef enum {
|
||||
MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */
|
||||
MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */
|
||||
MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */
|
||||
MD_LINUX_DSO_DEBUG = 0x4767000A /* MDRawDebug */
|
||||
MD_LINUX_DSO_DEBUG = 0x4767000A /* MDRawDebug{32,64} */
|
||||
} MDStreamType; /* MINIDUMP_STREAM_TYPE */
|
||||
|
||||
|
||||
@ -930,21 +930,39 @@ typedef enum {
|
||||
} MDAssertionInfoData;
|
||||
|
||||
/* These structs are used to store the DSO debug data in Linux minidumps,
|
||||
* which is necessary for converting minidumps to usable coredumps. */
|
||||
* which is necessary for converting minidumps to usable coredumps.
|
||||
* Because of a historical accident, several fields are variably encoded
|
||||
* according to client word size, so tools potentially need to support both. */
|
||||
|
||||
typedef struct {
|
||||
void* addr;
|
||||
uint32_t addr;
|
||||
MDRVA name;
|
||||
void* ld;
|
||||
} MDRawLinkMap;
|
||||
uint32_t ld;
|
||||
} MDRawLinkMap32;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
MDRVA map;
|
||||
MDRVA map; /* array of MDRawLinkMap32 */
|
||||
uint32_t dso_count;
|
||||
void* brk;
|
||||
void* ldbase;
|
||||
void* dynamic;
|
||||
} MDRawDebug;
|
||||
uint32_t brk;
|
||||
uint32_t ldbase;
|
||||
uint32_t dynamic;
|
||||
} MDRawDebug32;
|
||||
|
||||
typedef struct {
|
||||
uint64_t addr;
|
||||
MDRVA name;
|
||||
uint64_t ld;
|
||||
} MDRawLinkMap64;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
MDRVA map; /* array of MDRawLinkMap64 */
|
||||
uint32_t dso_count;
|
||||
uint64_t brk;
|
||||
uint64_t ldbase;
|
||||
uint64_t dynamic;
|
||||
} MDRawDebug64;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
|
126
src/google_breakpad/processor/microdump.h
Normal file
126
src/google_breakpad/processor/microdump.h
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2014 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.
|
||||
|
||||
// microdump.h: A microdump reader. Microdump is a minified variant of a
|
||||
// minidump (see minidump.h for documentation) which contains the minimum
|
||||
// amount of information required to get a stack trace for the crashing thread.
|
||||
// The information contained in a microdump is:
|
||||
// - the crashing thread stack
|
||||
// - system information (os type / version)
|
||||
// - cpu context (state of the registers)
|
||||
// - list of mmaps
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__
|
||||
#define GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/processor/dump_context.h"
|
||||
#include "google_breakpad/processor/memory_region.h"
|
||||
#include "google_breakpad/processor/system_info.h"
|
||||
#include "processor/basic_code_modules.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// MicrodumpModuleList contains all of the loaded code modules for a process
|
||||
// in the form of MicrodumpModules. It maintains a vector of these modules
|
||||
// and provides access to a code module corresponding to a specific address.
|
||||
class MicrodumpModules : public BasicCodeModules {
|
||||
public:
|
||||
// Takes over ownership of |module|.
|
||||
void Add(const CodeModule* module);
|
||||
};
|
||||
|
||||
// MicrodumpContext carries a CPU-specific context.
|
||||
// See dump_context.h for documentation.
|
||||
class MicrodumpContext : public DumpContext {
|
||||
public:
|
||||
virtual void SetContextARM(MDRawContextARM* arm);
|
||||
virtual void SetContextARM64(MDRawContextARM64* arm64);
|
||||
};
|
||||
|
||||
// This class provides access to microdump memory regions.
|
||||
// See memory_region.h for documentation.
|
||||
class MicrodumpMemoryRegion : public MemoryRegion {
|
||||
public:
|
||||
MicrodumpMemoryRegion();
|
||||
virtual ~MicrodumpMemoryRegion() {}
|
||||
|
||||
// Set this region's address and contents. If we have placed an
|
||||
// instance of this class in a test fixture class, individual tests
|
||||
// can use this to provide the region's contents.
|
||||
void Init(uint64_t base_address, const std::vector<uint8_t>& contents);
|
||||
|
||||
virtual uint64_t GetBase() const;
|
||||
virtual uint32_t GetSize() const;
|
||||
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const;
|
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
virtual void Print() const;
|
||||
|
||||
private:
|
||||
// Fetch a little-endian value from ADDRESS in contents_ whose size
|
||||
// is BYTES, and store it in *VALUE. Returns true on success.
|
||||
template<typename ValueType>
|
||||
bool GetMemoryLittleEndian(uint64_t address, ValueType* value) const;
|
||||
|
||||
uint64_t base_address_;
|
||||
std::vector<uint8_t> contents_;
|
||||
};
|
||||
|
||||
// Microdump is the user's interface to a microdump file. It provides access to
|
||||
// the microdump's context, memory regions and modules.
|
||||
class Microdump {
|
||||
public:
|
||||
explicit Microdump(const string& contents);
|
||||
virtual ~Microdump() {}
|
||||
|
||||
DumpContext* GetContext() { return context_.get(); }
|
||||
MicrodumpMemoryRegion* GetMemory() { return stack_region_.get(); }
|
||||
MicrodumpModules* GetModules() { return modules_.get(); }
|
||||
SystemInfo* GetSystemInfo() { return system_info_.get(); }
|
||||
|
||||
private:
|
||||
scoped_ptr<MicrodumpContext> context_;
|
||||
scoped_ptr<MicrodumpMemoryRegion> stack_region_;
|
||||
scoped_ptr<MicrodumpModules> modules_;
|
||||
scoped_ptr<SystemInfo> system_info_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__
|
||||
|
@ -27,6 +27,9 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// The processor for microdump (a reduced dump containing only the state of the
|
||||
// crashing thread). See crbug.com/410294 for more info and design docs.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_PROCESSOR_H__
|
||||
#define GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_PROCESSOR_H__
|
||||
|
||||
|
@ -732,6 +732,7 @@ class MinidumpMiscInfo : public MinidumpStream {
|
||||
|
||||
private:
|
||||
friend class Minidump;
|
||||
friend class TestMinidumpMiscInfo;
|
||||
|
||||
static const uint32_t kStreamType = MD_MISC_INFO_STREAM;
|
||||
|
||||
@ -902,14 +903,14 @@ class Minidump {
|
||||
// to avoid exposing an ugly API (GetStream needs to accept a garbage
|
||||
// parameter).
|
||||
virtual MinidumpThreadList* GetThreadList();
|
||||
MinidumpModuleList* GetModuleList();
|
||||
virtual MinidumpModuleList* GetModuleList();
|
||||
virtual MinidumpMemoryList* GetMemoryList();
|
||||
MinidumpException* GetException();
|
||||
MinidumpAssertion* GetAssertion();
|
||||
virtual MinidumpException* GetException();
|
||||
virtual MinidumpAssertion* GetAssertion();
|
||||
virtual MinidumpSystemInfo* GetSystemInfo();
|
||||
MinidumpMiscInfo* GetMiscInfo();
|
||||
MinidumpBreakpadInfo* GetBreakpadInfo();
|
||||
MinidumpMemoryInfoList* GetMemoryInfoList();
|
||||
virtual MinidumpMiscInfo* GetMiscInfo();
|
||||
virtual MinidumpBreakpadInfo* GetBreakpadInfo();
|
||||
virtual MinidumpMemoryInfoList* GetMemoryInfoList();
|
||||
|
||||
// The next set of methods are provided for users who wish to access
|
||||
// data in minidump files directly, while leveraging the rest of
|
||||
|
@ -89,6 +89,12 @@ class MinidumpProcessor {
|
||||
// the minidump.
|
||||
static bool GetOSInfo(Minidump* dump, SystemInfo* info);
|
||||
|
||||
// Populates the |process_create_time| parameter with the create time of the
|
||||
// crashed process. Returns false if this information is not available in
|
||||
// the minidump |dump|.
|
||||
static bool GetProcessCreateTime(Minidump* dump,
|
||||
uint32_t* process_create_time);
|
||||
|
||||
// Returns a textual representation of the reason that a crash occurred,
|
||||
// if the minidump in dump was produced as a result of a crash. Returns
|
||||
// an empty string if this information cannot be determined. If address
|
||||
|
@ -97,6 +97,7 @@ class ProcessState {
|
||||
|
||||
// Accessors. See the data declarations below.
|
||||
uint32_t time_date_stamp() const { return time_date_stamp_; }
|
||||
uint32_t process_create_time() const { return process_create_time_; }
|
||||
bool crashed() const { return crashed_; }
|
||||
string crash_reason() const { return crash_reason_; }
|
||||
uint64_t crash_address() const { return crash_address_; }
|
||||
@ -117,12 +118,17 @@ class ProcessState {
|
||||
ExploitabilityRating exploitability() const { return exploitability_; }
|
||||
|
||||
private:
|
||||
// MinidumpProcessor is responsible for building ProcessState objects.
|
||||
// MinidumpProcessor and MicrodumpProcessor are responsible for building
|
||||
// ProcessState objects.
|
||||
friend class MinidumpProcessor;
|
||||
friend class MicrodumpProcessor;
|
||||
|
||||
// The time-date stamp of the minidump (time_t format)
|
||||
uint32_t time_date_stamp_;
|
||||
|
||||
// The time-date stamp when the process was created (time_t format)
|
||||
uint32_t process_create_time_;
|
||||
|
||||
// True if the process crashed, false if the dump was produced outside
|
||||
// of an exception handler.
|
||||
bool crashed_;
|
||||
|
@ -73,6 +73,11 @@ BasicCodeModules::BasicCodeModules(const CodeModules *that)
|
||||
}
|
||||
}
|
||||
|
||||
BasicCodeModules::BasicCodeModules()
|
||||
: main_address_(0),
|
||||
map_(new RangeMap<uint64_t, linked_ptr<const CodeModule> >()) {
|
||||
}
|
||||
|
||||
BasicCodeModules::~BasicCodeModules() {
|
||||
delete map_;
|
||||
}
|
||||
|
@ -67,7 +67,9 @@ class BasicCodeModules : public CodeModules {
|
||||
virtual const CodeModule* GetModuleAtIndex(unsigned int index) const;
|
||||
virtual const CodeModules* Copy() const;
|
||||
|
||||
private:
|
||||
protected:
|
||||
BasicCodeModules();
|
||||
|
||||
// The base address of the main module.
|
||||
uint64_t main_address_;
|
||||
|
||||
@ -75,6 +77,7 @@ class BasicCodeModules : public CodeModules {
|
||||
// address range.
|
||||
RangeMap<uint64_t, linked_ptr<const CodeModule> > *map_;
|
||||
|
||||
private:
|
||||
// Disallow copy constructor and assignment operator.
|
||||
BasicCodeModules(const BasicCodeModules &that);
|
||||
void operator=(const BasicCodeModules &that);
|
||||
|
@ -43,7 +43,6 @@
|
||||
#define snprintf _snprintf
|
||||
#else // _WIN32
|
||||
#include <unistd.h>
|
||||
#define O_BINARY 0
|
||||
#endif // _WIN32
|
||||
|
||||
#include "processor/logging.h"
|
||||
|
306
src/processor/microdump.cc
Normal file
306
src/processor/microdump.cc
Normal file
@ -0,0 +1,306 @@
|
||||
// Copyright (c) 2014 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.
|
||||
|
||||
// microdump.cc: A microdump reader.
|
||||
//
|
||||
// See microdump.h for documentation.
|
||||
|
||||
#include "google_breakpad/processor/microdump.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "google_breakpad/common/minidump_cpu_arm.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "processor/basic_code_module.h"
|
||||
#include "processor/linked_ptr.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/range_map-inl.h"
|
||||
|
||||
namespace {
|
||||
static const char kGoogleBreakpadKey[] = "/google-breakpad(";
|
||||
static const char kMicrodumpBegin[] = "-----BEGIN BREAKPAD MICRODUMP-----";
|
||||
static const char kMicrodumpEnd[] = "-----END BREAKPAD MICRODUMP-----";
|
||||
static const char kOsKey[] = ": O ";
|
||||
static const char kCpuKey[] = ": C ";
|
||||
static const char kMmapKey[] = ": M ";
|
||||
static const char kStackKey[] = ": S ";
|
||||
static const char kStackFirstLineKey[] = ": S 0 ";
|
||||
static const char kArmArchitecture[] = "arm";
|
||||
static const char kArm64Architecture[] = "arm64";
|
||||
|
||||
template<typename T>
|
||||
T HexStrToL(const string& str) {
|
||||
uint64_t res = 0;
|
||||
std::istringstream ss(str);
|
||||
ss >> std::hex >> res;
|
||||
return static_cast<T>(res);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ParseHexBuf(const string& str) {
|
||||
std::vector<uint8_t> buf;
|
||||
for (size_t i = 0; i < str.length(); i += 2) {
|
||||
buf.push_back(HexStrToL<uint8_t>(str.substr(i, 2)));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
//
|
||||
// MicrodumpModules
|
||||
//
|
||||
|
||||
void MicrodumpModules::Add(const CodeModule* module) {
|
||||
linked_ptr<const CodeModule> module_ptr(module);
|
||||
if (!map_->StoreRange(module->base_address(), module->size(), module_ptr)) {
|
||||
BPLOG(ERROR) << "Module " << module->code_file() <<
|
||||
" could not be stored";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MicrodumpContext
|
||||
//
|
||||
|
||||
void MicrodumpContext::SetContextARM(MDRawContextARM* arm) {
|
||||
DumpContext::SetContextFlags(MD_CONTEXT_ARM);
|
||||
DumpContext::SetContextARM(arm);
|
||||
valid_ = true;
|
||||
}
|
||||
|
||||
void MicrodumpContext::SetContextARM64(MDRawContextARM64* arm64) {
|
||||
DumpContext::SetContextFlags(MD_CONTEXT_ARM64);
|
||||
DumpContext::SetContextARM64(arm64);
|
||||
valid_ = true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MicrodumpMemoryRegion
|
||||
//
|
||||
|
||||
MicrodumpMemoryRegion::MicrodumpMemoryRegion() : base_address_(0) { }
|
||||
|
||||
void MicrodumpMemoryRegion::Init(uint64_t base_address,
|
||||
const std::vector<uint8_t>& contents) {
|
||||
base_address_ = base_address;
|
||||
contents_ = contents;
|
||||
}
|
||||
|
||||
uint64_t MicrodumpMemoryRegion::GetBase() const { return base_address_; }
|
||||
|
||||
uint32_t MicrodumpMemoryRegion::GetSize() const { return contents_.size(); }
|
||||
|
||||
bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
uint8_t* value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
|
||||
bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
uint16_t* value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
|
||||
bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
uint32_t* value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
|
||||
bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
uint64_t* value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
bool MicrodumpMemoryRegion::GetMemoryLittleEndian(uint64_t address,
|
||||
ValueType* value) const {
|
||||
if (address < base_address_ ||
|
||||
address - base_address_ + sizeof(ValueType) > contents_.size())
|
||||
return false;
|
||||
ValueType v = 0;
|
||||
uint64_t start = address - base_address_;
|
||||
// The loop condition is odd, but it's correct for size_t.
|
||||
for (size_t i = sizeof(ValueType) - 1; i < sizeof(ValueType); i--)
|
||||
v = (v << 8) | static_cast<uint8_t>(contents_[start + i]);
|
||||
*value = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MicrodumpMemoryRegion::Print() const {
|
||||
// Not reached, just needed to honor the base class contract.
|
||||
assert(false);
|
||||
}
|
||||
|
||||
//
|
||||
// Microdump
|
||||
//
|
||||
Microdump::Microdump(const string& contents)
|
||||
: context_(new MicrodumpContext()),
|
||||
stack_region_(new MicrodumpMemoryRegion()),
|
||||
modules_(new MicrodumpModules()),
|
||||
system_info_(new SystemInfo()) {
|
||||
assert(!contents.empty());
|
||||
|
||||
bool in_microdump = false;
|
||||
string line;
|
||||
uint64_t stack_start = 0;
|
||||
std::vector<uint8_t> stack_content;
|
||||
string arch;
|
||||
|
||||
std::istringstream stream(contents);
|
||||
while (std::getline(stream, line)) {
|
||||
if (line.find(kGoogleBreakpadKey) == string::npos) {
|
||||
continue;
|
||||
}
|
||||
if (line.find(kMicrodumpBegin) != string::npos) {
|
||||
in_microdump = true;
|
||||
continue;
|
||||
}
|
||||
if (line.find(kMicrodumpEnd) != string::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!in_microdump) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t pos;
|
||||
if ((pos = line.find(kOsKey)) != string::npos) {
|
||||
string os_str(line, pos + strlen(kOsKey));
|
||||
std::istringstream os_tokens(os_str);
|
||||
string os_id;
|
||||
string num_cpus;
|
||||
string os_version;
|
||||
// This reflect the actual HW arch and might not match the arch emulated
|
||||
// for the execution (e.g., running a 32-bit binary on a 64-bit cpu).
|
||||
string hw_arch;
|
||||
|
||||
os_tokens >> os_id;
|
||||
os_tokens >> arch;
|
||||
os_tokens >> num_cpus;
|
||||
os_tokens >> hw_arch;
|
||||
std::getline(os_tokens, os_version);
|
||||
os_version.erase(0, 1); // remove leading space.
|
||||
|
||||
system_info_->cpu = hw_arch;
|
||||
system_info_->cpu_count = HexStrToL<uint8_t>(num_cpus);
|
||||
system_info_->os_version = os_version;
|
||||
|
||||
if (os_id == "L") {
|
||||
system_info_->os = "Linux";
|
||||
system_info_->os_short = "linux";
|
||||
} else if (os_id == "A") {
|
||||
system_info_->os = "Android";
|
||||
system_info_->os_short = "android";
|
||||
}
|
||||
|
||||
// OS line also contains release and version for future use.
|
||||
} else if ((pos = line.find(kStackKey)) != string::npos) {
|
||||
if (line.find(kStackFirstLineKey) != string::npos) {
|
||||
// The first line of the stack (S 0 stack header) provides the value of
|
||||
// the stack pointer, the start address of the stack being dumped and
|
||||
// the length of the stack. We could use it in future to double check
|
||||
// that we received all the stack as expected.
|
||||
continue;
|
||||
}
|
||||
string stack_str(line, pos + strlen(kStackKey));
|
||||
std::istringstream stack_tokens(stack_str);
|
||||
string start_addr_str;
|
||||
string raw_content;
|
||||
stack_tokens >> start_addr_str;
|
||||
stack_tokens >> raw_content;
|
||||
uint64_t start_addr = HexStrToL<uint64_t>(start_addr_str);
|
||||
|
||||
if (stack_start != 0) {
|
||||
// Verify that the stack chunks in the microdump are contiguous.
|
||||
assert(start_addr == stack_start + stack_content.size());
|
||||
} else {
|
||||
stack_start = start_addr;
|
||||
}
|
||||
std::vector<uint8_t> chunk = ParseHexBuf(raw_content);
|
||||
stack_content.insert(stack_content.end(), chunk.begin(), chunk.end());
|
||||
|
||||
} else if ((pos = line.find(kCpuKey)) != string::npos) {
|
||||
string cpu_state_str(line, pos + strlen(kCpuKey));
|
||||
std::vector<uint8_t> cpu_state_raw = ParseHexBuf(cpu_state_str);
|
||||
if (strcmp(arch.c_str(), kArmArchitecture) == 0) {
|
||||
if (cpu_state_raw.size() != sizeof(MDRawContextARM)) {
|
||||
std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() <<
|
||||
" bytes instead of " << sizeof(MDRawContextARM) << std::endl;
|
||||
continue;
|
||||
}
|
||||
MDRawContextARM* arm = new MDRawContextARM();
|
||||
memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size());
|
||||
context_->SetContextARM(arm);
|
||||
} else if (strcmp(arch.c_str(), kArm64Architecture) == 0) {
|
||||
if (cpu_state_raw.size() != sizeof(MDRawContextARM64)) {
|
||||
std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() <<
|
||||
" bytes instead of " << sizeof(MDRawContextARM64) << std::endl;
|
||||
continue;
|
||||
}
|
||||
MDRawContextARM64* arm = new MDRawContextARM64();
|
||||
memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size());
|
||||
context_->SetContextARM64(arm);
|
||||
} else {
|
||||
std::cerr << "Unsupported architecture: " << arch << std::endl;
|
||||
}
|
||||
} else if ((pos = line.find(kMmapKey)) != string::npos) {
|
||||
string mmap_line(line, pos + strlen(kMmapKey));
|
||||
std::istringstream mmap_tokens(mmap_line);
|
||||
string addr, offset, size, identifier, filename;
|
||||
mmap_tokens >> addr;
|
||||
mmap_tokens >> offset;
|
||||
mmap_tokens >> size;
|
||||
mmap_tokens >> identifier;
|
||||
mmap_tokens >> filename;
|
||||
|
||||
modules_->Add(new BasicCodeModule(
|
||||
HexStrToL<uint64_t>(addr), // base_address
|
||||
HexStrToL<uint64_t>(size), // size
|
||||
filename, // code_file
|
||||
identifier, // code_identifier
|
||||
filename, // debug_file
|
||||
identifier, // debug_identifier
|
||||
"")); // version
|
||||
}
|
||||
}
|
||||
stack_region_->Init(stack_start, stack_content);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
@ -27,6 +27,10 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// microdump_processor.cc: A microdump processor.
|
||||
//
|
||||
// See microdump_processor.h for documentation.
|
||||
|
||||
#include "google_breakpad/processor/microdump_processor.h"
|
||||
|
||||
#include <assert.h>
|
||||
@ -35,8 +39,11 @@
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/microdump.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/stackwalker.h"
|
||||
#include "google_breakpad/processor/stack_frame_symbolizer.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
@ -51,7 +58,41 @@ ProcessResult MicrodumpProcessor::Process(const string µdump_contents,
|
||||
ProcessState* process_state) {
|
||||
assert(process_state);
|
||||
|
||||
// TODO(mmandlis): Implement MicrodumpProcessor. See crbug.com/410294
|
||||
process_state->Clear();
|
||||
|
||||
if (microdump_contents.empty()) {
|
||||
BPLOG(ERROR) << "Microdump is empty.";
|
||||
return PROCESS_ERROR_MINIDUMP_NOT_FOUND;
|
||||
}
|
||||
|
||||
Microdump microdump(microdump_contents);
|
||||
process_state->modules_ = microdump.GetModules()->Copy();
|
||||
scoped_ptr<Stackwalker> stackwalker(
|
||||
Stackwalker::StackwalkerForCPU(
|
||||
&process_state->system_info_,
|
||||
microdump.GetContext(),
|
||||
microdump.GetMemory(),
|
||||
process_state->modules_,
|
||||
frame_symbolizer_));
|
||||
|
||||
scoped_ptr<CallStack> stack(new CallStack());
|
||||
if (stackwalker.get()) {
|
||||
if (!stackwalker->Walk(stack.get(),
|
||||
&process_state->modules_without_symbols_,
|
||||
&process_state->modules_with_corrupt_symbols_)) {
|
||||
BPLOG(INFO) << "Processing was interrupted.";
|
||||
return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED;
|
||||
}
|
||||
} else {
|
||||
BPLOG(ERROR) << "No stackwalker found for microdump.";
|
||||
return PROCESS_ERROR_NO_THREAD_LIST;
|
||||
}
|
||||
|
||||
process_state->threads_.push_back(stack.release());
|
||||
process_state->thread_memory_regions_.push_back(microdump.GetMemory());
|
||||
process_state->crashed_ = true;
|
||||
process_state->requesting_thread_ = 0;
|
||||
process_state->system_info_ = *microdump.GetSystemInfo();
|
||||
|
||||
return PROCESS_OK;
|
||||
}
|
||||
|
@ -29,18 +29,169 @@
|
||||
|
||||
// Unit test for MicrodumpProcessor.
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/microdump_processor.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/stack_frame.h"
|
||||
#include "google_breakpad/processor/stack_frame_symbolizer.h"
|
||||
#include "processor/simple_symbol_supplier.h"
|
||||
#include "processor/stackwalker_unittest_utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::MicrodumpProcessor;
|
||||
using google_breakpad::ProcessState;
|
||||
using google_breakpad::SimpleSymbolSupplier;
|
||||
using google_breakpad::StackFrameSymbolizer;
|
||||
|
||||
class MicrodumpProcessorTest : public ::testing::Test {
|
||||
public:
|
||||
MicrodumpProcessorTest()
|
||||
: files_path_(string(getenv("srcdir") ? getenv("srcdir") : ".") +
|
||||
"/src/processor/testdata/") {
|
||||
}
|
||||
|
||||
void ReadFile(const string& file_name, string* file_contents) {
|
||||
assert(file_contents);
|
||||
std::ifstream file_stream(file_name.c_str(), std::ios::in);
|
||||
ASSERT_TRUE(file_stream.good());
|
||||
std::vector<char> bytes;
|
||||
file_stream.seekg(0, std::ios_base::end);
|
||||
ASSERT_TRUE(file_stream.good());
|
||||
bytes.resize(file_stream.tellg());
|
||||
file_stream.seekg(0, std::ios_base::beg);
|
||||
ASSERT_TRUE(file_stream.good());
|
||||
file_stream.read(&bytes[0], bytes.size());
|
||||
ASSERT_TRUE(file_stream.good());
|
||||
*file_contents = string(&bytes[0], bytes.size());
|
||||
}
|
||||
|
||||
google_breakpad::ProcessResult ProcessMicrodump(
|
||||
const string& symbols_file,
|
||||
const string& microdump_contents,
|
||||
ProcessState* state) {
|
||||
SimpleSymbolSupplier supplier(symbols_file);
|
||||
BasicSourceLineResolver resolver;
|
||||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
MicrodumpProcessor processor(&frame_symbolizer);
|
||||
|
||||
return processor.Process(microdump_contents, state);
|
||||
}
|
||||
|
||||
void AnalyzeDump(const string& microdump_file_name, ProcessState* state,
|
||||
bool omit_symbols) {
|
||||
string symbols_file = omit_symbols ? "" : files_path_ + "symbols/microdump";
|
||||
string microdump_file_path = files_path_ + microdump_file_name;
|
||||
string microdump_contents;
|
||||
ReadFile(microdump_file_path, µdump_contents);
|
||||
|
||||
google_breakpad::ProcessResult result =
|
||||
ProcessMicrodump(symbols_file, microdump_contents, state);
|
||||
|
||||
ASSERT_EQ(google_breakpad::PROCESS_OK, result);
|
||||
ASSERT_TRUE(state->crashed());
|
||||
ASSERT_EQ(0, state->requesting_thread());
|
||||
ASSERT_EQ(1U, state->threads()->size());
|
||||
|
||||
ASSERT_EQ(2, state->system_info()->cpu_count);
|
||||
ASSERT_EQ("android", state->system_info()->os_short);
|
||||
ASSERT_EQ("Android", state->system_info()->os);
|
||||
}
|
||||
|
||||
string files_path_;
|
||||
};
|
||||
|
||||
// TODO(mmandlis): Add MicrodumpProcessor tests. See crbug.com/410294
|
||||
TEST_F(MicrodumpProcessorTest, TestProcess_Empty) {
|
||||
ProcessState state;
|
||||
google_breakpad::ProcessResult result =
|
||||
ProcessMicrodump("", "", &state);
|
||||
ASSERT_EQ(google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND, result);
|
||||
}
|
||||
|
||||
TEST_F(MicrodumpProcessorTest, TestProcess_Invalid) {
|
||||
ProcessState state;
|
||||
google_breakpad::ProcessResult result =
|
||||
ProcessMicrodump("", "This is not a valid microdump", &state);
|
||||
ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result);
|
||||
}
|
||||
|
||||
TEST_F(MicrodumpProcessorTest, TestProcess_MissingSymbols) {
|
||||
ProcessState state;
|
||||
AnalyzeDump("microdump-arm64.dmp", &state, true /* omit_symbols */);
|
||||
|
||||
ASSERT_EQ(8U, state.modules()->module_count());
|
||||
ASSERT_EQ("aarch64", state.system_info()->cpu);
|
||||
ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version);
|
||||
ASSERT_EQ(1U, state.threads()->size());
|
||||
ASSERT_EQ(12U, state.threads()->at(0)->frames()->size());
|
||||
|
||||
ASSERT_EQ("",
|
||||
state.threads()->at(0)->frames()->at(0)->function_name);
|
||||
ASSERT_EQ("",
|
||||
state.threads()->at(0)->frames()->at(3)->function_name);
|
||||
}
|
||||
|
||||
TEST_F(MicrodumpProcessorTest, TestProcess_UnsupportedArch) {
|
||||
string microdump_contents =
|
||||
"W/google-breakpad(26491): -----BEGIN BREAKPAD MICRODUMP-----\n"
|
||||
"W/google-breakpad(26491): O A \"unsupported-arch\"\n"
|
||||
"W/google-breakpad(26491): S 0 A48BD840 A48BD000 00002000\n";
|
||||
|
||||
ProcessState state;
|
||||
|
||||
google_breakpad::ProcessResult result =
|
||||
ProcessMicrodump("", microdump_contents, &state);
|
||||
|
||||
ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result);
|
||||
}
|
||||
|
||||
TEST_F(MicrodumpProcessorTest, TestProcessArm) {
|
||||
ProcessState state;
|
||||
AnalyzeDump("microdump-arm.dmp", &state, false /* omit_symbols */);
|
||||
|
||||
ASSERT_EQ(6U, state.modules()->module_count());
|
||||
ASSERT_EQ("armv7l", state.system_info()->cpu);
|
||||
ASSERT_EQ("OS VERSION INFO", state.system_info()->os_version);
|
||||
ASSERT_EQ(8U, state.threads()->at(0)->frames()->size());
|
||||
ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody",
|
||||
state.threads()->at(0)->frames()->at(0)->function_name);
|
||||
ASSERT_EQ("testing::Test::Run",
|
||||
state.threads()->at(0)->frames()->at(1)->function_name);
|
||||
ASSERT_EQ("main",
|
||||
state.threads()->at(0)->frames()->at(6)->function_name);
|
||||
ASSERT_EQ("breakpad_unittests",
|
||||
state.threads()->at(0)->frames()->at(6)->module->code_file());
|
||||
}
|
||||
|
||||
TEST_F(MicrodumpProcessorTest, TestProcessArm64) {
|
||||
ProcessState state;
|
||||
AnalyzeDump("microdump-arm64.dmp", &state, false /* omit_symbols */);
|
||||
|
||||
ASSERT_EQ(8U, state.modules()->module_count());
|
||||
ASSERT_EQ("aarch64", state.system_info()->cpu);
|
||||
ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version);
|
||||
ASSERT_EQ(9U, state.threads()->at(0)->frames()->size());
|
||||
ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody",
|
||||
state.threads()->at(0)->frames()->at(0)->function_name);
|
||||
ASSERT_EQ("testing::Test::Run",
|
||||
state.threads()->at(0)->frames()->at(2)->function_name);
|
||||
ASSERT_EQ("main",
|
||||
state.threads()->at(0)->frames()->at(7)->function_name);
|
||||
ASSERT_EQ("breakpad_unittests",
|
||||
state.threads()->at(0)->frames()->at(7)->module->code_file());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int main(int argc, char* argv[]) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
151
src/processor/microdump_stackwalk.cc
Normal file
151
src/processor/microdump_stackwalk.cc
Normal file
@ -0,0 +1,151 @@
|
||||
// Copyright (c) 2014 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.
|
||||
|
||||
// microdump_stackwalk.cc: Process a microdump with MicrodumpProcessor, printing
|
||||
// the results, including stack traces.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/microdump_processor.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/stack_frame_symbolizer.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/simple_symbol_supplier.h"
|
||||
#include "processor/stackwalk_common.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::MicrodumpProcessor;
|
||||
using google_breakpad::ProcessResult;
|
||||
using google_breakpad::ProcessState;
|
||||
using google_breakpad::scoped_ptr;
|
||||
using google_breakpad::SimpleSymbolSupplier;
|
||||
using google_breakpad::StackFrameSymbolizer;
|
||||
|
||||
// Processes |microdump_file| using MicrodumpProcessor. |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 MicrodumpProcessor.
|
||||
//
|
||||
// Returns the value of MicrodumpProcessor::Process. If processing succeeds,
|
||||
// prints identifying OS and CPU information from the microdump, crash
|
||||
// information and call stacks for the crashing thread.
|
||||
// All information is printed to stdout.
|
||||
int PrintMicrodumpProcess(const char* microdump_file,
|
||||
const std::vector<string>& symbol_paths,
|
||||
bool machine_readable) {
|
||||
std::ifstream file_stream(microdump_file);
|
||||
std::vector<char> bytes;
|
||||
file_stream.seekg(0, std::ios_base::end);
|
||||
bytes.resize(file_stream.tellg());
|
||||
file_stream.seekg(0, std::ios_base::beg);
|
||||
file_stream.read(&bytes[0], bytes.size());
|
||||
string microdump_content(&bytes[0], bytes.size());
|
||||
|
||||
scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
|
||||
if (!symbol_paths.empty()) {
|
||||
symbol_supplier.reset(new SimpleSymbolSupplier(symbol_paths));
|
||||
}
|
||||
|
||||
BasicSourceLineResolver resolver;
|
||||
StackFrameSymbolizer frame_symbolizer(symbol_supplier.get(), &resolver);
|
||||
ProcessState process_state;
|
||||
MicrodumpProcessor microdump_processor(&frame_symbolizer);
|
||||
ProcessResult res = microdump_processor.Process(microdump_content,
|
||||
&process_state);
|
||||
|
||||
if (res == google_breakpad::PROCESS_OK) {
|
||||
if (machine_readable) {
|
||||
PrintProcessStateMachineReadable(process_state);
|
||||
} else {
|
||||
PrintProcessState(process_state, false, &resolver);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BPLOG(ERROR) << "MicrodumpProcessor::Process failed (code = " << res << ")";
|
||||
return 1;
|
||||
}
|
||||
|
||||
void usage(const char *program_name) {
|
||||
fprintf(stderr, "usage: %s [-m] <microdump-file> [symbol-path ...]\n"
|
||||
" -m : Output in machine-readable format\n",
|
||||
program_name);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
if (argc < 2) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* microdump_file;
|
||||
bool machine_readable;
|
||||
int symbol_path_arg;
|
||||
|
||||
if (strcmp(argv[1], "-m") == 0) {
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
machine_readable = true;
|
||||
microdump_file = argv[2];
|
||||
symbol_path_arg = 3;
|
||||
} else {
|
||||
machine_readable = false;
|
||||
microdump_file = argv[1];
|
||||
symbol_path_arg = 2;
|
||||
}
|
||||
|
||||
// extra arguments are symbol paths
|
||||
std::vector<string> symbol_paths;
|
||||
if (argc > symbol_path_arg) {
|
||||
for (int argi = symbol_path_arg; argi < argc; ++argi)
|
||||
symbol_paths.push_back(argv[argi]);
|
||||
}
|
||||
|
||||
return PrintMicrodumpProcess(microdump_file,
|
||||
symbol_paths,
|
||||
machine_readable);
|
||||
}
|
43
src/processor/microdump_stackwalk_machine_readable_test
Executable file
43
src/processor/microdump_stackwalk_machine_readable_test
Executable file
@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2014, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
source "${0%/*}/microdump_stackwalk_test_vars" # for MICRODUMP_SUPPORTED_ARCHS.
|
||||
testdata_dir=$srcdir/src/processor/testdata
|
||||
|
||||
set -e # Bail out with an error if any of the commands below fails.
|
||||
for ARCH in $MICRODUMP_SUPPORTED_ARCHS; do
|
||||
echo "Testing microdump_stackwalk -m for arch $ARCH"
|
||||
./src/processor/microdump_stackwalk -m $testdata_dir/microdump-${ARCH}.dmp \
|
||||
$testdata_dir/symbols/microdump | \
|
||||
tr -d '\015' | \
|
||||
diff -u $testdata_dir/microdump.stackwalk.machine_readable-${ARCH}.out -
|
||||
done
|
||||
exit 0
|
43
src/processor/microdump_stackwalk_test
Executable file
43
src/processor/microdump_stackwalk_test
Executable file
@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2014, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
source "${0%/*}/microdump_stackwalk_test_vars" # for MICRODUMP_SUPPORTED_ARCHS.
|
||||
testdata_dir=$srcdir/src/processor/testdata
|
||||
|
||||
set -e # Bail out with an error if any of the commands below fails.
|
||||
for ARCH in $MICRODUMP_SUPPORTED_ARCHS; do
|
||||
echo "Testing microdump_stackwalk for arch $ARCH"
|
||||
./src/processor/microdump_stackwalk $testdata_dir/microdump-${ARCH}.dmp \
|
||||
$testdata_dir/symbols/microdump | \
|
||||
tr -d '\015' | \
|
||||
diff -u $testdata_dir/microdump.stackwalk-${ARCH}.out -
|
||||
done
|
||||
exit 0
|
1
src/processor/microdump_stackwalk_test_vars
Normal file
1
src/processor/microdump_stackwalk_test_vars
Normal file
@ -0,0 +1 @@
|
||||
MICRODUMP_SUPPORTED_ARCHS="arm arm64"
|
@ -49,7 +49,6 @@
|
||||
#define snprintf _snprintf
|
||||
#else // _WIN32
|
||||
#include <unistd.h>
|
||||
#define O_BINARY 0
|
||||
#endif // _WIN32
|
||||
|
||||
#include <fstream>
|
||||
@ -2548,12 +2547,26 @@ bool MinidumpModuleList::Read(uint32_t expected_size) {
|
||||
}
|
||||
|
||||
if (!range_map_->StoreRange(base_address, module_size, module_index)) {
|
||||
// Android's shared memory implementation /dev/ashmem can contain
|
||||
// duplicate entries for JITted code, so ignore these.
|
||||
// TODO(wfh): Remove this code when Android is fixed.
|
||||
// See https://crbug.com/439531
|
||||
const string kDevAshmem("/dev/ashmem/");
|
||||
if (module->code_file().compare(
|
||||
0, kDevAshmem.length(), kDevAshmem) != 0) {
|
||||
BPLOG(ERROR) << "MinidumpModuleList could not store module " <<
|
||||
module_index << "/" << module_count << ", " <<
|
||||
module->code_file() << ", " <<
|
||||
HexString(base_address) << "+" <<
|
||||
HexString(module_size);
|
||||
return false;
|
||||
} else {
|
||||
BPLOG(INFO) << "MinidumpModuleList ignoring overlapping module " <<
|
||||
module_index << "/" << module_count << ", " <<
|
||||
module->code_file() << ", " <<
|
||||
HexString(base_address) << "+" <<
|
||||
HexString(module_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,9 @@ ProcessResult MinidumpProcessor::Process(
|
||||
}
|
||||
process_state->time_date_stamp_ = header->time_date_stamp;
|
||||
|
||||
bool has_process_create_time =
|
||||
GetProcessCreateTime(dump, &process_state->process_create_time_);
|
||||
|
||||
bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_);
|
||||
bool has_os_info = GetOSInfo(dump, &process_state->system_info_);
|
||||
|
||||
@ -141,8 +144,9 @@ ProcessResult MinidumpProcessor::Process(
|
||||
(exception != NULL ? "" : "no ") << "exception, " <<
|
||||
(module_list != NULL ? "" : "no ") << "module list, " <<
|
||||
(threads != NULL ? "" : "no ") << "thread list, " <<
|
||||
(has_dump_thread ? "" : "no ") << "dump thread, and " <<
|
||||
(has_requesting_thread ? "" : "no ") << "requesting thread";
|
||||
(has_dump_thread ? "" : "no ") << "dump thread, " <<
|
||||
(has_requesting_thread ? "" : "no ") << "requesting thread, and " <<
|
||||
(has_process_create_time ? "" : "no ") << "process create time";
|
||||
|
||||
bool interrupted = false;
|
||||
bool found_requesting_thread = false;
|
||||
@ -618,6 +622,32 @@ bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump,
|
||||
uint32_t* process_create_time) {
|
||||
assert(dump);
|
||||
assert(process_create_time);
|
||||
|
||||
*process_create_time = 0;
|
||||
|
||||
MinidumpMiscInfo* minidump_misc_info = dump->GetMiscInfo();
|
||||
if (!minidump_misc_info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const MDRawMiscInfo* md_raw_misc_info = minidump_misc_info->misc_info();
|
||||
if (!md_raw_misc_info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(md_raw_misc_info->flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*process_create_time = md_raw_misc_info->process_create_time;
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
|
||||
MinidumpException *exception = dump->GetException();
|
||||
|
@ -66,6 +66,7 @@ class MockMinidump : public Minidump {
|
||||
MOCK_CONST_METHOD0(header, const MDRawHeader*());
|
||||
MOCK_METHOD0(GetThreadList, MinidumpThreadList*());
|
||||
MOCK_METHOD0(GetSystemInfo, MinidumpSystemInfo*());
|
||||
MOCK_METHOD0(GetMiscInfo, MinidumpMiscInfo*());
|
||||
MOCK_METHOD0(GetBreakpadInfo, MinidumpBreakpadInfo*());
|
||||
MOCK_METHOD0(GetException, MinidumpException*());
|
||||
MOCK_METHOD0(GetAssertion, MinidumpAssertion*());
|
||||
@ -126,6 +127,17 @@ class MockMinidumpMemoryRegion : public MinidumpMemoryRegion {
|
||||
MockMemoryRegion region_;
|
||||
};
|
||||
|
||||
// A test miscelaneous info stream, just returns values from the
|
||||
// MDRawMiscInfo fed to it.
|
||||
class TestMinidumpMiscInfo : public MinidumpMiscInfo {
|
||||
public:
|
||||
explicit TestMinidumpMiscInfo(const MDRawMiscInfo& misc_info) :
|
||||
MinidumpMiscInfo(NULL) {
|
||||
valid_ = true;
|
||||
misc_info_ = misc_info;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
namespace {
|
||||
@ -135,6 +147,7 @@ using google_breakpad::CallStack;
|
||||
using google_breakpad::CodeModule;
|
||||
using google_breakpad::MinidumpContext;
|
||||
using google_breakpad::MinidumpMemoryRegion;
|
||||
using google_breakpad::MinidumpMiscInfo;
|
||||
using google_breakpad::MinidumpProcessor;
|
||||
using google_breakpad::MinidumpSystemInfo;
|
||||
using google_breakpad::MinidumpThreadList;
|
||||
@ -402,6 +415,8 @@ TEST_F(MinidumpProcessorTest, TestBasicProcessing) {
|
||||
ASSERT_EQ(state.crash_address(), 0x45U);
|
||||
ASSERT_EQ(state.threads()->size(), size_t(1));
|
||||
ASSERT_EQ(state.requesting_thread(), 0);
|
||||
EXPECT_EQ(1171480435U, state.time_date_stamp());
|
||||
EXPECT_EQ(1171480435U, state.process_create_time());
|
||||
|
||||
CallStack *stack = state.threads()->at(0);
|
||||
ASSERT_TRUE(stack);
|
||||
@ -529,6 +544,40 @@ TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) {
|
||||
ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction);
|
||||
}
|
||||
|
||||
TEST_F(MinidumpProcessorTest, GetProcessCreateTime) {
|
||||
const uint32_t kProcessCreateTime = 2000;
|
||||
const uint32_t kTimeDateStamp = 5000;
|
||||
MockMinidump dump;
|
||||
EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
|
||||
EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true));
|
||||
|
||||
// Set time of crash.
|
||||
MDRawHeader fake_header;
|
||||
fake_header.time_date_stamp = kTimeDateStamp;
|
||||
EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header));
|
||||
|
||||
// Set process create time.
|
||||
MDRawMiscInfo raw_misc_info;
|
||||
memset(&raw_misc_info, 0, sizeof(raw_misc_info));
|
||||
raw_misc_info.process_create_time = kProcessCreateTime;
|
||||
raw_misc_info.flags1 |= MD_MISCINFO_FLAGS1_PROCESS_TIMES;
|
||||
google_breakpad::TestMinidumpMiscInfo dump_misc_info(raw_misc_info);
|
||||
EXPECT_CALL(dump, GetMiscInfo()).WillRepeatedly(Return(&dump_misc_info));
|
||||
|
||||
// No threads
|
||||
MockMinidumpThreadList thread_list;
|
||||
EXPECT_CALL(dump, GetThreadList()).WillOnce(Return(&thread_list));
|
||||
EXPECT_CALL(thread_list, thread_count()).WillRepeatedly(Return(0));
|
||||
|
||||
MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
|
||||
ProcessState state;
|
||||
EXPECT_EQ(google_breakpad::PROCESS_OK, processor.Process(&dump, &state));
|
||||
|
||||
// Verify the time stamps.
|
||||
ASSERT_EQ(kTimeDateStamp, state.time_date_stamp());
|
||||
ASSERT_EQ(kProcessCreateTime, state.process_create_time());
|
||||
}
|
||||
|
||||
TEST_F(MinidumpProcessorTest, TestThreadMissingContext) {
|
||||
MockMinidump dump;
|
||||
EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump"));
|
||||
|
@ -33,7 +33,6 @@
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
@ -42,744 +41,22 @@
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/code_modules.h"
|
||||
#include "google_breakpad/processor/minidump.h"
|
||||
#include "google_breakpad/processor/minidump_processor.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/pathname_stripper.h"
|
||||
#include "processor/simple_symbol_supplier.h"
|
||||
#include "processor/stackwalk_common.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
using std::vector;
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::CallStack;
|
||||
using google_breakpad::CodeModule;
|
||||
using google_breakpad::CodeModules;
|
||||
using google_breakpad::MinidumpModule;
|
||||
using google_breakpad::Minidump;
|
||||
using google_breakpad::MinidumpProcessor;
|
||||
using google_breakpad::PathnameStripper;
|
||||
using google_breakpad::ProcessState;
|
||||
using google_breakpad::scoped_ptr;
|
||||
using google_breakpad::SimpleSymbolSupplier;
|
||||
using google_breakpad::StackFrame;
|
||||
using google_breakpad::StackFramePPC;
|
||||
using google_breakpad::StackFrameSPARC;
|
||||
using google_breakpad::StackFrameX86;
|
||||
using google_breakpad::StackFrameAMD64;
|
||||
using google_breakpad::StackFrameARM;
|
||||
using google_breakpad::StackFrameARM64;
|
||||
using google_breakpad::StackFrameMIPS;
|
||||
|
||||
// Separator character for machine readable output.
|
||||
static const char kOutputSeparator = '|';
|
||||
|
||||
// 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 |start_col|. For registers in a set, pass the most recent
|
||||
// return value of PrintRegister.
|
||||
// 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 const int kMaxWidth = 80; // optimize for an 80-column terminal
|
||||
static int PrintRegister(const char *name, uint32_t value, int start_col) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), " %5s = 0x%08x", name, value);
|
||||
|
||||
if (start_col + static_cast<ssize_t>(strlen(buffer)) > kMaxWidth) {
|
||||
start_col = 0;
|
||||
printf("\n ");
|
||||
}
|
||||
fputs(buffer, stdout);
|
||||
|
||||
return start_col + strlen(buffer);
|
||||
}
|
||||
|
||||
// PrintRegister64 does the same thing, but for 64-bit registers.
|
||||
static int PrintRegister64(const char *name, uint64_t value, int start_col) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), " %5s = 0x%016" PRIx64 , name, value);
|
||||
|
||||
if (start_col + static_cast<ssize_t>(strlen(buffer)) > kMaxWidth) {
|
||||
start_col = 0;
|
||||
printf("\n ");
|
||||
}
|
||||
fputs(buffer, stdout);
|
||||
|
||||
return start_col + strlen(buffer);
|
||||
}
|
||||
|
||||
// StripSeparator takes a string |original| and returns a copy
|
||||
// of the string with all occurences of |kOutputSeparator| removed.
|
||||
static string StripSeparator(const string &original) {
|
||||
string result = original;
|
||||
string::size_type position = 0;
|
||||
while ((position = result.find(kOutputSeparator, position)) != string::npos) {
|
||||
result.erase(position, 1);
|
||||
}
|
||||
position = 0;
|
||||
while ((position = result.find('\n', position)) != string::npos) {
|
||||
result.erase(position, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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();
|
||||
if (frame_count == 0) {
|
||||
printf(" <no frames>\n");
|
||||
}
|
||||
for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
|
||||
const StackFrame *frame = stack->frames()->at(frame_index);
|
||||
printf("%2d ", frame_index);
|
||||
|
||||
uint64_t instruction_address = frame->ReturnAddress();
|
||||
|
||||
if (frame->module) {
|
||||
printf("%s", PathnameStripper::File(frame->module->code_file()).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%" PRIx64 "]",
|
||||
source_file.c_str(),
|
||||
frame->source_line,
|
||||
instruction_address - frame->source_line_base);
|
||||
} else {
|
||||
printf(" + 0x%" PRIx64, instruction_address - frame->function_base);
|
||||
}
|
||||
} else {
|
||||
printf(" + 0x%" PRIx64,
|
||||
instruction_address - frame->module->base_address());
|
||||
}
|
||||
} else {
|
||||
printf("0x%" PRIx64, instruction_address);
|
||||
}
|
||||
printf("\n ");
|
||||
|
||||
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);
|
||||
} else if (cpu == "amd64") {
|
||||
const StackFrameAMD64 *frame_amd64 =
|
||||
reinterpret_cast<const StackFrameAMD64*>(frame);
|
||||
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RAX)
|
||||
sequence = PrintRegister64("rax", frame_amd64->context.rax, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDX)
|
||||
sequence = PrintRegister64("rdx", frame_amd64->context.rdx, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RCX)
|
||||
sequence = PrintRegister64("rcx", frame_amd64->context.rcx, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBX)
|
||||
sequence = PrintRegister64("rbx", frame_amd64->context.rbx, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSI)
|
||||
sequence = PrintRegister64("rsi", frame_amd64->context.rsi, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDI)
|
||||
sequence = PrintRegister64("rdi", frame_amd64->context.rdi, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP)
|
||||
sequence = PrintRegister64("rbp", frame_amd64->context.rbp, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP)
|
||||
sequence = PrintRegister64("rsp", frame_amd64->context.rsp, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R8)
|
||||
sequence = PrintRegister64("r8", frame_amd64->context.r8, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R9)
|
||||
sequence = PrintRegister64("r9", frame_amd64->context.r9, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R10)
|
||||
sequence = PrintRegister64("r10", frame_amd64->context.r10, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R11)
|
||||
sequence = PrintRegister64("r11", frame_amd64->context.r11, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R12)
|
||||
sequence = PrintRegister64("r12", frame_amd64->context.r12, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R13)
|
||||
sequence = PrintRegister64("r13", frame_amd64->context.r13, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R14)
|
||||
sequence = PrintRegister64("r14", frame_amd64->context.r14, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R15)
|
||||
sequence = PrintRegister64("r15", frame_amd64->context.r15, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP)
|
||||
sequence = PrintRegister64("rip", frame_amd64->context.rip, sequence);
|
||||
} else if (cpu == "sparc") {
|
||||
const StackFrameSPARC *frame_sparc =
|
||||
reinterpret_cast<const StackFrameSPARC*>(frame);
|
||||
|
||||
if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP)
|
||||
sequence = PrintRegister("sp", frame_sparc->context.g_r[14], sequence);
|
||||
if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP)
|
||||
sequence = PrintRegister("fp", frame_sparc->context.g_r[30], sequence);
|
||||
if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC)
|
||||
sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
|
||||
} else if (cpu == "arm") {
|
||||
const StackFrameARM *frame_arm =
|
||||
reinterpret_cast<const StackFrameARM*>(frame);
|
||||
|
||||
// Argument registers (caller-saves), which will likely only be valid
|
||||
// for the youngest frame.
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0)
|
||||
sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1)
|
||||
sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2)
|
||||
sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3)
|
||||
sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence);
|
||||
|
||||
// General-purpose callee-saves registers.
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4)
|
||||
sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R5)
|
||||
sequence = PrintRegister("r5", frame_arm->context.iregs[5], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R6)
|
||||
sequence = PrintRegister("r6", frame_arm->context.iregs[6], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R7)
|
||||
sequence = PrintRegister("r7", frame_arm->context.iregs[7], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R8)
|
||||
sequence = PrintRegister("r8", frame_arm->context.iregs[8], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R9)
|
||||
sequence = PrintRegister("r9", frame_arm->context.iregs[9], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R10)
|
||||
sequence = PrintRegister("r10", frame_arm->context.iregs[10], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R12)
|
||||
sequence = PrintRegister("r12", frame_arm->context.iregs[12], sequence);
|
||||
|
||||
// Registers with a dedicated or conventional purpose.
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_FP)
|
||||
sequence = PrintRegister("fp", frame_arm->context.iregs[11], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)
|
||||
sequence = PrintRegister("sp", frame_arm->context.iregs[13], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_LR)
|
||||
sequence = PrintRegister("lr", frame_arm->context.iregs[14], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_PC)
|
||||
sequence = PrintRegister("pc", frame_arm->context.iregs[15], sequence);
|
||||
} else if (cpu == "arm64") {
|
||||
const StackFrameARM64 *frame_arm64 =
|
||||
reinterpret_cast<const StackFrameARM64*>(frame);
|
||||
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X0) {
|
||||
sequence =
|
||||
PrintRegister64("x0", frame_arm64->context.iregs[0], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X1) {
|
||||
sequence =
|
||||
PrintRegister64("x1", frame_arm64->context.iregs[1], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X2) {
|
||||
sequence =
|
||||
PrintRegister64("x2", frame_arm64->context.iregs[2], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X3) {
|
||||
sequence =
|
||||
PrintRegister64("x3", frame_arm64->context.iregs[3], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X4) {
|
||||
sequence =
|
||||
PrintRegister64("x4", frame_arm64->context.iregs[4], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X5) {
|
||||
sequence =
|
||||
PrintRegister64("x5", frame_arm64->context.iregs[5], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X6) {
|
||||
sequence =
|
||||
PrintRegister64("x6", frame_arm64->context.iregs[6], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X7) {
|
||||
sequence =
|
||||
PrintRegister64("x7", frame_arm64->context.iregs[7], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X8) {
|
||||
sequence =
|
||||
PrintRegister64("x8", frame_arm64->context.iregs[8], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X9) {
|
||||
sequence =
|
||||
PrintRegister64("x9", frame_arm64->context.iregs[9], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X10) {
|
||||
sequence =
|
||||
PrintRegister64("x10", frame_arm64->context.iregs[10], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X11) {
|
||||
sequence =
|
||||
PrintRegister64("x11", frame_arm64->context.iregs[11], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X12) {
|
||||
sequence =
|
||||
PrintRegister64("x12", frame_arm64->context.iregs[12], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X13) {
|
||||
sequence =
|
||||
PrintRegister64("x13", frame_arm64->context.iregs[13], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X14) {
|
||||
sequence =
|
||||
PrintRegister64("x14", frame_arm64->context.iregs[14], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X15) {
|
||||
sequence =
|
||||
PrintRegister64("x15", frame_arm64->context.iregs[15], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X16) {
|
||||
sequence =
|
||||
PrintRegister64("x16", frame_arm64->context.iregs[16], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X17) {
|
||||
sequence =
|
||||
PrintRegister64("x17", frame_arm64->context.iregs[17], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X18) {
|
||||
sequence =
|
||||
PrintRegister64("x18", frame_arm64->context.iregs[18], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X19) {
|
||||
sequence =
|
||||
PrintRegister64("x19", frame_arm64->context.iregs[19], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X20) {
|
||||
sequence =
|
||||
PrintRegister64("x20", frame_arm64->context.iregs[20], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X21) {
|
||||
sequence =
|
||||
PrintRegister64("x21", frame_arm64->context.iregs[21], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X22) {
|
||||
sequence =
|
||||
PrintRegister64("x22", frame_arm64->context.iregs[22], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X23) {
|
||||
sequence =
|
||||
PrintRegister64("x23", frame_arm64->context.iregs[23], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X24) {
|
||||
sequence =
|
||||
PrintRegister64("x24", frame_arm64->context.iregs[24], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X25) {
|
||||
sequence =
|
||||
PrintRegister64("x25", frame_arm64->context.iregs[25], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X26) {
|
||||
sequence =
|
||||
PrintRegister64("x26", frame_arm64->context.iregs[26], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X27) {
|
||||
sequence =
|
||||
PrintRegister64("x27", frame_arm64->context.iregs[27], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X28) {
|
||||
sequence =
|
||||
PrintRegister64("x28", frame_arm64->context.iregs[28], sequence);
|
||||
}
|
||||
|
||||
// Registers with a dedicated or conventional purpose.
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_FP) {
|
||||
sequence =
|
||||
PrintRegister64("fp", frame_arm64->context.iregs[29], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_LR) {
|
||||
sequence =
|
||||
PrintRegister64("lr", frame_arm64->context.iregs[30], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) {
|
||||
sequence =
|
||||
PrintRegister64("sp", frame_arm64->context.iregs[31], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_PC) {
|
||||
sequence =
|
||||
PrintRegister64("pc", frame_arm64->context.iregs[32], sequence);
|
||||
}
|
||||
} else if (cpu == "mips") {
|
||||
const StackFrameMIPS* frame_mips =
|
||||
reinterpret_cast<const StackFrameMIPS*>(frame);
|
||||
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_GP)
|
||||
sequence = PrintRegister64("gp",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_GP],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_SP)
|
||||
sequence = PrintRegister64("sp",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_SP],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_FP)
|
||||
sequence = PrintRegister64("fp",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_FP],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_RA)
|
||||
sequence = PrintRegister64("ra",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_RA],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_PC)
|
||||
sequence = PrintRegister64("pc", frame_mips->context.epc, sequence);
|
||||
|
||||
// Save registers s0-s7
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S0)
|
||||
sequence = PrintRegister64("s0",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S0],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S1)
|
||||
sequence = PrintRegister64("s1",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S1],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S2)
|
||||
sequence = PrintRegister64("s2",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S2],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S3)
|
||||
sequence = PrintRegister64("s3",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S3],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S4)
|
||||
sequence = PrintRegister64("s4",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S4],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S5)
|
||||
sequence = PrintRegister64("s5",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S5],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6)
|
||||
sequence = PrintRegister64("s6",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7)
|
||||
sequence = PrintRegister64("s7",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7],
|
||||
sequence);
|
||||
}
|
||||
printf("\n Found by: %s\n", frame->trust_description().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// PrintStackMachineReadable prints the call stack in |stack| to stdout,
|
||||
// in the following machine readable pipe-delimited text format:
|
||||
// thread number|frame number|module|function|source file|line|offset
|
||||
//
|
||||
// Module, function, source file, and source line may all be empty
|
||||
// depending on availability. The code offset follows the same rules as
|
||||
// PrintStack above.
|
||||
static void PrintStackMachineReadable(int thread_num, const CallStack *stack) {
|
||||
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("%d%c%d%c", thread_num, kOutputSeparator, frame_index,
|
||||
kOutputSeparator);
|
||||
|
||||
uint64_t instruction_address = frame->ReturnAddress();
|
||||
|
||||
if (frame->module) {
|
||||
assert(!frame->module->code_file().empty());
|
||||
printf("%s", StripSeparator(PathnameStripper::File(
|
||||
frame->module->code_file())).c_str());
|
||||
if (!frame->function_name.empty()) {
|
||||
printf("%c%s", kOutputSeparator,
|
||||
StripSeparator(frame->function_name).c_str());
|
||||
if (!frame->source_file_name.empty()) {
|
||||
printf("%c%s%c%d%c0x%" PRIx64,
|
||||
kOutputSeparator,
|
||||
StripSeparator(frame->source_file_name).c_str(),
|
||||
kOutputSeparator,
|
||||
frame->source_line,
|
||||
kOutputSeparator,
|
||||
instruction_address - frame->source_line_base);
|
||||
} else {
|
||||
printf("%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
instruction_address - frame->function_base);
|
||||
}
|
||||
} else {
|
||||
printf("%c%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty function name
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
instruction_address - frame->module->base_address());
|
||||
}
|
||||
} else {
|
||||
// the printf before this prints a trailing separator for module name
|
||||
printf("%c%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty function name
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
instruction_address);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ContainsModule checks whether a given |module| is in the vector
|
||||
// |modules_without_symbols|.
|
||||
static bool ContainsModule(
|
||||
const vector<const CodeModule*> *modules,
|
||||
const CodeModule *module) {
|
||||
assert(modules);
|
||||
assert(module);
|
||||
vector<const CodeModule*>::const_iterator iter;
|
||||
for (iter = modules->begin(); iter != modules->end(); ++iter) {
|
||||
if (module->debug_file().compare((*iter)->debug_file()) == 0 &&
|
||||
module->debug_identifier().compare((*iter)->debug_identifier()) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// PrintModule prints a single |module| to stdout.
|
||||
// |modules_without_symbols| should contain the list of modules that were
|
||||
// confirmed to be missing their symbols during the stack walk.
|
||||
static void PrintModule(
|
||||
const CodeModule *module,
|
||||
const vector<const CodeModule*> *modules_without_symbols,
|
||||
const vector<const CodeModule*> *modules_with_corrupt_symbols,
|
||||
uint64_t main_address) {
|
||||
string symbol_issues;
|
||||
if (ContainsModule(modules_without_symbols, module)) {
|
||||
symbol_issues = " (WARNING: No symbols, " +
|
||||
PathnameStripper::File(module->debug_file()) + ", " +
|
||||
module->debug_identifier() + ")";
|
||||
} else if (ContainsModule(modules_with_corrupt_symbols, module)) {
|
||||
symbol_issues = " (WARNING: Corrupt symbols, " +
|
||||
PathnameStripper::File(module->debug_file()) + ", " +
|
||||
module->debug_identifier() + ")";
|
||||
}
|
||||
uint64_t base_address = module->base_address();
|
||||
printf("0x%08" PRIx64 " - 0x%08" PRIx64 " %s %s%s%s\n",
|
||||
base_address, base_address + module->size() - 1,
|
||||
PathnameStripper::File(module->code_file()).c_str(),
|
||||
module->version().empty() ? "???" : module->version().c_str(),
|
||||
main_address != 0 && base_address == main_address ? " (main)" : "",
|
||||
symbol_issues.c_str());
|
||||
}
|
||||
|
||||
// PrintModules prints the list of all loaded |modules| to stdout.
|
||||
// |modules_without_symbols| should contain the list of modules that were
|
||||
// confirmed to be missing their symbols during the stack walk.
|
||||
static void PrintModules(
|
||||
const CodeModules *modules,
|
||||
const vector<const CodeModule*> *modules_without_symbols,
|
||||
const vector<const CodeModule*> *modules_with_corrupt_symbols) {
|
||||
if (!modules)
|
||||
return;
|
||||
|
||||
printf("\n");
|
||||
printf("Loaded modules:\n");
|
||||
|
||||
uint64_t main_address = 0;
|
||||
const CodeModule *main_module = modules->GetMainModule();
|
||||
if (main_module) {
|
||||
main_address = main_module->base_address();
|
||||
}
|
||||
|
||||
unsigned int module_count = modules->module_count();
|
||||
for (unsigned int module_sequence = 0;
|
||||
module_sequence < module_count;
|
||||
++module_sequence) {
|
||||
const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
|
||||
PrintModule(module, modules_without_symbols, modules_with_corrupt_symbols,
|
||||
main_address);
|
||||
}
|
||||
}
|
||||
|
||||
// PrintModulesMachineReadable outputs a list of loaded modules,
|
||||
// one per line, in the following machine-readable pipe-delimited
|
||||
// text format:
|
||||
// Module|{Module Filename}|{Version}|{Debug Filename}|{Debug Identifier}|
|
||||
// {Base Address}|{Max Address}|{Main}
|
||||
static void PrintModulesMachineReadable(const CodeModules *modules) {
|
||||
if (!modules)
|
||||
return;
|
||||
|
||||
uint64_t main_address = 0;
|
||||
const CodeModule *main_module = modules->GetMainModule();
|
||||
if (main_module) {
|
||||
main_address = main_module->base_address();
|
||||
}
|
||||
|
||||
unsigned int module_count = modules->module_count();
|
||||
for (unsigned int module_sequence = 0;
|
||||
module_sequence < module_count;
|
||||
++module_sequence) {
|
||||
const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
|
||||
uint64_t base_address = module->base_address();
|
||||
printf("Module%c%s%c%s%c%s%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n",
|
||||
kOutputSeparator,
|
||||
StripSeparator(PathnameStripper::File(module->code_file())).c_str(),
|
||||
kOutputSeparator, StripSeparator(module->version()).c_str(),
|
||||
kOutputSeparator,
|
||||
StripSeparator(PathnameStripper::File(module->debug_file())).c_str(),
|
||||
kOutputSeparator,
|
||||
StripSeparator(module->debug_identifier()).c_str(),
|
||||
kOutputSeparator, base_address,
|
||||
kOutputSeparator, base_address + module->size() - 1,
|
||||
kOutputSeparator,
|
||||
main_module != NULL && base_address == main_address ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintProcessState(const ProcessState& process_state) {
|
||||
// Print OS and CPU information.
|
||||
string cpu = process_state.system_info()->cpu;
|
||||
string cpu_info = process_state.system_info()->cpu_info;
|
||||
printf("Operating system: %s\n", process_state.system_info()->os.c_str());
|
||||
printf(" %s\n",
|
||||
process_state.system_info()->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(" %d CPU%s\n",
|
||||
process_state.system_info()->cpu_count,
|
||||
process_state.system_info()->cpu_count != 1 ? "s" : "");
|
||||
printf("\n");
|
||||
|
||||
// Print crash information.
|
||||
if (process_state.crashed()) {
|
||||
printf("Crash reason: %s\n", process_state.crash_reason().c_str());
|
||||
printf("Crash address: 0x%" PRIx64 "\n", process_state.crash_address());
|
||||
} else {
|
||||
printf("No crash\n");
|
||||
}
|
||||
|
||||
string assertion = process_state.assertion();
|
||||
if (!assertion.empty()) {
|
||||
printf("Assertion: %s\n", assertion.c_str());
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
PrintModules(process_state.modules(),
|
||||
process_state.modules_without_symbols(),
|
||||
process_state.modules_with_corrupt_symbols());
|
||||
}
|
||||
|
||||
static void PrintProcessStateMachineReadable(const ProcessState& process_state)
|
||||
{
|
||||
// Print OS and CPU information.
|
||||
// OS|{OS Name}|{OS Version}
|
||||
// CPU|{CPU Name}|{CPU Info}|{Number of CPUs}
|
||||
printf("OS%c%s%c%s\n", kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->os).c_str(),
|
||||
kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->os_version).c_str());
|
||||
printf("CPU%c%s%c%s%c%d\n", kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->cpu).c_str(),
|
||||
kOutputSeparator,
|
||||
// this may be empty
|
||||
StripSeparator(process_state.system_info()->cpu_info).c_str(),
|
||||
kOutputSeparator,
|
||||
process_state.system_info()->cpu_count);
|
||||
|
||||
int requesting_thread = process_state.requesting_thread();
|
||||
|
||||
// Print crash information.
|
||||
// Crash|{Crash Reason}|{Crash Address}|{Crashed Thread}
|
||||
printf("Crash%c", kOutputSeparator);
|
||||
if (process_state.crashed()) {
|
||||
printf("%s%c0x%" PRIx64 "%c",
|
||||
StripSeparator(process_state.crash_reason()).c_str(),
|
||||
kOutputSeparator, process_state.crash_address(), kOutputSeparator);
|
||||
} else {
|
||||
// print assertion info, if available, in place of crash reason,
|
||||
// instead of the unhelpful "No crash"
|
||||
string assertion = process_state.assertion();
|
||||
if (!assertion.empty()) {
|
||||
printf("%s%c%c", StripSeparator(assertion).c_str(),
|
||||
kOutputSeparator, kOutputSeparator);
|
||||
} else {
|
||||
printf("No crash%c%c", kOutputSeparator, kOutputSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
if (requesting_thread != -1) {
|
||||
printf("%d\n", requesting_thread);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
PrintModulesMachineReadable(process_state.modules());
|
||||
|
||||
// blank line to indicate start of threads
|
||||
printf("\n");
|
||||
|
||||
// If the thread that requested the dump is known, print it first.
|
||||
if (requesting_thread != -1) {
|
||||
PrintStackMachineReadable(requesting_thread,
|
||||
process_state.threads()->at(requesting_thread));
|
||||
}
|
||||
|
||||
// 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.
|
||||
PrintStackMachineReadable(thread_index,
|
||||
process_state.threads()->at(thread_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
using google_breakpad::scoped_ptr;
|
||||
|
||||
// Processes |minidump_file| using MinidumpProcessor. |symbol_path|, if
|
||||
// non-empty, is the base directory of a symbol storage area, laid out in
|
||||
@ -791,9 +68,10 @@ static void PrintProcessStateMachineReadable(const ProcessState& process_state)
|
||||
// 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 vector<string> &symbol_paths,
|
||||
bool machine_readable) {
|
||||
bool PrintMinidumpProcess(const string &minidump_file,
|
||||
const std::vector<string> &symbol_paths,
|
||||
bool machine_readable,
|
||||
bool output_stack_contents) {
|
||||
scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
|
||||
if (!symbol_paths.empty()) {
|
||||
// TODO(mmentovai): check existence of symbol_path if specified?
|
||||
@ -804,8 +82,13 @@ static bool PrintMinidumpProcess(const string &minidump_file,
|
||||
MinidumpProcessor minidump_processor(symbol_supplier.get(), &resolver);
|
||||
|
||||
// Process the minidump.
|
||||
Minidump dump(minidump_file);
|
||||
if (!dump.Read()) {
|
||||
BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read";
|
||||
return false;
|
||||
}
|
||||
ProcessState process_state;
|
||||
if (minidump_processor.Process(minidump_file, &process_state) !=
|
||||
if (minidump_processor.Process(&dump, &process_state) !=
|
||||
google_breakpad::PROCESS_OK) {
|
||||
BPLOG(ERROR) << "MinidumpProcessor::Process failed";
|
||||
return false;
|
||||
@ -814,20 +97,21 @@ static bool PrintMinidumpProcess(const string &minidump_file,
|
||||
if (machine_readable) {
|
||||
PrintProcessStateMachineReadable(process_state);
|
||||
} else {
|
||||
PrintProcessState(process_state);
|
||||
PrintProcessState(process_state, output_stack_contents, &resolver);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static void usage(const char *program_name) {
|
||||
fprintf(stderr, "usage: %s [-m] <minidump-file> [symbol-path ...]\n"
|
||||
" -m : Output in machine-readable format\n",
|
||||
void usage(const char *program_name) {
|
||||
fprintf(stderr, "usage: %s [-m|-s] <minidump-file> [symbol-path ...]\n"
|
||||
" -m : Output in machine-readable format\n"
|
||||
" -s : Output stack contents\n",
|
||||
program_name);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
BPLOG_INIT(&argc, &argv);
|
||||
|
||||
@ -837,7 +121,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
const char *minidump_file;
|
||||
bool machine_readable;
|
||||
bool machine_readable = false;
|
||||
bool output_stack_contents = false;
|
||||
int symbol_path_arg;
|
||||
|
||||
if (strcmp(argv[1], "-m") == 0) {
|
||||
@ -849,8 +134,16 @@ int main(int argc, char **argv) {
|
||||
machine_readable = true;
|
||||
minidump_file = argv[2];
|
||||
symbol_path_arg = 3;
|
||||
} else if (strcmp(argv[1], "-s") == 0) {
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
output_stack_contents = true;
|
||||
minidump_file = argv[2];
|
||||
symbol_path_arg = 3;
|
||||
} else {
|
||||
machine_readable = false;
|
||||
minidump_file = argv[1];
|
||||
symbol_path_arg = 2;
|
||||
}
|
||||
@ -864,5 +157,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
return PrintMinidumpProcess(minidump_file,
|
||||
symbol_paths,
|
||||
machine_readable) ? 0 : 1;
|
||||
machine_readable,
|
||||
output_stack_contents) ? 0 : 1;
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ ProcessState::~ProcessState() {
|
||||
|
||||
void ProcessState::Clear() {
|
||||
time_date_stamp_ = 0;
|
||||
process_create_time_ = 0;
|
||||
crashed_ = false;
|
||||
crash_reason_.clear();
|
||||
crash_address_ = 0;
|
||||
|
@ -46,11 +46,14 @@ package google_breakpad;
|
||||
// A proto representation of a process, in a fully-digested state.
|
||||
// See src/google_breakpad/processor/process_state.h
|
||||
message ProcessStateProto {
|
||||
// Next value: 13
|
||||
// Next value: 14
|
||||
|
||||
// The time-date stamp of the original minidump (time_t format)
|
||||
optional int64 time_date_stamp = 1;
|
||||
|
||||
// The time-date stamp when the process was created (time_t format)
|
||||
optional int64 process_create_time = 13;
|
||||
|
||||
message Crash {
|
||||
// The type of crash. OS- and possibly CPU- specific. For example,
|
||||
// "EXCEPTION_ACCESS_VIOLATION" (Windows), "EXC_BAD_ACCESS /
|
||||
|
929
src/processor/stackwalk_common.cc
Normal file
929
src/processor/stackwalk_common.cc
Normal file
@ -0,0 +1,929 @@
|
||||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stackwalk_common.cc: Module shared by the {micro,mini}dump_stackwalck
|
||||
// executables to print the content of dumps (w/ stack traces) on the console.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#include "processor/stackwalk_common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/code_modules.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/pathname_stripper.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
namespace {
|
||||
|
||||
using std::vector;
|
||||
|
||||
// Separator character for machine readable output.
|
||||
static const char kOutputSeparator = '|';
|
||||
|
||||
// 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 |start_col|. For registers in a set, pass the most recent
|
||||
// return value of PrintRegister.
|
||||
// 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 const int kMaxWidth = 80; // optimize for an 80-column terminal
|
||||
static int PrintRegister(const char *name, uint32_t value, int start_col) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), " %5s = 0x%08x", name, value);
|
||||
|
||||
if (start_col + static_cast<ssize_t>(strlen(buffer)) > kMaxWidth) {
|
||||
start_col = 0;
|
||||
printf("\n ");
|
||||
}
|
||||
fputs(buffer, stdout);
|
||||
|
||||
return start_col + strlen(buffer);
|
||||
}
|
||||
|
||||
// PrintRegister64 does the same thing, but for 64-bit registers.
|
||||
static int PrintRegister64(const char *name, uint64_t value, int start_col) {
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), " %5s = 0x%016" PRIx64 , name, value);
|
||||
|
||||
if (start_col + static_cast<ssize_t>(strlen(buffer)) > kMaxWidth) {
|
||||
start_col = 0;
|
||||
printf("\n ");
|
||||
}
|
||||
fputs(buffer, stdout);
|
||||
|
||||
return start_col + strlen(buffer);
|
||||
}
|
||||
|
||||
// StripSeparator takes a string |original| and returns a copy
|
||||
// of the string with all occurences of |kOutputSeparator| removed.
|
||||
static string StripSeparator(const string &original) {
|
||||
string result = original;
|
||||
string::size_type position = 0;
|
||||
while ((position = result.find(kOutputSeparator, position)) != string::npos) {
|
||||
result.erase(position, 1);
|
||||
}
|
||||
position = 0;
|
||||
while ((position = result.find('\n', position)) != string::npos) {
|
||||
result.erase(position, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// PrintStackContents prints the stack contents of the current frame to stdout.
|
||||
static void PrintStackContents(const std::string &indent,
|
||||
const StackFrame *frame,
|
||||
const StackFrame *prev_frame,
|
||||
const std::string &cpu,
|
||||
const MemoryRegion *memory,
|
||||
const CodeModules* modules,
|
||||
SourceLineResolverInterface *resolver) {
|
||||
// Find stack range.
|
||||
int word_length = 0;
|
||||
uint64_t stack_begin = 0, stack_end = 0;
|
||||
if (cpu == "x86") {
|
||||
word_length = 4;
|
||||
const StackFrameX86 *frame_x86 = static_cast<const StackFrameX86*>(frame);
|
||||
const StackFrameX86 *prev_frame_x86 =
|
||||
static_cast<const StackFrameX86*>(prev_frame);
|
||||
if ((frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) &&
|
||||
(prev_frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)) {
|
||||
stack_begin = frame_x86->context.esp;
|
||||
stack_end = prev_frame_x86->context.esp;
|
||||
}
|
||||
} else if (cpu == "amd64") {
|
||||
word_length = 8;
|
||||
const StackFrameAMD64 *frame_amd64 =
|
||||
static_cast<const StackFrameAMD64*>(frame);
|
||||
const StackFrameAMD64 *prev_frame_amd64 =
|
||||
static_cast<const StackFrameAMD64*>(prev_frame);
|
||||
if ((frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) &&
|
||||
(prev_frame_amd64->context_validity &
|
||||
StackFrameAMD64::CONTEXT_VALID_RSP)) {
|
||||
stack_begin = frame_amd64->context.rsp;
|
||||
stack_end = prev_frame_amd64->context.rsp;
|
||||
}
|
||||
} else if (cpu == "arm") {
|
||||
word_length = 4;
|
||||
const StackFrameARM *frame_arm = static_cast<const StackFrameARM*>(frame);
|
||||
const StackFrameARM *prev_frame_arm =
|
||||
static_cast<const StackFrameARM*>(prev_frame);
|
||||
if ((frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) &&
|
||||
(prev_frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)) {
|
||||
stack_begin = frame_arm->context.iregs[13];
|
||||
stack_end = prev_frame_arm->context.iregs[13];
|
||||
}
|
||||
} else if (cpu == "arm64") {
|
||||
word_length = 8;
|
||||
const StackFrameARM64 *frame_arm64 =
|
||||
static_cast<const StackFrameARM64*>(frame);
|
||||
const StackFrameARM64 *prev_frame_arm64 =
|
||||
static_cast<const StackFrameARM64*>(prev_frame);
|
||||
if ((frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) &&
|
||||
(prev_frame_arm64->context_validity &
|
||||
StackFrameARM64::CONTEXT_VALID_SP)) {
|
||||
stack_begin = frame_arm64->context.iregs[31];
|
||||
stack_end = prev_frame_arm64->context.iregs[31];
|
||||
}
|
||||
}
|
||||
if (!word_length || !stack_begin || !stack_end)
|
||||
return;
|
||||
|
||||
// Print stack contents.
|
||||
printf("\n%sStack contents:", indent.c_str());
|
||||
for(uint64_t address = stack_begin; address < stack_end; ) {
|
||||
// Print the start address of this row.
|
||||
if (word_length == 4)
|
||||
printf("\n%s %08x", indent.c_str(), static_cast<uint32_t>(address));
|
||||
else
|
||||
printf("\n%s %016" PRIx64, indent.c_str(), address);
|
||||
|
||||
// Print data in hex.
|
||||
const int kBytesPerRow = 16;
|
||||
std::string data_as_string;
|
||||
for (int i = 0; i < kBytesPerRow; ++i, ++address) {
|
||||
uint8_t value = 0;
|
||||
if (address < stack_end &&
|
||||
memory->GetMemoryAtAddress(address, &value)) {
|
||||
printf(" %02x", value);
|
||||
data_as_string.push_back(isprint(value) ? value : '.');
|
||||
} else {
|
||||
printf(" ");
|
||||
data_as_string.push_back(' ');
|
||||
}
|
||||
}
|
||||
// Print data as string.
|
||||
printf(" %s", data_as_string.c_str());
|
||||
}
|
||||
|
||||
// Try to find instruction pointers from stack.
|
||||
printf("\n%sPossible instruction pointers:\n", indent.c_str());
|
||||
for (uint64_t address = stack_begin; address < stack_end;
|
||||
address += word_length) {
|
||||
StackFrame pointee_frame;
|
||||
|
||||
// Read a word (possible instruction pointer) from stack.
|
||||
if (word_length == 4) {
|
||||
uint32_t data32 = 0;
|
||||
memory->GetMemoryAtAddress(address, &data32);
|
||||
pointee_frame.instruction = data32;
|
||||
} else {
|
||||
uint64_t data64 = 0;
|
||||
memory->GetMemoryAtAddress(address, &data64);
|
||||
pointee_frame.instruction = data64;
|
||||
}
|
||||
pointee_frame.module =
|
||||
modules->GetModuleForAddress(pointee_frame.instruction);
|
||||
|
||||
// Try to look up the function name.
|
||||
if (pointee_frame.module)
|
||||
resolver->FillSourceLineInfo(&pointee_frame);
|
||||
|
||||
// Print function name.
|
||||
if (!pointee_frame.function_name.empty()) {
|
||||
if (word_length == 4) {
|
||||
printf("%s *(0x%08x) = 0x%08x", indent.c_str(),
|
||||
static_cast<uint32_t>(address),
|
||||
static_cast<uint32_t>(pointee_frame.instruction));
|
||||
} else {
|
||||
printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64,
|
||||
indent.c_str(), address, pointee_frame.instruction);
|
||||
}
|
||||
printf(" <%s> [%s : %d + 0x%" PRIx64 "]\n",
|
||||
pointee_frame.function_name.c_str(),
|
||||
PathnameStripper::File(pointee_frame.source_file_name).c_str(),
|
||||
pointee_frame.source_line,
|
||||
pointee_frame.instruction - pointee_frame.source_line_base);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// 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,
|
||||
bool output_stack_contents,
|
||||
const MemoryRegion* memory,
|
||||
const CodeModules* modules,
|
||||
SourceLineResolverInterface* resolver) {
|
||||
int frame_count = stack->frames()->size();
|
||||
if (frame_count == 0) {
|
||||
printf(" <no frames>\n");
|
||||
}
|
||||
for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
|
||||
const StackFrame *frame = stack->frames()->at(frame_index);
|
||||
printf("%2d ", frame_index);
|
||||
|
||||
uint64_t instruction_address = frame->ReturnAddress();
|
||||
|
||||
if (frame->module) {
|
||||
printf("%s", PathnameStripper::File(frame->module->code_file()).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%" PRIx64 "]",
|
||||
source_file.c_str(),
|
||||
frame->source_line,
|
||||
instruction_address - frame->source_line_base);
|
||||
} else {
|
||||
printf(" + 0x%" PRIx64, instruction_address - frame->function_base);
|
||||
}
|
||||
} else {
|
||||
printf(" + 0x%" PRIx64,
|
||||
instruction_address - frame->module->base_address());
|
||||
}
|
||||
} else {
|
||||
printf("0x%" PRIx64, instruction_address);
|
||||
}
|
||||
printf("\n ");
|
||||
|
||||
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);
|
||||
} else if (cpu == "amd64") {
|
||||
const StackFrameAMD64 *frame_amd64 =
|
||||
reinterpret_cast<const StackFrameAMD64*>(frame);
|
||||
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RAX)
|
||||
sequence = PrintRegister64("rax", frame_amd64->context.rax, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDX)
|
||||
sequence = PrintRegister64("rdx", frame_amd64->context.rdx, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RCX)
|
||||
sequence = PrintRegister64("rcx", frame_amd64->context.rcx, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBX)
|
||||
sequence = PrintRegister64("rbx", frame_amd64->context.rbx, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSI)
|
||||
sequence = PrintRegister64("rsi", frame_amd64->context.rsi, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDI)
|
||||
sequence = PrintRegister64("rdi", frame_amd64->context.rdi, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP)
|
||||
sequence = PrintRegister64("rbp", frame_amd64->context.rbp, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP)
|
||||
sequence = PrintRegister64("rsp", frame_amd64->context.rsp, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R8)
|
||||
sequence = PrintRegister64("r8", frame_amd64->context.r8, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R9)
|
||||
sequence = PrintRegister64("r9", frame_amd64->context.r9, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R10)
|
||||
sequence = PrintRegister64("r10", frame_amd64->context.r10, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R11)
|
||||
sequence = PrintRegister64("r11", frame_amd64->context.r11, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R12)
|
||||
sequence = PrintRegister64("r12", frame_amd64->context.r12, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R13)
|
||||
sequence = PrintRegister64("r13", frame_amd64->context.r13, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R14)
|
||||
sequence = PrintRegister64("r14", frame_amd64->context.r14, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R15)
|
||||
sequence = PrintRegister64("r15", frame_amd64->context.r15, sequence);
|
||||
if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP)
|
||||
sequence = PrintRegister64("rip", frame_amd64->context.rip, sequence);
|
||||
} else if (cpu == "sparc") {
|
||||
const StackFrameSPARC *frame_sparc =
|
||||
reinterpret_cast<const StackFrameSPARC*>(frame);
|
||||
|
||||
if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP)
|
||||
sequence = PrintRegister("sp", frame_sparc->context.g_r[14], sequence);
|
||||
if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP)
|
||||
sequence = PrintRegister("fp", frame_sparc->context.g_r[30], sequence);
|
||||
if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC)
|
||||
sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
|
||||
} else if (cpu == "arm") {
|
||||
const StackFrameARM *frame_arm =
|
||||
reinterpret_cast<const StackFrameARM*>(frame);
|
||||
|
||||
// Argument registers (caller-saves), which will likely only be valid
|
||||
// for the youngest frame.
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0)
|
||||
sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1)
|
||||
sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2)
|
||||
sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3)
|
||||
sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence);
|
||||
|
||||
// General-purpose callee-saves registers.
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4)
|
||||
sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R5)
|
||||
sequence = PrintRegister("r5", frame_arm->context.iregs[5], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R6)
|
||||
sequence = PrintRegister("r6", frame_arm->context.iregs[6], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R7)
|
||||
sequence = PrintRegister("r7", frame_arm->context.iregs[7], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R8)
|
||||
sequence = PrintRegister("r8", frame_arm->context.iregs[8], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R9)
|
||||
sequence = PrintRegister("r9", frame_arm->context.iregs[9], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R10)
|
||||
sequence = PrintRegister("r10", frame_arm->context.iregs[10], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R12)
|
||||
sequence = PrintRegister("r12", frame_arm->context.iregs[12], sequence);
|
||||
|
||||
// Registers with a dedicated or conventional purpose.
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_FP)
|
||||
sequence = PrintRegister("fp", frame_arm->context.iregs[11], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)
|
||||
sequence = PrintRegister("sp", frame_arm->context.iregs[13], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_LR)
|
||||
sequence = PrintRegister("lr", frame_arm->context.iregs[14], sequence);
|
||||
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_PC)
|
||||
sequence = PrintRegister("pc", frame_arm->context.iregs[15], sequence);
|
||||
} else if (cpu == "arm64") {
|
||||
const StackFrameARM64 *frame_arm64 =
|
||||
reinterpret_cast<const StackFrameARM64*>(frame);
|
||||
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X0) {
|
||||
sequence =
|
||||
PrintRegister64("x0", frame_arm64->context.iregs[0], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X1) {
|
||||
sequence =
|
||||
PrintRegister64("x1", frame_arm64->context.iregs[1], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X2) {
|
||||
sequence =
|
||||
PrintRegister64("x2", frame_arm64->context.iregs[2], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X3) {
|
||||
sequence =
|
||||
PrintRegister64("x3", frame_arm64->context.iregs[3], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X4) {
|
||||
sequence =
|
||||
PrintRegister64("x4", frame_arm64->context.iregs[4], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X5) {
|
||||
sequence =
|
||||
PrintRegister64("x5", frame_arm64->context.iregs[5], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X6) {
|
||||
sequence =
|
||||
PrintRegister64("x6", frame_arm64->context.iregs[6], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X7) {
|
||||
sequence =
|
||||
PrintRegister64("x7", frame_arm64->context.iregs[7], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X8) {
|
||||
sequence =
|
||||
PrintRegister64("x8", frame_arm64->context.iregs[8], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X9) {
|
||||
sequence =
|
||||
PrintRegister64("x9", frame_arm64->context.iregs[9], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X10) {
|
||||
sequence =
|
||||
PrintRegister64("x10", frame_arm64->context.iregs[10], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X11) {
|
||||
sequence =
|
||||
PrintRegister64("x11", frame_arm64->context.iregs[11], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X12) {
|
||||
sequence =
|
||||
PrintRegister64("x12", frame_arm64->context.iregs[12], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X13) {
|
||||
sequence =
|
||||
PrintRegister64("x13", frame_arm64->context.iregs[13], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X14) {
|
||||
sequence =
|
||||
PrintRegister64("x14", frame_arm64->context.iregs[14], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X15) {
|
||||
sequence =
|
||||
PrintRegister64("x15", frame_arm64->context.iregs[15], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X16) {
|
||||
sequence =
|
||||
PrintRegister64("x16", frame_arm64->context.iregs[16], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X17) {
|
||||
sequence =
|
||||
PrintRegister64("x17", frame_arm64->context.iregs[17], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X18) {
|
||||
sequence =
|
||||
PrintRegister64("x18", frame_arm64->context.iregs[18], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X19) {
|
||||
sequence =
|
||||
PrintRegister64("x19", frame_arm64->context.iregs[19], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X20) {
|
||||
sequence =
|
||||
PrintRegister64("x20", frame_arm64->context.iregs[20], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X21) {
|
||||
sequence =
|
||||
PrintRegister64("x21", frame_arm64->context.iregs[21], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X22) {
|
||||
sequence =
|
||||
PrintRegister64("x22", frame_arm64->context.iregs[22], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X23) {
|
||||
sequence =
|
||||
PrintRegister64("x23", frame_arm64->context.iregs[23], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X24) {
|
||||
sequence =
|
||||
PrintRegister64("x24", frame_arm64->context.iregs[24], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X25) {
|
||||
sequence =
|
||||
PrintRegister64("x25", frame_arm64->context.iregs[25], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X26) {
|
||||
sequence =
|
||||
PrintRegister64("x26", frame_arm64->context.iregs[26], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X27) {
|
||||
sequence =
|
||||
PrintRegister64("x27", frame_arm64->context.iregs[27], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X28) {
|
||||
sequence =
|
||||
PrintRegister64("x28", frame_arm64->context.iregs[28], sequence);
|
||||
}
|
||||
|
||||
// Registers with a dedicated or conventional purpose.
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_FP) {
|
||||
sequence =
|
||||
PrintRegister64("fp", frame_arm64->context.iregs[29], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_LR) {
|
||||
sequence =
|
||||
PrintRegister64("lr", frame_arm64->context.iregs[30], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) {
|
||||
sequence =
|
||||
PrintRegister64("sp", frame_arm64->context.iregs[31], sequence);
|
||||
}
|
||||
if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_PC) {
|
||||
sequence =
|
||||
PrintRegister64("pc", frame_arm64->context.iregs[32], sequence);
|
||||
}
|
||||
} else if (cpu == "mips") {
|
||||
const StackFrameMIPS* frame_mips =
|
||||
reinterpret_cast<const StackFrameMIPS*>(frame);
|
||||
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_GP)
|
||||
sequence = PrintRegister64("gp",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_GP],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_SP)
|
||||
sequence = PrintRegister64("sp",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_SP],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_FP)
|
||||
sequence = PrintRegister64("fp",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_FP],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_RA)
|
||||
sequence = PrintRegister64("ra",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_RA],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_PC)
|
||||
sequence = PrintRegister64("pc", frame_mips->context.epc, sequence);
|
||||
|
||||
// Save registers s0-s7
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S0)
|
||||
sequence = PrintRegister64("s0",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S0],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S1)
|
||||
sequence = PrintRegister64("s1",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S1],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S2)
|
||||
sequence = PrintRegister64("s2",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S2],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S3)
|
||||
sequence = PrintRegister64("s3",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S3],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S4)
|
||||
sequence = PrintRegister64("s4",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S4],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S5)
|
||||
sequence = PrintRegister64("s5",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S5],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6)
|
||||
sequence = PrintRegister64("s6",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6],
|
||||
sequence);
|
||||
if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7)
|
||||
sequence = PrintRegister64("s7",
|
||||
frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7],
|
||||
sequence);
|
||||
}
|
||||
printf("\n Found by: %s\n", frame->trust_description().c_str());
|
||||
|
||||
// Print stack contents.
|
||||
if (output_stack_contents && frame_index + 1 < frame_count) {
|
||||
const std::string indent(" ");
|
||||
PrintStackContents(indent, frame, stack->frames()->at(frame_index + 1),
|
||||
cpu, memory, modules, resolver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PrintStackMachineReadable prints the call stack in |stack| to stdout,
|
||||
// in the following machine readable pipe-delimited text format:
|
||||
// thread number|frame number|module|function|source file|line|offset
|
||||
//
|
||||
// Module, function, source file, and source line may all be empty
|
||||
// depending on availability. The code offset follows the same rules as
|
||||
// PrintStack above.
|
||||
static void PrintStackMachineReadable(int thread_num, const CallStack *stack) {
|
||||
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("%d%c%d%c", thread_num, kOutputSeparator, frame_index,
|
||||
kOutputSeparator);
|
||||
|
||||
uint64_t instruction_address = frame->ReturnAddress();
|
||||
|
||||
if (frame->module) {
|
||||
assert(!frame->module->code_file().empty());
|
||||
printf("%s", StripSeparator(PathnameStripper::File(
|
||||
frame->module->code_file())).c_str());
|
||||
if (!frame->function_name.empty()) {
|
||||
printf("%c%s", kOutputSeparator,
|
||||
StripSeparator(frame->function_name).c_str());
|
||||
if (!frame->source_file_name.empty()) {
|
||||
printf("%c%s%c%d%c0x%" PRIx64,
|
||||
kOutputSeparator,
|
||||
StripSeparator(frame->source_file_name).c_str(),
|
||||
kOutputSeparator,
|
||||
frame->source_line,
|
||||
kOutputSeparator,
|
||||
instruction_address - frame->source_line_base);
|
||||
} else {
|
||||
printf("%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
instruction_address - frame->function_base);
|
||||
}
|
||||
} else {
|
||||
printf("%c%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty function name
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
instruction_address - frame->module->base_address());
|
||||
}
|
||||
} else {
|
||||
// the printf before this prints a trailing separator for module name
|
||||
printf("%c%c%c%c0x%" PRIx64,
|
||||
kOutputSeparator, // empty function name
|
||||
kOutputSeparator, // empty source file
|
||||
kOutputSeparator, // empty source line
|
||||
kOutputSeparator,
|
||||
instruction_address);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ContainsModule checks whether a given |module| is in the vector
|
||||
// |modules_without_symbols|.
|
||||
static bool ContainsModule(
|
||||
const vector<const CodeModule*> *modules,
|
||||
const CodeModule *module) {
|
||||
assert(modules);
|
||||
assert(module);
|
||||
vector<const CodeModule*>::const_iterator iter;
|
||||
for (iter = modules->begin(); iter != modules->end(); ++iter) {
|
||||
if (module->debug_file().compare((*iter)->debug_file()) == 0 &&
|
||||
module->debug_identifier().compare((*iter)->debug_identifier()) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// PrintModule prints a single |module| to stdout.
|
||||
// |modules_without_symbols| should contain the list of modules that were
|
||||
// confirmed to be missing their symbols during the stack walk.
|
||||
static void PrintModule(
|
||||
const CodeModule *module,
|
||||
const vector<const CodeModule*> *modules_without_symbols,
|
||||
const vector<const CodeModule*> *modules_with_corrupt_symbols,
|
||||
uint64_t main_address) {
|
||||
string symbol_issues;
|
||||
if (ContainsModule(modules_without_symbols, module)) {
|
||||
symbol_issues = " (WARNING: No symbols, " +
|
||||
PathnameStripper::File(module->debug_file()) + ", " +
|
||||
module->debug_identifier() + ")";
|
||||
} else if (ContainsModule(modules_with_corrupt_symbols, module)) {
|
||||
symbol_issues = " (WARNING: Corrupt symbols, " +
|
||||
PathnameStripper::File(module->debug_file()) + ", " +
|
||||
module->debug_identifier() + ")";
|
||||
}
|
||||
uint64_t base_address = module->base_address();
|
||||
printf("0x%08" PRIx64 " - 0x%08" PRIx64 " %s %s%s%s\n",
|
||||
base_address, base_address + module->size() - 1,
|
||||
PathnameStripper::File(module->code_file()).c_str(),
|
||||
module->version().empty() ? "???" : module->version().c_str(),
|
||||
main_address != 0 && base_address == main_address ? " (main)" : "",
|
||||
symbol_issues.c_str());
|
||||
}
|
||||
|
||||
// PrintModules prints the list of all loaded |modules| to stdout.
|
||||
// |modules_without_symbols| should contain the list of modules that were
|
||||
// confirmed to be missing their symbols during the stack walk.
|
||||
static void PrintModules(
|
||||
const CodeModules *modules,
|
||||
const vector<const CodeModule*> *modules_without_symbols,
|
||||
const vector<const CodeModule*> *modules_with_corrupt_symbols) {
|
||||
if (!modules)
|
||||
return;
|
||||
|
||||
printf("\n");
|
||||
printf("Loaded modules:\n");
|
||||
|
||||
uint64_t main_address = 0;
|
||||
const CodeModule *main_module = modules->GetMainModule();
|
||||
if (main_module) {
|
||||
main_address = main_module->base_address();
|
||||
}
|
||||
|
||||
unsigned int module_count = modules->module_count();
|
||||
for (unsigned int module_sequence = 0;
|
||||
module_sequence < module_count;
|
||||
++module_sequence) {
|
||||
const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
|
||||
PrintModule(module, modules_without_symbols, modules_with_corrupt_symbols,
|
||||
main_address);
|
||||
}
|
||||
}
|
||||
|
||||
// PrintModulesMachineReadable outputs a list of loaded modules,
|
||||
// one per line, in the following machine-readable pipe-delimited
|
||||
// text format:
|
||||
// Module|{Module Filename}|{Version}|{Debug Filename}|{Debug Identifier}|
|
||||
// {Base Address}|{Max Address}|{Main}
|
||||
static void PrintModulesMachineReadable(const CodeModules *modules) {
|
||||
if (!modules)
|
||||
return;
|
||||
|
||||
uint64_t main_address = 0;
|
||||
const CodeModule *main_module = modules->GetMainModule();
|
||||
if (main_module) {
|
||||
main_address = main_module->base_address();
|
||||
}
|
||||
|
||||
unsigned int module_count = modules->module_count();
|
||||
for (unsigned int module_sequence = 0;
|
||||
module_sequence < module_count;
|
||||
++module_sequence) {
|
||||
const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
|
||||
uint64_t base_address = module->base_address();
|
||||
printf("Module%c%s%c%s%c%s%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n",
|
||||
kOutputSeparator,
|
||||
StripSeparator(PathnameStripper::File(module->code_file())).c_str(),
|
||||
kOutputSeparator, StripSeparator(module->version()).c_str(),
|
||||
kOutputSeparator,
|
||||
StripSeparator(PathnameStripper::File(module->debug_file())).c_str(),
|
||||
kOutputSeparator,
|
||||
StripSeparator(module->debug_identifier()).c_str(),
|
||||
kOutputSeparator, base_address,
|
||||
kOutputSeparator, base_address + module->size() - 1,
|
||||
kOutputSeparator,
|
||||
main_module != NULL && base_address == main_address ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void PrintProcessState(const ProcessState& process_state,
|
||||
bool output_stack_contents,
|
||||
SourceLineResolverInterface* resolver) {
|
||||
// Print OS and CPU information.
|
||||
string cpu = process_state.system_info()->cpu;
|
||||
string cpu_info = process_state.system_info()->cpu_info;
|
||||
printf("Operating system: %s\n", process_state.system_info()->os.c_str());
|
||||
printf(" %s\n",
|
||||
process_state.system_info()->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(" %d CPU%s\n",
|
||||
process_state.system_info()->cpu_count,
|
||||
process_state.system_info()->cpu_count != 1 ? "s" : "");
|
||||
printf("\n");
|
||||
|
||||
// Print crash information.
|
||||
if (process_state.crashed()) {
|
||||
printf("Crash reason: %s\n", process_state.crash_reason().c_str());
|
||||
printf("Crash address: 0x%" PRIx64 "\n", process_state.crash_address());
|
||||
} else {
|
||||
printf("No crash\n");
|
||||
}
|
||||
|
||||
string assertion = process_state.assertion();
|
||||
if (!assertion.empty()) {
|
||||
printf("Assertion: %s\n", assertion.c_str());
|
||||
}
|
||||
|
||||
// Compute process uptime if the process creation and crash times are
|
||||
// available in the dump.
|
||||
if (process_state.time_date_stamp() != 0 &&
|
||||
process_state.process_create_time() != 0 &&
|
||||
process_state.time_date_stamp() >= process_state.process_create_time()) {
|
||||
printf("Process uptime: %d seconds\n",
|
||||
process_state.time_date_stamp() -
|
||||
process_state.process_create_time());
|
||||
} else {
|
||||
printf("Process uptime: not available\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,
|
||||
output_stack_contents,
|
||||
process_state.thread_memory_regions()->at(requesting_thread),
|
||||
process_state.modules(), resolver);
|
||||
}
|
||||
|
||||
// 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,
|
||||
output_stack_contents,
|
||||
process_state.thread_memory_regions()->at(thread_index),
|
||||
process_state.modules(), resolver);
|
||||
}
|
||||
}
|
||||
|
||||
PrintModules(process_state.modules(),
|
||||
process_state.modules_without_symbols(),
|
||||
process_state.modules_with_corrupt_symbols());
|
||||
}
|
||||
|
||||
void PrintProcessStateMachineReadable(const ProcessState& process_state) {
|
||||
// Print OS and CPU information.
|
||||
// OS|{OS Name}|{OS Version}
|
||||
// CPU|{CPU Name}|{CPU Info}|{Number of CPUs}
|
||||
printf("OS%c%s%c%s\n", kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->os).c_str(),
|
||||
kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->os_version).c_str());
|
||||
printf("CPU%c%s%c%s%c%d\n", kOutputSeparator,
|
||||
StripSeparator(process_state.system_info()->cpu).c_str(),
|
||||
kOutputSeparator,
|
||||
// this may be empty
|
||||
StripSeparator(process_state.system_info()->cpu_info).c_str(),
|
||||
kOutputSeparator,
|
||||
process_state.system_info()->cpu_count);
|
||||
|
||||
int requesting_thread = process_state.requesting_thread();
|
||||
|
||||
// Print crash information.
|
||||
// Crash|{Crash Reason}|{Crash Address}|{Crashed Thread}
|
||||
printf("Crash%c", kOutputSeparator);
|
||||
if (process_state.crashed()) {
|
||||
printf("%s%c0x%" PRIx64 "%c",
|
||||
StripSeparator(process_state.crash_reason()).c_str(),
|
||||
kOutputSeparator, process_state.crash_address(), kOutputSeparator);
|
||||
} else {
|
||||
// print assertion info, if available, in place of crash reason,
|
||||
// instead of the unhelpful "No crash"
|
||||
string assertion = process_state.assertion();
|
||||
if (!assertion.empty()) {
|
||||
printf("%s%c%c", StripSeparator(assertion).c_str(),
|
||||
kOutputSeparator, kOutputSeparator);
|
||||
} else {
|
||||
printf("No crash%c%c", kOutputSeparator, kOutputSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
if (requesting_thread != -1) {
|
||||
printf("%d\n", requesting_thread);
|
||||
} else {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
PrintModulesMachineReadable(process_state.modules());
|
||||
|
||||
// blank line to indicate start of threads
|
||||
printf("\n");
|
||||
|
||||
// If the thread that requested the dump is known, print it first.
|
||||
if (requesting_thread != -1) {
|
||||
PrintStackMachineReadable(requesting_thread,
|
||||
process_state.threads()->at(requesting_thread));
|
||||
}
|
||||
|
||||
// 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.
|
||||
PrintStackMachineReadable(thread_index,
|
||||
process_state.threads()->at(thread_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
49
src/processor/stackwalk_common.h
Normal file
49
src/processor/stackwalk_common.h
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2010 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// stackwalk_common.cc: Module shared by the {micro,mini}dump_stackwalck
|
||||
// executables to print the content of dumps (w/ stack traces) on the console.
|
||||
|
||||
|
||||
#ifndef PROCESSOR_STACKWALK_COMMON_H__
|
||||
#define PROCESSOR_STACKWALK_COMMON_H__
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class ProcessState;
|
||||
class SourceLineResolverInterface;
|
||||
|
||||
void PrintProcessStateMachineReadable(const ProcessState& process_state);
|
||||
void PrintProcessState(const ProcessState& process_state,
|
||||
bool output_stack_contents,
|
||||
SourceLineResolverInterface* resolver);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_STACKWALK_COMMON_H__
|
33
src/processor/testdata/microdump-arm.dmp
vendored
Normal file
33
src/processor/testdata/microdump-arm.dmp
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
W/google-breakpad( 3745): -----BEGIN BREAKPAD MICRODUMP-----
|
||||
W/google-breakpad( 3745): O A arm 02 armv7l OS VERSION INFO
|
||||
W/google-breakpad( 3745): S 0 FFEA68C0 FFEA6000 00002000
|
||||
W/google-breakpad( 3745): S FFEA6000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080020000A000002CA705F728000000000000000A000000000000000000000028000000
|
||||
W/google-breakpad( 3745): S FFEA6180 2168EAFFC59104F77C67EAFF7C62EAFF4062EAFF1E71B3AA040000001E71B3AA4062EAFF020000007C62EAFFD062EAFFE867EAFFFAFFFFFF8263EAFFC9A404F700000000000000000000000000000000000000008363EAFF000000005462EAFFFFFFFFFF7C67EAFF1E71B3AA00000000000000003B62EAFF800000000600000000000000000000003C62EAFF06000000000000001B71B3AA000000005C62EAFF0000000000000000000000004462EAFF80000000D4ED06F7000000000000000000000000000000000000000000000000000000000000000000000000E467EAFF00000000000000000000000000000000000000000000000000000000C862EAFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008263EAFF06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA6300 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003430313631380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA6480 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA6600 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BAE0417D0000000000000000060000002168EAFFD4ED06F71869EAFFF867EAFF070000001B71B3AAA76805F70000000000000000E467EAFF000000000000000000000000000000000000000000000000FFFFFFFF004000002768EAFF
|
||||
W/google-breakpad( 3745): S FFEA6780 0000000000000000285F20ABB467EAFF030000002768EAFF200000007702B3AA1869EAFF1F0000000868EAFF6347AEAA1869EAFF200000001869EAFF1F0000002768EAFF0868EAFF1869EAFF4548AEAA00000000800000000868EAFF2168EAFFD4ED06F7B549AEAA00000000000000000000000000000000010000000000000058585858585800002F646174612F6C6F63616C2F746D702F627265616B7061642E3430313631380000FD0000000000000000000031000000F941000002000000D0070000D0070000000000000000000000000000000000000010000000000000001000000000000080B220AB9468EAFFA0B220ABD53AAEAA3069EAFF914BAEAA3069EAFF4882B3AA083020ABF068EAFFA20E0000FFFFFFFF083020ABE99902F7C8DE08F7FF8102F700000000D0DE08F70069EAFFF068EAFFF868EAFFB3B2AEAAD068EAFF0000000000000000D4ED06F70500000000000000000000000000000003000000040000000000000000000000FFFFFFFF00000000FFFFFFFF00000000
|
||||
W/google-breakpad( 3745): S FFEA6900 010000000000000000000000000000000000000000000000485F20AB000000000000000000000000475F20AB285F20ABB0B220AB05000000D1D320AB379304F7AAB220AB80B220ABF869EAFF3BBAB3AA040000003BBAB3AAF869EAFF03000000346AEAFF906AEAFF346FEAFFFBFFFFFF605420ABC9A404F74C6AEAFFA86AEAFF4C6FEAFFEDFFFFFF303D20AB046AEAFF6FCAB3AA0C6AEAFFFFFFFFFFF4D306F73BBAB3AA0000000000000000F369EAFF0000000019000000EC69EAFF00000000F469EAFF050000000000000036BAB3AA00000000146AEAFF0C6AEAFFF469EAFF00000000FC69EAFF00000000D4ED06F70000000000000000000000000000000000000000000000000000000000000000000000002C6FEAFF0000000000000000DC3CB4AA000000005C6AEAFF786AEAFF00000000806AEAFF0000000000000000DC3CB4AA906AEAFF00000000986AEAFF0000000000000000000000000000000000000000000000005D6BEAFF30A820ABA06BEAFF0000000028BAB3AA0D000000
|
||||
W/google-breakpad( 3745): S FFEA6A80 38BAB3AA01000000605420AB05000000FAB9B3AA0D00000083C9B3AA06000000303D20AB13000000746FEAFF0B00000000A820ABF8A720AB904020AB78A820ABC52DAEAAC72DAEAA0A0000000A0000000000000046696C654944546573742F3100A820ABE06AEAFFFAB9B3AA0D0000004944546573742F3100000000F86AEAFFEC6AEAFF46696C6572000000874220ABCD6EEAFF6163B0AA6F000000864220ABCD6EEAFF6163B0AA65000000BDC620ABCD6EEAFF6163B0AA70000000BCC620ABCD6EEAFF6163B0AA79000000BBC620ABCD6EEAFF6163B0AA54000000BAC620ABCD6EEAFF6163B0AA65000000B9C620ABCD6EEAFF6163B0AA74000000B8C620ABCD6EEAFF6163B0AA61000000B7C620ABCD6EEAFF6163B0AA6C000000B6C620ABCD6EEAFF6163B0AA70000000B5C620ABCD6EEAFF6163B0AA6D000000B4C620ABCD6EEAFF6163B0AA65000000B3C620ABCD6EEAFF6163B0AA54000000B2C620ABCD6EEAFF6163B0AA68000000B1C620ABCD6EEAFF6163B0AA74000000B0C620AB
|
||||
W/google-breakpad( 3745): S FFEA6C00 CD6EEAFF6163B0AA67000000A7B220ABCD6EEAFF6163B0AA6E000000A6B220ABCD6EEAFF6163B0AA69000000A5B220ABCD6EEAFF6163B0AA72000000A4B220ABCD6EEAFF6163B0AA74000000A3B220ABCD6EEAFF6163B0AA53000000A2B220ABCD6EEAFF6163B0AA44000000A1B220ABCD6EEAFF6163B0AA4D000000A0B220ABCD6EEAFF6163B0AA690000009FB220ABCD6EEAFF6163B0AA690000009EB220ABCD6EEAFF6163B0AA630000009DB220ABCD6EEAFF6163B0AA730000009CB220ABCD6EEAFF6163B0AA74000000435F20ABCD6EEAFF6163B0AA65000000425F20AB00000000C4D720AB310000007762AEAAC4D720AB7E6EEAFFC06EEAFF693BB2AAC4D720AB01CAB3AAC4D720AB01CAB3AAC4D720AB00000000C06EEAFF20000000C06EEAFF08100000088120ABFBACB2AA088120ABC4D720AB01CAB3AAC4D720AB016FEAFF6163B0AA6D0000003B5F20ABCD6EEAFF6163B0AA670000003A5F20ABCD6EEAFF6163B0AA69000000395F20ABCD6EEAFF6163B0AAB8E8B4AACC6DEAFF
|
||||
W/google-breakpad( 3745): S FFEA6D80 15000000010000007D6EEAFF00D820ABC06EEAFF08100000088120AB01000000D83420ABC7AFB2AA01000000C4D720AB01CAB3AA0810000000000000200000002B0000002D000000B8E8B4AAB8E8B4AA00D820AB1C6EEAFF0000000000000000D06DEAFFD06DEAFF0A0000000A000000000000000000000000000000A35DB3AA01000000000000000A00000031000000000000007D6EEAFF7D6EEAFF005DB3AA286EEAFF5F24B2AAB8E8B4AA20D820AB12000000BCE8B4AAFC6EEAFFBB2CB2AAB8E8B4AA20D820ABB8D720AB02000000B0D720AB000000C0B8D720ABB8D720ABFC6EEAFF29F003F7B8D720ABC0D720ABB8D720ABA86EEAFFFC6EEAFF595D02F7B542AEAAC342AEAAA86EEAFF073BAEAAAC6EEAFFD19DAFAA00D820AB20000000576FEAFFD53AAEAA546FEAFF914BAEAA546FEAFF76C9B3AA546FEAFF146FEAFFBB00000048070000E0D720AB0300000018D820ABF4E3B4AA18D820AB0700000000000000485420ABD0D720AB8399B0AA23C8B3AAD0D720ABD0D720ABBAE0417D
|
||||
W/google-breakpad( 3745): S FFEA6F00 23C8B3AADC31B4AAD0D720AB783420AB49010000883520ABD0D720AB606FEAFFD83420AB41A7B0AA08000000010000001000000001000000783420AB8399B0AA485420AB783420ABDD1CD2F675A8B0AA08000000010000005AC8B3AAC85420AB08000000010000000800000001000000C85420AB00000000DD1CD2F649010000783420AB883520AB01000000FDA8B0AA715FB0AA0000000000000000C78404F7D160B0AA783420AB883520AB000000000100000000000000F04720ABFDAAB0AAF4E8B4AA01000000DD1CD2F64901000040E4B4AA40E4B4AA2EBCB3AAE7C8B3AA1EC9B3AA33C9B3AA02000000B0B220AB2C70EAFF00000000783420AB02000000192CAEAA0000000000000000000000006C70EAFF619AB0AA2C70EAFF7470EAFF020000003B2CAEAA02000000010000008070EAFF7470EAFF8070EAFF9F5E02F75870EAFF00000000000000000000000000000000842DAEAA00B9B4AA98B8B4AA90B8B4AAF8B8B4AA00000000FF2608F7020000007F7BEAFF0000000000000000
|
||||
W/google-breakpad( 3745): S FFEA7080 B97BEAFFDE7BEAFF0A7CEAFF1D7CEAFFD97DEAFF167EEAFF2F7EEAFF447EEAFF6E7EEAFF877EEAFF9E7EEAFFC87EEAFFE37EEAFFFD7EEAFF0A7FEAFF247FEAFF437FEAFFC27FEAFF0000000010000000D6B00700060000000010000011000000640000000300000034D0ACAA040000002000000005000000080000000700000000F007F7080000000000000009000000282DAEAA0B000000000000000C000000000000000D000000000000000E000000000000001700000000000000190000006C71EAFF1A0000001F0000001F000000D57FEAFF0F0000007C71EAFF00000000000000000000000000000000BAE0417DA395F6D9D5EFEE82959378DA76386C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA7200 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA7380 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA7500 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA7680 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA7800 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA7980 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): S FFEA7B00 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002F646174612F6C6F63616C2F746D702F627265616B7061645F756E69747465737473002D2D67746573745F66696C7465723D2A4D6963726F2A005F3D2F646174612F6C6F63616C2F746D702F627265616B7061645F756E6974746573747300454D554C415445445F53544F524147455F534F555243453D2F6D6E742F7368656C6C2F656D756C6174656400414E44524F49445F444154413D2F6461746100424F4F54434C415353504154483D2F73797374656D2F6672616D65776F726B2F636F72652D6C69626172742E6A61723A2F73797374656D2F6672616D65776F726B2F636F6E7363727970742E6A61723A2F73797374656D2F6672616D65776F726B2F6F
|
||||
W/google-breakpad( 3745): S FFEA7C80 6B687474702E6A61723A2F73797374656D2F6672616D65776F726B2F636F72652D6A756E69742E6A61723A2F73797374656D2F6672616D65776F726B2F626F756E6379636173746C652E6A61723A2F73797374656D2F6672616D65776F726B2F6578742E6A61723A2F73797374656D2F6672616D65776F726B2F6672616D65776F726B2E6A61723A2F73797374656D2F6672616D65776F726B2F74656C6570686F6E792D636F6D6D6F6E2E6A61723A2F73797374656D2F6672616D65776F726B2F766F69702D636F6D6D6F6E2E6A61723A2F73797374656D2F6672616D65776F726B2F696D732D636F6D6D6F6E2E6A61723A2F73797374656D2F6672616D65776F726B2F6D6D732D636F6D6D6F6E2E6A61723A2F73797374656D2F6672616D65776F726B2F616E64726F69642E706F6C6963792E6A61723A2F73797374656D2F6672616D65776F726B2F6170616368652D786D6C2E6A617200504154483D2F7362696E3A2F76656E646F722F62696E3A2F73797374656D2F7362696E3A2F7379
|
||||
W/google-breakpad( 3745): S FFEA7E00 7374656D2F62696E3A2F73797374656D2F7862696E004C4F4F505F4D4F554E54504F494E543D2F6D6E742F6F626200414E44524F49445F524F4F543D2F73797374656D00454D554C415445445F53544F524147455F5441524745543D2F73746F726167652F656D756C6174656400414E44524F49445F53544F524147453D2F73746F7261676500414E44524F49445F534F434B45545F616462643D31310045585445524E414C5F53544F524147453D2F73746F726167652F656D756C617465642F6C656761637900414E44524F49445F4153534554533D2F73797374656D2F617070004C445F5052454C4F41443D6C6962736967636861696E2E736F0052414E444F4D3D313131373200415345435F4D4F554E54504F494E543D2F6D6E742F6173656300414E44524F49445F50524F50455254595F574F524B53504143453D392C300053595354454D534552564552434C415353504154483D2F73797374656D2F6672616D65776F726B2F73657276696365732E6A61723A2F73797374656D2F
|
||||
W/google-breakpad( 3745): S FFEA7F80 6672616D65776F726B2F65746865726E65742D736572766963652E6A61723A2F73797374656D2F6672616D65776F726B2F776966692D736572766963652E6A617200414E44524F49445F424F4F544C4F474F3D31002F646174612F6C6F63616C2F746D702F627265616B7061645F756E69747465737473000000000000000000
|
||||
W/google-breakpad( 3745): C 06000040000000000000000000000000000000000069EAFFF068EAFFF868EAFF0469EAFFE068EAFF0069EAFF3069EAFFA20E000000000000C068EAFF07B3AEAA07B3AEAA000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3745): M AAACD000 00000000 0007C000 DA7778FB66018A4E9B4110ED06E730D00 breakpad_unittests
|
||||
W/google-breakpad( 3745): M F6FCA000 00000000 00004000 56B149396A4DAF176E26B4A85DA87BF30 libnetd_client.so
|
||||
W/google-breakpad( 3745): M F6FEE000 00000000 00004000 DFCD7772F3A5BD1E84A50C4DBFDE6F570 libstdc++.so
|
||||
W/google-breakpad( 3745): M F6FF2000 00000000 00019000 AE3467401278371A956801500FC8187D0 libm.so
|
||||
W/google-breakpad( 3745): M F700C000 00000000 00007000 0A492DEF82842051996A468D87F23F010 liblog.so
|
||||
W/google-breakpad( 3745): M F7014000 00000000 0005A000 167F187B09A27F7444EF989603AAFD3D0 libc.so
|
||||
W/google-breakpad( 3745): -----END BREAKPAD MICRODUMP-----
|
45
src/processor/testdata/microdump-arm64.dmp
vendored
Normal file
45
src/processor/testdata/microdump-arm64.dmp
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
W/google-breakpad( 3728): -----BEGIN BREAKPAD MICRODUMP-----
|
||||
W/google-breakpad( 3728): O A arm64 02 aarch64 OS 64 VERSION INFO
|
||||
W/google-breakpad( 3728): S 0 0000007FE2BA6120 0000007FE2BA6000 0000000000003000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6000 0700000000000000A060BAE27F0000007060BAE27F000000E4006A5F550000007060BAE27F000000FC006A5F550000001000000000000000D0006E5F550000002061BAE27F0000004C6E635F550000002061BAE27F0000002061BAE27F000000F060BAE27F000000D0FFFFFF80FFFFFFD060BAE27F00000020142B807F00000010E04E9555000000E065BAE27F000000A061BAE27F00000000406B5F55000000D060BAE27F00000058142B807F00000010E04E955500000000000000000000000104104001041040FFFFFFFFFFFFFFFFF060BAE27F00000048E62A807F000000E8C036807F00000040E62A807F0000002061BAE27F000000E86E635F55000000506ABAE27F000000E065BAE27F000000A061BAE27F000000FEFE2E7273636471507ABAE27F0000003C32665F55000000D02250955500000070E14E955500000070E14E955500000090E34E95550000004A62D1F64901000000F06D5F5500000001000000000000004962D1F6490100000100000000000000C9356B5F55000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6180 00000000000000009863BAE27F0000000000000005000000000000000000000003000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002F646174612F6C6F63616C2F746D702F627265616B7061642E323839333833000F62BAE27F000000F061BAE27F000000D0F34E9555000000000000000000000000000000000000000000000000000000CAF34E9555000000A0F34E95550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6300 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6480 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6600 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004067BAE27F000000A04E2D807F0000004067BAE27F000000104E2D807F000000186E33807F0000002000000000000000006033807F000000007033807F00000090E64E9555000000000000000000000000000000000000000000000000000000A067BAE27F00000010C22A807F000000020000000000000000F06D5F550000002079BAE27F00000058F66D5F55000000D067BAE27F000000986A2D807F000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6780 80E64E9555000000006033807F00000090E64E955500000058F66D5F5500000020B5625F550000001CB5625F550000000068BAE27F000000C8C12A807F0000004868BAE27F0000008068BAE27F0000002079BAE27F00000058F66D5F5500000020B5625F550000008068BAE27F0000002079BAE27F00000058F66D5F550000001068BAE27F000000D0B9665F550000008078BAE27F000000987C665F550000002079BAE27F00000070E14E955500000060E04E9555000000000000000000000000000000000000002F000000000000000000000000000000000000000000000000000000000000004968BAE27F0000004868BAE27F0000002F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6900 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6A80 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6C00 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6D80 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA6F00 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008070BAE27F000000DC4C2E807F0000002300000000000000000C509555000000702333807F0000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7080 B070BAE27F000000B8672E807F000000C070BAE27F000000DC4C2E807F0000002E00000000000000000C5095550000001071BAE27F000000A4882E807F0000000073BAE27F000000B073BAE27F0000000D000000000000000D00000000000000DB336B5F55000000702333807F0000005071BAE27F000000A4882E807F0000004073BAE27F000000F073BAE27F0000007071BAE27F0000001C8A2E807F000000F472BAE27F000000F073BAE27F0000000073BAE27F000000E1336B5F55000000E1336B5F55000000702333807F0000000000000000000000050000000000000005000000000000004073BAE27F000000F078BAE27F000000F0BB2E807F000000702333807F00000090E34E955500000090384F955500000090E34E95550000004A62D1F64901000000F06D5F5500000001000000000000004962D1F6490100000100000000000000C9356B5F55000000000000000000000050E24E9555000000D3416B5F550000000A426B5F5500000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7200 00000000000000000000000000000000000000000000000000000000000000002F73BAE27F0000005073BAE27F0000003F73BAE280FFFFFF2873BAE27F0000000000000000000000107ABAE27F0000000000000000000000207ABAE27F0000000000000000000000A772BAE27F0000007F73BAE280FFFFFFCDCCCCCCCCCCCCCC0000000000000000507ABAE27F000000E46E30807F000000607ABAE27F000000E872BAE27F000000E772BAE27F000000000000007F000000030000007F000000000000000000000003000000CCCCCCCC0000000000000000E07ABAE27F00000000000000000000006000655F550000008DEE4E95000000008100BAE27F000000000000000000000000000000000000000000000000000000507ABAE27F000000207ABAE27F000000D0FFFFFF80FFFFFF307ABAE27F000000D0FFFFFF80FFFFFFF073BAE27F0000000000000000000000507ABAE27F000000507ABAE27F000000107ABAE27F000000C8FFFFFF80FFFFFF207ABAE27F000000C8FFFFFF80FFFFFF
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7380 A073BAE27F00000060DC655F550000004074BAE27F0000000000000000000000E07ABAE27F000000E07ABAE27F000000CE336B5F550000000D00000000000000A0336B5F550000000D00000000000000C6F34E95550000008179BAE27F0000000074BAE27F00000060DC655F55000000DE336B5F550000000100000000000000C0384F95550000000500000000000000A8394F955500000013000000000000004074BAE27F00000060DC655F55000000C3F34E95550000008179BAE27F000000A0336B5F550000000D00000000000000C2F34E95550000008179BAE27F0000008074BAE27F00000060DC655F55000000C1F34E95550000008179BAE27F000000A074BAE27F00000060DC655F55000000C0F34E95550000008179BAE27F000000C074BAE27F00000060DC655F55000000BFF34E95550000008179BAE27F000000E074BAE27F00000060DC655F55000000BEF34E95550000008179BAE27F0000000075BAE27F00000060DC655F55000000BDF34E95550000008179BAE27F000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7500 2075BAE27F00000060DC655F55000000BCF34E95550000008179BAE27F0000004075BAE27F00000060DC655F550000006B79BAE27F0000008179BAE27F0000006075BAE27F00000060DC655F550000006A79BAE27F0000008179BAE27F0000008075BAE27F00000060DC655F550000006979BAE27F0000008179BAE27F000000A075BAE27F00000060DC655F550000006879BAE27F0000008179BAE27F000000C075BAE27F00000060DC655F550000006779BAE27F0000008179BAE27F000000E075BAE27F00000060DC655F550000006679BAE27F0000008179BAE27F0000000076BAE27F00000060DC655F550000006579BAE27F0000008179BAE27F0000002076BAE27F00000060DC655F550000006479BAE27F0000008179BAE27F0000004076BAE27F00000060DC655F550000006379BAE27F0000008179BAE27F0000006076BAE27F00000060DC655F550000006279BAE27F0000008179BAE27F0000008076BAE27F00000060DC655F550000006179BAE27F0000008179BAE27F000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7680 A076BAE27F00000060DC655F550000006079BAE27F0000008179BAE27F000000C076BAE27F00000060DC655F550000005F79BAE27F0000008179BAE27F000000E076BAE27F00000060DC655F550000005E79BAE27F0000008179BAE27F0000000077BAE27F00000060DC655F550000005D79BAE27F0000008179BAE27F0000002077BAE27F00000060DC655F55000000E077BAE27F000000AC74685F55000000F077BAE27F000000AC74685F550000004023509555000000A078BAE27F00000010235095550000009878BAE27F0000002078BAE27F000000AC74685F550000008077BAE27F000000C006635F5500000098225095550000003100000000000000B077BAE27F00000088BB695F5500000098225095550000005979BAE27F0000005A79BAE27F0000004488685F550000001078BAE27F00000054BF695F55000000B078BAE27F000000010000000000000050834F95550000008078BAE27F0000005979BAE27F000000982250955500000098225095550000000100000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7800 2D00000000000000C8FF6D5F55000000F078BAE27F00000068C4695F550000005A79BAE27F0000001023509555000000200000000000000098225095550000000100000000000000007ABAE27F000000B078BAE27F000000CCBB2E807F000000B078BAE27F000000FCBB2E807F000000702333807F0000000D00000000000000020000000000000090E34E9555000000F078BAE27F000000CCBB2E807F000000F078BAE27F000000FCBB2E807F000000702333807F000000190000000000000090384F955500000090E34E95550000004A62D1F649010000CE336B5F55000000507ABAE27F000000443272DD1F92C7154079BAE27F000000C0752E807F00000090384F955500000090E34E95550000005079BAE27F000000DC336B5F550000008079BAE27F000000A04E2D807F0000008079BAE27F000000104E2D807F000000186E33807F0000006001000000000000006033807F000000007033807F000000F022509555000000C8FFFFFF80FFFFFFC079BAE27F00000090DD625F55000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7980 60235095550000000700000000000000D7F66D5F55000000D0F66D5F55000000C079BAE27F00000068DD625F5500000010245095550000000000000000000000F079BAE27F000000C4F2655F55000000007ABAE27F000000F031665F55000000D022509555000000D022509555000000107ABAE27F00000060FE655F55000000107ABAE27F0000001441665F55000000407ABAE27F000000F031665F55000000D02250955500000070E14E9555000000607ABAE27F000000F031665F55000000507ABAE27F0000001832665F55000000807ABAE27F0000008C44665F55000000D02250955500000070E14E955500000020000000000000000100000000000000A07ABAE27F000000B845665F5500000090384F9555000000D022509555000000E07ABAE27F0000007446665F55000000A0394F955500000070E14E955500000090E34E955500000001000000000000004A62D1F6490100005EC60A0000000000207BBAE27F0000004C49665F5500000070E14E95550000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7B00 90E34E955500000002000000000000000000000000000000D048665F55000000C07BBAE27F000000684B665F55000000000000000000000070E14E9555000000020000000000000060B3625F550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C07BBAE27F000000E0054F9555000000C07BBAE27F000000604B665F55000000F07BBAE27F00000098B3625F550000001C7CBAE27F000000887CBAE27F0000000200000000000000A0F34E9555000000207CBAE27F0000008CC32A807F000000A07CBAE27F0000000000000000000000887CBAE27F0000000010000001000000507CBAE27F00000004B5625F550000000000000000000000000000000000000000000000000000000000000000000000000000000000000050B635807F0000000000000000000000D07D6D5F55000000E07D6D5F55000000A07E6D5F55000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7C80 02000000000000007F8BBAE27F00000000000000000000000000000000000000B98BBAE27F000000DE8BBAE27F0000000A8CBAE27F0000001D8CBAE27F000000D98DBAE27F000000168EBAE27F0000002F8EBAE27F000000448EBAE27F0000006E8EBAE27F000000878EBAE27F0000009E8EBAE27F000000C88EBAE27F000000E38EBAE27F000000FD8EBAE27F0000000A8FBAE27F000000248FBAE27F000000438FBAE27F000000C28FBAE27F00000000000000000000002100000000000000008035807F0000001000000000000000FB00000000000000060000000000000000100000000000001100000000000000640000000000000003000000000000004080605F550000000400000000000000380000000000000005000000000000000800000000000000070000000000000000A035807F000000080000000000000000000000000000000900000000000000A4B4625F550000000B0000000000000000000000000000000C0000000000000000000000000000000D00000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7E00 00000000000000000E000000000000000000000000000000170000000000000000000000000000001900000000000000687EBAE27F0000001F00000000000000D58FBAE27F0000000F00000000000000787EBAE27F00000000000000000000000000000000000000443272DD1F92C715BDF280FA6D8DE039616172636836340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA7F80 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8100 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8280 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8400 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8580 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8700 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8880 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8A00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002F
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8B80 646174612F6C6F63616C2F746D702F627265616B7061645F756E69747465737473002D2D67746573745F66696C7465723D2A4D6963726F2A005F3D2F646174612F6C6F63616C2F746D702F627265616B7061645F756E6974746573747300454D554C415445445F53544F524147455F534F555243453D2F6D6E742F7368656C6C2F656D756C6174656400414E44524F49445F444154413D2F6461746100424F4F54434C415353504154483D2F73797374656D2F6672616D65776F726B2F636F72652D6C69626172742E6A61723A2F73797374656D2F6672616D65776F726B2F636F6E7363727970742E6A61723A2F73797374656D2F6672616D65776F726B2F6F6B687474702E6A61723A2F73797374656D2F6672616D65776F726B2F636F72652D6A756E69742E6A61723A2F73797374656D2F6672616D65776F726B2F626F756E6379636173746C652E6A61723A2F73797374656D2F6672616D65776F726B2F6578742E6A61723A2F73797374656D2F6672616D65776F726B2F6672616D6577
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8D00 6F726B2E6A61723A2F73797374656D2F6672616D65776F726B2F74656C6570686F6E792D636F6D6D6F6E2E6A61723A2F73797374656D2F6672616D65776F726B2F766F69702D636F6D6D6F6E2E6A61723A2F73797374656D2F6672616D65776F726B2F696D732D636F6D6D6F6E2E6A61723A2F73797374656D2F6672616D65776F726B2F6D6D732D636F6D6D6F6E2E6A61723A2F73797374656D2F6672616D65776F726B2F616E64726F69642E706F6C6963792E6A61723A2F73797374656D2F6672616D65776F726B2F6170616368652D786D6C2E6A617200504154483D2F7362696E3A2F76656E646F722F62696E3A2F73797374656D2F7362696E3A2F73797374656D2F62696E3A2F73797374656D2F7862696E004C4F4F505F4D4F554E54504F494E543D2F6D6E742F6F626200414E44524F49445F524F4F543D2F73797374656D00454D554C415445445F53544F524147455F5441524745543D2F73746F726167652F656D756C6174656400414E44524F49445F53544F524147453D2F73
|
||||
W/google-breakpad( 3728): S 0000007FE2BA8E80 746F7261676500414E44524F49445F534F434B45545F616462643D31310045585445524E414C5F53544F524147453D2F73746F726167652F656D756C617465642F6C656761637900414E44524F49445F4153534554533D2F73797374656D2F617070004C445F5052454C4F41443D6C6962736967636861696E2E736F0052414E444F4D3D313638323700415345435F4D4F554E54504F494E543D2F6D6E742F6173656300414E44524F49445F50524F50455254595F574F524B53504143453D392C300053595354454D534552564552434C415353504154483D2F73797374656D2F6672616D65776F726B2F73657276696365732E6A61723A2F73797374656D2F6672616D65776F726B2F65746865726E65742D736572766963652E6A61723A2F73797374656D2F6672616D65776F726B2F776966692D736572766963652E6A617200414E44524F49445F424F4F544C4F474F3D31002F646174612F6C6F63616C2F746D702F627265616B7061645F756E69747465737473000000000000000000
|
||||
W/google-breakpad( 3728): C 06000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000506ABAE27F000000E065BAE27F000000E061BAE27F00000000406B5F550000008062BAE27F0000005062BAE27F000000514C6B5F55000000910E0000000000002062BAE27F000000F061BAE27F0000002061BAE27F0000006C6F635F550000002061BAE27F0000006C6F635F550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
W/google-breakpad( 3728): M 000000555F608000 0000000000000000 00000000000C0000 D6D1FEC9A15DE7F38A236898871A2E770 breakpad_unittests
|
||||
W/google-breakpad( 3728): M 0000007F801F6000 0000000000000000 0000000000013000 7735F44BA6D7C27FD5C3636A43369B7C0 libnetd_client.so
|
||||
W/google-breakpad( 3728): M 0000007F80229000 0000000000000000 0000000000014000 380C0B7CD8FA3F094BC3BA58A81CBAD00 libstdc++.so
|
||||
W/google-breakpad( 3728): M 0000007F8023D000 0000000000000000 000000000003D000 F832D47D1E237E46D835991594DA6E890 libm.so
|
||||
W/google-breakpad( 3728): M 0000007F8027B000 0000000000000000 0000000000019000 C407B93F87A835BE05451FC7B0B3E65E0 liblog.so
|
||||
W/google-breakpad( 3728): M 0000007F80295000 0000000000000000 000000000009E000 479D5438753E27F019F2C9980DDBF4F30 libc.so
|
||||
W/google-breakpad( 3728): M 0000007F80341000 0000000000000000 0000000000013000 9DA3FF8EF9CA0FDC481292EE530DF6EC0 libsigchain.so
|
||||
W/google-breakpad( 3728): M 0000007F80358000 0000000000000000 0000000000002000 672B2CD6CF8AF6C43BD70F2AB02B3D0C0 linux-gate.so
|
||||
W/google-breakpad( 3728): -----END BREAKPAD MICRODUMP-----
|
42
src/processor/testdata/microdump.stackwalk-arm.out
vendored
Normal file
42
src/processor/testdata/microdump.stackwalk-arm.out
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
Operating system: Android
|
||||
OS VERSION INFO
|
||||
CPU: armv7l
|
||||
2 CPUs
|
||||
|
||||
Crash reason:
|
||||
Crash address: 0x0
|
||||
Process uptime: not available
|
||||
|
||||
Thread 0 (crashed)
|
||||
0 breakpad_unittests!MicrodumpWriterTest_Setup_Test::TestBody [gtest.h : 1481 + 0x1]
|
||||
|
||||
Found by: given as instruction pointer in context
|
||||
1 breakpad_unittests!testing::Test::Run [gtest.cc : 2435 + 0x17]
|
||||
|
||||
Found by: call frame info
|
||||
2 breakpad_unittests!testing::TestInfo::Run [gtest.cc : 2610 + 0x5]
|
||||
|
||||
Found by: call frame info
|
||||
3 breakpad_unittests!testing::TestCase::Run [gtest.cc : 2728 + 0x3]
|
||||
|
||||
Found by: call frame info
|
||||
4 breakpad_unittests!testing::internal::UnitTestImpl::RunAllTests [gtest.cc : 4591 + 0x3]
|
||||
|
||||
Found by: call frame info
|
||||
5 breakpad_unittests!testing::UnitTest::Run [gtest.cc : 2418 + 0x5]
|
||||
|
||||
Found by: call frame info
|
||||
6 breakpad_unittests!main [gtest.h : 2326 + 0x3]
|
||||
|
||||
Found by: call frame info
|
||||
7 libc.so + 0x11e9d
|
||||
|
||||
Found by: call frame info
|
||||
|
||||
Loaded modules:
|
||||
0xaaacd000 - 0xaab48fff breakpad_unittests ???
|
||||
0xf6fca000 - 0xf6fcdfff libnetd_client.so ???
|
||||
0xf6fee000 - 0xf6ff1fff libstdc++.so ???
|
||||
0xf6ff2000 - 0xf700afff libm.so ???
|
||||
0xf700c000 - 0xf7012fff liblog.so ???
|
||||
0xf7014000 - 0xf706dfff libc.so ??? (WARNING: No symbols, libc.so, 167F187B09A27F7444EF989603AAFD3D0)
|
47
src/processor/testdata/microdump.stackwalk-arm64.out
vendored
Normal file
47
src/processor/testdata/microdump.stackwalk-arm64.out
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
Operating system: Android
|
||||
OS 64 VERSION INFO
|
||||
CPU: aarch64
|
||||
2 CPUs
|
||||
|
||||
Crash reason:
|
||||
Crash address: 0x0
|
||||
Process uptime: not available
|
||||
|
||||
Thread 0 (crashed)
|
||||
0 breakpad_unittests!MicrodumpWriterTest_Setup_Test::TestBody [microdump_writer_unittest.cc : 77 + 0xc]
|
||||
|
||||
Found by: given as instruction pointer in context
|
||||
1 breakpad_unittests!testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void> [gtest.cc : 2418 + 0x4]
|
||||
|
||||
Found by: call frame info
|
||||
2 breakpad_unittests!testing::Test::Run [gtest.cc : 2435 + 0x14]
|
||||
|
||||
Found by: call frame info
|
||||
3 breakpad_unittests!testing::TestInfo::Run [gtest.cc : 2610 + 0x4]
|
||||
|
||||
Found by: call frame info
|
||||
4 breakpad_unittests!testing::TestCase::Run [gtest.cc : 2728 + 0x0]
|
||||
|
||||
Found by: call frame info
|
||||
5 breakpad_unittests!testing::internal::UnitTestImpl::RunAllTests [gtest.cc : 4591 + 0x0]
|
||||
|
||||
Found by: call frame info
|
||||
6 breakpad_unittests!testing::UnitTest::Run [gtest.cc : 2418 + 0x4]
|
||||
|
||||
Found by: call frame info
|
||||
7 breakpad_unittests!main [gtest.h : 2326 + 0x0]
|
||||
|
||||
Found by: call frame info
|
||||
8 libc.so + 0x17388
|
||||
|
||||
Found by: call frame info
|
||||
|
||||
Loaded modules:
|
||||
0x555f608000 - 0x555f6c7fff breakpad_unittests ???
|
||||
0x7f801f6000 - 0x7f80208fff libnetd_client.so ???
|
||||
0x7f80229000 - 0x7f8023cfff libstdc++.so ???
|
||||
0x7f8023d000 - 0x7f80279fff libm.so ???
|
||||
0x7f8027b000 - 0x7f80293fff liblog.so ???
|
||||
0x7f80295000 - 0x7f80332fff libc.so ??? (WARNING: No symbols, libc.so, 479D5438753E27F019F2C9980DDBF4F30)
|
||||
0x7f80341000 - 0x7f80353fff libsigchain.so ???
|
||||
0x7f80358000 - 0x7f80359fff linux-gate.so ???
|
18
src/processor/testdata/microdump.stackwalk.machine_readable-arm.out
vendored
Normal file
18
src/processor/testdata/microdump.stackwalk.machine_readable-arm.out
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
OS|Android|OS VERSION INFO
|
||||
CPU|armv7l||2
|
||||
Crash||0x0|0
|
||||
Module|breakpad_unittests||breakpad_unittests|DA7778FB66018A4E9B4110ED06E730D00|0xaaacd000|0xaab48fff|0
|
||||
Module|libnetd_client.so||libnetd_client.so|56B149396A4DAF176E26B4A85DA87BF30|0xf6fca000|0xf6fcdfff|0
|
||||
Module|libstdc++.so||libstdc++.so|DFCD7772F3A5BD1E84A50C4DBFDE6F570|0xf6fee000|0xf6ff1fff|0
|
||||
Module|libm.so||libm.so|AE3467401278371A956801500FC8187D0|0xf6ff2000|0xf700afff|0
|
||||
Module|liblog.so||liblog.so|0A492DEF82842051996A468D87F23F010|0xf700c000|0xf7012fff|0
|
||||
Module|libc.so||libc.so|167F187B09A27F7444EF989603AAFD3D0|0xf7014000|0xf706dfff|0
|
||||
|
||||
0|0|breakpad_unittests|MicrodumpWriterTest_Setup_Test::TestBody|/s/clank/src/out_arm/Release/../../testing/gtest/include/gtest/gtest.h|1481|0x1
|
||||
0|1|breakpad_unittests|testing::Test::Run|/s/clank/src/out_arm/Release/../../testing/gtest/src/gtest.cc|2435|0x17
|
||||
0|2|breakpad_unittests|testing::TestInfo::Run|/s/clank/src/out_arm/Release/../../testing/gtest/src/gtest.cc|2610|0x5
|
||||
0|3|breakpad_unittests|testing::TestCase::Run|/s/clank/src/out_arm/Release/../../testing/gtest/src/gtest.cc|2728|0x3
|
||||
0|4|breakpad_unittests|testing::internal::UnitTestImpl::RunAllTests|/s/clank/src/out_arm/Release/../../testing/gtest/src/gtest.cc|4591|0x3
|
||||
0|5|breakpad_unittests|testing::UnitTest::Run|/s/clank/src/out_arm/Release/../../testing/gtest/src/gtest.cc|2418|0x5
|
||||
0|6|breakpad_unittests|main|/s/clank/src/out_arm/Release/../../testing/gtest/include/gtest/gtest.h|2326|0x3
|
||||
0|7|libc.so||||0x11e9d
|
21
src/processor/testdata/microdump.stackwalk.machine_readable-arm64.out
vendored
Normal file
21
src/processor/testdata/microdump.stackwalk.machine_readable-arm64.out
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
OS|Android|OS 64 VERSION INFO
|
||||
CPU|aarch64||2
|
||||
Crash||0x0|0
|
||||
Module|breakpad_unittests||breakpad_unittests|D6D1FEC9A15DE7F38A236898871A2E770|0x555f608000|0x555f6c7fff|0
|
||||
Module|libnetd_client.so||libnetd_client.so|7735F44BA6D7C27FD5C3636A43369B7C0|0x7f801f6000|0x7f80208fff|0
|
||||
Module|libstdc++.so||libstdc++.so|380C0B7CD8FA3F094BC3BA58A81CBAD00|0x7f80229000|0x7f8023cfff|0
|
||||
Module|libm.so||libm.so|F832D47D1E237E46D835991594DA6E890|0x7f8023d000|0x7f80279fff|0
|
||||
Module|liblog.so||liblog.so|C407B93F87A835BE05451FC7B0B3E65E0|0x7f8027b000|0x7f80293fff|0
|
||||
Module|libc.so||libc.so|479D5438753E27F019F2C9980DDBF4F30|0x7f80295000|0x7f80332fff|0
|
||||
Module|libsigchain.so||libsigchain.so|9DA3FF8EF9CA0FDC481292EE530DF6EC0|0x7f80341000|0x7f80353fff|0
|
||||
Module|linux-gate.so||linux-gate.so|672B2CD6CF8AF6C43BD70F2AB02B3D0C0|0x7f80358000|0x7f80359fff|0
|
||||
|
||||
0|0|breakpad_unittests|MicrodumpWriterTest_Setup_Test::TestBody|/s/clank/src/out/Release/../../breakpad/src/client/linux/microdump_writer/microdump_writer_unittest.cc|77|0xc
|
||||
0|1|breakpad_unittests|testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>|/s/clank/src/out/Release/../../testing/gtest/src/gtest.cc|2418|0x4
|
||||
0|2|breakpad_unittests|testing::Test::Run|/s/clank/src/out/Release/../../testing/gtest/src/gtest.cc|2435|0x14
|
||||
0|3|breakpad_unittests|testing::TestInfo::Run|/s/clank/src/out/Release/../../testing/gtest/src/gtest.cc|2610|0x4
|
||||
0|4|breakpad_unittests|testing::TestCase::Run|/s/clank/src/out/Release/../../testing/gtest/src/gtest.cc|2728|0x0
|
||||
0|5|breakpad_unittests|testing::internal::UnitTestImpl::RunAllTests|/s/clank/src/out/Release/../../testing/gtest/src/gtest.cc|4591|0x0
|
||||
0|6|breakpad_unittests|testing::UnitTest::Run|/s/clank/src/out/Release/../../testing/gtest/src/gtest.cc|2418|0x4
|
||||
0|7|breakpad_unittests|main|/s/clank/src/out/Release/../../testing/gtest/include/gtest/gtest.h|2326|0x0
|
||||
0|8|libc.so||||0x17388
|
@ -6,6 +6,7 @@ CPU: x86
|
||||
|
||||
Crash reason: EXCEPTION_ACCESS_VIOLATION_WRITE
|
||||
Crash address: 0x45
|
||||
Process uptime: 0 seconds
|
||||
|
||||
Thread 0 (crashed)
|
||||
0 test_app.exe!`anonymous namespace'::CrashFunction [test_app.cc : 58 + 0x3]
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -35,6 +35,7 @@
|
||||
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <link.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -47,6 +48,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "common/minidump_type_helper.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
@ -81,9 +83,13 @@
|
||||
typedef user_regs user_regs_struct;
|
||||
#endif
|
||||
|
||||
using google_breakpad::MDTypeHelper;
|
||||
using google_breakpad::MemoryMappedFile;
|
||||
using google_breakpad::MinidumpMemoryRange;
|
||||
|
||||
typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawDebug MDRawDebug;
|
||||
typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawLinkMap MDRawLinkMap;
|
||||
|
||||
static const MDRVA kInvalidMDRVA = static_cast<MDRVA>(-1);
|
||||
static bool verbose;
|
||||
static std::string g_custom_so_basedir;
|
||||
@ -691,14 +697,14 @@ ParseDSODebugInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
|
||||
"MD_LINUX_DSO_DEBUG:\n"
|
||||
"Version: %d\n"
|
||||
"Number of DSOs: %d\n"
|
||||
"Brk handler: %p\n"
|
||||
"Dynamic loader at: %p\n"
|
||||
"_DYNAMIC: %p\n",
|
||||
"Brk handler: 0x%" PRIx64 "\n"
|
||||
"Dynamic loader at: 0x%" PRIx64 "\n"
|
||||
"_DYNAMIC: 0x%" PRIx64 "\n",
|
||||
debug->version,
|
||||
debug->dso_count,
|
||||
debug->brk,
|
||||
debug->ldbase,
|
||||
debug->dynamic);
|
||||
static_cast<uint64_t>(debug->brk),
|
||||
static_cast<uint64_t>(debug->ldbase),
|
||||
static_cast<uint64_t>(debug->dynamic));
|
||||
}
|
||||
crashinfo->debug = *debug;
|
||||
if (range.length() > sizeof(MDRawDebug)) {
|
||||
@ -713,8 +719,9 @@ ParseDSODebugInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
|
||||
if (link_map) {
|
||||
if (verbose) {
|
||||
fprintf(stderr,
|
||||
"#%03d: %p, %p, \"%s\"\n",
|
||||
i, link_map->addr, link_map->ld,
|
||||
"#%03d: %" PRIx64 ", %" PRIx64 ", \"%s\"\n",
|
||||
i, static_cast<uint64_t>(link_map->addr),
|
||||
static_cast<uint64_t>(link_map->ld),
|
||||
full_file.GetAsciiMDString(link_map->name).c_str());
|
||||
}
|
||||
crashinfo->link_map.push_back(*link_map);
|
||||
|
@ -64,6 +64,7 @@
|
||||
F44DDD8719C85CD50047280E /* dump_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8419C85CD50047280E /* dump_context.cc */; };
|
||||
F44DDD8819C85CD50047280E /* dump_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8519C85CD50047280E /* dump_object.cc */; };
|
||||
F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8619C85CD50047280E /* microdump_processor.cc */; };
|
||||
F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4D43B2E1A38490700C290B2 /* microdump.cc */; };
|
||||
F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE20E8ABCA600E953AD /* bytereader.cc */; };
|
||||
F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */; };
|
||||
F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */; };
|
||||
@ -179,6 +180,8 @@
|
||||
F44DDD8B19C85CFB0047280E /* dump_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_object.h; path = ../../../google_breakpad/processor/dump_object.h; sourceTree = "<group>"; };
|
||||
F44DDD8C19C85CFC0047280E /* microdump_processor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump_processor.h; path = ../../../google_breakpad/processor/microdump_processor.h; sourceTree = "<group>"; };
|
||||
F44DDD8D19C85CFC0047280E /* process_result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = process_result.h; path = ../../../google_breakpad/processor/process_result.h; sourceTree = "<group>"; };
|
||||
F4D43B2E1A38490700C290B2 /* microdump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump.cc; path = ../../../processor/microdump.cc; sourceTree = "<group>"; };
|
||||
F4D43B301A38492000C290B2 /* microdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump.h; path = ../../../google_breakpad/processor/microdump.h; sourceTree = "<group>"; };
|
||||
F9C7ECE20E8ABCA600E953AD /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; };
|
||||
F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
|
||||
F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; };
|
||||
@ -224,6 +227,8 @@
|
||||
F44DDD8A19C85CFB0047280E /* dump_context.h */,
|
||||
F44DDD8519C85CD50047280E /* dump_object.cc */,
|
||||
F44DDD8B19C85CFB0047280E /* dump_object.h */,
|
||||
F4D43B2E1A38490700C290B2 /* microdump.cc */,
|
||||
F4D43B301A38492000C290B2 /* microdump.h */,
|
||||
F44DDD8619C85CD50047280E /* microdump_processor.cc */,
|
||||
F44DDD8C19C85CFC0047280E /* microdump_processor.h */,
|
||||
9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */,
|
||||
@ -482,6 +487,7 @@
|
||||
D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */,
|
||||
D2A5DD631188658B00081F03 /* tokenize.cc in Sources */,
|
||||
8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */,
|
||||
F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */,
|
||||
8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */,
|
||||
F44DDD8819C85CD50047280E /* dump_object.cc in Sources */,
|
||||
8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */,
|
||||
|
Loading…
Reference in New Issue
Block a user