aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbenchan@chromium.org <benchan@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-01-19 07:14:51 +0000
committerbenchan@chromium.org <benchan@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-01-19 07:14:51 +0000
commit30566abed8d95b752f31f67fde94c0ae0a1502d2 (patch)
tree90f98f074cebf21102ad8f8717a2e70e9f4438a9
parentSkip ElfCoreDumpTest.ValidCoreFile test if no core dump is generated. (diff)
downloadbreakpad-30566abed8d95b752f31f67fde94c0ae0a1502d2.tar.xz
Implement core dump to minidump conversion.
This patch is part of a bigger patch that helps merging the breakpad code with the modified version in Chromium OS. Specifically, this patch makes the following changes: 1. Turn the LinuxDumper class into a base class and move ptrace related code into a new derived class, LinuxPtraceDumper. 2. Add a LinuxCoreDumper class, which is derived from LinuxDumper, to extract information from a crashed process via a core dump file instead of ptrace. 3. Add a WriteMinidumpFromCore function to src/client/linux/minidump_writer/minidump_writer.h, which uses LinuxCoreDumper to extract information from a core dump file. 4. Add a core2md utility, which simply wraps WriteMinidumpFromCore, for converting a core dump to a minidump. BUG=455 TEST=Tested the following: 1. Build on 32-bit and 64-bit Linux with gcc 4.4.3 and gcc 4.6. 2. Build on Mac OS X 10.6.8 with gcc 4.2 and clang 3.0 (with latest gmock). 3. All unit tests pass. 4. Run Chromium OS tests to test core2md. Review URL: http://breakpad.appspot.com/343001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@905 4c0a9323-5329-0410-9bdc-e9ce6186880e
-rw-r--r--Makefile.am57
-rw-r--r--Makefile.in224
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper.cc234
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper.h122
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper_unittest.cc117
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.cc275
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.h47
-rw-r--r--src/client/linux/minidump_writer/linux_ptrace_dumper.cc292
-rw-r--r--src/client/linux/minidump_writer/linux_ptrace_dumper.h92
-rw-r--r--src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc (renamed from src/client/linux/minidump_writer/linux_dumper_unittest.cc)116
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc60
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.h6
-rw-r--r--src/common/linux/elf_core_dump_unittest.cc2
-rw-r--r--src/common/linux/tests/crash_generator.cc6
-rw-r--r--src/common/linux/tests/crash_generator.h2
-rw-r--r--src/tools/linux/core2md/core2md.cc57
16 files changed, 1278 insertions, 431 deletions
diff --git a/Makefile.am b/Makefile.am
index d4540f15..934b72d2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -66,6 +66,8 @@ src_client_linux_libbreakpad_client_a_SOURCES = \
src/client/linux/crash_generation/crash_generation_client.cc \
src/client/linux/handler/exception_handler.cc \
src/client/linux/minidump_writer/linux_dumper.cc \
+ src/client/linux/minidump_writer/linux_core_dumper.cc \
+ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
src/client/linux/minidump_writer/minidump_writer.cc \
src/client/minidump_file_writer.cc \
src/common/convert_UTF.c \
@@ -214,6 +216,7 @@ bin_PROGRAMS += \
if !DISABLE_TOOLS
bin_PROGRAMS += \
+ src/tools/linux/core2md/core2md \
src/tools/linux/dump_syms/dump_syms \
src/tools/linux/md2core/minidump-2-core \
src/tools/linux/symupload/minidump_upload \
@@ -289,10 +292,13 @@ src_client_linux_linux_client_unittest_SOURCES = \
src/client/linux/handler/exception_handler_unittest.cc \
src/client/linux/minidump_writer/directory_reader_unittest.cc \
src/client/linux/minidump_writer/line_reader_unittest.cc \
- src/client/linux/minidump_writer/linux_dumper_unittest.cc \
+ src/client/linux/minidump_writer/linux_core_dumper_unittest.cc \
+ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \
src/client/linux/minidump_writer/minidump_writer_unittest.cc \
src/common/linux/linux_libc_support_unittest.cc \
+ src/common/linux/tests/crash_generator.cc \
src/common/memory_unittest.cc \
+ src/common/tests/file_utils.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc \
@@ -311,6 +317,8 @@ src_client_linux_linux_client_unittest_LDADD = \
src/client/linux/handler/exception_handler.o \
src/client/linux/crash_generation/crash_generation_client.o \
src/client/linux/minidump_writer/linux_dumper.o \
+ src/client/linux/minidump_writer/linux_core_dumper.o \
+ src/client/linux/minidump_writer/linux_ptrace_dumper.o \
src/client/linux/minidump_writer/minidump_writer.o \
src/client/minidump_file_writer.o \
src/common/convert_UTF.o \
@@ -320,11 +328,20 @@ src_client_linux_linux_client_unittest_LDADD = \
src/common/linux/guid_creator.o \
src/common/linux/memory_mapped_file.o \
src/common/linux/safe_readlink.o \
- src/common/string_conversion.o
+ src/common/string_conversion.o \
+ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
-src_client_linux_linux_client_unittest_DEPENDENCIES = src/client/linux/linux_dumper_unittest_helper src/client/linux/libbreakpad_client.a src/libbreakpad.a
+src_client_linux_linux_client_unittest_DEPENDENCIES = \
+ src/client/linux/linux_dumper_unittest_helper \
+ src/client/linux/libbreakpad_client.a \
+ src/libbreakpad.a
if !DISABLE_TOOLS
+src_tools_linux_core2md_core2md_SOURCES = \
+ src/tools/linux/core2md/core2md.cc
+src_tools_linux_core2md_core2md_LDADD = \
+ src/client/linux/libbreakpad_client.a
+
src_tools_linux_dump_syms_dump_syms_SOURCES = \
src/common/dwarf_cfi_to_module.cc \
src/common/dwarf_cu_to_module.cc \
@@ -534,25 +551,25 @@ src_processor_disassembler_x86_unittest_LDADD = \
src/third_party/libdisasm/libdisasm.a
src_processor_fast_source_line_resolver_unittest_SOURCES = \
- src/processor/fast_source_line_resolver_unittest.cc \
- src/testing/gtest/src/gtest-all.cc \
- src/testing/src/gmock-all.cc
+ src/processor/fast_source_line_resolver_unittest.cc \
+ src/testing/gtest/src/gtest-all.cc \
+ src/testing/src/gmock-all.cc
src_processor_fast_source_line_resolver_unittest_CPPFLAGS = \
- -I$(top_srcdir)/src \
- -I$(top_srcdir)/src/testing/include \
- -I$(top_srcdir)/src/testing/gtest/include \
- -I$(top_srcdir)/src/testing/gtest \
- -I$(top_srcdir)/src/testing
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/testing/include \
+ -I$(top_srcdir)/src/testing/gtest/include \
+ -I$(top_srcdir)/src/testing/gtest \
+ -I$(top_srcdir)/src/testing
src_processor_fast_source_line_resolver_unittest_LDADD = \
- src/processor/fast_source_line_resolver.o \
- src/processor/basic_source_line_resolver.o \
- src/processor/cfi_frame_info.o \
- src/processor/module_comparer.o \
- src/processor/module_serializer.o \
- src/processor/pathname_stripper.o \
- src/processor/logging.o \
- src/processor/source_line_resolver_base.o \
- src/processor/tokenize.o
+ src/processor/fast_source_line_resolver.o \
+ src/processor/basic_source_line_resolver.o \
+ src/processor/cfi_frame_info.o \
+ src/processor/module_comparer.o \
+ src/processor/module_serializer.o \
+ src/processor/pathname_stripper.o \
+ src/processor/logging.o \
+ src/processor/source_line_resolver_base.o \
+ src/processor/tokenize.o
src_processor_map_serializers_unittest_SOURCES = \
src/processor/map_serializers_unittest.cc \
diff --git a/Makefile.in b/Makefile.in
index e42e3d1d..651ae6c8 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -80,6 +80,7 @@ check_PROGRAMS = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
@LINUX_HOST_TRUE@ src/client/linux/linux_dumper_unittest_helper
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__append_6 = \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/core2md/core2md \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload \
@@ -171,6 +172,8 @@ am__src_client_linux_libbreakpad_client_a_SOURCES_DIST = \
src/client/linux/crash_generation/crash_generation_client.cc \
src/client/linux/handler/exception_handler.cc \
src/client/linux/minidump_writer/linux_dumper.cc \
+ src/client/linux/minidump_writer/linux_core_dumper.cc \
+ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
src/client/linux/minidump_writer/minidump_writer.cc \
src/client/minidump_file_writer.cc src/common/convert_UTF.c \
src/common/md5.cc src/common/string_conversion.cc \
@@ -182,6 +185,8 @@ am__dirstamp = $(am__leading_dot)dirstamp
@LINUX_HOST_TRUE@am_src_client_linux_libbreakpad_client_a_OBJECTS = src/client/linux/crash_generation/crash_generation_client.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.$(OBJEXT) \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.$(OBJEXT) \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/client/minidump_file_writer.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/common/convert_UTF.$(OBJEXT) \
@@ -352,7 +357,8 @@ src_third_party_libdisasm_libdisasm_a_OBJECTS = \
@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)
-@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__EXEEXT_3 = src/tools/linux/dump_syms/dump_syms$(EXEEXT) \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__EXEEXT_3 = src/tools/linux/core2md/core2md$(EXEEXT) \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms$(EXEEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core$(EXEEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload$(EXEEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload$(EXEEXT)
@@ -388,10 +394,12 @@ am__src_client_linux_linux_client_unittest_SOURCES_DIST = \
src/client/linux/handler/exception_handler_unittest.cc \
src/client/linux/minidump_writer/directory_reader_unittest.cc \
src/client/linux/minidump_writer/line_reader_unittest.cc \
- src/client/linux/minidump_writer/linux_dumper_unittest.cc \
+ src/client/linux/minidump_writer/linux_core_dumper_unittest.cc \
+ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \
src/client/linux/minidump_writer/minidump_writer_unittest.cc \
src/common/linux/linux_libc_support_unittest.cc \
- src/common/memory_unittest.cc \
+ src/common/linux/tests/crash_generator.cc \
+ src/common/memory_unittest.cc src/common/tests/file_utils.cc \
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc \
@@ -400,10 +408,13 @@ am__src_client_linux_linux_client_unittest_SOURCES_DIST = \
@LINUX_HOST_TRUE@am_src_client_linux_linux_client_unittest_OBJECTS = src/client/linux/handler/src_client_linux_linux_client_unittest-exception_handler_unittest.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-directory_reader_unittest.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-line_reader_unittest.$(OBJEXT) \
-@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.$(OBJEXT) \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.$(OBJEXT) \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-minidump_writer_unittest.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/common/linux/src_client_linux_linux_client_unittest-linux_libc_support_unittest.$(OBJEXT) \
+@LINUX_HOST_TRUE@ src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/common/src_client_linux_linux_client_unittest-memory_unittest.$(OBJEXT) \
+@LINUX_HOST_TRUE@ src/common/tests/src_client_linux_linux_client_unittest-file_utils.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/testing/gtest/src/src_client_linux_linux_client_unittest-gtest-all.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/testing/gtest/src/src_client_linux_linux_client_unittest-gtest_main.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/testing/src/src_client_linux_linux_client_unittest-gmock-all.$(OBJEXT) \
@@ -413,6 +424,7 @@ am__src_client_linux_linux_client_unittest_SOURCES_DIST = \
@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest-pathname_stripper.$(OBJEXT)
src_client_linux_linux_client_unittest_OBJECTS = \
$(am_src_client_linux_linux_client_unittest_OBJECTS)
+am__DEPENDENCIES_1 =
am__src_client_linux_linux_dumper_unittest_helper_SOURCES_DIST = src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc
@LINUX_HOST_TRUE@am_src_client_linux_linux_dumper_unittest_helper_OBJECTS = src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.$(OBJEXT)
src_client_linux_linux_dumper_unittest_helper_OBJECTS = \
@@ -506,7 +518,6 @@ am__src_common_dumper_unittest_SOURCES_DIST = \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/testing/src/src_common_dumper_unittest-gmock-all.$(OBJEXT)
src_common_dumper_unittest_OBJECTS = \
$(am_src_common_dumper_unittest_OBJECTS)
-am__DEPENDENCIES_1 =
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_DEPENDENCIES = \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1)
@@ -900,6 +911,12 @@ am__src_processor_synth_minidump_unittest_SOURCES_DIST = \
src_processor_synth_minidump_unittest_OBJECTS = \
$(am_src_processor_synth_minidump_unittest_OBJECTS)
src_processor_synth_minidump_unittest_LDADD = $(LDADD)
+am__src_tools_linux_core2md_core2md_SOURCES_DIST = \
+ src/tools/linux/core2md/core2md.cc
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_core2md_core2md_OBJECTS = src/tools/linux/core2md/core2md.$(OBJEXT)
+src_tools_linux_core2md_core2md_OBJECTS = \
+ $(am_src_tools_linux_core2md_core2md_OBJECTS)
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_DEPENDENCIES = src/client/linux/libbreakpad_client.a
am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST = \
src/common/dwarf_cfi_to_module.cc \
src/common/dwarf_cu_to_module.cc \
@@ -1021,6 +1038,7 @@ SOURCES = $(src_client_linux_libbreakpad_client_a_SOURCES) \
$(src_processor_static_map_unittest_SOURCES) \
$(src_processor_static_range_map_unittest_SOURCES) \
$(src_processor_synth_minidump_unittest_SOURCES) \
+ $(src_tools_linux_core2md_core2md_SOURCES) \
$(src_tools_linux_dump_syms_dump_syms_SOURCES) \
$(src_tools_linux_md2core_minidump_2_core_SOURCES) \
$(src_tools_linux_md2core_minidump_2_core_unittest_SOURCES) \
@@ -1059,6 +1077,7 @@ DIST_SOURCES = \
$(am__src_processor_static_map_unittest_SOURCES_DIST) \
$(am__src_processor_static_range_map_unittest_SOURCES_DIST) \
$(am__src_processor_synth_minidump_unittest_SOURCES_DIST) \
+ $(am__src_tools_linux_core2md_core2md_SOURCES_DIST) \
$(am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST) \
$(am__src_tools_linux_md2core_minidump_2_core_SOURCES_DIST) \
$(am__src_tools_linux_md2core_minidump_2_core_unittest_SOURCES_DIST) \
@@ -1203,6 +1222,8 @@ lib_LIBRARIES = $(am__append_1) $(am__append_3)
@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_client.cc \
@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.cc \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.cc \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.cc \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.cc \
@LINUX_HOST_TRUE@ src/client/minidump_file_writer.cc \
@LINUX_HOST_TRUE@ src/common/convert_UTF.c \
@@ -1353,10 +1374,13 @@ TESTS_ENVIRONMENT =
@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler_unittest.cc \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/directory_reader_unittest.cc \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/line_reader_unittest.cc \
-@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper_unittest.cc \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper_unittest.cc \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer_unittest.cc \
@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support_unittest.cc \
+@LINUX_HOST_TRUE@ src/common/linux/tests/crash_generator.cc \
@LINUX_HOST_TRUE@ src/common/memory_unittest.cc \
+@LINUX_HOST_TRUE@ src/common/tests/file_utils.cc \
@LINUX_HOST_TRUE@ src/testing/gtest/src/gtest-all.cc \
@LINUX_HOST_TRUE@ src/testing/gtest/src/gtest_main.cc \
@LINUX_HOST_TRUE@ src/testing/src/gmock-all.cc \
@@ -1376,6 +1400,8 @@ TESTS_ENVIRONMENT =
@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.o \
@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_client.o \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.o \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.o \
+@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.o \
@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.o \
@LINUX_HOST_TRUE@ src/client/minidump_file_writer.o \
@LINUX_HOST_TRUE@ src/common/convert_UTF.o \
@@ -1385,9 +1411,20 @@ TESTS_ENVIRONMENT =
@LINUX_HOST_TRUE@ src/common/linux/guid_creator.o \
@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.o \
@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.o \
-@LINUX_HOST_TRUE@ src/common/string_conversion.o
+@LINUX_HOST_TRUE@ src/common/string_conversion.o \
+@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+
+@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_DEPENDENCIES = \
+@LINUX_HOST_TRUE@ src/client/linux/linux_dumper_unittest_helper \
+@LINUX_HOST_TRUE@ src/client/linux/libbreakpad_client.a \
+@LINUX_HOST_TRUE@ src/libbreakpad.a
+
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_SOURCES = \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/core2md/core2md.cc
+
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_LDADD = \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/client/linux/libbreakpad_client.a
-@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_DEPENDENCIES = src/client/linux/linux_dumper_unittest_helper src/client/linux/libbreakpad_client.a src/libbreakpad.a
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_SOURCES = \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \
@@ -1607,27 +1644,27 @@ TESTS_ENVIRONMENT =
@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a
@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_SOURCES = \
-@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_unittest.cc \
-@DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/gtest-all.cc \
-@DISABLE_PROCESSOR_FALSE@ src/testing/src/gmock-all.cc
+@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_unittest.cc \
+@DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/gtest-all.cc \
+@DISABLE_PROCESSOR_FALSE@ src/testing/src/gmock-all.cc
@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_CPPFLAGS = \
-@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src \
-@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/include \
-@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest/include \
-@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest \
-@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing
+@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src \
+@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/include \
+@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest/include \
+@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest \
+@DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing
@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_LDADD = \
-@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.o \
-@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \
-@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \
-@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.o \
-@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.o \
-@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
-@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
-@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
-@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o
+@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.o \
+@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \
+@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \
+@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.o \
+@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.o \
+@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \
+@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \
+@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \
+@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o
@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_SOURCES = \
@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers_unittest.cc \
@@ -2178,6 +2215,12 @@ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp):
src/client/linux/minidump_writer/linux_dumper.$(OBJEXT): \
src/client/linux/minidump_writer/$(am__dirstamp) \
src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp)
+src/client/linux/minidump_writer/linux_core_dumper.$(OBJEXT): \
+ src/client/linux/minidump_writer/$(am__dirstamp) \
+ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp)
+src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT): \
+ src/client/linux/minidump_writer/$(am__dirstamp) \
+ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp)
src/client/linux/minidump_writer/minidump_writer.$(OBJEXT): \
src/client/linux/minidump_writer/$(am__dirstamp) \
src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp)
@@ -2411,7 +2454,10 @@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-director
src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-line_reader_unittest.$(OBJEXT): \
src/client/linux/minidump_writer/$(am__dirstamp) \
src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp)
-src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.$(OBJEXT): \
+src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.$(OBJEXT): \
+ src/client/linux/minidump_writer/$(am__dirstamp) \
+ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp)
+src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.$(OBJEXT): \
src/client/linux/minidump_writer/$(am__dirstamp) \
src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp)
src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-minidump_writer_unittest.$(OBJEXT): \
@@ -2420,9 +2466,27 @@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-minidump
src/common/linux/src_client_linux_linux_client_unittest-linux_libc_support_unittest.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
+src/common/linux/tests/$(am__dirstamp):
+ @$(MKDIR_P) src/common/linux/tests
+ @: > src/common/linux/tests/$(am__dirstamp)
+src/common/linux/tests/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) src/common/linux/tests/$(DEPDIR)
+ @: > src/common/linux/tests/$(DEPDIR)/$(am__dirstamp)
+src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.$(OBJEXT): \
+ src/common/linux/tests/$(am__dirstamp) \
+ src/common/linux/tests/$(DEPDIR)/$(am__dirstamp)
src/common/src_client_linux_linux_client_unittest-memory_unittest.$(OBJEXT): \
src/common/$(am__dirstamp) \
src/common/$(DEPDIR)/$(am__dirstamp)
+src/common/tests/$(am__dirstamp):
+ @$(MKDIR_P) src/common/tests
+ @: > src/common/tests/$(am__dirstamp)
+src/common/tests/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) src/common/tests/$(DEPDIR)
+ @: > src/common/tests/$(DEPDIR)/$(am__dirstamp)
+src/common/tests/src_client_linux_linux_client_unittest-file_utils.$(OBJEXT): \
+ src/common/tests/$(am__dirstamp) \
+ src/common/tests/$(DEPDIR)/$(am__dirstamp)
src/testing/gtest/src/$(am__dirstamp):
@$(MKDIR_P) src/testing/gtest/src
@: > src/testing/gtest/src/$(am__dirstamp)
@@ -2582,21 +2646,9 @@ src/common/linux/src_common_dumper_unittest-safe_readlink.$(OBJEXT): \
src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
-src/common/linux/tests/$(am__dirstamp):
- @$(MKDIR_P) src/common/linux/tests
- @: > src/common/linux/tests/$(am__dirstamp)
-src/common/linux/tests/$(DEPDIR)/$(am__dirstamp):
- @$(MKDIR_P) src/common/linux/tests/$(DEPDIR)
- @: > src/common/linux/tests/$(DEPDIR)/$(am__dirstamp)
src/common/linux/tests/src_common_dumper_unittest-crash_generator.$(OBJEXT): \
src/common/linux/tests/$(am__dirstamp) \
src/common/linux/tests/$(DEPDIR)/$(am__dirstamp)
-src/common/tests/$(am__dirstamp):
- @$(MKDIR_P) src/common/tests
- @: > src/common/tests/$(am__dirstamp)
-src/common/tests/$(DEPDIR)/$(am__dirstamp):
- @$(MKDIR_P) src/common/tests/$(DEPDIR)
- @: > src/common/tests/$(DEPDIR)/$(am__dirstamp)
src/common/tests/src_common_dumper_unittest-file_utils.$(OBJEXT): \
src/common/tests/$(am__dirstamp) \
src/common/tests/$(DEPDIR)/$(am__dirstamp)
@@ -2926,6 +2978,18 @@ src/processor/src_processor_synth_minidump_unittest-synth_minidump.$(OBJEXT): \
src/processor/synth_minidump_unittest$(EXEEXT): $(src_processor_synth_minidump_unittest_OBJECTS) $(src_processor_synth_minidump_unittest_DEPENDENCIES) src/processor/$(am__dirstamp)
@rm -f src/processor/synth_minidump_unittest$(EXEEXT)
$(CXXLINK) $(src_processor_synth_minidump_unittest_OBJECTS) $(src_processor_synth_minidump_unittest_LDADD) $(LIBS)
+src/tools/linux/core2md/$(am__dirstamp):
+ @$(MKDIR_P) src/tools/linux/core2md
+ @: > src/tools/linux/core2md/$(am__dirstamp)
+src/tools/linux/core2md/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) src/tools/linux/core2md/$(DEPDIR)
+ @: > src/tools/linux/core2md/$(DEPDIR)/$(am__dirstamp)
+src/tools/linux/core2md/core2md.$(OBJEXT): \
+ src/tools/linux/core2md/$(am__dirstamp) \
+ src/tools/linux/core2md/$(DEPDIR)/$(am__dirstamp)
+src/tools/linux/core2md/core2md$(EXEEXT): $(src_tools_linux_core2md_core2md_OBJECTS) $(src_tools_linux_core2md_core2md_DEPENDENCIES) src/tools/linux/core2md/$(am__dirstamp)
+ @rm -f src/tools/linux/core2md/core2md$(EXEEXT)
+ $(CXXLINK) $(src_tools_linux_core2md_core2md_OBJECTS) $(src_tools_linux_core2md_core2md_LDADD) $(LIBS)
src/common/dwarf_cfi_to_module.$(OBJEXT): src/common/$(am__dirstamp) \
src/common/$(DEPDIR)/$(am__dirstamp)
src/common/dwarf_cu_to_module.$(OBJEXT): src/common/$(am__dirstamp) \
@@ -3021,11 +3085,14 @@ mostlyclean-compile:
-rm -f src/client/linux/crash_generation/crash_generation_client.$(OBJEXT)
-rm -f src/client/linux/handler/exception_handler.$(OBJEXT)
-rm -f src/client/linux/handler/src_client_linux_linux_client_unittest-exception_handler_unittest.$(OBJEXT)
+ -rm -f src/client/linux/minidump_writer/linux_core_dumper.$(OBJEXT)
-rm -f src/client/linux/minidump_writer/linux_dumper.$(OBJEXT)
+ -rm -f src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT)
-rm -f src/client/linux/minidump_writer/minidump_writer.$(OBJEXT)
-rm -f src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-directory_reader_unittest.$(OBJEXT)
-rm -f src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-line_reader_unittest.$(OBJEXT)
- -rm -f src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.$(OBJEXT)
+ -rm -f src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.$(OBJEXT)
+ -rm -f src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.$(OBJEXT)
-rm -f src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-minidump_writer_unittest.$(OBJEXT)
-rm -f src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.$(OBJEXT)
-rm -f src/client/minidump_file_writer.$(OBJEXT)
@@ -3067,6 +3134,7 @@ mostlyclean-compile:
-rm -f src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-synth_elf.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-synth_elf_unittest.$(OBJEXT)
+ -rm -f src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.$(OBJEXT)
-rm -f src/common/linux/tests/src_common_dumper_unittest-crash_generator.$(OBJEXT)
-rm -f src/common/md5.$(OBJEXT)
-rm -f src/common/module.$(OBJEXT)
@@ -3097,6 +3165,7 @@ mostlyclean-compile:
-rm -f src/common/stabs_reader.$(OBJEXT)
-rm -f src/common/stabs_to_module.$(OBJEXT)
-rm -f src/common/string_conversion.$(OBJEXT)
+ -rm -f src/common/tests/src_client_linux_linux_client_unittest-file_utils.$(OBJEXT)
-rm -f src/common/tests/src_common_dumper_unittest-file_utils.$(OBJEXT)
-rm -f src/processor/address_map_unittest.$(OBJEXT)
-rm -f src/processor/basic_code_modules.$(OBJEXT)
@@ -3222,6 +3291,7 @@ mostlyclean-compile:
-rm -f src/third_party/libdisasm/x86_insn.$(OBJEXT)
-rm -f src/third_party/libdisasm/x86_misc.$(OBJEXT)
-rm -f src/third_party/libdisasm/x86_operand_list.$(OBJEXT)
+ -rm -f src/tools/linux/core2md/core2md.$(OBJEXT)
-rm -f src/tools/linux/dump_syms/dump_syms.$(OBJEXT)
-rm -f src/tools/linux/md2core/minidump-2-core.$(OBJEXT)
-rm -f src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.$(OBJEXT)
@@ -3235,11 +3305,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/crash_generation/$(DEPDIR)/crash_generation_client.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/exception_handler.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest-exception_handler_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-directory_reader_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-line_reader_unittest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_dumper_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-minidump_writer_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/convert_UTF.Po@am__quote@
@@ -3309,7 +3382,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-crash_generator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/tests/$(DEPDIR)/src_common_dumper_unittest-crash_generator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-file_utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/tests/$(DEPDIR)/src_common_dumper_unittest-file_utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/address_map_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/basic_code_modules.Po@am__quote@
@@ -3435,6 +3510,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_insn.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_misc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_operand_list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/core2md/$(DEPDIR)/core2md.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/dump_syms/$(DEPDIR)/dump_syms.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/md2core/$(DEPDIR)/minidump-2-core.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/md2core/$(DEPDIR)/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.Po@am__quote@
@@ -3515,19 +3591,33 @@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-line_rea
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-line_reader_unittest.obj `if test -f 'src/client/linux/minidump_writer/line_reader_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/line_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/line_reader_unittest.cc'; fi`
-src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.o: src/client/linux/minidump_writer/linux_dumper_unittest.cc
-@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_dumper_unittest.cc
-@am__fastdepCXX_TRUE@ $(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_dumper_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/client/linux/minidump_writer/linux_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.o' libtool=no @AMDEPBACKSLASH@
+src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.o: src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
+@am__fastdepCXX_TRUE@ $(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/client/linux/minidump_writer/linux_core_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
+
+src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.obj: src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/client/linux/minidump_writer/linux_core_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_core_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; fi`
+
+src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.o: src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
+@am__fastdepCXX_TRUE@ $(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_dumper_unittest.cc
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
-src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.obj: src/client/linux/minidump_writer/linux_dumper_unittest.cc
-@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_dumper_unittest.cc'; fi`
-@am__fastdepCXX_TRUE@ $(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_dumper_unittest.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/client/linux/minidump_writer/linux_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.obj' libtool=no @AMDEPBACKSLASH@
+src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.obj: src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@ $(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_dumper_unittest.cc'; fi`
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-linux_ptrace_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; fi`
src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-minidump_writer_unittest.o: src/client/linux/minidump_writer/minidump_writer_unittest.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-minidump_writer_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest-minidump_writer_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest-minidump_writer_unittest.o `test -f 'src/client/linux/minidump_writer/minidump_writer_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/minidump_writer_unittest.cc
@@ -3557,6 +3647,20 @@ src/common/linux/src_client_linux_linux_client_unittest-linux_libc_support_unitt
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_client_linux_linux_client_unittest-linux_libc_support_unittest.obj `if test -f 'src/common/linux/linux_libc_support_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/linux_libc_support_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/linux_libc_support_unittest.cc'; fi`
+src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.o: src/common/linux/tests/crash_generator.cc
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.o -MD -MP -MF src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-crash_generator.Tpo -c -o src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.o `test -f 'src/common/linux/tests/crash_generator.cc' || echo '$(srcdir)/'`src/common/linux/tests/crash_generator.cc
+@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-crash_generator.Tpo src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-crash_generator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/linux/tests/crash_generator.cc' object='src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.o `test -f 'src/common/linux/tests/crash_generator.cc' || echo '$(srcdir)/'`src/common/linux/tests/crash_generator.cc
+
+src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.obj: src/common/linux/tests/crash_generator.cc
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.obj -MD -MP -MF src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-crash_generator.Tpo -c -o src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.obj `if test -f 'src/common/linux/tests/crash_generator.cc'; then $(CYGPATH_W) 'src/common/linux/tests/crash_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/tests/crash_generator.cc'; fi`
+@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-crash_generator.Tpo src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-crash_generator.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/linux/tests/crash_generator.cc' object='src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/tests/src_client_linux_linux_client_unittest-crash_generator.obj `if test -f 'src/common/linux/tests/crash_generator.cc'; then $(CYGPATH_W) 'src/common/linux/tests/crash_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/tests/crash_generator.cc'; fi`
+
src/common/src_client_linux_linux_client_unittest-memory_unittest.o: src/common/memory_unittest.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_client_linux_linux_client_unittest-memory_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_client_linux_linux_client_unittest-memory_unittest.Tpo -c -o src/common/src_client_linux_linux_client_unittest-memory_unittest.o `test -f 'src/common/memory_unittest.cc' || echo '$(srcdir)/'`src/common/memory_unittest.cc
@am__fastdepCXX_TRUE@ $(am__mv) src/common/$(DEPDIR)/src_client_linux_linux_client_unittest-memory_unittest.Tpo src/common/$(DEPDIR)/src_client_linux_linux_client_unittest-memory_unittest.Po
@@ -3571,6 +3675,20 @@ src/common/src_client_linux_linux_client_unittest-memory_unittest.obj: src/commo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_client_linux_linux_client_unittest-memory_unittest.obj `if test -f 'src/common/memory_unittest.cc'; then $(CYGPATH_W) 'src/common/memory_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/memory_unittest.cc'; fi`
+src/common/tests/src_client_linux_linux_client_unittest-file_utils.o: src/common/tests/file_utils.cc
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/tests/src_client_linux_linux_client_unittest-file_utils.o -MD -MP -MF src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-file_utils.Tpo -c -o src/common/tests/src_client_linux_linux_client_unittest-file_utils.o `test -f 'src/common/tests/file_utils.cc' || echo '$(srcdir)/'`src/common/tests/file_utils.cc
+@am__fastdepCXX_TRUE@ $(am__mv) src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-file_utils.Tpo src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-file_utils.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/tests/file_utils.cc' object='src/common/tests/src_client_linux_linux_client_unittest-file_utils.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/src_client_linux_linux_client_unittest-file_utils.o `test -f 'src/common/tests/file_utils.cc' || echo '$(srcdir)/'`src/common/tests/file_utils.cc
+
+src/common/tests/src_client_linux_linux_client_unittest-file_utils.obj: src/common/tests/file_utils.cc
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/tests/src_client_linux_linux_client_unittest-file_utils.obj -MD -MP -MF src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-file_utils.Tpo -c -o src/common/tests/src_client_linux_linux_client_unittest-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi`
+@am__fastdepCXX_TRUE@ $(am__mv) src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-file_utils.Tpo src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest-file_utils.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/tests/file_utils.cc' object='src/common/tests/src_client_linux_linux_client_unittest-file_utils.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/src_client_linux_linux_client_unittest-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi`
+
src/testing/gtest/src/src_client_linux_linux_client_unittest-gtest-all.o: src/testing/gtest/src/gtest-all.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_client_linux_linux_client_unittest-gtest-all.o -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest-gtest-all.Tpo -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest-gtest-all.o `test -f 'src/testing/gtest/src/gtest-all.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest-all.cc
@am__fastdepCXX_TRUE@ $(am__mv) src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest-gtest-all.Tpo src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest-gtest-all.Po
@@ -5690,6 +5808,8 @@ distclean-generic:
-rm -f src/testing/src/$(am__dirstamp)
-rm -f src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp)
-rm -f src/third_party/libdisasm/$(am__dirstamp)
+ -rm -f src/tools/linux/core2md/$(DEPDIR)/$(am__dirstamp)
+ -rm -f src/tools/linux/core2md/$(am__dirstamp)
-rm -f src/tools/linux/dump_syms/$(DEPDIR)/$(am__dirstamp)
-rm -f src/tools/linux/dump_syms/$(am__dirstamp)
-rm -f src/tools/linux/md2core/$(DEPDIR)/$(am__dirstamp)
@@ -5708,7 +5828,7 @@ clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
distclean: distclean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
- -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR)
+ -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/core2md/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-tags
@@ -5756,7 +5876,7 @@ installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
- -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR)
+ -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/core2md/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc
new file mode 100644
index 00000000..3e8c92fe
--- /dev/null
+++ b/src/client/linux/minidump_writer/linux_core_dumper.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2012, 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.
+
+// linux_core_dumper.cc: Implement google_breakpad::LinuxCoreDumper.
+// See linux_core_dumper.h for details.
+
+#include "client/linux/minidump_writer/linux_core_dumper.h"
+
+#include <asm/ptrace.h>
+#include <assert.h>
+#include <elf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/procfs.h>
+
+#include "common/linux/linux_libc_support.h"
+
+namespace google_breakpad {
+
+LinuxCoreDumper::LinuxCoreDumper(pid_t pid,
+ const char* core_path,
+ const char* procfs_path)
+ : LinuxDumper(pid),
+ core_path_(core_path),
+ procfs_path_(procfs_path),
+ thread_infos_(&allocator_, 8) {
+ assert(core_path_);
+}
+
+bool LinuxCoreDumper::BuildProcPath(char* path, pid_t pid,
+ const char* node) const {
+ if (!path || !node)
+ return false;
+
+ size_t node_len = my_strlen(node);
+ if (node_len == 0)
+ return false;
+
+ size_t procfs_path_len = my_strlen(procfs_path_);
+ size_t total_length = procfs_path_len + 1 + node_len;
+ if (total_length >= NAME_MAX)
+ return false;
+
+ memcpy(path, procfs_path_, procfs_path_len);
+ path[procfs_path_len] = '/';
+ memcpy(path + procfs_path_len + 1, node, node_len);
+ path[total_length] = '\0';
+ return true;
+}
+
+void LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
+ const void* src, size_t length) {
+ ElfCoreDump::Addr virtual_address = reinterpret_cast<ElfCoreDump::Addr>(src);
+ // TODO(benchan): Investigate whether the data to be copied could span
+ // across multiple segments in the core dump file. ElfCoreDump::CopyData
+ // and this method do not handle that case yet.
+ if (!core_.CopyData(dest, virtual_address, length)) {
+ // If the data segment is not found in the core dump, fill the result
+ // with marker characters.
+ memset(dest, 0xab, length);
+ }
+}
+
+bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
+ if (index >= thread_infos_.size())
+ return false;
+
+ *info = thread_infos_[index];
+ const uint8_t* stack_pointer;
+#if defined(__i386)
+ memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
+#elif defined(__x86_64)
+ memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
+#elif defined(__ARM_EABI__)
+ memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
+#else
+#error "This code hasn't been ported to your platform yet."
+#endif
+
+ return GetStackInfo(&info->stack, &info->stack_len,
+ reinterpret_cast<uintptr_t>(stack_pointer));
+}
+
+bool LinuxCoreDumper::IsPostMortem() const {
+ return true;
+}
+
+bool LinuxCoreDumper::ThreadsSuspend() {
+ return true;
+}
+
+bool LinuxCoreDumper::ThreadsResume() {
+ return true;
+}
+
+bool LinuxCoreDumper::EnumerateThreads() {
+ if (!mapped_core_file_.Map(core_path_)) {
+ fprintf(stderr, "Could not map core dump file into memory\n");
+ return false;
+ }
+
+ core_.SetContent(mapped_core_file_.content());
+ if (!core_.IsValid()) {
+ fprintf(stderr, "Invalid core dump file\n");
+ return false;
+ }
+
+ ElfCoreDump::Note note = core_.GetFirstNote();
+ if (!note.IsValid()) {
+ fprintf(stderr, "PT_NOTE section not found\n");
+ return false;
+ }
+
+ bool first_thread = true;
+ do {
+ ElfCoreDump::Word type = note.GetType();
+ MemoryRange name = note.GetName();
+ MemoryRange description = note.GetDescription();
+
+ if (type == 0 || name.IsEmpty() || description.IsEmpty()) {
+ fprintf(stderr, "Could not found a valid PT_NOTE.\n");
+ return false;
+ }
+
+ // Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are
+ // ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific):
+ // Thread Name Type
+ // -------------------------------------------------------------------
+ // 1st thread CORE NT_PRSTATUS
+ // process-wide CORE NT_PRPSINFO
+ // process-wide CORE NT_AUXV
+ // 1st thread CORE NT_FPREGSET
+ // 1st thread LINUX NT_PRXFPREG
+ // 1st thread LINUX NT_386_TLS
+ //
+ // 2nd thread CORE NT_PRSTATUS
+ // 2nd thread CORE NT_FPREGSET
+ // 2nd thread LINUX NT_PRXFPREG
+ // 2nd thread LINUX NT_386_TLS
+ //
+ // 3rd thread CORE NT_PRSTATUS
+ // 3rd thread CORE NT_FPREGSET
+ // 3rd thread LINUX NT_PRXFPREG
+ // 3rd thread LINUX NT_386_TLS
+ //
+ // The following code only works if notes are ordered as expected.
+ switch (type) {
+ case NT_PRSTATUS: {
+ if (description.length() != sizeof(elf_prstatus)) {
+ fprintf(stderr, "Found NT_PRSTATUS descriptor of unexpected size\n");
+ return false;
+ }
+
+ const elf_prstatus* status =
+ reinterpret_cast<const elf_prstatus*>(description.data());
+ pid_t pid = status->pr_pid;
+ ThreadInfo info;
+ memset(&info, 0, sizeof(ThreadInfo));
+ info.tgid = status->pr_pgrp;
+ info.ppid = status->pr_ppid;
+ memcpy(&info.regs, status->pr_reg, sizeof(info.regs));
+ if (first_thread) {
+ crash_thread_ = pid;
+ crash_signal_ = status->pr_info.si_signo;
+ }
+ first_thread = false;
+ threads_.push_back(pid);
+ thread_infos_.push_back(info);
+ break;
+ }
+#if defined(__i386) || defined(__x86_64)
+ case NT_FPREGSET: {
+ if (thread_infos_.empty())
+ return false;
+
+ ThreadInfo* info = &thread_infos_.back();
+ if (description.length() != sizeof(info->fpregs)) {
+ fprintf(stderr, "Found NT_FPREGSET descriptor of unexpected size\n");
+ return false;
+ }
+
+ memcpy(&info->fpregs, description.data(), sizeof(info->fpregs));
+ break;
+ }
+#endif
+#if defined(__i386)
+ case NT_PRXFPREG: {
+ if (thread_infos_.empty())
+ return false;
+
+ ThreadInfo* info = &thread_infos_.back();
+ if (description.length() != sizeof(info->fpxregs)) {
+ fprintf(stderr, "Found NT_PRXFPREG descriptor of unexpected size\n");
+ return false;
+ }
+
+ memcpy(&info->fpxregs, description.data(), sizeof(info->fpxregs));
+ break;
+ }
+#endif
+ }
+ note = note.GetNextNote();
+ } while (note.IsValid());
+
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/src/client/linux/minidump_writer/linux_core_dumper.h b/src/client/linux/minidump_writer/linux_core_dumper.h
new file mode 100644
index 00000000..edb9e738
--- /dev/null
+++ b/src/client/linux/minidump_writer/linux_core_dumper.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2012, 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.
+
+// linux_core_dumper.h: Define the google_breakpad::LinuxCoreDumper
+// class, which is derived from google_breakpad::LinuxDumper to extract
+// information from a crashed process via its core dump and proc files.
+
+#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_CORE_DUMPER_H_
+#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_CORE_DUMPER_H_
+
+#include "client/linux/minidump_writer/linux_dumper.h"
+#include "common/linux/elf_core_dump.h"
+#include "common/linux/memory_mapped_file.h"
+
+namespace google_breakpad {
+
+class LinuxCoreDumper : public LinuxDumper {
+ public:
+ // Constructs a dumper for extracting information of a given process
+ // with a process ID of |pid| via its core dump file at |core_path| and
+ // its proc files at |procfs_path|. If |procfs_path| is a copy of
+ // /proc/<pid>, it should contain the following files:
+ // auxv, cmdline, environ, exe, maps, status
+ LinuxCoreDumper(pid_t pid, const char* core_path, const char* procfs_path);
+
+ // Implements LinuxDumper::BuildProcPath().
+ // Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
+ // |path| is a character array of at least NAME_MAX bytes to return the
+ // result.|node| is the final node without any slashes. Return true on
+ // success.
+ //
+ // As this dumper performs a post-mortem dump and makes use of a copy
+ // of the proc files of the crashed process, this derived method does
+ // not actually make use of |pid| and always returns a subpath of
+ // |procfs_path_| regardless of whether |pid| corresponds to the main
+ // process or a thread of the process, i.e. assuming both the main process
+ // and its threads have the following proc files with the same content:
+ // auxv, cmdline, environ, exe, maps, status
+ virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const;
+
+ // Implements LinuxDumper::CopyFromProcess().
+ // Copies content of |length| bytes from a given process |child|,
+ // starting from |src|, into |dest|. This method extracts the content
+ // the core dump and fills |dest| with a sequence of marker bytes
+ // if the expected data is not found in the core dump.
+ virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
+ size_t length);
+
+ // Implements LinuxDumper::GetThreadInfoByIndex().
+ // Reads information about the |index|-th thread of |threads_|.
+ // Returns true on success. One must have called |ThreadsSuspend| first.
+ virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info);
+
+ // Implements LinuxDumper::IsPostMortem().
+ // Always returns true to indicate that this dumper performs a
+ // post-mortem dump of a crashed process via a core dump file.
+ virtual bool IsPostMortem() const;
+
+ // Implements LinuxDumper::ThreadsSuspend().
+ // As the dumper performs a post-mortem dump via a core dump file,
+ // there is no threads to suspend. This method does nothing and
+ // always returns true.
+ virtual bool ThreadsSuspend();
+
+ // Implements LinuxDumper::ThreadsResume().
+ // As the dumper performs a post-mortem dump via a core dump file,
+ // there is no threads to resume. This method does nothing and
+ // always returns true.
+ virtual bool ThreadsResume();
+
+ protected:
+ // Implements LinuxDumper::EnumerateThreads().
+ // Enumerates all threads of the given process into |threads_|.
+ virtual bool EnumerateThreads();
+
+ private:
+ // Path of the core dump file.
+ const char* core_path_;
+
+ // Path of the directory containing the proc files of the given process,
+ // which is usually a copy of /proc/<pid>.
+ const char* procfs_path_;
+
+ // Memory-mapped core dump file at |core_path_|.
+ MemoryMappedFile mapped_core_file_;
+
+ // Content of the core dump file.
+ ElfCoreDump core_;
+
+ // Thread info found in the core dump file.
+ wasteful_vector<ThreadInfo> thread_infos_;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_HANDLER_LINUX_CORE_DUMPER_H_
diff --git a/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
new file mode 100644
index 00000000..e335413b
--- /dev/null
+++ b/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2012, 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.
+
+// linux_core_dumper_unittest.cc:
+// Unit tests for google_breakpad::LinuxCoreDumoer.
+
+#include "breakpad_googletest_includes.h"
+#include "client/linux/minidump_writer/linux_core_dumper.h"
+#include "common/linux/tests/crash_generator.h"
+
+using std::string;
+using namespace google_breakpad;
+
+TEST(LinuxCoreDumperTest, BuildProcPath) {
+ const pid_t pid = getpid();
+ const char procfs_path[] = "/procfs_copy";
+ LinuxCoreDumper dumper(getpid(), "core_file", procfs_path);
+
+ char maps_path[NAME_MAX] = "";
+ char maps_path_expected[NAME_MAX];
+ snprintf(maps_path_expected, sizeof(maps_path_expected),
+ "%s/maps", procfs_path);
+ EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps"));
+ EXPECT_STREQ(maps_path_expected, maps_path);
+
+ EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps"));
+ EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, ""));
+ EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL));
+
+ char long_node[NAME_MAX];
+ size_t long_node_len = NAME_MAX - strlen(procfs_path) - 1;
+ memset(long_node, 'a', long_node_len);
+ long_node[long_node_len] = '\0';
+ EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, long_node));
+}
+
+TEST(LinuxCoreDumperTest, VerifyDumpWithMultipleThreads) {
+ CrashGenerator crash_generator;
+ if (!crash_generator.HasDefaultCorePattern()) {
+ fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test"
+ "is skipped due to non-default core pattern\n");
+ return;
+ }
+
+ const unsigned kNumOfThreads = 3;
+ const unsigned kCrashThread = 1;
+ const int kCrashSignal = SIGABRT;
+ pid_t child_pid;
+ // TODO(benchan): Revert to use ASSERT_TRUE once the flakiness in
+ // CrashGenerator is identified and fixed.
+ if (!crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread,
+ kCrashSignal, &child_pid)) {
+ fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test"
+ "is skipped due to no core dump generated\n");
+ return;
+ }
+
+ pid_t pid = getpid();
+ const char* core_file = crash_generator.GetCoreFilePath().c_str();
+
+ // Since CrashGenerator::CreateChildCrash() simply crashed a fork of
+ // this process, we expect that those proc files, which are used by
+ // LinuxCoreDumper, of crashed child process have the same content of
+ // this process. So we simply pass the proc files of this process to
+ // LinuxCoreDumper.
+ char procfs_path[NAME_MAX];
+ snprintf(procfs_path, NAME_MAX, "/proc/%d", pid);
+
+ LinuxCoreDumper dumper(child_pid, core_file, procfs_path);
+ dumper.Init();
+
+ EXPECT_TRUE(dumper.IsPostMortem());
+
+ // These are no-ops and should always return true.
+ EXPECT_TRUE(dumper.ThreadsSuspend());
+ EXPECT_TRUE(dumper.ThreadsResume());
+
+ // LinuxCoreDumper cannot determine the crash address and thus it always
+ // sets the crash address to 0.
+ EXPECT_EQ(0, dumper.crash_address());
+ EXPECT_EQ(kCrashSignal, dumper.crash_signal());
+ EXPECT_EQ(crash_generator.GetThreadId(kCrashThread),
+ dumper.crash_thread());
+
+ EXPECT_EQ(kNumOfThreads, dumper.threads().size());
+ for (unsigned i = 0; i < kNumOfThreads; ++i) {
+ ThreadInfo info;
+ EXPECT_TRUE(dumper.GetThreadInfoByIndex(i, &info));
+ EXPECT_EQ(getpid(), info.ppid);
+ }
+}
diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc
index e1eb9847..2cf1b40f 100644
--- a/src/client/linux/minidump_writer/linux_dumper.cc
+++ b/src/client/linux/minidump_writer/linux_dumper.cc
@@ -27,6 +27,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// linux_dumper.cc: Implement google_breakpad::LinuxDumper.
+// See linux_dumper.h for details.
+
// This code deals with the mechanics of getting information about a crashed
// process. Since this code may run in a compromised address space, the same
// rules apply as detailed at the top of minidump_writer.h: no libc calls and
@@ -34,25 +37,12 @@
#include "client/linux/minidump_writer/linux_dumper.h"
-#include <asm/ptrace.h>
#include <assert.h>
-#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#if !defined(__ANDROID__)
-#include <link.h>
-#endif
#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include "client/linux/minidump_writer/directory_reader.h"
#include "client/linux/minidump_writer/line_reader.h"
#include "common/linux/file_id.h"
#include "common/linux/linux_libc_support.h"
@@ -63,48 +53,6 @@
static const char kMappedFileUnsafePrefix[] = "/dev/";
static const char kDeletedSuffix[] = " (deleted)";
-// Suspend a thread by attaching to it.
-static bool SuspendThread(pid_t pid) {
- // This may fail if the thread has just died or debugged.
- errno = 0;
- if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
- errno != 0) {
- return false;
- }
- while (sys_waitpid(pid, NULL, __WALL) < 0) {
- if (errno != EINTR) {
- sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
- return false;
- }
- }
-#if defined(__i386) || defined(__x86_64)
- // On x86, the stack pointer is NULL or -1, when executing trusted code in
- // the seccomp sandbox. Not only does this cause difficulties down the line
- // when trying to dump the thread's stack, it also results in the minidumps
- // containing information about the trusted threads. This information is
- // generally completely meaningless and just pollutes the minidumps.
- // We thus test the stack pointer and exclude any threads that are part of
- // the seccomp sandbox's trusted code.
- user_regs_struct regs;
- if (sys_ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1 ||
-#if defined(__i386)
- !regs.esp
-#elif defined(__x86_64)
- !regs.rsp
-#endif
- ) {
- sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
- return false;
- }
-#endif
- return true;
-}
-
-// Resume a thread by detaching from it.
-static bool ResumeThread(pid_t pid) {
- return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
-}
-
inline static bool IsMappedFileOpenUnsafe(
const google_breakpad::MappingInfo& mapping) {
// It is unsafe to attempt to open a mapped file that lives under /dev,
@@ -123,7 +71,6 @@ LinuxDumper::LinuxDumper(pid_t pid)
crash_address_(0),
crash_signal_(0),
crash_thread_(0),
- threads_suspended_(false),
threads_(&allocator_, 8),
mappings_(&allocator_) {
}
@@ -135,80 +82,6 @@ bool LinuxDumper::Init() {
return EnumerateThreads() && EnumerateMappings();
}
-bool LinuxDumper::ThreadsSuspend() {
- if (threads_suspended_)
- return true;
- for (size_t i = 0; i < threads_.size(); ++i) {
- if (!SuspendThread(threads_[i])) {
- // If the thread either disappeared before we could attach to it, or if
- // it was part of the seccomp sandbox's trusted code, it is OK to
- // silently drop it from the minidump.
- memmove(&threads_[i], &threads_[i+1],
- (threads_.size() - i - 1) * sizeof(threads_[i]));
- threads_.resize(threads_.size() - 1);
- --i;
- }
- }
- threads_suspended_ = true;
- return threads_.size() > 0;
-}
-
-bool LinuxDumper::ThreadsResume() {
- if (!threads_suspended_)
- return false;
- bool good = true;
- for (size_t i = 0; i < threads_.size(); ++i)
- good &= ResumeThread(threads_[i]);
- threads_suspended_ = false;
- return good;
-}
-
-void
-LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const {
- assert(path);
- if (!path) {
- return;
- }
-
- path[0] = '\0';
-
- const unsigned pid_len = my_int_len(pid);
-
- assert(node);
- if (!node) {
- return;
- }
-
- size_t node_len = my_strlen(node);
- assert(node_len < NAME_MAX);
- if (node_len >= NAME_MAX) {
- return;
- }
-
- assert(node_len > 0);
- if (node_len == 0) {
- return;
- }
-
- assert(pid > 0);
- if (pid <= 0) {
- return;
- }
-
- const size_t total_length = 6 + pid_len + 1 + node_len;
-
- assert(total_length < NAME_MAX);
- if (total_length >= NAME_MAX) {
- return;
- }
-
- memcpy(path, "/proc/", 6);
- my_itos(path + 6, pid, pid_len);
- memcpy(path + 6 + pid_len, "/", 1);
- memcpy(path + 6 + pid_len + 1, node, node_len);
- path[total_length] = '\0';
-}
-
bool
LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
bool member,
@@ -261,10 +134,8 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
void*
LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
char auxv_path[NAME_MAX];
- BuildProcPath(auxv_path, pid, "auxv");
-
- // If BuildProcPath errors out due to invalid input, we'll handle it when
- // we try to sys_open the file.
+ if (!BuildProcPath(auxv_path, pid, "auxv"))
+ return NULL;
// Find the AT_SYSINFO_EHDR entry for linux-gate.so
// See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
@@ -290,7 +161,8 @@ LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
bool LinuxDumper::EnumerateMappings() {
char maps_path[NAME_MAX];
- BuildProcPath(maps_path, pid_, "maps");
+ if (!BuildProcPath(maps_path, pid_, "maps"))
+ return false;
// linux_gate_loc is the beginning of the kernel's mapping of
// linux-gate.so in the process. It doesn't actually show up in the
@@ -359,118 +231,6 @@ bool LinuxDumper::EnumerateMappings() {
return !mappings_.empty();
}
-// Parse /proc/$pid/task to list all the threads of the process identified by
-// pid.
-bool LinuxDumper::EnumerateThreads() {
- char task_path[NAME_MAX];
- BuildProcPath(task_path, pid_, "task");
-
- const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
- if (fd < 0)
- return false;
- DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
-
- // The directory may contain duplicate entries which we filter by assuming
- // that they are consecutive.
- int last_tid = -1;
- const char* dent_name;
- while (dir_reader->GetNextEntry(&dent_name)) {
- if (my_strcmp(dent_name, ".") &&
- my_strcmp(dent_name, "..")) {
- int tid = 0;
- if (my_strtoui(&tid, dent_name) &&
- last_tid != tid) {
- last_tid = tid;
- threads_.push_back(tid);
- }
- }
- dir_reader->PopEntry();
- }
-
- sys_close(fd);
- return true;
-}
-
-// Read thread info from /proc/$pid/status.
-// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
-// these members are set to -1. Returns true iff all three members are
-// available.
-bool LinuxDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
- if (index >= threads_.size())
- return false;
-
- pid_t tid = threads_[index];
-
- assert(info != NULL);
- char status_path[NAME_MAX];
- BuildProcPath(status_path, tid, "status");
-
- const int fd = sys_open(status_path, O_RDONLY, 0);
- if (fd < 0)
- return false;
-
- LineReader* const line_reader = new(allocator_) LineReader(fd);
- const char* line;
- unsigned line_len;
-
- info->ppid = info->tgid = -1;
-
- while (line_reader->GetNextLine(&line, &line_len)) {
- if (my_strncmp("Tgid:\t", line, 6) == 0) {
- my_strtoui(&info->tgid, line + 6);
- } else if (my_strncmp("PPid:\t", line, 6) == 0) {
- my_strtoui(&info->ppid, line + 6);
- }
-
- line_reader->PopLine(line_len);
- }
-
- if (info->ppid == -1 || info->tgid == -1)
- return false;
-
- if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
- return false;
- }
-
-#if !defined(__ANDROID__)
- if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
- return false;
- }
-#endif
-
-#if defined(__i386)
- if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
- return false;
-#endif
-
-#if defined(__i386) || defined(__x86_64)
- for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
- if (sys_ptrace(
- PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*> (offsetof(struct user,
- u_debugreg[0]) + i *
- sizeof(debugreg_t)),
- &info->dregs[i]) == -1) {
- return false;
- }
- }
-#endif
-
- const uint8_t* stack_pointer;
-#if defined(__i386)
- memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
-#elif defined(__x86_64)
- memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
-#elif defined(__ARM_EABI__)
- memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
-#else
-#error "This code hasn't been ported to your platform yet."
-#endif
-
- return GetStackInfo(&info->stack, &info->stack_len,
- (uintptr_t) stack_pointer);
-}
-
// Get information about the stack, given the stack pointer. We don't try to
// walk the stack since we might not have all the information needed to do
// unwind. So we just grab, up to, 32k of stack.
@@ -497,24 +257,6 @@ bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
return true;
}
-void LinuxDumper::CopyFromProcess(void* dest, pid_t child, const void* src,
- size_t length) {
- unsigned long tmp = 55;
- size_t done = 0;
- static const size_t word_size = sizeof(tmp);
- uint8_t* const local = (uint8_t*) dest;
- uint8_t* const remote = (uint8_t*) src;
-
- while (done < length) {
- const size_t l = length - done > word_size ? word_size : length - done;
- if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) {
- tmp = 0;
- }
- memcpy(local + done, &tmp, l);
- done += l;
- }
-}
-
// Find the mapping which the given memory address falls in.
const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
const uintptr_t addr = (uintptr_t) address;
@@ -544,7 +286,8 @@ bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
// Check |path| against the /proc/pid/exe 'symlink'.
char exe_link[NAME_MAX];
char new_path[NAME_MAX];
- BuildProcPath(exe_link, pid_, "exe");
+ if (!BuildProcPath(exe_link, pid_, "exe"))
+ return false;
if (!SafeReadLink(exe_link, new_path))
return false;
if (my_strcmp(path, new_path) != 0)
diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h
index b0e4f855..45779699 100644
--- a/src/client/linux/minidump_writer/linux_dumper.h
+++ b/src/client/linux/minidump_writer/linux_dumper.h
@@ -27,6 +27,14 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// linux_dumper.h: Define the google_breakpad::LinuxDumper class, which
+// is a base class for extracting information of a crashed process. It
+// was originally a complete implementation using the ptrace API, but
+// has been refactored to allow derived implementations supporting both
+// ptrace and core dump. A portion of the original implementation is now
+// in google_breakpad::LinuxPtraceDumper (see linux_ptrace_dumper.h for
+// details).
+
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
@@ -121,15 +129,18 @@ class LinuxDumper {
virtual ~LinuxDumper();
// Parse the data for |threads| and |mappings|.
- bool Init();
+ virtual bool Init();
+
+ // Return true if the dumper performs a post-mortem dump.
+ virtual bool IsPostMortem() const = 0;
// Suspend/resume all threads in the given process.
- bool ThreadsSuspend();
- bool ThreadsResume();
+ virtual bool ThreadsSuspend() = 0;
+ virtual bool ThreadsResume() = 0;
// Read information about the |index|-th thread of |threads_|.
// Returns true on success. One must have called |ThreadsSuspend| first.
- virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info);
+ virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info) = 0;
// These are only valid after a call to |Init|.
const wasteful_vector<pid_t> &threads() { return threads_; }
@@ -146,13 +157,14 @@ class LinuxDumper {
// Copy content of |length| bytes from a given process |child|,
// starting from |src|, into |dest|.
- void CopyFromProcess(void* dest, pid_t child, const void* src,
- size_t length);
+ virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
+ size_t length) = 0;
- // Builds a proc path for a certain pid for a node. path is a
- // character array that is overwritten, and node is the final node
- // without any slashes.
- void BuildProcPath(char* path, pid_t pid, const char* node) const;
+ // Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
+ // |path| is a character array of at least NAME_MAX bytes to return the
+ // result.|node| is the final node without any slashes. Returns true on
+ // success.
+ virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0;
// Generate a File ID from the .text section of a mapped entry.
// If not a member, mapping_id is ignored.
@@ -179,9 +191,10 @@ class LinuxDumper {
pid_t crash_thread() const { return crash_thread_; }
void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
- private:
- bool EnumerateMappings();
- bool EnumerateThreads();
+ protected:
+ virtual bool EnumerateMappings();
+
+ virtual bool EnumerateThreads() = 0;
// For the case where a running program has been deleted, it'll show up in
// /proc/pid/maps as "/path/to/program (deleted)". If this is the case, then
@@ -208,9 +221,11 @@ class LinuxDumper {
mutable PageAllocator allocator_;
- bool threads_suspended_;
- wasteful_vector<pid_t> threads_; // the ids of all the threads
- wasteful_vector<MappingInfo*> mappings_; // info from /proc/<pid>/maps
+ // IDs of all the threads.
+ wasteful_vector<pid_t> threads_;
+
+ // Info from /proc/<pid>/maps.
+ wasteful_vector<MappingInfo*> mappings_;
};
} // namespace google_breakpad
diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
new file mode 100644
index 00000000..ea58dd11
--- /dev/null
+++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
@@ -0,0 +1,292 @@
+// Copyright (c) 2012, 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.
+
+// linux_ptrace_dumper.cc: Implement google_breakpad::LinuxPtraceDumper.
+// See linux_ptrace_dumper.h for detals.
+// This class was originally splitted from google_breakpad::LinuxDumper.
+
+// This code deals with the mechanics of getting information about a crashed
+// process. Since this code may run in a compromised address space, the same
+// rules apply as detailed at the top of minidump_writer.h: no libc calls and
+// use the alternative allocator.
+
+#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
+
+#include <asm/ptrace.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+
+#include "client/linux/minidump_writer/directory_reader.h"
+#include "client/linux/minidump_writer/line_reader.h"
+#include "common/linux/linux_libc_support.h"
+#include "third_party/lss/linux_syscall_support.h"
+
+// Suspends a thread by attaching to it.
+static bool SuspendThread(pid_t pid) {
+ // This may fail if the thread has just died or debugged.
+ errno = 0;
+ if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
+ errno != 0) {
+ return false;
+ }
+ while (sys_waitpid(pid, NULL, __WALL) < 0) {
+ if (errno != EINTR) {
+ sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
+ return false;
+ }
+ }
+#if defined(__i386) || defined(__x86_64)
+ // On x86, the stack pointer is NULL or -1, when executing trusted code in
+ // the seccomp sandbox. Not only does this cause difficulties down the line
+ // when trying to dump the thread's stack, it also results in the minidumps
+ // containing information about the trusted threads. This information is
+ // generally completely meaningless and just pollutes the minidumps.
+ // We thus test the stack pointer and exclude any threads that are part of
+ // the seccomp sandbox's trusted code.
+ user_regs_struct regs;
+ if (sys_ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1 ||
+#if defined(__i386)
+ !regs.esp
+#elif defined(__x86_64)
+ !regs.rsp
+#endif
+ ) {
+ sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
+ return false;
+ }
+#endif
+ return true;
+}
+
+// Resumes a thread by detaching from it.
+static bool ResumeThread(pid_t pid) {
+ return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
+}
+
+namespace google_breakpad {
+
+LinuxPtraceDumper::LinuxPtraceDumper(pid_t pid)
+ : LinuxDumper(pid),
+ threads_suspended_(false) {
+}
+
+bool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid,
+ const char* node) const {
+ if (!path || !node || pid <= 0)
+ return false;
+
+ size_t node_len = my_strlen(node);
+ if (node_len == 0)
+ return false;
+
+ const unsigned pid_len = my_int_len(pid);
+ const size_t total_length = 6 + pid_len + 1 + node_len;
+ if (total_length >= NAME_MAX)
+ return false;
+
+ memcpy(path, "/proc/", 6);
+ my_itos(path + 6, pid, pid_len);
+ path[6 + pid_len] = '/';
+ memcpy(path + 6 + pid_len + 1, node, node_len);
+ path[total_length] = '\0';
+ return true;
+}
+
+void LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
+ const void* src, size_t length) {
+ unsigned long tmp = 55;
+ size_t done = 0;
+ static const size_t word_size = sizeof(tmp);
+ uint8_t* const local = (uint8_t*) dest;
+ uint8_t* const remote = (uint8_t*) src;
+
+ while (done < length) {
+ const size_t l = (length - done > word_size) ? word_size : (length - done);
+ if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) {
+ tmp = 0;
+ }
+ memcpy(local + done, &tmp, l);
+ done += l;
+ }
+}
+
+// Read thread info from /proc/$pid/status.
+// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
+// these members are set to -1. Returns true iff all three members are
+// available.
+bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
+ if (index >= threads_.size())
+ return false;
+
+ pid_t tid = threads_[index];
+
+ assert(info != NULL);
+ char status_path[NAME_MAX];
+ if (!BuildProcPath(status_path, tid, "status"))
+ return false;
+
+ const int fd = sys_open(status_path, O_RDONLY, 0);
+ if (fd < 0)
+ return false;
+
+ LineReader* const line_reader = new(allocator_) LineReader(fd);
+ const char* line;
+ unsigned line_len;
+
+ info->ppid = info->tgid = -1;
+
+ while (line_reader->GetNextLine(&line, &line_len)) {
+ if (my_strncmp("Tgid:\t", line, 6) == 0) {
+ my_strtoui(&info->tgid, line + 6);
+ } else if (my_strncmp("PPid:\t", line, 6) == 0) {
+ my_strtoui(&info->ppid, line + 6);
+ }
+
+ line_reader->PopLine(line_len);
+ }
+
+ if (info->ppid == -1 || info->tgid == -1)
+ return false;
+
+ if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
+ return false;
+ }
+
+#if !defined(__ANDROID__)
+ if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
+ return false;
+ }
+#endif
+
+#if defined(__i386)
+ if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
+ return false;
+#endif
+
+#if defined(__i386) || defined(__x86_64)
+ for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
+ if (sys_ptrace(
+ PTRACE_PEEKUSER, tid,
+ reinterpret_cast<void*> (offsetof(struct user,
+ u_debugreg[0]) + i *
+ sizeof(debugreg_t)),
+ &info->dregs[i]) == -1) {
+ return false;
+ }
+ }
+#endif
+
+ const uint8_t* stack_pointer;
+#if defined(__i386)
+ memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
+#elif defined(__x86_64)
+ memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
+#elif defined(__ARM_EABI__)
+ memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
+#else
+#error "This code hasn't been ported to your platform yet."
+#endif
+
+ return GetStackInfo(&info->stack, &info->stack_len,
+ (uintptr_t) stack_pointer);
+}
+
+bool LinuxPtraceDumper::IsPostMortem() const {
+ return false;
+}
+
+bool LinuxPtraceDumper::ThreadsSuspend() {
+ if (threads_suspended_)
+ return true;
+ for (size_t i = 0; i < threads_.size(); ++i) {
+ if (!SuspendThread(threads_[i])) {
+ // If the thread either disappeared before we could attach to it, or if
+ // it was part of the seccomp sandbox's trusted code, it is OK to
+ // silently drop it from the minidump.
+ memmove(&threads_[i], &threads_[i+1],
+ (threads_.size() - i - 1) * sizeof(threads_[i]));
+ threads_.resize(threads_.size() - 1);
+ --i;
+ }
+ }
+ threads_suspended_ = true;
+ return threads_.size() > 0;
+}
+
+bool LinuxPtraceDumper::ThreadsResume() {
+ if (!threads_suspended_)
+ return false;
+ bool good = true;
+ for (size_t i = 0; i < threads_.size(); ++i)
+ good &= ResumeThread(threads_[i]);
+ threads_suspended_ = false;
+ return good;
+}
+
+// Parse /proc/$pid/task to list all the threads of the process identified by
+// pid.
+bool LinuxPtraceDumper::EnumerateThreads() {
+ char task_path[NAME_MAX];
+ if (!BuildProcPath(task_path, pid_, "task"))
+ return false;
+
+ const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
+ if (fd < 0)
+ return false;
+ DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
+
+ // The directory may contain duplicate entries which we filter by assuming
+ // that they are consecutive.
+ int last_tid = -1;
+ const char* dent_name;
+ while (dir_reader->GetNextEntry(&dent_name)) {
+ if (my_strcmp(dent_name, ".") &&
+ my_strcmp(dent_name, "..")) {
+ int tid = 0;
+ if (my_strtoui(&tid, dent_name) &&
+ last_tid != tid) {
+ last_tid = tid;
+ threads_.push_back(tid);
+ }
+ }
+ dir_reader->PopEntry();
+ }
+
+ sys_close(fd);
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.h b/src/client/linux/minidump_writer/linux_ptrace_dumper.h
new file mode 100644
index 00000000..1e9bcfdf
--- /dev/null
+++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2012, 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.
+
+// linux_ptrace_dumper.h: Define the google_breakpad::LinuxPtraceDumper
+// class, which is derived from google_breakpad::LinuxDumper to extract
+// information from a crashed process via ptrace.
+// This class was originally splitted from google_breakpad::LinuxDumper.
+
+#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_PTRACE_DUMPER_H_
+#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_PTRACE_DUMPER_H_
+
+#include "client/linux/minidump_writer/linux_dumper.h"
+
+namespace google_breakpad {
+
+class LinuxPtraceDumper : public LinuxDumper {
+ public:
+ // Constructs a dumper for extracting information of a given process
+ // with a process ID of |pid|.
+ explicit LinuxPtraceDumper(pid_t pid);
+
+ // Implements LinuxDumper::BuildProcPath().
+ // Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
+ // |path| is a character array of at least NAME_MAX bytes to return the
+ // result. |node| is the final node without any slashes. Returns true on
+ // success.
+ virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const;
+
+ // Implements LinuxDumper::CopyFromProcess().
+ // Copies content of |length| bytes from a given process |child|,
+ // starting from |src|, into |dest|. This method uses ptrace to extract
+ // the content from the target process.
+ virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
+ size_t length);
+
+ // Implements LinuxDumper::GetThreadInfoByIndex().
+ // Reads information about the |index|-th thread of |threads_|.
+ // Returns true on success. One must have called |ThreadsSuspend| first.
+ virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info);
+
+ // Implements LinuxDumper::IsPostMortem().
+ // Always returns false to indicate this dumper performs a dump of
+ // a crashed process via ptrace.
+ virtual bool IsPostMortem() const;
+
+ // Implements LinuxDumper::ThreadsSuspend().
+ // Suspends all threads in the given process. Returns true on success.
+ virtual bool ThreadsSuspend();
+
+ // Implements LinuxDumper::ThreadsResume().
+ // Resumes all threads in the given process. Returns true on success.
+ virtual bool ThreadsResume();
+
+ protected:
+ // Implements LinuxDumper::EnumerateThreads().
+ // Enumerates all threads of the given process into |threads_|.
+ virtual bool EnumerateThreads();
+
+ private:
+ // Set to true if all threads of the crashed process are suspended.
+ bool threads_suspended_;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_HANDLER_LINUX_PTRACE_DUMPER_H_
diff --git a/src/client/linux/minidump_writer/linux_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
index cf389b57..84e1974f 100644
--- a/src/client/linux/minidump_writer/linux_dumper_unittest.cc
+++ b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
@@ -27,7 +27,11 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <string>
+// linux_ptrace_dumper_unittest.cc:
+// Unit tests for google_breakpad::LinuxPtraceDumoer.
+//
+// This file was renamed from linux_dumper_unittest.cc and modified due
+// to LinuxDumper being splitted into two classes.
#include <fcntl.h>
#include <limits.h>
@@ -39,8 +43,10 @@
#include <sys/stat.h>
#include <sys/types.h>
+#include <string>
+
#include "breakpad_googletest_includes.h"
-#include "client/linux/minidump_writer/linux_dumper.h"
+#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/file_id.h"
#include "common/linux/safe_readlink.h"
@@ -50,7 +56,8 @@ using std::string;
using namespace google_breakpad;
namespace {
-typedef testing::Test LinuxDumperTest;
+
+typedef testing::Test LinuxPtraceDumperTest;
string GetHelperBinary() {
// Locate helper binary next to the current binary.
@@ -69,14 +76,14 @@ string GetHelperBinary() {
return helper_path;
}
-}
+} // namespace
-TEST(LinuxDumperTest, Setup) {
- LinuxDumper dumper(getpid());
+TEST(LinuxPtraceDumperTest, Setup) {
+ LinuxPtraceDumper dumper(getpid());
}
-TEST(LinuxDumperTest, FindMappings) {
- LinuxDumper dumper(getpid());
+TEST(LinuxPtraceDumperTest, FindMappings) {
+ LinuxPtraceDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid)));
@@ -84,8 +91,8 @@ TEST(LinuxDumperTest, FindMappings) {
ASSERT_FALSE(dumper.FindMapping(NULL));
}
-TEST(LinuxDumperTest, ThreadList) {
- LinuxDumper dumper(getpid());
+TEST(LinuxPtraceDumperTest, ThreadList) {
+ LinuxPtraceDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
ASSERT_GE(dumper.threads().size(), (size_t)1);
@@ -101,7 +108,7 @@ TEST(LinuxDumperTest, ThreadList) {
// Helper stack class to close a file descriptor and unmap
// a mmap'ed mapping.
class StackHelper {
-public:
+ public:
StackHelper(int fd, char* mapping, size_t size)
: fd_(fd), mapping_(mapping), size_(size) {}
~StackHelper() {
@@ -109,13 +116,13 @@ public:
close(fd_);
}
-private:
+ private:
int fd_;
char* mapping_;
size_t size_;
};
-TEST(LinuxDumperTest, MergedMappings) {
+TEST(LinuxPtraceDumperTest, MergedMappings) {
string helper_path(GetHelperBinary());
if (helper_path.empty()) {
FAIL() << "Couldn't find helper binary";
@@ -143,18 +150,19 @@ TEST(LinuxDumperTest, MergedMappings) {
StackHelper helper(fd, mapping, kMappingSize);
// Carve a page out of the first mapping with different permissions.
- char* inside_mapping = reinterpret_cast<char*>(mmap(mapping + 2 *kPageSize,
- kPageSize,
- PROT_NONE,
- MAP_SHARED | MAP_FIXED,
- fd,
- // Map a different offset just to
- // better test real-world conditions.
- kPageSize));
+ char* inside_mapping = reinterpret_cast<char*>(
+ mmap(mapping + 2 *kPageSize,
+ kPageSize,
+ PROT_NONE,
+ MAP_SHARED | MAP_FIXED,
+ fd,
+ // Map a different offset just to
+ // better test real-world conditions.
+ kPageSize));
ASSERT_TRUE(inside_mapping);
- // Now check that LinuxDumper interpreted the mappings properly.
- LinuxDumper dumper(getpid());
+ // Now check that LinuxPtraceDumper interpreted the mappings properly.
+ LinuxPtraceDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
int mapping_count = 0;
for (unsigned i = 0; i < dumper.mappings().size(); ++i) {
@@ -171,7 +179,7 @@ TEST(LinuxDumperTest, MergedMappings) {
EXPECT_EQ(1, mapping_count);
}
-TEST(LinuxDumperTest, VerifyStackReadWithMultipleThreads) {
+TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
static const int kNumberOfThreadsInHelperProgram = 5;
char kNumberOfThreadsArgument[2];
sprintf(kNumberOfThreadsArgument, "%d", kNumberOfThreadsInHelperProgram);
@@ -218,13 +226,13 @@ TEST(LinuxDumperTest, VerifyStackReadWithMultipleThreads) {
close(fds[0]);
// Child is ready now.
- LinuxDumper dumper(child_pid);
+ LinuxPtraceDumper dumper(child_pid);
ASSERT_TRUE(dumper.Init());
EXPECT_EQ((size_t)kNumberOfThreadsInHelperProgram, dumper.threads().size());
EXPECT_TRUE(dumper.ThreadsSuspend());
ThreadInfo one_thread;
- for(size_t i = 0; i < dumper.threads().size(); ++i) {
+ for (size_t i = 0; i < dumper.threads().size(); ++i) {
EXPECT_TRUE(dumper.GetThreadInfoByIndex(i, &one_thread));
// In the helper program, we stored a pointer to the thread id in a
// specific register. Check that we can recover its value.
@@ -247,39 +255,33 @@ TEST(LinuxDumperTest, VerifyStackReadWithMultipleThreads) {
kill(child_pid, SIGKILL);
}
-TEST(LinuxDumperTest, BuildProcPath) {
+TEST(LinuxPtraceDumperTest, BuildProcPath) {
const pid_t pid = getpid();
- LinuxDumper dumper(pid);
+ LinuxPtraceDumper dumper(pid);
- char maps_path[256] = "dummymappath";
- char maps_path_expected[256];
+ char maps_path[NAME_MAX] = "";
+ char maps_path_expected[NAME_MAX];
snprintf(maps_path_expected, sizeof(maps_path_expected),
"/proc/%d/maps", pid);
- dumper.BuildProcPath(maps_path, pid, "maps");
- ASSERT_STREQ(maps_path, maps_path_expected);
-
- // In release mode, we expect BuildProcPath to handle the invalid
- // parameters correctly and fill map_path with an empty
- // NULL-terminated string.
-#ifdef NDEBUG
- snprintf(maps_path, sizeof(maps_path), "dummymappath");
- dumper.BuildProcPath(maps_path, 0, "maps");
- EXPECT_STREQ(maps_path, "");
-
- snprintf(maps_path, sizeof(maps_path), "dummymappath");
- dumper.BuildProcPath(maps_path, getpid(), "");
- EXPECT_STREQ(maps_path, "");
-
- snprintf(maps_path, sizeof(maps_path), "dummymappath");
- dumper.BuildProcPath(maps_path, getpid(), NULL);
- EXPECT_STREQ(maps_path, "");
-#endif
+ EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps"));
+ EXPECT_STREQ(maps_path_expected, maps_path);
+
+ EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps"));
+ EXPECT_FALSE(dumper.BuildProcPath(maps_path, 0, "maps"));
+ EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, ""));
+ EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL));
+
+ char long_node[NAME_MAX];
+ size_t long_node_len = NAME_MAX - strlen("/proc/123") - 1;
+ memset(long_node, 'a', long_node_len);
+ long_node[long_node_len] = '\0';
+ EXPECT_FALSE(dumper.BuildProcPath(maps_path, 123, long_node));
}
#if !defined(__ARM_EABI__)
// Ensure that the linux-gate VDSO is included in the mapping list.
-TEST(LinuxDumperTest, MappingsIncludeLinuxGate) {
- LinuxDumper dumper(getpid());
+TEST(LinuxPtraceDumperTest, MappingsIncludeLinuxGate) {
+ LinuxPtraceDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
void* linux_gate_loc = dumper.FindBeginningOfLinuxGateSharedLibrary(getpid());
@@ -301,8 +303,8 @@ TEST(LinuxDumperTest, MappingsIncludeLinuxGate) {
}
// Ensure that the linux-gate VDSO can generate a non-zeroed File ID.
-TEST(LinuxDumperTest, LinuxGateMappingID) {
- LinuxDumper dumper(getpid());
+TEST(LinuxPtraceDumperTest, LinuxGateMappingID) {
+ LinuxPtraceDumper dumper(getpid());
ASSERT_TRUE(dumper.Init());
bool found_linux_gate = false;
@@ -329,7 +331,7 @@ TEST(LinuxDumperTest, LinuxGateMappingID) {
// Ensure that the linux-gate VDSO can generate a non-zeroed File ID
// from a child process.
-TEST(LinuxDumperTest, LinuxGateMappingIDChild) {
+TEST(LinuxPtraceDumperTest, LinuxGateMappingIDChild) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
@@ -345,7 +347,7 @@ TEST(LinuxDumperTest, LinuxGateMappingIDChild) {
}
close(fds[0]);
- LinuxDumper dumper(child);
+ LinuxPtraceDumper dumper(child);
ASSERT_TRUE(dumper.Init());
bool found_linux_gate = false;
@@ -375,7 +377,7 @@ TEST(LinuxDumperTest, LinuxGateMappingIDChild) {
}
#endif
-TEST(LinuxDumperTest, FileIDsMatch) {
+TEST(LinuxPtraceDumperTest, FileIDsMatch) {
// Calculate the File ID of our binary using both
// FileID::ElfFileIdentifier and LinuxDumper::ElfFileIdentifierForMapping
// and ensure that we get the same result from both.
@@ -397,7 +399,7 @@ TEST(LinuxDumperTest, FileIDsMatch) {
}
close(fds[0]);
- LinuxDumper dumper(child);
+ LinuxPtraceDumper dumper(child);
ASSERT_TRUE(dumper.Init());
const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
bool found_exe = false;
diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc
index 9a3d37fe..c6feabdd 100644
--- a/src/client/linux/minidump_writer/minidump_writer.cc
+++ b/src/client/linux/minidump_writer/minidump_writer.cc
@@ -74,6 +74,8 @@
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/line_reader.h"
#include "client/linux/minidump_writer/linux_dumper.h"
+#include "client/linux/minidump_writer/linux_core_dumper.h"
+#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
#include "client/linux/minidump_writer/minidump_extension_linux.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
@@ -372,9 +374,9 @@ class MinidumpWriter {
const MappingList& mappings,
LinuxDumper* dumper)
: filename_(filename),
- ucontext_(&context->context),
+ ucontext_(context ? &context->context : NULL),
#if !defined(__ARM_EABI__)
- float_state_(&context->float_state),
+ float_state_(context ? &context->float_state : NULL),
#else
// TODO: fix this after fixing ExceptionHandler
float_state_(NULL),
@@ -401,18 +403,25 @@ class MinidumpWriter {
struct r_debug* r_debug = NULL;
uint32_t dynamic_length = 0;
#if !defined(__ANDROID__)
- // The Android NDK is missing structure definitions for most of this.
- // For now, it's simpler just to skip it.
- for (int i = 0;;) {
- ElfW(Dyn) dyn;
- dynamic_length += sizeof(dyn);
- dumper_->CopyFromProcess(&dyn, GetCrashThread(), _DYNAMIC+i++,
- sizeof(dyn));
- if (dyn.d_tag == DT_DEBUG) {
- r_debug = (struct r_debug*)dyn.d_un.d_ptr;
- continue;
- } else if (dyn.d_tag == DT_NULL) {
- break;
+ // This code assumes the crashing process is the same as this process and
+ // may hang or take a long time to complete if not so.
+ // Thus, we skip this code for a post-mortem based dump.
+ if (!dumper_->IsPostMortem()) {
+ // The Android NDK is missing structure definitions for most of this.
+ // For now, it's simpler just to skip it.
+ for (int i = 0;;) {
+ ElfW(Dyn) dyn;
+ dynamic_length += sizeof(dyn);
+ // NOTE: Use of _DYNAMIC assumes this is the same process as the
+ // crashing process. This loop will go forever if it's out of bounds.
+ dumper_->CopyFromProcess(&dyn, GetCrashThread(), _DYNAMIC+i++,
+ sizeof(dyn));
+ if (dyn.d_tag == DT_DEBUG) {
+ r_debug = (struct r_debug*)dyn.d_un.d_ptr;
+ continue;
+ } else if (dyn.d_tag == DT_NULL) {
+ break;
+ }
}
}
#endif
@@ -647,7 +656,8 @@ class MinidumpWriter {
// we used the actual state of the thread we would find it running in the
// signal handler with the alternative stack, which would be deeply
// unhelpful.
- if ((pid_t)thread.thread_id == GetCrashThread()) {
+ if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
+ !dumper_->IsPostMortem()) {
const void* stack;
size_t stack_len;
if (!dumper_->GetStackInfo(&stack, &stack_len, GetStackPointer()))
@@ -736,6 +746,10 @@ class MinidumpWriter {
CPUFillFromThreadInfo(cpu.get(), info);
PopSeccompStackFrame(cpu.get(), thread, stack_copy);
thread.thread_context = cpu.location();
+ if (dumper_->threads()[i] == GetCrashThread()) {
+ assert(dumper_->IsPostMortem());
+ crashing_thread_context_ = cpu.location();
+ }
}
list.CopyIndexAfterObject(i, &thread, sizeof(thread));
@@ -1281,7 +1295,8 @@ class MinidumpWriter {
bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
const char* filename) {
char buf[NAME_MAX];
- dumper_->BuildProcPath(buf, pid, filename);
+ if (!dumper_->BuildProcPath(buf, pid, filename))
+ return false;
return WriteFile(result, buf);
}
@@ -1312,7 +1327,7 @@ bool WriteMinidump(const char* filename, pid_t crashing_process,
return false;
const ExceptionHandler::CrashContext* context =
reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
- LinuxDumper dumper(crashing_process);
+ LinuxPtraceDumper dumper(crashing_process);
dumper.set_crash_address(
reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
dumper.set_crash_signal(context->siginfo.si_signo);
@@ -1323,4 +1338,15 @@ bool WriteMinidump(const char* filename, pid_t crashing_process,
return writer.Dump();
}
+bool WriteMinidumpFromCore(const char* filename,
+ const char* core_path,
+ const char* procfs_override) {
+ MappingList mappings;
+ LinuxCoreDumper dumper(0, core_path, procfs_override);
+ MinidumpWriter writer(filename, NULL, mappings, &dumper);
+ if (!writer.Init())
+ return false;
+ return writer.Dump();
+}
+
} // namespace google_breakpad
diff --git a/src/client/linux/minidump_writer/minidump_writer.h b/src/client/linux/minidump_writer/minidump_writer.h
index 156ca35f..731249e3 100644
--- a/src/client/linux/minidump_writer/minidump_writer.h
+++ b/src/client/linux/minidump_writer/minidump_writer.h
@@ -62,6 +62,12 @@ bool WriteMinidump(const char* filename, pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings);
+// Write a minidump to the filesystem. Same as above, but uses the given
+// core file and procfs directory to generate the minidump post mortem.
+bool WriteMinidumpFromCore(const char* filename,
+ const char* core_path,
+ const char* procfs_override);
+
} // namespace google_breakpad
#endif // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
diff --git a/src/common/linux/elf_core_dump_unittest.cc b/src/common/linux/elf_core_dump_unittest.cc
index 89496ab9..11920f25 100644
--- a/src/common/linux/elf_core_dump_unittest.cc
+++ b/src/common/linux/elf_core_dump_unittest.cc
@@ -141,7 +141,7 @@ TEST(ElfCoreDumpTest, ValidCoreFile) {
// TODO(benchan): Revert to use ASSERT_TRUE once the flakiness in
// CrashGenerator is identified and fixed.
if (!crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread,
- kCrashSignal)) {
+ kCrashSignal, NULL)) {
fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped "
"due to no core dump generated");
return;
diff --git a/src/common/linux/tests/crash_generator.cc b/src/common/linux/tests/crash_generator.cc
index fd96e6ca..7274acf9 100644
--- a/src/common/linux/tests/crash_generator.cc
+++ b/src/common/linux/tests/crash_generator.cc
@@ -144,7 +144,8 @@ bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const {
}
bool CrashGenerator::CreateChildCrash(
- unsigned num_threads, unsigned crash_thread, int crash_signal) {
+ unsigned num_threads, unsigned crash_thread, int crash_signal,
+ pid_t* child_pid) {
if (num_threads == 0 || crash_thread >= num_threads)
return false;
@@ -178,6 +179,9 @@ bool CrashGenerator::CreateChildCrash(
perror("CrashGenerator: Child process not killed by the expected signal");
return false;
}
+
+ if (child_pid)
+ *child_pid = pid;
return true;
}
diff --git a/src/common/linux/tests/crash_generator.h b/src/common/linux/tests/crash_generator.h
index c88a8920..874b15cd 100644
--- a/src/common/linux/tests/crash_generator.h
+++ b/src/common/linux/tests/crash_generator.h
@@ -70,7 +70,7 @@ class CrashGenerator {
// a signal with number |crash_signal| to the |crash_thread|-th thread.
// Returns true on success.
bool CreateChildCrash(unsigned num_threads, unsigned crash_thread,
- int crash_signal);
+ int crash_signal, pid_t* child_pid);
// Creates |num_threads| threads in the child process.
void CreateThreadsInChildProcess(unsigned num_threads);
diff --git a/src/tools/linux/core2md/core2md.cc b/src/tools/linux/core2md/core2md.cc
new file mode 100644
index 00000000..c8060b5e
--- /dev/null
+++ b/src/tools/linux/core2md/core2md.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012, 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.
+
+// core2md.cc: A utility to convert an ELF core file to a minidump file.
+
+#include <stdio.h>
+
+#include "client/linux/minidump_writer/minidump_writer.h"
+
+static int ShowUsage(const char* argv0) {
+ fprintf(stderr, "Usage: %s <core file> <procfs dir> <output>\n", argv0);
+ return 1;
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 4) {
+ return ShowUsage(argv[0]);
+ }
+
+ const char* core_file = argv[1];
+ const char* procfs_dir = argv[2];
+ const char* minidump_file = argv[3];
+ if (!google_breakpad::WriteMinidumpFromCore(minidump_file,
+ core_file,
+ procfs_dir)) {
+ fprintf(stderr, "Unable to generate minidump.\n");
+ return 1;
+ }
+
+ return 0;
+}