diff options
author | primiano@chromium.org <primiano@chromium.org> | 2014-11-25 11:36:38 +0000 |
---|---|---|
committer | primiano@chromium.org <primiano@chromium.org> | 2014-11-25 11:36:38 +0000 |
commit | 57e5b074f6a56295a126ff025797bde13b4e2ccf (patch) | |
tree | e3619b1d0f371e2b95b1a6e1a26b8a38a9307044 | |
parent | Fix microdump_writer and add unittest. (diff) | |
download | breakpad-57e5b074f6a56295a126ff025797bde13b4e2ccf.tar.xz |
Introduce microdump_stackwalk comand line executable
This introduces the microdump_stackwalk binary which takes advantage
of the MicrodumpProcessor to symbolize microdumps.
Its operation is identical to the one of minidump_stackwalk.
This CL, in fact, is also refactoring most of the common bits into
stackwalk_common.
BUG=chromium:410294
R=mmandlis@chromium.org
Review URL: https://breakpad.appspot.com/4704002
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1405 4c0a9323-5329-0410-9bdc-e9ce6186880e
-rw-r--r-- | Makefile.am | 48 | ||||
-rw-r--r-- | Makefile.in | 122 | ||||
-rw-r--r-- | src/processor/microdump_stackwalk.cc | 151 | ||||
-rwxr-xr-x | src/processor/microdump_stackwalk_machine_readable_test | 37 | ||||
-rwxr-xr-x | src/processor/microdump_stackwalk_test | 37 | ||||
-rw-r--r-- | src/processor/minidump_stackwalk.cc | 743 | ||||
-rw-r--r-- | src/processor/stackwalk_common.cc | 767 | ||||
-rw-r--r-- | src/processor/stackwalk_common.h | 46 | ||||
-rw-r--r-- | src/processor/testdata/microdump.stackwalk.machine_readable.out | 129 | ||||
-rw-r--r-- | src/processor/testdata/microdump.stackwalk.out | 178 |
10 files changed, 1508 insertions, 750 deletions
diff --git a/Makefile.am b/Makefile.am index b7da8c21..c2b3c0a7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -301,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 @@ -375,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 @@ -710,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 \ @@ -802,10 +805,10 @@ src_processor_microdump_processor_unittest_LDADD = \ 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_address_list.o \ src/processor/stackwalker_mips.o \ src/processor/stackwalker_ppc.o \ src/processor/stackwalker_ppc64.o \ @@ -844,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 \ @@ -976,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 \ @@ -1130,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 = \ @@ -1153,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 \ diff --git a/Makefile.in b/Makefile.in index cc0dc035..4c24a6ea 100644 --- a/Makefile.in +++ b/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 @@ -516,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) @@ -852,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 \ @@ -923,10 +924,10 @@ src_processor_microdump_processor_unittest_OBJECTS = \ @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_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 \ @@ -935,6 +936,42 @@ src_processor_microdump_processor_unittest_OBJECTS = \ @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) @@ -976,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 \ @@ -1015,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 \ @@ -1185,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 \ @@ -1440,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) \ @@ -1484,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) \ @@ -2053,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 @@ -2370,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 \ @@ -2470,10 +2512,10 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS) @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_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 \ @@ -2514,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 \ @@ -2660,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 \ @@ -2826,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 @@ -2850,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 \ @@ -3849,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) @@ -4384,6 +4469,7 @@ distclean-compile: @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@ @@ -7539,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'; \ diff --git a/src/processor/microdump_stackwalk.cc b/src/processor/microdump_stackwalk.cc new file mode 100644 index 00000000..68f8e195 --- /dev/null +++ b/src/processor/microdump_stackwalk.cc @@ -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); + } + 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); +} diff --git a/src/processor/microdump_stackwalk_machine_readable_test b/src/processor/microdump_stackwalk_machine_readable_test new file mode 100755 index 00000000..06762b4b --- /dev/null +++ b/src/processor/microdump_stackwalk_machine_readable_test @@ -0,0 +1,37 @@ +#!/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. + +testdata_dir=$srcdir/src/processor/testdata +./src/processor/microdump_stackwalk -m $testdata_dir/microdump.dmp \ + $testdata_dir/symbols/microdump | \ + tr -d '\015' | \ + diff -u $testdata_dir/microdump.stackwalk.machine_readable.out - +exit $? diff --git a/src/processor/microdump_stackwalk_test b/src/processor/microdump_stackwalk_test new file mode 100755 index 00000000..c5390f94 --- /dev/null +++ b/src/processor/microdump_stackwalk_test @@ -0,0 +1,37 @@ +#!/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. + +testdata_dir=$srcdir/src/processor/testdata +./src/processor/microdump_stackwalk $testdata_dir/microdump.dmp \ + $testdata_dir/symbols/microdump | \ + tr -d '\015' | \ + diff -u $testdata_dir/microdump.stackwalk.out - +exit $? diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc index 47e08575..af45f1ff 100644 --- a/src/processor/minidump_stackwalk.cc +++ b/src/processor/minidump_stackwalk.cc @@ -33,7 +33,6 @@ // Author: Mark Mentovai #include <stdio.h> -#include <stdlib.h> #include <string.h> #include <string> @@ -42,744 +41,20 @@ #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::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 +66,9 @@ 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) { scoped_ptr<SimpleSymbolSupplier> symbol_supplier; if (!symbol_paths.empty()) { // TODO(mmentovai): check existence of symbol_path if specified? @@ -820,14 +95,14 @@ static bool PrintMinidumpProcess(const string &minidump_file, return true; } -} // namespace - -static void usage(const char *program_name) { +void usage(const char *program_name) { fprintf(stderr, "usage: %s [-m] <minidump-file> [symbol-path ...]\n" " -m : Output in machine-readable format\n", program_name); } +} // namespace + int main(int argc, char **argv) { BPLOG_INIT(&argc, &argv); diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc new file mode 100644 index 00000000..72398700 --- /dev/null +++ b/src/processor/stackwalk_common.cc @@ -0,0 +1,767 @@ +// 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/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; +} + +// 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); + } +} + +} // namespace + +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()); +} + +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 diff --git a/src/processor/stackwalk_common.h b/src/processor/stackwalk_common.h new file mode 100644 index 00000000..7ee6e75b --- /dev/null +++ b/src/processor/stackwalk_common.h @@ -0,0 +1,46 @@ +// 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; + +void PrintProcessStateMachineReadable(const ProcessState& process_state); +void PrintProcessState(const ProcessState& process_state); + +} // namespace google_breakpad + +#endif // PROCESSOR_STACKWALK_COMMON_H__ diff --git a/src/processor/testdata/microdump.stackwalk.machine_readable.out b/src/processor/testdata/microdump.stackwalk.machine_readable.out new file mode 100644 index 00000000..4a62a9dc --- /dev/null +++ b/src/processor/testdata/microdump.stackwalk.machine_readable.out @@ -0,0 +1,129 @@ +OS|| +CPU|||0 +Crash||0x0|0 +Module|libchromeshell.so||libchromeshell.so|76304586D0CD2C8FF899C602BF1756A20|0x987ab000|0x9b359fff|0 +Module|RELRO:libchromeshell.so||RELRO:libchromeshell.so|000000000000000000000000000000000|0x9b35a000|0x9b4b5fff|0 +Module|libchromeshell.so||libchromeshell.so|000000000000000000000000000000000|0x9b4b6000|0x9b4cbfff|0 +Module|libchromium_android_linker.so||libchromium_android_linker.so|AC480D966558562B46D4583A55D904E60|0xa47a3000|0xa47b3fff|0 +Module|libwebviewchromium_loader.so||libwebviewchromium_loader.so|932CC9935B065A05D39E38681E0A5F2E0|0xac35d000|0xac35ffff|0 +Module|libandroid.so||libandroid.so|E2C6CBE7D4588EF8111B01903B27FEA80|0xac360000|0xac36ffff|0 +Module|libGLESv2_adreno.so||libGLESv2_adreno.so|83D249BAACD2F2C10C13B70C1F64252C0|0xac370000|0xac4b1fff|0 +Module|libGLESv1_CM_adreno.so||libGLESv1_CM_adreno.so|58A32EAAFDADB17139F988E96B860C8E0|0xac4b3000|0xac4e6fff|0 +Module|libgsl.so||libgsl.so|C71008FE91C209D6D5E9EA5DBB44BF080|0xac4e7000|0xac51afff|0 +Module|libEGL_adreno.so||libEGL_adreno.so|134B50AAA945C8C16B0021DF014AA6150|0xac51b000|0xac544fff|0 +Module|libjavacrypto.so||libjavacrypto.so|9D372357993C7650365479A34E676E290|0xace37000|0xace4efff|0 +Module|librs_jni.so||librs_jni.so|0D2147262F4305E3AED211CB96FC96BA0|0xace4f000|0xace57fff|0 +Module|libaudioeffect_jni.so||libaudioeffect_jni.so|3F276EEAE72C2C9FC768FF2E482957510|0xace58000|0xace5dfff|0 +Module|libsoundpool.so||libsoundpool.so|CDA9BA072D4DECC71C5E63467275E7EE0|0xace5e000|0xace61fff|0 +Module|libstagefright_amrnb_common.so||libstagefright_amrnb_common.so|D02CB251CF8787A770DE2CFDC52A2B040|0xace62000|0xace6ffff|0 +Module|libvorbisidec.so||libvorbisidec.so|F59669C665FE4B073886A8DAAECEA86F0|0xace70000|0xace8afff|0 +Module|libstagefright_yuv.so||libstagefright_yuv.so|9FC00D0B150FE9FC57763A76206D1D550|0xace8b000|0xace8efff|0 +Module|libstagefright_omx.so||libstagefright_omx.so|C2D6408786A8582A0EAE64D047577F800|0xace90000|0xaceaefff|0 +Module|libstagefright_enc_common.so||libstagefright_enc_common.so|E11DA546CE9E08D1D647E8E1135DAD810|0xaceaf000|0xaceb1fff|0 +Module|libstagefright_avc_common.so||libstagefright_avc_common.so|741CC494F5299870A1C62FD71E37AE5F0|0xaceb2000|0xaceb8fff|0 +Module|libpowermanager.so||libpowermanager.so|D3EA22EB9F383751AB500AE5951F0DB30|0xaceb9000|0xacebdfff|0 +Module|libopus.so||libopus.so|F19A7DFF3B6F3AF94EAE23CA21905BAD0|0xacebe000|0xacef9fff|0 +Module|libdrmframework.so||libdrmframework.so|87AFCC5E47ED503148F1AA03777E88590|0xacefa000|0xacf14fff|0 +Module|libstagefright.so||libstagefright.so|A0D663218D972496B104B7B9FF0727BD0|0xacf16000|0xad029fff|0 +Module|libmtp.so||libmtp.so|55B5F5E024DB37CABEC6A8F31DD950870|0xad02a000|0xad03ffff|0 +Module|libjhead.so||libjhead.so|D2AB743CCCD8D2EB9B66A47707CC1E530|0xad040000|0xad04afff|0 +Module|libexif.so||libexif.so|4D1E2F0F58012FABA091A21E4CEEFFE20|0xad04c000|0xad077fff|0 +Module|libmedia_jni.so||libmedia_jni.so|20D19E07A0CA5B5790EEB83C8F6915570|0xad078000|0xad0b3fff|0 +Module|libjnigraphics.so||libjnigraphics.so|8FF5949AE957364C270D0F448DAD4FE20|0xafe8a000|0xafe8cfff|0 +Module|libcompiler_rt.so||libcompiler_rt.so|F2B1298EE4C6EA0900CDACD17FB5C16B0|0xafe8d000|0xafe94fff|0 +Module|libadreno_utils.so||libadreno_utils.so|37FA52E92BF716E0268B9619EE8D61630|0xafe95000|0xafe98fff|0 +Module|memtrack.msm8960.so||memtrack.msm8960.so|F36630BD0C6DC4B52A0E5D5D57BE682A0|0xafe9b000|0xafe9dfff|0 +Module|libjavacore.so||libjavacore.so|FE4EB304B0639D600DFB5871136831C50|0xb15ab000|0xb15e2fff|0 +Module|libbacktrace_libc++.so||libbacktrace_libc++.so|CF0326786BDECFB45A519C7005E851000|0xb4fc8000|0xb4fd0fff|0 +Module|libart.so||libart.so|3E343A5B3F9534F5E40AD9BEAC46C8E80|0xb4fd2000|0xb52d5fff|0 +Module|libusbhost.so||libusbhost.so|3CBDF0DE27B9554508AD60FDC96CBC620|0xb52f9000|0xb52fcfff|0 +Module|libssl.so||libssl.so|36F280D15D51F4EEFA92279E8BBD84360|0xb52fd000|0xb533dfff|0 +Module|libsqlite.so||libsqlite.so|D02DDA779C053EF3CC279A1E1789C4250|0xb533e000|0xb539cfff|0 +Module|libsoundtrigger.so||libsoundtrigger.so|F954BA248E12C9AF32F54434F977FEF80|0xb539e000|0xb53acfff|0 +Module|libselinux.so||libselinux.so|125671BDF56FEE67902BE338575373000|0xb53ad000|0xb53bafff|0 +Module|libprocessgroup.so||libprocessgroup.so|4E6C8C876BA563C3C4B0B3BA562093920|0xb53bb000|0xb53befff|0 +Module|libpdfium.so||libpdfium.so|83C5B450634DDB5C4FC41CA61A35B3740|0xb53bf000|0xb5819fff|0 +Module|libnetd_client.so||libnetd_client.so|56B149396A4DAF176E26B4A85DA87BF30|0xb581f000|0xb5822fff|0 +Module|libnativehelper.so||libnativehelper.so|A20D742D5BF711D12587563B5C4BF64A0|0xb5823000|0xb5829fff|0 +Module|libnativebridge.so||libnativebridge.so|495F8887F27909EE1E3E69A657E0A9AB0|0xb582a000|0xb582dfff|0 +Module|libminikin.so||libminikin.so|31B45FE1FA6CC789F945332C6FECF9750|0xb582e000|0xb5839fff|0 +Module|libmemtrack.so||libmemtrack.so|CCA8BE0D07D24523C8D02FEE5F724EA70|0xb583a000|0xb583cfff|0 +Module|libstagefright_foundation.so||libstagefright_foundation.so|60A6E0B998632198B80EB0941121CD710|0xb583d000|0xb5851fff|0 +Module|libsonivox.so||libsonivox.so|6E42AB0836D73C21533C08A98EE7B24C0|0xb5852000|0xb58a2fff|0 +Module|libcommon_time_client.so||libcommon_time_client.so|E43E7FA869E4BCDAA3CC9601DF5A6A520|0xb58a8000|0xb58b6fff|0 +Module|libnbaio.so||libnbaio.so|C84019C90BCA7E95A773B5A75A460D880|0xb58b7000|0xb58c0fff|0 +Module|libmedia.so||libmedia.so|895A37F76D93E51B0ED7E90E5B71A9330|0xb58c1000|0xb595afff|0 +Module|libinputflinger.so||libinputflinger.so|C5323479053FDA41E355482925A30D120|0xb595b000|0xb5996fff|0 +Module|libinput.so||libinput.so|74F168649BE8583159D23A6406D107740|0xb5997000|0xb59b1fff|0 +Module|libimg_utils.so||libimg_utils.so|41712F8718C430707F8CEE5532CB59200|0xb59b2000|0xb59c0fff|0 +Module|libjpeg.so||libjpeg.so|89A4F06810290EEAF309C12642A3ECFA0|0xb59c1000|0xb59f2fff|0 +Module|libskia.so||libskia.so|65E6AAFD915FB244BFE6BE6C4E5E3EC40|0xb59f4000|0xb5c22fff|0 +Module|libRScpp.so||libRScpp.so|23FBB5490C5DBF1E99CD76AC2AA151410|0xb5c28000|0xb5c44fff|0 +Module|libpng.so||libpng.so|3BFE44EFE288C7A1AD7BE317B9F1BDBC0|0xb5c45000|0xb5c6cfff|0 +Module|libft2.so||libft2.so|659F1470013A04F7702E4BAB65F034E70|0xb5c6d000|0xb5cc6fff|0 +Module|libbcinfo.so||libbcinfo.so|FB93884C5EC21F71C68861C20993EB6C0|0xb5cc7000|0xb5d03fff|0 +Module|libbcc.so||libbcc.so|21B734672A14ED6267B966640C16823E0|0xb5d04000|0xb5d26fff|0 +Module|libc++.so||libc++.so|BE6F28596E6CE20F5E49A9E0BC824DA00|0xb5d47000|0xb5ddafff|0 +Module|libLLVM.so||libLLVM.so|377A25164D6ACDC0F7A38F5E378EC8670|0xb5ddd000|0xb6714fff|0 +Module|libRS.so||libRS.so|8D7E15A890FAF52D874044C9F02C6D130|0xb671c000|0xb6755fff|0 +Module|libhwui.so||libhwui.so|670166E37528A7F183D1B05F52020ABD0|0xb6756000|0xb67a1fff|0 +Module|libicuuc.so||libicuuc.so|1B1FD653750DE88B86D7E83095EE37160|0xb67a2000|0xb68b1fff|0 +Module|libgabi++.so||libgabi++.so|F4F99E4A6E63BF8C8005D96B2BAC8CEB0|0xb68b6000|0xb68bbfff|0 +Module|libicui18n.so||libicui18n.so|237F53C12084A7F42405B410FDE8B4020|0xb68bc000|0xb6a22fff|0 +Module|libharfbuzz_ng.so||libharfbuzz_ng.so|AC5AE16EC01F4362C8E63DF66565090D0|0xb6a23000|0xb6a6afff|0 +Module|libwpa_client.so||libwpa_client.so|254351EC49125FE3A72F78EAB38381410|0xb6a6b000|0xb6a6ffff|0 +Module|libnetutils.so||libnetutils.so|F8BA9819E3B7FA0BE155985B6C09FC570|0xb6a70000|0xb6a76fff|0 +Module|libhardware_legacy.so||libhardware_legacy.so|C08391F010B5A32265D4D781325FFCEE0|0xb6a77000|0xb6a7cfff|0 +Module|libexpat.so||libexpat.so|B98E65710C415C83E972EBDC1EB52AC00|0xb6a7e000|0xb6a94fff|0 +Module|libcrypto.so||libcrypto.so|E26A420F0A5BCD2AC04E9B7B19F67C3D0|0xb6a95000|0xb6b96fff|0 +Module|libhardware.so||libhardware.so|914425D16565257955F7E1574360B71F0|0xb6b99000|0xb6b9bfff|0 +Module|libui.so||libui.so|4F3E1A188AE72585AF4278E4FA5266730|0xb6b9c000|0xb6ba7fff|0 +Module|libsync.so||libsync.so|2D9083CB8C22C02E1412DA13B1CA43AE0|0xb6ba8000|0xb6baafff|0 +Module|libgui.so||libgui.so|559E784386AC5E53A9D4D7F9916AA7F90|0xb6bab000|0xb6bf9fff|0 +Module|libcamera_metadata.so||libcamera_metadata.so|D8696CD80D9B725AFEA007DFCE2562E60|0xb6bfa000|0xb6c01fff|0 +Module|libcamera_client.so||libcamera_client.so|116B760482930C77445ABAC1A3276D0B0|0xb6c02000|0xb6c3bfff|0 +Module|libspeexresampler.so||libspeexresampler.so|AC1D054A26491BE96E8BCCB1E5F2926F0|0xb6c3c000|0xb6c41fff|0 +Module|libaudioutils.so||libaudioutils.so|D330B25521C028B95D7E9360F7C6D6510|0xb6c42000|0xb6c47fff|0 +Module|libz.so||libz.so|03AD92B0BEDAA751C0016E97AE374CAE0|0xb6c48000|0xb6c61fff|0 +Module|libbinder.so||libbinder.so|AC6C388A36224541CD74B35818111B760|0xb6c62000|0xb6c91fff|0 +Module|libandroidfw.so||libandroidfw.so|102764B5F4D4D6F6F1A0C7360182BDEE0|0xb6c92000|0xb6cb9fff|0 +Module|libGLESv2.so||libGLESv2.so|E2F67EE50006FD0ED1482E1463C5CCFF0|0xb6cba000|0xb6cc4fff|0 +Module|libGLESv1_CM.so||libGLESv1_CM.so|EFE6AB19F4060BCECF8CF0E68958C2F60|0xb6cc5000|0xb6ccbfff|0 +Module|libETC1.so||libETC1.so|C91EAF69D18F0D499BD58532BBA173690|0xb6ccc000|0xb6ccffff|0 +Module|libunwind-ptrace.so||libunwind-ptrace.so|7AE0C00FAEDEA3E81109CC784D49A6960|0xb6cd0000|0xb6cd3fff|0 +Module|libunwind.so||libunwind.so|EF89B10946BDF6079AAF789F56192FDA0|0xb6cd4000|0xb6ce1fff|0 +Module|libgccdemangle.so||libgccdemangle.so|3874D35A672DF92604963290963F44990|0xb6d28000|0xb6d2efff|0 +Module|libbacktrace.so||libbacktrace.so|45B51BF91D330E793C9142C2617D7A8E0|0xb6d31000|0xb6d38fff|0 +Module|libutils.so||libutils.so|4939CC7D9325757DDAB52A218D55F4720|0xb6d3a000|0xb6d51fff|0 +Module|libstlport.so||libstlport.so|2FE003E5119C67BABE1A9FAB459A5A5D0|0xb6d52000|0xb6d8cfff|0 +Module|libcutils.so||libcutils.so|8AE85E0A2B96C0006F4BC72D01BDB7BD0|0xb6d8d000|0xb6d99fff|0 +Module|libGLES_trace.so||libGLES_trace.so|A12BAF7D82BE28EC681730452D351E880|0xb6d9b000|0xb6e0bfff|0 +Module|libEGL.so||libEGL.so|924D4C5446BF1132A902C15519E5C4FD0|0xb6e0c000|0xb6e73fff|0 +Module|libandroid_runtime.so||libandroid_runtime.so|EE75A142ED1607624B6579D4590DD7CB0|0xb6e77000|0xb6f52fff|0 +Module|libstdc++.so||libstdc++.so|DFCD7772F3A5BD1E84A50C4DBFDE6F570|0xb6f53000|0xb6f56fff|0 +Module|libm.so||libm.so|AE3467401278371A956801500FC8187D0|0xb6f57000|0xb6f6ffff|0 +Module|liblog.so||liblog.so|0A492DEF82842051996A468D87F23F010|0xb6f71000|0xb6f77fff|0 +Module|libc.so||libc.so|10EC186B04E97F6A24DAA891779479380|0xb6f79000|0xb6fd2fff|0 +Module|libsigchain.so||libsigchain.so|D773C773634B82249E887ECBC5D28C900|0xb6fdd000|0xb6fdffff|0 + +0|0|libchromeshell.so|content::::CrashIntentionally|/s/chrome-brkpad/src/out/Debug/../../content/renderer/render_frame_impl.cc|267|0x2 +0|1|libchromeshell.so|content::::MaybeHandleDebugURL|/s/chrome-brkpad/src/out/Debug/../../content/renderer/render_frame_impl.cc|310|0x3 +0|2|libchromeshell.so|content::RenderFrameImpl::PrepareRenderViewForNavigation|/s/chrome-brkpad/src/out/Debug/../../content/renderer/render_frame_impl.cc|4008|0x3 +0|3|libchromeshell.so|content::RenderFrameImpl::OnNavigate|/s/chrome-brkpad/src/out/Debug/../../content/renderer/render_frame_impl.cc|936|0x1f +0|4|libchromeshell.so|content::RenderFrameImpl::OnMessageReceived|/s/chrome-brkpad/src/out/Debug/../../base/tuple.h|548|0x7 +0|5|libchromeshell.so|content::MessageRouter::RouteMessage|/s/chrome-brkpad/src/out/Debug/../../content/common/message_router.cc|54|0x7 +0|6|libchromeshell.so|content::ChildThread::OnMessageReceived|/s/chrome-brkpad/src/out/Debug/../../content/child/child_thread.cc|502|0x9 +0|7|libchromeshell.so|IPC::ChannelProxy::Context::OnDispatchMessage|/s/chrome-brkpad/src/out/Debug/../../ipc/ipc_channel_proxy.cc|274|0x9 +0|8|libchromeshell.so|base::debug::TaskAnnotator::RunTask|/s/chrome-brkpad/src/out/Debug/../../base/callback.h|401|0x5 +0|9|libchromeshell.so|base::MessageLoop::RunTask|/s/chrome-brkpad/src/out/Debug/../../base/message_loop/message_loop.cc|447|0x11 +0|10|libchromeshell.so|base::MessageLoop::DeferOrRunPendingTask|/s/chrome-brkpad/src/out/Debug/../../base/message_loop/message_loop.cc|456|0x7 +0|11|libchromeshell.so|base::MessageLoop::DoWork|/s/chrome-brkpad/src/out/Debug/../../base/message_loop/message_loop.cc|565|0x7 +0|12|libchromeshell.so|base::MessagePumpDefault::Run|/s/chrome-brkpad/src/out/Debug/../../base/message_loop/message_pump_default.cc|32|0x7 +0|13|libchromeshell.so|base::MessageLoop::RunHandler|/s/chrome-brkpad/src/out/Debug/../../base/message_loop/message_loop.cc|415|0x5 +0|14|libchromeshell.so|base::RunLoop::Run|/s/chrome-brkpad/src/out/Debug/../../base/run_loop.cc|54|0x5 +0|15|libchromeshell.so|base::MessageLoop::Run|/s/chrome-brkpad/src/out/Debug/../../base/message_loop/message_loop.cc|308|0x5 +0|16|libchromeshell.so|content::RendererMain|/s/chrome-brkpad/src/out/Debug/../../content/renderer/renderer_main.cc|235|0x3 +0|17|libchromeshell.so|content::RunNamedProcessTypeMain|/s/chrome-brkpad/src/out/Debug/../../content/app/content_main_runner.cc|423|0xb +0|18|libchromeshell.so|content::ContentMainRunnerImpl::Run|/s/chrome-brkpad/src/out/Debug/../../content/app/content_main_runner.cc|789|0x3 +0|19|libchromeshell.so|content::Start|/s/chrome-brkpad/src/out/Debug/../../content/app/android/content_main.cc|48|0x3 +0|20|||||0xa4d56459 diff --git a/src/processor/testdata/microdump.stackwalk.out b/src/processor/testdata/microdump.stackwalk.out new file mode 100644 index 00000000..c596e769 --- /dev/null +++ b/src/processor/testdata/microdump.stackwalk.out @@ -0,0 +1,178 @@ +Operating system: + +CPU: + 0 CPUs + +Crash reason: +Crash address: 0x0 + +Thread 0 (crashed) + 0 libchromeshell.so!content::::CrashIntentionally [render_frame_impl.cc : 267 + 0x2] + + Found by: given as instruction pointer in context + 1 libchromeshell.so!content::::MaybeHandleDebugURL [render_frame_impl.cc : 310 + 0x3] + + Found by: call frame info + 2 libchromeshell.so!content::RenderFrameImpl::PrepareRenderViewForNavigation [render_frame_impl.cc : 4008 + 0x3] + + Found by: call frame info + 3 libchromeshell.so!content::RenderFrameImpl::OnNavigate [render_frame_impl.cc : 936 + 0x1f] + + Found by: call frame info + 4 libchromeshell.so!content::RenderFrameImpl::OnMessageReceived [tuple.h : 548 + 0x7] + + Found by: call frame info + 5 libchromeshell.so!content::MessageRouter::RouteMessage [message_router.cc : 54 + 0x7] + + Found by: call frame info + 6 libchromeshell.so!content::ChildThread::OnMessageReceived [child_thread.cc : 502 + 0x9] + + Found by: call frame info + 7 libchromeshell.so!IPC::ChannelProxy::Context::OnDispatchMessage [ipc_channel_proxy.cc : 274 + 0x9] + + Found by: call frame info + 8 libchromeshell.so!base::debug::TaskAnnotator::RunTask [callback.h : 401 + 0x5] + + Found by: call frame info + 9 libchromeshell.so!base::MessageLoop::RunTask [message_loop.cc : 447 + 0x11] + + Found by: call frame info +10 libchromeshell.so!base::MessageLoop::DeferOrRunPendingTask [message_loop.cc : 456 + 0x7] + + Found by: call frame info +11 libchromeshell.so!base::MessageLoop::DoWork [message_loop.cc : 565 + 0x7] + + Found by: call frame info +12 libchromeshell.so!base::MessagePumpDefault::Run [message_pump_default.cc : 32 + 0x7] + + Found by: call frame info +13 libchromeshell.so!base::MessageLoop::RunHandler [message_loop.cc : 415 + 0x5] + + Found by: call frame info +14 libchromeshell.so!base::RunLoop::Run [run_loop.cc : 54 + 0x5] + + Found by: call frame info +15 libchromeshell.so!base::MessageLoop::Run [message_loop.cc : 308 + 0x5] + + Found by: call frame info +16 libchromeshell.so!content::RendererMain [renderer_main.cc : 235 + 0x3] + + Found by: call frame info +17 libchromeshell.so!content::RunNamedProcessTypeMain [content_main_runner.cc : 423 + 0xb] + + Found by: call frame info +18 libchromeshell.so!content::ContentMainRunnerImpl::Run [content_main_runner.cc : 789 + 0x3] + + Found by: call frame info +19 libchromeshell.so!content::Start [content_main.cc : 48 + 0x3] + + Found by: call frame info +20 0xa4d56459 + + Found by: call frame info + +Loaded modules: +0x987ab000 - 0x9b359fff libchromeshell.so ??? +0x9b35a000 - 0x9b4b5fff RELRO:libchromeshell.so ??? +0x9b4b6000 - 0x9b4cbfff libchromeshell.so ??? +0xa47a3000 - 0xa47b3fff libchromium_android_linker.so ??? +0xac35d000 - 0xac35ffff libwebviewchromium_loader.so ??? +0xac360000 - 0xac36ffff libandroid.so ??? +0xac370000 - 0xac4b1fff libGLESv2_adreno.so ??? +0xac4b3000 - 0xac4e6fff libGLESv1_CM_adreno.so ??? +0xac4e7000 - 0xac51afff libgsl.so ??? +0xac51b000 - 0xac544fff libEGL_adreno.so ??? +0xace37000 - 0xace4efff libjavacrypto.so ??? +0xace4f000 - 0xace57fff librs_jni.so ??? +0xace58000 - 0xace5dfff libaudioeffect_jni.so ??? +0xace5e000 - 0xace61fff libsoundpool.so ??? +0xace62000 - 0xace6ffff libstagefright_amrnb_common.so ??? +0xace70000 - 0xace8afff libvorbisidec.so ??? +0xace8b000 - 0xace8efff libstagefright_yuv.so ??? +0xace90000 - 0xaceaefff libstagefright_omx.so ??? +0xaceaf000 - 0xaceb1fff libstagefright_enc_common.so ??? +0xaceb2000 - 0xaceb8fff libstagefright_avc_common.so ??? +0xaceb9000 - 0xacebdfff libpowermanager.so ??? +0xacebe000 - 0xacef9fff libopus.so ??? +0xacefa000 - 0xacf14fff libdrmframework.so ??? +0xacf16000 - 0xad029fff libstagefright.so ??? +0xad02a000 - 0xad03ffff libmtp.so ??? +0xad040000 - 0xad04afff libjhead.so ??? +0xad04c000 - 0xad077fff libexif.so ??? +0xad078000 - 0xad0b3fff libmedia_jni.so ??? +0xafe8a000 - 0xafe8cfff libjnigraphics.so ??? +0xafe8d000 - 0xafe94fff libcompiler_rt.so ??? +0xafe95000 - 0xafe98fff libadreno_utils.so ??? +0xafe9b000 - 0xafe9dfff memtrack.msm8960.so ??? +0xb15ab000 - 0xb15e2fff libjavacore.so ??? +0xb4fc8000 - 0xb4fd0fff libbacktrace_libc++.so ??? +0xb4fd2000 - 0xb52d5fff libart.so ??? +0xb52f9000 - 0xb52fcfff libusbhost.so ??? +0xb52fd000 - 0xb533dfff libssl.so ??? +0xb533e000 - 0xb539cfff libsqlite.so ??? +0xb539e000 - 0xb53acfff libsoundtrigger.so ??? +0xb53ad000 - 0xb53bafff libselinux.so ??? +0xb53bb000 - 0xb53befff libprocessgroup.so ??? +0xb53bf000 - 0xb5819fff libpdfium.so ??? +0xb581f000 - 0xb5822fff libnetd_client.so ??? +0xb5823000 - 0xb5829fff libnativehelper.so ??? +0xb582a000 - 0xb582dfff libnativebridge.so ??? +0xb582e000 - 0xb5839fff libminikin.so ??? +0xb583a000 - 0xb583cfff libmemtrack.so ??? +0xb583d000 - 0xb5851fff libstagefright_foundation.so ??? +0xb5852000 - 0xb58a2fff libsonivox.so ??? +0xb58a8000 - 0xb58b6fff libcommon_time_client.so ??? +0xb58b7000 - 0xb58c0fff libnbaio.so ??? +0xb58c1000 - 0xb595afff libmedia.so ??? +0xb595b000 - 0xb5996fff libinputflinger.so ??? +0xb5997000 - 0xb59b1fff libinput.so ??? +0xb59b2000 - 0xb59c0fff libimg_utils.so ??? +0xb59c1000 - 0xb59f2fff libjpeg.so ??? +0xb59f4000 - 0xb5c22fff libskia.so ??? +0xb5c28000 - 0xb5c44fff libRScpp.so ??? +0xb5c45000 - 0xb5c6cfff libpng.so ??? +0xb5c6d000 - 0xb5cc6fff libft2.so ??? +0xb5cc7000 - 0xb5d03fff libbcinfo.so ??? +0xb5d04000 - 0xb5d26fff libbcc.so ??? +0xb5d47000 - 0xb5ddafff libc++.so ??? +0xb5ddd000 - 0xb6714fff libLLVM.so ??? +0xb671c000 - 0xb6755fff libRS.so ??? +0xb6756000 - 0xb67a1fff libhwui.so ??? +0xb67a2000 - 0xb68b1fff libicuuc.so ??? +0xb68b6000 - 0xb68bbfff libgabi++.so ??? +0xb68bc000 - 0xb6a22fff libicui18n.so ??? +0xb6a23000 - 0xb6a6afff libharfbuzz_ng.so ??? +0xb6a6b000 - 0xb6a6ffff libwpa_client.so ??? +0xb6a70000 - 0xb6a76fff libnetutils.so ??? +0xb6a77000 - 0xb6a7cfff libhardware_legacy.so ??? +0xb6a7e000 - 0xb6a94fff libexpat.so ??? +0xb6a95000 - 0xb6b96fff libcrypto.so ??? +0xb6b99000 - 0xb6b9bfff libhardware.so ??? +0xb6b9c000 - 0xb6ba7fff libui.so ??? +0xb6ba8000 - 0xb6baafff libsync.so ??? +0xb6bab000 - 0xb6bf9fff libgui.so ??? +0xb6bfa000 - 0xb6c01fff libcamera_metadata.so ??? +0xb6c02000 - 0xb6c3bfff libcamera_client.so ??? +0xb6c3c000 - 0xb6c41fff libspeexresampler.so ??? +0xb6c42000 - 0xb6c47fff libaudioutils.so ??? +0xb6c48000 - 0xb6c61fff libz.so ??? +0xb6c62000 - 0xb6c91fff libbinder.so ??? +0xb6c92000 - 0xb6cb9fff libandroidfw.so ??? +0xb6cba000 - 0xb6cc4fff libGLESv2.so ??? +0xb6cc5000 - 0xb6ccbfff libGLESv1_CM.so ??? +0xb6ccc000 - 0xb6ccffff libETC1.so ??? +0xb6cd0000 - 0xb6cd3fff libunwind-ptrace.so ??? +0xb6cd4000 - 0xb6ce1fff libunwind.so ??? +0xb6d28000 - 0xb6d2efff libgccdemangle.so ??? +0xb6d31000 - 0xb6d38fff libbacktrace.so ??? +0xb6d3a000 - 0xb6d51fff libutils.so ??? +0xb6d52000 - 0xb6d8cfff libstlport.so ??? +0xb6d8d000 - 0xb6d99fff libcutils.so ??? +0xb6d9b000 - 0xb6e0bfff libGLES_trace.so ??? +0xb6e0c000 - 0xb6e73fff libEGL.so ??? +0xb6e77000 - 0xb6f52fff libandroid_runtime.so ??? +0xb6f53000 - 0xb6f56fff libstdc++.so ??? +0xb6f57000 - 0xb6f6ffff libm.so ??? +0xb6f71000 - 0xb6f77fff liblog.so ??? +0xb6f79000 - 0xb6fd2fff libc.so ??? +0xb6fdd000 - 0xb6fdffff libsigchain.so ??? |