From c4c43b80ea8854c57a4374ac32579b577172dc23 Mon Sep 17 00:00:00 2001 From: Iryna Shakhova Date: Thu, 12 May 2022 09:32:52 +0000 Subject: [PATCH] Reland "Support PE modules in core files when running core2md" This is a reland of commit 0808030bee8bc88a34675cd1dd83b965a2249a08 Original change's description: > Support PE modules in core files when running core2md > > Core files generated from `wine` contain both ELF and PE modules. Module > format can be guessed by checking the file contents. If the module > corresponds to PE-file conditions (has specific fields set up as > described in https://code.google.com/archive/p/corkami/wikis/PE.wiki) > we'll create a MDCVInfoPDB70 record in the minidump for it, but if > the file cannot be opened, is too short or is not a PE file, we'll > fall back to ELF procedure. > > Added /src/client/linux/minidump_writer/pe_file.{cc,h} to > src_client_linux_libbreakpad_client_a_SOURCES and > src_client_linux_linux_client_unittest_shlib_SOURCES. > Makefile.in and aclocal.m4 were generated by running 'aclocal && automake'. > > Test: build core2md and use it to convert a core file into dmp, validate > that the generated dmp file can be opened. Ran './configure & make'. > > Change-Id: I225ffeea3f582deed40ecdfe7ab77f5754e90cbe > Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3629189 > Reviewed-by: Joshua Peraza Change-Id: I09dd067a39a95f81f48656595e811c263561ebf2 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3695863 Reviewed-by: Joshua Peraza --- Makefile.am | 2 + Makefile.in | 51 +++- aclocal.m4 | 76 +++--- .../linux/minidump_writer/minidump_writer.cc | 107 ++++++--- src/client/linux/minidump_writer/pe_file.cc | 148 ++++++++++++ src/client/linux/minidump_writer/pe_file.h | 77 ++++++ src/client/linux/minidump_writer/pe_structs.h | 226 ++++++++++++++++++ 7 files changed, 622 insertions(+), 65 deletions(-) create mode 100644 src/client/linux/minidump_writer/pe_file.cc create mode 100644 src/client/linux/minidump_writer/pe_file.h create mode 100644 src/client/linux/minidump_writer/pe_structs.h diff --git a/Makefile.am b/Makefile.am index e7dc06ac..2cde8649 100644 --- a/Makefile.am +++ b/Makefile.am @@ -168,6 +168,7 @@ src_client_linux_libbreakpad_client_a_SOURCES = \ src/client/linux/minidump_writer/linux_dumper.cc \ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/linux/minidump_writer/pe_file.cc \ src/client/minidump_file_writer-inl.h \ src/client/minidump_file_writer.cc \ src/client/minidump_file_writer.h \ @@ -491,6 +492,7 @@ src_client_linux_linux_client_unittest_shlib_SOURCES = \ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ src/client/linux/minidump_writer/minidump_writer_unittest.cc \ src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ + src/client/linux/minidump_writer/pe_file.cc \ src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ src/common/linux/elf_core_dump.cc \ src/common/linux/linux_libc_support_unittest.cc \ diff --git a/Makefile.in b/Makefile.in index 87377f3a..aaf79133 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.3 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -360,6 +360,7 @@ am__src_client_linux_libbreakpad_client_a_SOURCES_DIST = \ src/client/linux/minidump_writer/linux_dumper.cc \ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/linux/minidump_writer/pe_file.cc \ src/client/minidump_file_writer-inl.h \ src/client/minidump_file_writer.cc \ src/client/minidump_file_writer.h src/common/convert_UTF.cc \ @@ -387,6 +388,7 @@ am__dirstamp = $(am__leading_dot)dirstamp @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_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/linux/minidump_writer/pe_file.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/client/minidump_file_writer.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/common/convert_UTF.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/common/md5.$(OBJEXT) \ @@ -632,6 +634,7 @@ am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST = \ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ src/client/linux/minidump_writer/minidump_writer_unittest.cc \ src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ + src/client/linux/minidump_writer/pe_file.cc \ src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ src/common/linux/elf_core_dump.cc \ src/common/linux/linux_libc_support_unittest.cc \ @@ -665,6 +668,7 @@ am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST = \ @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest_utils.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/common/linux/client_linux_linux_client_unittest_shlib-elf_core_dump.$(OBJEXT) \ @LINUX_HOST_TRUE@ src/common/linux/client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.$(OBJEXT) \ @@ -1645,12 +1649,14 @@ am__depfiles_remade = src/client/$(DEPDIR)/minidump_file_writer.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest_utils.Po \ + src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po \ src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po \ src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po \ + src/client/linux/minidump_writer/$(DEPDIR)/pe_file.Po \ src/common/$(DEPDIR)/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po \ src/common/$(DEPDIR)/convert_UTF.Po \ src/common/$(DEPDIR)/dumper_unittest-byte_cursor_unittest.Po \ @@ -2101,9 +2107,6 @@ am__define_uniq_tagged_files = \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -CSCOPE = cscope AM_RECURSIVE_TARGETS = cscope check recheck am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ @@ -2291,9 +2294,9 @@ am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/autotools/missing \ $(top_srcdir)/autotools/test-driver \ $(top_srcdir)/src/config.h.in AUTHORS ChangeLog INSTALL NEWS \ - autotools/ar-lib autotools/compile autotools/config.guess \ - autotools/config.sub autotools/depcomp autotools/install-sh \ - autotools/ltmain.sh autotools/missing + README.md autotools/ar-lib autotools/compile \ + autotools/config.guess autotools/config.sub autotools/depcomp \ + autotools/install-sh autotools/ltmain.sh autotools/missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -2329,6 +2332,8 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ @@ -2339,6 +2344,7 @@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ +ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ GMOCK_CFLAGS = @GMOCK_CFLAGS@ GMOCK_LIBS = @GMOCK_LIBS@ @@ -2513,6 +2519,7 @@ CLEANFILES = $(am__append_12) @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_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/linux/minidump_writer/pe_file.cc \ @LINUX_HOST_TRUE@ src/client/minidump_file_writer-inl.h \ @LINUX_HOST_TRUE@ src/client/minidump_file_writer.cc \ @LINUX_HOST_TRUE@ src/client/minidump_file_writer.h \ @@ -2718,6 +2725,7 @@ TESTS = $(check_PROGRAMS) $(check_SCRIPTS) @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/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/pe_file.cc \ @LINUX_HOST_TRUE@ src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ @LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.cc \ @LINUX_HOST_TRUE@ src/common/linux/linux_libc_support_unittest.cc \ @@ -4151,6 +4159,9 @@ src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT): \ src/client/linux/minidump_writer/minidump_writer.$(OBJEXT): \ src/client/linux/minidump_writer/$(am__dirstamp) \ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/pe_file.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) src/client/$(am__dirstamp): @$(MKDIR_P) src/client @: > src/client/$(am__dirstamp) @@ -4452,6 +4463,9 @@ src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_uni src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest_utils.$(OBJEXT): \ src/client/linux/minidump_writer/$(am__dirstamp) \ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.$(OBJEXT): \ src/client/linux/minidump_writer/$(am__dirstamp) \ src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) @@ -5357,12 +5371,14 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest_utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/pe_file.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/convert_UTF.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/dumper_unittest-byte_cursor_unittest.Po@am__quote@ # am--include-marker @@ -5921,6 +5937,20 @@ src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_uni @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-minidump_writer_unittest_utils.obj `if test -f 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; fi` +src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o: src/client/linux/minidump_writer/pe_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Tpo -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o `test -f 'src/client/linux/minidump_writer/pe_file.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/pe_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Tpo src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/pe_file.cc' object='src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.o `test -f 'src/client/linux/minidump_writer/pe_file.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/pe_file.cc + +src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj: src/client/linux/minidump_writer/pe_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Tpo -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj `if test -f 'src/client/linux/minidump_writer/pe_file.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/pe_file.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/pe_file.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Tpo src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/pe_file.cc' object='src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-pe_file.obj `if test -f 'src/client/linux/minidump_writer/pe_file.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/pe_file.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/pe_file.cc'; fi` + src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o: src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Tpo -c -o src/client/linux/minidump_writer/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o `test -f 'src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po @@ -9131,7 +9161,6 @@ src/processor/minidump_stackwalk_machine_readable_test.log: src/processor/minidu @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) - distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am @@ -9427,12 +9456,14 @@ distclean: distclean-am -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest_utils.Po + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/pe_file.Po -rm -f src/common/$(DEPDIR)/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po -rm -f src/common/$(DEPDIR)/convert_UTF.Po -rm -f src/common/$(DEPDIR)/dumper_unittest-byte_cursor_unittest.Po @@ -9770,12 +9801,14 @@ maintainer-clean: maintainer-clean-am -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-minidump_writer_unittest_utils.Po + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-pe_file.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po -rm -f src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/pe_file.Po -rm -f src/common/$(DEPDIR)/client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po -rm -f src/common/$(DEPDIR)/convert_UTF.Po -rm -f src/common/$(DEPDIR)/dumper_unittest-byte_cursor_unittest.Po diff --git a/aclocal.m4 b/aclocal.m4 index be219b42..009cc48e 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.16.3 -*- Autoconf -*- +# generated automatically by aclocal 1.16.5 -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,13 +14,13 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, -[m4_warning([this file was generated for autoconf 2.69. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, +[m4_warning([this file was generated for autoconf 2.71. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# Copyright (C) 2002-2020 Free Software Foundation, Inc. +# Copyright (C) 2002-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -35,7 +35,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.16.3], [], +m4_if([$1], [1.16.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -51,12 +51,12 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.16.3])dnl +[AM_AUTOMAKE_VERSION([1.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) -# Copyright (C) 2011-2020 Free Software Foundation, Inc. +# Copyright (C) 2011-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -118,7 +118,7 @@ AC_SUBST([AR])dnl # Figure out how to run the assembler. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -138,7 +138,7 @@ _AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -190,7 +190,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -221,7 +221,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -412,7 +412,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -480,7 +480,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -508,6 +508,10 @@ m4_defn([AC_PROG_CC]) # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl +m4_ifdef([_$0_ALREADY_INIT], + [m4_fatal([$0 expanded multiple times +]m4_defn([_$0_ALREADY_INIT]))], + [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl @@ -544,7 +548,7 @@ m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( - m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl @@ -596,6 +600,20 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) +# Variables for tags utilities; see am/tags.am +if test -z "$CTAGS"; then + CTAGS=ctags +fi +AC_SUBST([CTAGS]) +if test -z "$ETAGS"; then + ETAGS=etags +fi +AC_SUBST([ETAGS]) +if test -z "$CSCOPE"; then + CSCOPE=cscope +fi +AC_SUBST([CSCOPE]) + AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This @@ -677,7 +695,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -698,7 +716,7 @@ if test x"${install_sh+set}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2020 Free Software Foundation, Inc. +# Copyright (C) 2003-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -720,7 +738,7 @@ AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -755,7 +773,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -798,7 +816,7 @@ AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2020 Free Software Foundation, Inc. +# Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -834,7 +852,7 @@ fi # Obsolete and "removed" macros, that must however still report explicit # error messages when used, to smooth transition. # -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -861,7 +879,7 @@ AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -890,7 +908,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2020 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -937,7 +955,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -956,7 +974,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2020 Free Software Foundation, Inc. +# Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1037,7 +1055,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2020 Free Software Foundation, Inc. +# Copyright (C) 2009-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1097,7 +1115,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2020 Free Software Foundation, Inc. +# Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1125,7 +1143,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2020 Free Software Foundation, Inc. +# Copyright (C) 2006-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1144,7 +1162,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2020 Free Software Foundation, Inc. +# Copyright (C) 2004-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index 72a92166..7ce9ac57 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -71,6 +71,8 @@ #include "client/linux/minidump_writer/line_reader.h" #include "client/linux/minidump_writer/linux_dumper.h" #include "client/linux/minidump_writer/linux_ptrace_dumper.h" +#include "client/linux/minidump_writer/pe_file.h" +#include "client/linux/minidump_writer/pe_structs.h" #include "client/linux/minidump_writer/proc_cpuinfo_reader.h" #include "client/minidump_file_writer.h" #include "common/linux/file_id.h" @@ -95,8 +97,11 @@ using google_breakpad::MappingInfo; using google_breakpad::MappingList; using google_breakpad::MinidumpFileWriter; using google_breakpad::PageAllocator; +using google_breakpad::PEFile; +using google_breakpad::PEFileFormat; using google_breakpad::ProcCpuInfoReader; using google_breakpad::RawContextCPU; +using google_breakpad::RSDS_DEBUG_FORMAT; using google_breakpad::ThreadInfo; using google_breakpad::TypedMDRVA; using google_breakpad::UContextReader; @@ -632,40 +637,88 @@ class MinidumpWriter { mod->base_of_image = mapping.start_addr; mod->size_of_image = mapping.size; - auto_wasteful_vector identifier_bytes( - dumper_->allocator()); + char file_name[NAME_MAX]; + char file_path[NAME_MAX]; - if (identifier) { - // GUID was provided by caller. - identifier_bytes.insert(identifier_bytes.end(), - identifier, - identifier + sizeof(MDGUID)); + dumper_->GetMappingEffectiveNameAndPath(mapping, file_path, + sizeof(file_path), file_name, + sizeof(file_name)); + + RSDS_DEBUG_FORMAT rsds; + PEFileFormat file_format = PEFile::TryGetDebugInfo(file_path, &rsds); + + if (file_format == PEFileFormat::notPeCoff) { + // The module is not a PE/COFF file, process as an ELF. + auto_wasteful_vector identifier_bytes( + dumper_->allocator()); + + if (identifier) { + // GUID was provided by caller. + identifier_bytes.insert(identifier_bytes.end(), identifier, + identifier + sizeof(MDGUID)); + } else { + // Note: ElfFileIdentifierForMapping() can manipulate the + // |mapping.name|, that is why we need to call the method + // GetMappingEffectiveNameAndPath again. + dumper_->ElfFileIdentifierForMapping(mapping, member, mapping_id, + identifier_bytes); + dumper_->GetMappingEffectiveNameAndPath(mapping, file_path, + sizeof(file_path), file_name, + sizeof(file_name)); + } + + if (!identifier_bytes.empty()) { + UntypedMDRVA cv(&minidump_writer_); + if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size())) + return false; + + const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE; + cv.Copy(&cv_signature, sizeof(cv_signature)); + cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0], + identifier_bytes.size()); + + mod->cv_record = cv.location(); + } } else { - // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|. - dumper_->ElfFileIdentifierForMapping(mapping, - member, - mapping_id, - identifier_bytes); - } - - if (!identifier_bytes.empty()) { - UntypedMDRVA cv(&minidump_writer_); - if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size())) + // The module is a PE/COFF file. Create MDCVInfoPDB70 struct for it. + size_t file_name_length = strlen(file_name); + TypedMDRVA cv(&minidump_writer_); + if (!cv.AllocateObjectAndArray(file_name_length + 1, sizeof(uint8_t))) return false; - - const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE; - cv.Copy(&cv_signature, sizeof(cv_signature)); - cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0], - identifier_bytes.size()); + if (!cv.CopyIndexAfterObject(0, file_name, file_name_length)) + return false; + MDCVInfoPDB70* cv_ptr = cv.get(); + cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; + if (file_format == PEFileFormat::peWithBuildId) { + // Populate BuildId and age using RSDS instance. + cv_ptr->signature.data1 = static_cast(rsds.guid[0]) << 24 | + static_cast(rsds.guid[1]) << 16 | + static_cast(rsds.guid[2]) << 8 | + static_cast(rsds.guid[3]); + cv_ptr->signature.data2 = + static_cast(rsds.guid[4]) << 8 | rsds.guid[5]; + cv_ptr->signature.data3 = + static_cast(rsds.guid[6]) << 8 | rsds.guid[7]; + cv_ptr->signature.data4[0] = rsds.guid[8]; + cv_ptr->signature.data4[1] = rsds.guid[9]; + cv_ptr->signature.data4[2] = rsds.guid[10]; + cv_ptr->signature.data4[3] = rsds.guid[11]; + cv_ptr->signature.data4[4] = rsds.guid[12]; + cv_ptr->signature.data4[5] = rsds.guid[13]; + cv_ptr->signature.data4[6] = rsds.guid[14]; + cv_ptr->signature.data4[7] = rsds.guid[15]; + // The Age field should be reverted as well. + cv_ptr->age = static_cast(rsds.age[0]) << 24 | + static_cast(rsds.age[1]) << 16 | + static_cast(rsds.age[2]) << 8 | + static_cast(rsds.age[3]); + } else { + cv_ptr->age = 0; + } mod->cv_record = cv.location(); } - char file_name[NAME_MAX]; - char file_path[NAME_MAX]; - dumper_->GetMappingEffectiveNameAndPath( - mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); - MDLocationDescriptor ld; if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) return false; diff --git a/src/client/linux/minidump_writer/pe_file.cc b/src/client/linux/minidump_writer/pe_file.cc new file mode 100644 index 00000000..4a8f1936 --- /dev/null +++ b/src/client/linux/minidump_writer/pe_file.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2022, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "client/linux/minidump_writer/pe_file.h" +#include "client/linux/minidump_writer/pe_structs.h" +#include "common/linux/memory_mapped_file.h" + +namespace google_breakpad { + +PEFileFormat PEFile::TryGetDebugInfo(const char* filename, + PRSDS_DEBUG_FORMAT debug_info) { + MemoryMappedFile mapped_file(filename, 0); + if (!mapped_file.data()) + return PEFileFormat::notPeCoff; + const void* base = mapped_file.data(); + const size_t file_size = mapped_file.size(); + + const IMAGE_DOS_HEADER* header = + TryReadStruct(base, 0, file_size); + if (!header || (header->e_magic != IMAGE_DOS_SIGNATURE)) { + return PEFileFormat::notPeCoff; + } + + // NTHeader is at position 'e_lfanew'. + DWORD nt_header_offset = header->e_lfanew; + // First, read a common IMAGE_NT_HEADERS structure. It should contain a + // special flag marking whether PE module is x64 (OptionalHeader.Magic) + // and so-called NT_SIGNATURE in Signature field. + const IMAGE_NT_HEADERS* nt_header = + TryReadStruct(base, nt_header_offset, file_size); + if (!nt_header || (nt_header->Signature != IMAGE_NT_SIGNATURE) + || ((nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) + && (nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC))) + return PEFileFormat::notPeCoff; + + bool x64 = nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC; + WORD sections_number = nt_header->FileHeader.NumberOfSections; + DWORD debug_offset; + DWORD debug_size; + DWORD section_offset; + if (x64) { + const IMAGE_NT_HEADERS64* header_64 = + TryReadStruct(base, nt_header_offset, file_size); + if (!header_64) + return PEFileFormat::peWithoutBuildId; + debug_offset = + header_64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] + .VirtualAddress; + debug_size = + header_64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] + .Size; + section_offset = nt_header_offset + sizeof(IMAGE_NT_HEADERS64); + } else { + const IMAGE_NT_HEADERS32* header_32 = + TryReadStruct(base, nt_header_offset, file_size); + if (!header_32) + return PEFileFormat::peWithoutBuildId; + debug_offset = + header_32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] + .VirtualAddress; + debug_size = + header_32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] + .Size; + section_offset = nt_header_offset + sizeof(IMAGE_NT_HEADERS32); + } + + DWORD debug_end_pos = debug_offset + debug_size; + while (debug_offset < debug_end_pos) { + for (WORD i = 0; i < sections_number; ++i) { + // Section headers are placed sequentially after the NT_HEADER (32/64). + const IMAGE_SECTION_HEADER* section = + TryReadStruct(base, section_offset, file_size); + if (!section) + return PEFileFormat::peWithoutBuildId; + + section_offset += sizeof(IMAGE_SECTION_HEADER); + + // Current `debug_offset` should be inside a section, stop if we find + // a suitable one (we don't consider any malformed sections here). + if ((section->VirtualAddress <= debug_offset) && + (debug_offset < section->VirtualAddress + section->SizeOfRawData)) { + DWORD offset = + section->PointerToRawData + debug_offset - section->VirtualAddress; + // Go to the position of current ImageDebugDirectory (offset). + const IMAGE_DEBUG_DIRECTORY* debug_directory = + TryReadStruct(base, offset, file_size); + if (!debug_directory) + return PEFileFormat::peWithoutBuildId; + // Process ImageDebugDirectory with CodeViewRecord type and skip + // all others. + if (debug_directory->Type == IMAGE_DEBUG_TYPE_CODEVIEW) { + DWORD debug_directory_size = debug_directory->SizeOfData; + if (debug_directory_size < sizeof(RSDS_DEBUG_FORMAT)) + // RSDS section is malformed. + return PEFileFormat::peWithoutBuildId; + // Go to the position of current ImageDebugDirectory Raw Data + // (debug_directory->PointerToRawData) and read the RSDS section. + const RSDS_DEBUG_FORMAT* rsds = + TryReadStruct( + base, debug_directory->PointerToRawData, file_size); + + if (!rsds) + return PEFileFormat::peWithoutBuildId; + + memcpy(debug_info->guid, rsds->guid, sizeof(rsds->guid)); + memcpy(debug_info->age, rsds->age, sizeof(rsds->age)); + return PEFileFormat::peWithBuildId; + } + + break; + } + } + + debug_offset += sizeof(IMAGE_DEBUG_DIRECTORY); + } + + return PEFileFormat::peWithoutBuildId; +} + +} // namespace google_breakpad \ No newline at end of file diff --git a/src/client/linux/minidump_writer/pe_file.h b/src/client/linux/minidump_writer/pe_file.h new file mode 100644 index 00000000..cc7ed080 --- /dev/null +++ b/src/client/linux/minidump_writer/pe_file.h @@ -0,0 +1,77 @@ +// Copyright (c) 2022, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_ + +#include "client/linux/minidump_writer/pe_structs.h" + +namespace google_breakpad { + +typedef enum { + notPeCoff = 0, + peWithoutBuildId = 1, + peWithBuildId = 2 +} PEFileFormat; + +class PEFile { + public: + /** + * Attempts to parse RSDS_DEBUG_FORMAT record from a PE (Portable + * Executable) file. To do this we check whether the loaded file is a PE + * file, and if it is - try to find IMAGE_DEBUG_DIRECTORY structure with + * its type set to IMAGE_DEBUG_TYPE_CODEVIEW. + * + * @param filename Filename for the module to parse. + * @param debug_info RSDS_DEBUG_FORMAT struct to be populated with PE debug + * info (GUID and age). + * @return + * notPeCoff: not PE/COFF file; + * peWithoutBuildId: a PE/COFF file but build-id is not set; + * peWithBuildId: a PE/COFF file and build-id is set. + */ + static PEFileFormat TryGetDebugInfo(const char* filename, + PRSDS_DEBUG_FORMAT debug_info); + + private: + template + static const TStruct* TryReadStruct(const void* base, + const DWORD position, + const size_t file_size) { + if (position + sizeof(TStruct) >= file_size){ + return nullptr; + } + + const void* ptr = static_cast(base) + position; + return reinterpret_cast(ptr); + } +}; + +} // namespace google_breakpad +#endif // CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_ \ No newline at end of file diff --git a/src/client/linux/minidump_writer/pe_structs.h b/src/client/linux/minidump_writer/pe_structs.h new file mode 100644 index 00000000..843bd517 --- /dev/null +++ b/src/client/linux/minidump_writer/pe_structs.h @@ -0,0 +1,226 @@ +// Copyright (c) 2022, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_ + +#include + +namespace google_breakpad { + +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef uint64_t ULONGLONG; + +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + WORD e_magic; // Magic number + WORD e_cblp; // Bytes on last page of file + WORD e_cp; // Pages in file + WORD e_crlc; // Relocations + WORD e_cparhdr; // Size of header in paragraphs + WORD e_minalloc; // Minimum extra paragraphs needed + WORD e_maxalloc; // Maximum extra paragraphs needed + WORD e_ss; // Initial (relative) SS value + WORD e_sp; // Initial SP value + WORD e_csum; // Checksum + WORD e_ip; // Initial IP value + WORD e_cs; // Initial (relative) CS value + WORD e_lfarlc; // File address of relocation table + WORD e_ovno; // Overlay number + WORD e_res[4]; // Reserved words + WORD e_oemid; // OEM identifier (for e_oeminfo) + WORD e_oeminfo; // OEM information; e_oemid specific + WORD e_res2[10]; // Reserved words + DWORD e_lfanew; // File address of new exe header +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + + +typedef struct _IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD PointerToRawData; +} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY; + +typedef struct _IMAGE_OPTIONAL_HEADER64 { + // + // Standard fields - Magic. + // + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + // + // NT additional fields. + // + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + // + // NT additional fields. + // + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; + +typedef struct _IMAGE_NT_HEADERS32 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +typedef struct _RSDS_DEBUG_FORMAT { + DWORD signature; + BYTE guid[16]; + BYTE age[4]; + char pdbpath[1]; +} RSDS_DEBUG_FORMAT, *PRSDS_DEBUG_FORMAT; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_ \ No newline at end of file