diff --git a/DEPS b/DEPS index e08dbd4ca..3fcd524dc 100644 --- a/DEPS +++ b/DEPS @@ -52,7 +52,7 @@ deps = { hooks = [ { # Keep the manifest up to date. - "action": ["python", "src/src/tools/python/deps-to-manifest.py", + "action": ["src/src/tools/python/deps-to-manifest.py", "src/DEPS", "src/default.xml"], }, ] diff --git a/Makefile.am b/Makefile.am index 58e414831..06f34ce84 100644 --- a/Makefile.am +++ b/Makefile.am @@ -694,9 +694,11 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \ src/common/linux/safe_readlink.cc \ src/tools/linux/dump_syms/dump_syms.cc src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \ - $(RUSTC_DEMANGLE_CFLAGS) + $(RUSTC_DEMANGLE_CFLAGS) \ + $(ZSTD_CFLAGS) src_tools_linux_dump_syms_dump_syms_LDADD = \ $(RUSTC_DEMANGLE_LIBS) \ + $(ZSTD_CFLAGS) \ -lz src_tools_linux_md2core_minidump_2_core_SOURCES = \ @@ -821,11 +823,13 @@ src_common_dumper_unittest_SOURCES = \ src_common_dumper_unittest_CPPFLAGS = \ $(AM_CPPFLAGS) $(TEST_CFLAGS) \ $(RUSTC_DEMANGLE_CFLAGS) \ - $(PTHREAD_CFLAGS) + $(PTHREAD_CFLAGS) \ + $(ZSTD_CFLAGS) src_common_dumper_unittest_LDADD = \ $(TEST_LIBS) \ $(RUSTC_DEMANGLE_LIBS) \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + $(ZSTD_LIBS) \ -lz src_common_mac_macho_reader_unittest_SOURCES = \ diff --git a/Makefile.in b/Makefile.in index 184563836..0c47bf87d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2185,12 +2185,10 @@ DEPDIR = @DEPDIR@ 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@ -GREP = @GREP@ GTEST_CFLAGS = @GTEST_CFLAGS@ GTEST_LIBS = @GTEST_LIBS@ HAVE_CXX17 = @HAVE_CXX17@ @@ -2697,7 +2695,7 @@ src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \ src_tools_linux_dump_syms_dump_syms_LDADD = \ $(RUSTC_DEMANGLE_LIBS) \ - -lz + -lz -lzstd src_tools_linux_md2core_minidump_2_core_SOURCES = \ src/common/linux/memory_mapped_file.cc \ @@ -2830,7 +2828,7 @@ src_common_dumper_unittest_LDADD = \ $(TEST_LIBS) \ $(RUSTC_DEMANGLE_LIBS) \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ - -lz + -lz -lzstd src_common_mac_macho_reader_unittest_SOURCES = \ src/common/dwarf_cfi_to_module.cc \ diff --git a/aclocal.m4 b/aclocal.m4 index 009cc48ed..31be0bad8 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -848,35 +848,6 @@ else fi ]) -# -*- Autoconf -*- -# Obsolete and "removed" macros, that must however still report explicit -# error messages when used, to smooth transition. -# -# 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, -# with or without modifications, as long as this notice is preserved. - -AC_DEFUN([AM_CONFIG_HEADER], -[AC_DIAGNOSE([obsolete], -['$0': this macro is obsolete. -You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl -AC_CONFIG_HEADERS($@)]) - -AC_DEFUN([AM_PROG_CC_STDC], -[AC_PROG_CC -am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc -AC_DIAGNOSE([obsolete], -['$0': this macro is obsolete. -You should simply use the 'AC][_PROG_CC' macro instead. -Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', -but upon 'ac_cv_prog_cc_stdc'.])]) - -AC_DEFUN([AM_C_PROTOTYPES], - [AC_FATAL([automatic de-ANSI-fication support has been removed])]) -AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) - # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. diff --git a/configure b/configure index 76d4a9f61..3442e7969 100755 --- a/configure +++ b/configure @@ -182,8 +182,7 @@ test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes @@ -685,8 +684,6 @@ PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC ax_pthread_config -EGREP -GREP RANLIB am__fastdepCXX_FALSE am__fastdepCXX_TRUE @@ -813,6 +810,7 @@ enable_system_test_libs enable_selftest with_rustc_demangle enable_system_rustc_demangle +enable_zstd with_tests_as_root ' ac_precious_vars='build_alias @@ -1486,6 +1484,7 @@ Optional Features: is no). This assumes that rustc-demangle is installed in your sysroot, and all headers from it are available in your standard include path + --enable-zstd Enable decompression of ELF sections with zstd Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1719,39 +1718,6 @@ fi } # ac_fn_cxx_try_compile -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else $as_nop - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. @@ -1799,6 +1765,39 @@ fi } # ac_fn_c_try_link +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +printf %s "checking for $2... " >&6; } +if eval test \${$3+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + eval "$3=yes" +else $as_nop + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +eval ac_res=\$$3 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf "%s\n" "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly @@ -6597,11 +6596,11 @@ if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_11+y} +if test ${ac_cv_prog_cxx_cxx11+y} then : printf %s "(cached) " >&6 else $as_nop - ac_cv_prog_cxx_11=no + ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6643,11 +6642,11 @@ if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_98+y} +if test ${ac_cv_prog_cxx_cxx98+y} then : printf %s "(cached) " >&6 else $as_nop - ac_cv_prog_cxx_98=no + ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6937,180 +6936,6 @@ if test "x$enable_m32" = xyes; then CXXFLAGS="${CXXFLAGS} -m32" fi -# Autoupdate added the next two lines to ensure that your configure -# script's behavior did not change. They are probably safe to remove. -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf "%s\n" "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf "%s\n" 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf "%s\n" "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf "%s\n" 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf "%s\n" "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - - # Check whether --enable-largefile was given. if test ${enable_largefile+y} then : @@ -7678,6 +7503,35 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu +ac_header= ac_cache= +for ac_item in $ac_header_c_list +do + if test $ac_cache; then + ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" + if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then + printf "%s\n" "#define $ac_item 1" >> confdefs.h + fi + ac_header= ac_cache= + elif test $ac_header; then + ac_cache=$ac_item + else + ac_header=$ac_item + fi +done + + + + + + + + +if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes +then : + +printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + +fi ac_fn_c_check_header_compile "$LINENO" "a.out.h" "ac_cv_header_a_out_h" "$ac_includes_default" if test "x$ac_cv_header_a_out_h" = xyes then : @@ -10652,6 +10506,70 @@ fi +# Check whether --enable-zstd was given. +if test ${enable_zstd+y} +then : + enableval=$enable_zstd; +else $as_nop + enable_zstd=no +fi + +if test "x${enable_zstd}" != xno; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ZSTD_decompress in -lzstd" >&5 +printf %s "checking for ZSTD_decompress in -lzstd... " >&6; } +if test ${ac_cv_lib_zstd_ZSTD_decompress+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lzstd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +char ZSTD_decompress (); +int +main (void) +{ +return ZSTD_decompress (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_zstd_ZSTD_decompress=yes +else $as_nop + ac_cv_lib_zstd_ZSTD_decompress=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_zstd_ZSTD_decompress" >&5 +printf "%s\n" "$ac_cv_lib_zstd_ZSTD_decompress" >&6; } +if test "x$ac_cv_lib_zstd_ZSTD_decompress" = xyes +then : + printf "%s\n" "#define HAVE_LIBZSTD 1" >>confdefs.h + + LIBS="-lzstd $LIBS" + +else $as_nop + as_fn_error $? "zstd library not found." "$LINENO" 5 +fi + + ac_fn_c_check_header_compile "$LINENO" "zstd.h" "ac_cv_header_zstd_h" "$ac_includes_default" +if test "x$ac_cv_header_zstd_h" = xyes +then : + +else $as_nop + as_fn_error $? "zstd header not found." "$LINENO" 5 +fi + +fi + # Check whether --with-tests-as-root was given. if test ${with_tests_as_root+y} @@ -10767,6 +10685,7 @@ DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' diff --git a/configure.ac b/configure.ac index ca2936695..bfee372a3 100644 --- a/configure.ac +++ b/configure.ac @@ -37,7 +37,7 @@ AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_HOST AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.13) -AM_CONFIG_HEADER(src/config.h) +AC_CONFIG_HEADERS(src/config.h) AM_MAINTAINER_MODE AM_PROG_AR @@ -59,15 +59,6 @@ if test "x$enable_m32" = xyes; then CXXFLAGS="${CXXFLAGS} -m32" fi -m4_warn([obsolete], -[The preprocessor macro `STDC_HEADERS' is obsolete. - Except in unusual embedded environments, you can safely include all - ISO C90 headers unconditionally.])dnl -# Autoupdate added the next two lines to ensure that your configure -# script's behavior did not change. They are probably safe to remove. -AC_CHECK_INCLUDES_DEFAULT -AC_PROG_EGREP - AC_SYS_LARGEFILE AX_PTHREAD AC_CHECK_HEADERS([a.out.h sys/mman.h sys/random.h]) @@ -221,6 +212,17 @@ fi AC_ARG_VAR([RUSTC_DEMANGLE_CFLAGS], [Compiler flags for rustc-demangle]) AC_ARG_VAR([RUSTC_DEMANGLE_LIBS], [Linker flags for rustc-demangle]) +AC_ARG_ENABLE(zstd, + AS_HELP_STRING([--enable-zstd], + [Enable decompression of ELF sections with zstd]),, + [enable_zstd=no]) +if test "x${enable_zstd}" != xno; then + AC_CHECK_LIB(zstd, ZSTD_decompress, [], + [AC_MSG_ERROR([zstd library not found.])]) + AC_CHECK_HEADER(zstd.h, [], + [AC_MSG_ERROR([zstd header not found.])]) +fi + AC_ARG_WITH(tests-as-root, AS_HELP_STRING([--with-tests-as-root], [Run the tests as root. Use this on platforms] diff --git a/src/client/linux/crash_generation/crash_generation_client.cc b/src/client/linux/crash_generation/crash_generation_client.cc index f06273d58..020c61466 100644 --- a/src/client/linux/crash_generation/crash_generation_client.cc +++ b/src/client/linux/crash_generation/crash_generation_client.cc @@ -49,9 +49,11 @@ namespace { class CrashGenerationClientImpl : public CrashGenerationClient { public: explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {} - virtual ~CrashGenerationClientImpl() {} + CrashGenerationClientImpl(const CrashGenerationClientImpl&) = delete; + void operator=(const CrashGenerationClientImpl&) = delete; + ~CrashGenerationClientImpl() override = default; - virtual bool RequestDump(const void* blob, size_t blob_size) { + bool RequestDump(const void* blob, size_t blob_size) override { int fds[2]; if (sys_pipe(fds) < 0) return false; @@ -92,8 +94,6 @@ class CrashGenerationClientImpl : public CrashGenerationClient { private: int server_fd_; - - DISALLOW_COPY_AND_ASSIGN(CrashGenerationClientImpl); }; } // namespace diff --git a/src/client/linux/crash_generation/crash_generation_client.h b/src/client/linux/crash_generation/crash_generation_client.h index 915b5700f..1e4a7a5e5 100644 --- a/src/client/linux/crash_generation/crash_generation_client.h +++ b/src/client/linux/crash_generation/crash_generation_client.h @@ -29,8 +29,6 @@ #ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ #define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ -#include "common/basictypes.h" - #include namespace google_breakpad { @@ -41,8 +39,10 @@ namespace google_breakpad { // via a remote process. class CrashGenerationClient { public: - CrashGenerationClient() {} - virtual ~CrashGenerationClient() {} + CrashGenerationClient() = default; + CrashGenerationClient(const CrashGenerationClient&) = delete; + void operator=(const CrashGenerationClient&) = delete; + virtual ~CrashGenerationClient() = default; // Request the crash server to generate a dump. |blob| is an opaque // CrashContext pointer from exception_handler.h. @@ -54,9 +54,6 @@ class CrashGenerationClient { // The returned CrashGenerationClient* is owned by the caller of // this function. static CrashGenerationClient* TryCreate(int server_fd); - - private: - DISALLOW_COPY_AND_ASSIGN(CrashGenerationClient); }; } // namespace google_breakpad diff --git a/src/client/linux/dump_writer_common/thread_info.cc b/src/client/linux/dump_writer_common/thread_info.cc index fc82c0c62..6288a056e 100644 --- a/src/client/linux/dump_writer_common/thread_info.cc +++ b/src/client/linux/dump_writer_common/thread_info.cc @@ -322,23 +322,19 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const { out->t5 = mcontext.__gregs[30]; out->t6 = mcontext.__gregs[31]; -# if __riscv_flen == 32 - for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) - out->float_save.regs[i] = mcontext.__fpregs.__f.__f[i]; - out->float_save.fpcsr = mcontext.__fpregs.__f.__fcsr; -# elif __riscv_flen == 64 - for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) - out->float_save.regs[i] = mcontext.__fpregs.__d.__f[i]; - out->float_save.fpcsr = mcontext.__fpregs.__d.__fcsr; -# elif __riscv_flen == 128 - for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) { - out->float_save.regs[i].high = mcontext.__fpregs.__q.__f[2*i]; - out->float_save.regs[i].low = mcontext.__fpregs.__q.__f[2*i+1]; - } - out->float_save.fpcsr = mcontext.__fpregs.__q.__fcsr; -# else -# error "Unexpected __riscv_flen" -# endif + // Breakpad only supports RISCV32 with 32 bit floating point. + // Breakpad only supports RISCV64 with 64 bit floating point. +#if __riscv_xlen == 32 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) + out->fpregs[i] = mcontext.__fpregs.__f.__f[i]; + out->fcsr = mcontext.__fpregs.__f.__fcsr; +#elif __riscv_xlen == 64 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) + out->fpregs[i] = mcontext.__fpregs.__d.__f[i]; + out->fcsr = mcontext.__fpregs.__d.__fcsr; +#else +#error "Unexpected __riscv_xlen" +#endif } #endif // __riscv diff --git a/src/client/linux/dump_writer_common/ucontext_reader.cc b/src/client/linux/dump_writer_common/ucontext_reader.cc index c6a8e9aad..764976835 100644 --- a/src/client/linux/dump_writer_common/ucontext_reader.cc +++ b/src/client/linux/dump_writer_common/ucontext_reader.cc @@ -310,21 +310,19 @@ void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) { out->t5 = uc->uc_mcontext.__gregs[30]; out->t6 = uc->uc_mcontext.__gregs[31]; -# if __riscv_flen == 32 - for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) - out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__f.__f[i]; - out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__f.__fcsr; -# elif __riscv_flen == 64 - for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) - out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__d.__f[i]; - out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__d.__fcsr; -# elif __riscv_flen == 128 - for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) { - out->float_save.regs[i].high = uc->uc_mcontext.__fpregs.__q.__f[2*i]; - out->float_save.regs[i].low = uc->uc_mcontext.__fpregs.__q.__f[2*i+1]; - } - out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__q.__fcsr; -# endif + // Breakpad only supports RISCV32 with 32 bit floating point. + // Breakpad only supports RISCV64 with 64 bit floating point. +#if __riscv_xlen == 32 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) + out->fpregs[i] = uc->uc_mcontext.__fpregs.__f.__f[i]; + out->fcsr = uc->uc_mcontext.__fpregs.__f.__fcsr; +#elif __riscv_xlen == 64 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) + out->fpregs[i] = uc->uc_mcontext.__fpregs.__d.__f[i]; + out->fcsr = uc->uc_mcontext.__fpregs.__d.__fcsr; +#else +#error "Unexpected __riscv_xlen" +#endif } #endif diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc index 85922a9c4..5c4c389c3 100644 --- a/src/client/linux/minidump_writer/linux_dumper.cc +++ b/src/client/linux/minidump_writer/linux_dumper.cc @@ -346,7 +346,7 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, return false; bool filename_modified = HandleDeletedFileInMapping(filename); - MemoryMappedFile mapped_file(filename, mapping.offset); + MemoryMappedFile mapped_file(filename, 0); if (!mapped_file.data() || mapped_file.size() < SELFMAG) return false; @@ -459,7 +459,7 @@ bool ElfFileSoName(const LinuxDumper& dumper, if (!dumper.GetMappingAbsolutePath(mapping, filename)) return false; - MemoryMappedFile mapped_file(filename, mapping.offset); + MemoryMappedFile mapped_file(filename, 0); if (!mapped_file.data() || mapped_file.size() < SELFMAG) { // mmap failed return false; diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc index 0e58236b6..2adc39e12 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc @@ -179,6 +179,13 @@ bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) { return false; } + // When running on arm processors the binary may be built with softfp or + // hardfp. If built with softfp we have no hardware registers to read from, + // so the following read will always fail. gcc defines __SOFTFP__ macro, + // clang13 does not do so. see: https://reviews.llvm.org/D135680. + // If you are using clang and the macro is NOT defined, please include the + // macro define for applicable targets. +#if !defined(__SOFTFP__) #if !(defined(__ANDROID__) && defined(__ARM_EABI__)) // When running an arm build on an arm64 device, attempting to get the // floating point registers fails. On Android, the floating point registers @@ -190,6 +197,7 @@ bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) { return false; } #endif // !(defined(__ANDROID__) && defined(__ARM_EABI__)) +#endif // !defined(__SOFTFP__) return true; #else // PTRACE_GETREGS return false; diff --git a/src/common/basictypes.h b/src/common/basictypes.h index 6458a8932..79c9b7756 100644 --- a/src/common/basictypes.h +++ b/src/common/basictypes.h @@ -29,14 +29,6 @@ #ifndef COMMON_BASICTYPES_H_ #define COMMON_BASICTYPES_H_ -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#endif // DISALLOW_COPY_AND_ASSIGN - namespace google_breakpad { // Used to explicitly mark the return value of a function as unused. If you are diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h index 777d9bfca..f1c995f92 100644 --- a/src/common/dwarf/dwarf2enums.h +++ b/src/common/dwarf/dwarf2enums.h @@ -580,10 +580,10 @@ enum DwarfSectionId { DW_SECT_TYPES = 2, DW_SECT_ABBREV = 3, DW_SECT_LINE = 4, - DW_SECT_LOC = 5, + DW_SECT_LOCLISTS = 5, DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACINFO = 7, - DW_SECT_MACRO = 8 + DW_SECT_MACRO = 7, + DW_SECT_RNGLISTS = 8 }; // Source languages. These are values for DW_AT_language. diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index 65cb8e7d7..8a8bf6f86 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -80,9 +80,10 @@ CompilationUnit::CompilationUnit(const string& path, str_offsets_buffer_(NULL), str_offsets_buffer_length_(0), addr_buffer_(NULL), addr_buffer_length_(0), is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(), - skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), - str_offsets_base_(0), have_checked_for_dwp_(false), dwp_path_(), - dwp_byte_reader_(), dwp_reader_() {} + skeleton_dwo_id_(0), addr_base_(0), + str_offsets_base_(0), have_checked_for_dwp_(false), + should_process_split_dwarf_(false), low_pc_(0), + has_source_line_info_(false), source_line_offset_(0) {} // Initialize a compilation unit from a .dwo or .dwp file. // In this case, we need the .debug_addr section from the @@ -91,16 +92,10 @@ CompilationUnit::CompilationUnit(const string& path, // the executable file, and call it as if we were still // processing the original compilation unit. -void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer, - uint64_t addr_buffer_length, - uint64_t addr_base, - uint64_t ranges_base, +void CompilationUnit::SetSplitDwarf(uint64_t addr_base, uint64_t dwo_id) { is_split_dwarf_ = true; - addr_buffer_ = addr_buffer; - addr_buffer_length_ = addr_buffer_length; addr_base_ = addr_base; - ranges_base_ = ranges_base; skeleton_dwo_id_ = dwo_id; } @@ -400,7 +395,13 @@ uint64_t CompilationUnit::Start() { // Set up our buffer buffer_ = iter->second.first + offset_from_section_start_; - buffer_length_ = iter->second.second - offset_from_section_start_; + if (is_split_dwarf_) { + iter = GetSectionByName(sections_, ".debug_info_offset"); + assert(iter != sections_.end()); + buffer_length_ = iter->second.second; + } else { + buffer_length_ = iter->second.second - offset_from_section_start_; + } // Read the header ReadHeader(); @@ -434,6 +435,12 @@ uint64_t CompilationUnit::Start() { string_buffer_length_ = iter->second.second; } + iter = GetSectionByName(sections_, ".debug_line"); + if (iter != sections_.end()) { + line_buffer_ = iter->second.first; + line_buffer_length_ = iter->second.second; + } + // Set the line string section if we have one. iter = GetSectionByName(sections_, ".debug_line_str"); if (iter != sections_.end()) { @@ -461,10 +468,8 @@ uint64_t CompilationUnit::Start() { // If this is a skeleton compilation unit generated with split DWARF, // and the client needs the full debug info, we need to find the full // compilation unit in a .dwo or .dwp file. - if (!is_split_dwarf_ - && dwo_name_ != NULL - && handler_->NeedSplitDebugInfo()) - ProcessSplitDwarf(); + should_process_split_dwarf_ = + !is_split_dwarf_ && dwo_name_ != NULL && handler_->NeedSplitDebugInfo(); return ourlength; } @@ -885,7 +890,9 @@ const uint8_t* CompilationUnit::ProcessDIE(uint64_t dieoffset, // DW_AT_str_offsets_base or DW_AT_addr_base. If it does, that attribute must // be found and processed before trying to process the other attributes; // otherwise the string or address values will all come out incorrect. - if (abbrev.tag == DW_TAG_compile_unit && header_.version == 5) { + if ((abbrev.tag == DW_TAG_compile_unit || + abbrev.tag == DW_TAG_skeleton_unit) && + header_.version == 5) { uint64_t dieoffset_copy = dieoffset; const uint8_t* start_copy = start; for (AttributeList::const_iterator i = abbrev.attributes.begin(); @@ -994,66 +1001,69 @@ inline int GetElfWidth(const ElfReader& elf) { return 0; } -void CompilationUnit::ProcessSplitDwarf() { +bool CompilationUnit::ProcessSplitDwarf(std::string& split_file, + SectionMap& sections, + ByteReader& split_byte_reader, + uint64_t& cu_offset) { + if (!should_process_split_dwarf_) + return false; struct stat statbuf; + bool found_in_dwp = false; if (!have_checked_for_dwp_) { // Look for a .dwp file in the same directory as the executable. have_checked_for_dwp_ = true; string dwp_suffix(".dwp"); - dwp_path_ = path_ + dwp_suffix; - if (stat(dwp_path_.c_str(), &statbuf) != 0) { + std::string dwp_path = path_ + dwp_suffix; + if (stat(dwp_path.c_str(), &statbuf) != 0) { // Fall back to a split .debug file in the same directory. string debug_suffix(".debug"); - dwp_path_ = path_; + dwp_path = path_; size_t found = path_.rfind(debug_suffix); - if (found + debug_suffix.length() == path_.length()) - dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix); + if (found != string::npos && + found + debug_suffix.length() == path_.length()) + dwp_path = dwp_path.replace(found, debug_suffix.length(), dwp_suffix); } - if (stat(dwp_path_.c_str(), &statbuf) == 0) { - ElfReader* elf = new ElfReader(dwp_path_); - int width = GetElfWidth(*elf); + if (stat(dwp_path.c_str(), &statbuf) == 0) { + split_elf_reader_ = std::make_unique(dwp_path); + int width = GetElfWidth(*split_elf_reader_.get()); if (width != 0) { - dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness())); - dwp_byte_reader_->SetAddressSize(width); - dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf)); + split_byte_reader = ByteReader(reader_->GetEndianness()); + split_byte_reader.SetAddressSize(width); + dwp_reader_ = std::make_unique(split_byte_reader, + split_elf_reader_.get()); dwp_reader_->Initialize(); - } else { - delete elf; + // If we have a .dwp file, read the debug sections for the requested CU. + dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); + if (!sections.empty()) { + SectionMap::const_iterator cu_iter = + GetSectionByName(sections, ".debug_info_offset"); + SectionMap::const_iterator debug_info_iter = + GetSectionByName(sections, ".debug_info"); + assert(cu_iter != sections.end()); + assert(debug_info_iter != sections.end()); + cu_offset = cu_iter->second.first - debug_info_iter->second.first; + found_in_dwp = true; + split_file = dwp_path; + } } } } - bool found_in_dwp = false; - if (dwp_reader_) { - // If we have a .dwp file, read the debug sections for the requested CU. - SectionMap sections; - dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); - if (!sections.empty()) { - found_in_dwp = true; - CompilationUnit dwp_comp_unit(dwp_path_, sections, 0, - dwp_byte_reader_.get(), handler_); - dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_, - ranges_base_, dwo_id_); - dwp_comp_unit.Start(); - } - } if (!found_in_dwp) { // If no .dwp file, try to open the .dwo file. if (stat(dwo_name_, &statbuf) == 0) { - ElfReader elf(dwo_name_); - int width = GetElfWidth(elf); + split_elf_reader_ = std::make_unique(dwo_name_); + int width = GetElfWidth(*split_elf_reader_.get()); if (width != 0) { - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(width); - SectionMap sections; - ReadDebugSectionsFromDwo(&elf, §ions); - CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader, - handler_); - dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, - addr_base_, ranges_base_, dwo_id_); - dwo_comp_unit.Start(); + split_byte_reader = ByteReader(ENDIANNESS_LITTLE); + split_byte_reader.SetAddressSize(width); + ReadDebugSectionsFromDwo(split_elf_reader_.get(), §ions); + if (!sections.empty()) { + split_file = dwo_name_; + } } } } + return !split_file.empty(); } void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, @@ -1088,10 +1098,6 @@ DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader) abbrev_size_(0), info_data_(NULL), info_size_(0), str_offsets_data_(NULL), str_offsets_size_(0) {} -DwpReader::~DwpReader() { - if (elf_reader_) delete elf_reader_; -} - void DwpReader::Initialize() { cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index", &cu_index_size_); @@ -1131,6 +1137,8 @@ void DwpReader::Initialize() { info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_); str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo", &str_offsets_size_); + rnglist_data_ = + elf_reader_->GetSectionByName(".debug_rnglists.dwo", &rnglist_size_); if (size_table_ >= cu_index_ + cu_index_size_) { version_ = 0; } @@ -1231,13 +1239,24 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, } else if (section_id == DW_SECT_INFO) { sections->insert(std::make_pair( ".debug_info", - std::make_pair(reinterpret_cast (info_data_) - + offset, size))); + std::make_pair(reinterpret_cast(info_data_), 0))); + // .debug_info_offset will points the buffer for the CU with given + // dwo_id. + sections->insert(std::make_pair( + ".debug_info_offset", + std::make_pair( + reinterpret_cast(info_data_) + offset, size))); } else if (section_id == DW_SECT_STR_OFFSETS) { sections->insert(std::make_pair( ".debug_str_offsets", std::make_pair(reinterpret_cast (str_offsets_data_) + offset, size))); + } else if (section_id == DW_SECT_RNGLISTS) { + sections->insert(std::make_pair( + ".debug_rnglists", + std::make_pair( + reinterpret_cast(rnglist_data_) + offset, + size))); } } sections->insert(std::make_pair( @@ -1823,6 +1842,11 @@ bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) { return ReadDebugRngList(data); } } else if (form == DW_FORM_rnglistx) { + if (cu_info_->ranges_base_ == 0) { + // In split dwarf, there's no DW_AT_rnglists_base attribute, range_base + // will just be the first byte after the header. + cu_info_->ranges_base_ = reader_->OffsetSize() == 4? 12: 20; + } offset_array_ = cu_info_->ranges_base_; uint64_t index_offset = reader_->OffsetSize() * data; uint64_t range_list_offset = diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index ddcdd8011..b6bd2f31a 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -469,8 +469,7 @@ class CompilationUnit { // compilation unit. We also inherit the Dwarf2Handler from // the executable file, and call it as if we were still // processing the original compilation unit. - void SetSplitDwarf(const uint8_t* addr_buffer, uint64_t addr_buffer_length, - uint64_t addr_base, uint64_t ranges_base, uint64_t dwo_id); + void SetSplitDwarf(uint64_t addr_base, uint64_t dwo_id); // Begin reading a Dwarf2 compilation unit, and calling the // callbacks in the Dwarf2Handler @@ -481,6 +480,36 @@ class CompilationUnit { // start of the next compilation unit, if there is one. uint64_t Start(); + // Process the actual debug information in a split DWARF file. + bool ProcessSplitDwarf(std::string& split_file, + SectionMap& sections, + ByteReader& split_byte_reader, + uint64_t& cu_offset); + + const uint8_t* GetAddrBuffer() { return addr_buffer_; } + + uint64_t GetAddrBufferLen() { return addr_buffer_length_; } + + uint64_t GetAddrBase() { return addr_base_; } + + uint64_t GetLowPC() { return low_pc_; } + + uint64_t GetDWOID() { return dwo_id_; } + + const uint8_t* GetLineBuffer() { return line_buffer_; } + + uint64_t GetLineBufferLen() { return line_buffer_length_; } + + const uint8_t* GetLineStrBuffer() { return line_string_buffer_; } + + uint64_t GetLineStrBufferLen() { return line_string_buffer_length_; } + + bool HasSourceLineInfo() { return has_source_line_info_; } + + uint64_t GetSourceLineOffset() { return source_line_offset_; } + + bool ShouldProcessSplitDwarf() { return should_process_split_dwarf_; } + private: // This struct represents a single DWARF2/3 abbreviation @@ -565,14 +594,12 @@ class CompilationUnit { else if (attr == DW_AT_str_offsets_base) { str_offsets_base_ = data; } - else if (attr == DW_AT_GNU_ranges_base || attr == DW_AT_rnglists_base) { - ranges_base_ = data; + else if (attr == DW_AT_low_pc) { + low_pc_ = data; } - // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, - // that base will apply to DW_AT_ranges attributes in the - // skeleton CU as well as in the .dwo/.dwp files. - else if (attr == DW_AT_ranges && is_split_dwarf_) { - data += ranges_base_; + else if (attr == DW_AT_stmt_list) { + has_source_line_info_ = true; + source_line_offset_ = data; } handler_->ProcessAttributeUnsigned(offset, attr, form, data); } @@ -647,9 +674,6 @@ class CompilationUnit { // new place to position the stream to. const uint8_t* SkipAttribute(const uint8_t* start, enum DwarfForm form); - // Process the actual debug information in a split DWARF file. - void ProcessSplitDwarf(); - // Read the debug sections from a .dwo file. void ReadDebugSectionsFromDwo(ElfReader* elf_reader, SectionMap* sections); @@ -658,7 +682,7 @@ class CompilationUnit { const string path_; // Offset from section start is the offset of this compilation unit - // from the beginning of the .debug_info section. + // from the beginning of the .debug_info/.debug_info.dwo section. uint64_t offset_from_section_start_; // buffer is the buffer for our CU, starting at .debug_info + offset @@ -688,7 +712,7 @@ class CompilationUnit { const uint8_t* string_buffer_; uint64_t string_buffer_length_; - // Similarly for .debug_line_string. + // Similarly for .debug_line_str. const uint8_t* line_string_buffer_; uint64_t line_string_buffer_length_; @@ -702,6 +726,10 @@ class CompilationUnit { const uint8_t* addr_buffer_; uint64_t addr_buffer_length_; + // .debug_line section buffer and length. + const uint8_t* line_buffer_; + uint64_t line_buffer_length_; + // Flag indicating whether this compilation unit is part of a .dwo // or .dwp file. If true, we are reading this unit because a // skeleton compilation unit in an executable file had a @@ -730,10 +758,6 @@ class CompilationUnit { // from the skeleton CU. uint64_t skeleton_dwo_id_; - // The value of the DW_AT_GNU_ranges_base or DW_AT_rnglists_base attribute, - // if any. - uint64_t ranges_base_; - // The value of the DW_AT_GNU_addr_base attribute, if any. uint64_t addr_base_; @@ -743,14 +767,20 @@ class CompilationUnit { // True if we have already looked for a .dwp file. bool have_checked_for_dwp_; - // Path to the .dwp file. - string dwp_path_; - - // ByteReader for the DWP file. - std::unique_ptr dwp_byte_reader_; + // ElfReader for the dwo/dwo file. + std::unique_ptr split_elf_reader_; // DWP reader. - std::unique_ptr dwp_reader_; + std::unique_ptr dwp_reader_; + + bool should_process_split_dwarf_; + + // The value of the DW_AT_low_pc attribute, if any. + uint64_t low_pc_; + + // The value of DW_AT_stmt_list attribute if any. + bool has_source_line_info_; + uint64_t source_line_offset_; }; // A Reader for a .dwp file. Supports the fetching of DWARF debug @@ -770,8 +800,6 @@ class DwpReader { public: DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader); - ~DwpReader(); - // Read the CU index and initialize data members. void Initialize(); @@ -839,6 +867,8 @@ class DwpReader { size_t info_size_; const char* str_offsets_data_; size_t str_offsets_size_; + const char* rnglist_data_; + size_t rnglist_size_; }; // This class is a reader for DWARF's Call Frame Information. CFI diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index 442fa66c1..2b365396d 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -333,7 +333,8 @@ struct DwarfFormsFixture: public DIEFixture { uint64_t offset=0) { ByteReader byte_reader(params.endianness == kLittleEndian ? ENDIANNESS_LITTLE : ENDIANNESS_BIG); - CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler); + CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, + &handler); EXPECT_EQ(offset + parser.Start(), info_contents.size()); } diff --git a/src/common/dwarf_cfi_to_module.cc b/src/common/dwarf_cfi_to_module.cc index 7e04d3c55..4c594175e 100644 --- a/src/common/dwarf_cfi_to_module.cc +++ b/src/common/dwarf_cfi_to_module.cc @@ -149,10 +149,10 @@ vector DwarfCFIToModule::RegisterNames::MIPS() { vector DwarfCFIToModule::RegisterNames::RISCV() { static const char *const names[] = { - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", - "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", - "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", - "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", + "pc", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", diff --git a/src/common/dwarf_cfi_to_module_unittest.cc b/src/common/dwarf_cfi_to_module_unittest.cc index b407edd06..52653ec6e 100644 --- a/src/common/dwarf_cfi_to_module_unittest.cc +++ b/src/common/dwarf_cfi_to_module_unittest.cc @@ -311,8 +311,8 @@ TEST(RegisterNames, X86_64) { TEST(RegisterNames, RISCV) { vector names = DwarfCFIToModule::RegisterNames::RISCV(); - EXPECT_EQ("x0", names[0]); - EXPECT_EQ("x31", names[31]); + EXPECT_EQ("pc", names[0]); + EXPECT_EQ("t6", names[31]); EXPECT_EQ("f0", names[32]); EXPECT_EQ("f31", names[63]); EXPECT_EQ("v0", names[96]); diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index 708ed1431..94a0d428e 100644 --- a/src/common/dwarf_cu_to_module.cc +++ b/src/common/dwarf_cu_to_module.cc @@ -169,19 +169,23 @@ bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference( // parsing. This is for data shared across the CU's entire DIE tree, // and parameters from the code invoking the CU parser. struct DwarfCUToModule::CUContext { - CUContext(FileContext* file_context_arg, WarningReporter* reporter_arg, - RangesHandler* ranges_handler_arg) + CUContext(FileContext* file_context_arg, + WarningReporter* reporter_arg, + RangesHandler* ranges_handler_arg, + uint64_t low_pc, + uint64_t addr_base) : version(0), file_context(file_context_arg), reporter(reporter_arg), ranges_handler(ranges_handler_arg), language(Language::CPlusPlus), - low_pc(0), + low_pc(low_pc), high_pc(0), ranges_form(DW_FORM_sec_offset), ranges_data(0), ranges_base(0), - str_offsets_base(0) { } + addr_base(addr_base), + str_offsets_base(0) {} ~CUContext() { for (vector::iterator it = functions.begin(); @@ -575,6 +579,7 @@ class DwarfCUToModule::InlineHandler : public GenericDIEHandler { ranges_data_(0), call_site_line_(0), inline_nest_level_(inline_nest_level), + has_range_data_(false), inlines_(inlines) {} void ProcessAttributeUnsigned(enum DwarfAttribute attr, @@ -596,6 +601,7 @@ class DwarfCUToModule::InlineHandler : public GenericDIEHandler { int call_site_line_; // DW_AT_call_line int call_site_file_id_; // DW_AT_call_file int inline_nest_level_; + bool has_range_data_; // A vector of inlines in the same nest level. It's owned by its parent // function/inline. At Finish(), add this inline into the vector. vector>& inlines_; @@ -616,6 +622,7 @@ void DwarfCUToModule::InlineHandler::ProcessAttributeUnsigned( high_pc_ = data; break; case DW_AT_ranges: + has_range_data_ = true; ranges_data_ = data; ranges_form_ = form; break; @@ -659,7 +666,7 @@ bool DwarfCUToModule::InlineHandler::EndAttributes() { void DwarfCUToModule::InlineHandler::Finish() { vector ranges; - if (low_pc_ && high_pc_) { + if (!has_range_data_) { if (high_pc_form_ != DW_FORM_addr && high_pc_form_ != DW_FORM_GNU_addr_index && high_pc_form_ != DW_FORM_addrx && @@ -696,11 +703,12 @@ void DwarfCUToModule::InlineHandler::Finish() { // Every DW_TAG_inlined_subroutine should have a DW_AT_abstract_origin. assert(specification_offset_ != 0); - cu_context_->file_context->module_->inline_origin_map.SetReference( - specification_offset_, specification_offset_); + Module::InlineOriginMap& inline_origin_map = + cu_context_->file_context->module_ + ->inline_origin_maps[cu_context_->file_context->filename_]; + inline_origin_map.SetReference(specification_offset_, specification_offset_); Module::InlineOrigin* origin = - cu_context_->file_context->module_->inline_origin_map - .GetOrCreateInlineOrigin(specification_offset_, name_); + inline_origin_map.GetOrCreateInlineOrigin(specification_offset_, name_); unique_ptr in( new Module::Inline(origin, ranges, call_site_line_, call_site_file_id_, inline_nest_level_, std::move(child_inlines_))); @@ -740,7 +748,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { ranges_data_(0), inline_(false), handle_inline_(handle_inline), - has_qualified_name_(false) {} + has_qualified_name_(false), + has_range_data_(false) {} void ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, @@ -764,6 +773,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { vector> child_inlines_; bool handle_inline_; bool has_qualified_name_; + bool has_range_data_; DIEContext child_context_; // A context for our children. }; @@ -783,6 +793,7 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( high_pc_ = data; break; case DW_AT_ranges: + has_range_data_ = true; ranges_data_ = data; ranges_form_ = form; break; @@ -853,7 +864,7 @@ void DwarfCUToModule::FuncHandler::Finish() { iter->second->name = name_; } - if (!ranges_data_) { + if (!has_range_data_) { // Make high_pc_ an address, if it isn't already. if (high_pc_form_ != DW_FORM_addr && high_pc_form_ != DW_FORM_GNU_addr_index && @@ -929,10 +940,11 @@ void DwarfCUToModule::FuncHandler::Finish() { StringView name = name_.empty() ? name_omitted : name_; uint64_t offset = specification_offset_ != 0 ? specification_offset_ : offset_; - cu_context_->file_context->module_->inline_origin_map.SetReference(offset_, - offset); - cu_context_->file_context->module_->inline_origin_map - .GetOrCreateInlineOrigin(offset_, name); + Module::InlineOriginMap& inline_origin_map = + cu_context_->file_context->module_ + ->inline_origin_maps[cu_context_->file_context->filename_]; + inline_origin_map.SetReference(offset_, offset); + inline_origin_map.GetOrCreateInlineOrigin(offset_, name); } } @@ -1067,12 +1079,21 @@ DwarfCUToModule::DwarfCUToModule(FileContext* file_context, LineToModuleHandler* line_reader, RangesHandler* ranges_handler, WarningReporter* reporter, - bool handle_inline) + bool handle_inline, + uint64_t low_pc, + uint64_t addr_base, + bool has_source_line_info, + uint64_t source_line_offset) : RootDIEHandler(handle_inline), line_reader_(line_reader), - cu_context_(new CUContext(file_context, reporter, ranges_handler)), + cu_context_(new CUContext(file_context, + reporter, + ranges_handler, + low_pc, + addr_base)), child_context_(new DIEContext()), - has_source_line_info_(false) {} + has_source_line_info_(has_source_line_info), + source_line_offset_(source_line_offset) {} DwarfCUToModule::~DwarfCUToModule() { } diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h index 5a8001042..1ff0ebc7f 100644 --- a/src/common/dwarf_cu_to_module.h +++ b/src/common/dwarf_cu_to_module.h @@ -264,7 +264,11 @@ class DwarfCUToModule: public RootDIEHandler { LineToModuleHandler* line_reader, RangesHandler* ranges_handler, WarningReporter* reporter, - bool handle_inline = false); + bool handle_inline = false, + uint64_t low_pc = 0, + uint64_t addr_base = 0, + bool has_source_line_info = false, + uint64_t source_line_offset = 0); ~DwarfCUToModule(); void ProcessAttributeSigned(enum DwarfAttribute attr, diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index 8179663bb..b693fc9e1 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -51,6 +51,9 @@ #include #include #include +#ifdef HAVE_LIBZSTD +#include +#endif #include #include @@ -108,6 +111,11 @@ using google_breakpad::wasteful_vector; #define EM_AARCH64 183 #endif +// Define ZStd compression if host machine does not include this define. +#ifndef ELFCOMPRESS_ZSTD +#define ELFCOMPRESS_ZSTD 2 +#endif + // // FDWrapper // @@ -305,7 +313,7 @@ uint32_t GetCompressionHeader( return sizeof (*header); } -std::pair UncompressSectionContents( +std::pair UncompressZlibSectionContents( const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) { z_stream stream; memset(&stream, 0, sizeof stream); @@ -334,6 +342,90 @@ std::pair UncompressSectionContents( : std::make_pair(uncompressed_buffer.release(), uncompressed_size); } +#ifdef HAVE_LIBZSTD +std::pair UncompressZstdSectionContents( + const uint8_t* compressed_buffer, uint64_t compressed_size,uint64_t uncompressed_size) { + + google_breakpad::scoped_array uncompressed_buffer(new uint8_t[uncompressed_size]); + size_t out_size = ZSTD_decompress(uncompressed_buffer.get(), uncompressed_size, + compressed_buffer, compressed_size); + if (ZSTD_isError(out_size)) { + return std::make_pair(nullptr, 0); + } + assert(out_size == uncompressed_size); + return std::make_pair(uncompressed_buffer.release(), uncompressed_size); +} +#endif + +std::pair UncompressSectionContents( + uint64_t compression_type, const uint8_t* compressed_buffer, + uint64_t compressed_size, uint64_t uncompressed_size) { + if (compression_type == ELFCOMPRESS_ZLIB) { + return UncompressZlibSectionContents(compressed_buffer, compressed_size, uncompressed_size); + } + +#ifdef HAVE_LIBZSTD + if (compression_type == ELFCOMPRESS_ZSTD) { + return UncompressZstdSectionContents(compressed_buffer, compressed_size, uncompressed_size); + } +#endif + + return std::make_pair(nullptr, 0); +} + +void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) { + std::string split_file; + google_breakpad::SectionMap split_sections; + google_breakpad::ByteReader split_byte_reader(endianness); + uint64_t cu_offset = 0; + if (!reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader, + cu_offset)) + return; + DwarfCUToModule::FileContext file_context(split_file, module, + handle_inter_cu_refs); + for (auto section : split_sections) + file_context.AddSectionToSectionMap(section.first, section.second.first, + section.second.second); + // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str, + // its debug info will refer to .debug_addr/.debug_line in the main binary. + if (file_context.section_map().find(".debug_addr") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(), + reader->GetAddrBufferLen()); + if (file_context.section_map().find(".debug_line") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(), + reader->GetLineBufferLen()); + if (file_context.section_map().find(".debug_line_str") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line_str", + reader->GetLineStrBuffer(), + reader->GetLineStrBufferLen()); + + DumperRangesHandler ranges_handler(&split_byte_reader); + DumperLineToModule line_to_module(&split_byte_reader); + DwarfCUToModule::WarningReporter reporter(split_file, cu_offset); + DwarfCUToModule root_handler( + &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline, + reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(), + reader->GetSourceLineOffset()); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::CompilationUnit split_reader( + split_file, file_context.section_map(), cu_offset, &split_byte_reader, + &die_dispatcher); + split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID()); + split_reader.Start(); + // Normally, it won't happen unless we have transitive reference. + if (split_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&split_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } +} + template bool LoadDwarf(const string& dwarf_filename, const typename ElfClass::Ehdr* elf_header, @@ -384,7 +476,7 @@ bool LoadDwarf(const string& dwarf_filename, size -= compression_header_size; std::pair uncompressed = - UncompressSectionContents(contents, size, chdr.ch_size); + UncompressSectionContents(chdr.ch_type, contents, size, chdr.ch_size); if (uncompressed.first != nullptr && uncompressed.second != 0) { file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second); @@ -421,6 +513,11 @@ bool LoadDwarf(const string& dwarf_filename, &die_dispatcher); // Process the entire compilation unit; get the offset of the next. offset += reader.Start(); + // Start to process split dwarf file. + if (reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&reader, module, endianness, handle_inter_cu_refs, + handle_inline); + } } return true; } @@ -529,7 +626,7 @@ bool LoadDwarfCFI(const string& dwarf_filename, cfi_size -= compression_header_size; std::pair uncompressed = - UncompressSectionContents(cfi, cfi_size, chdr.ch_size); + UncompressSectionContents(chdr.ch_type, cfi, cfi_size, chdr.ch_size); if (uncompressed.first == nullptr || uncompressed.second == 0) { fprintf(stderr, "%s: decompression failed\n", dwarf_filename.c_str()); diff --git a/src/common/linux/memory_mapped_file.h b/src/common/linux/memory_mapped_file.h index d4a85051e..462e116eb 100644 --- a/src/common/linux/memory_mapped_file.h +++ b/src/common/linux/memory_mapped_file.h @@ -33,7 +33,7 @@ #define COMMON_LINUX_MEMORY_MAPPED_FILE_H_ #include -#include "common/basictypes.h" + #include "common/memory_range.h" namespace google_breakpad { @@ -49,6 +49,9 @@ class MemoryMappedFile { // If Map() fails, the object behaves as if it is default constructed. MemoryMappedFile(const char* path, size_t offset); + MemoryMappedFile(const MemoryMappedFile&) = delete; + void operator=(const MemoryMappedFile&) = delete; + ~MemoryMappedFile(); // Maps a file at |path| into memory, which can then be accessed via @@ -77,8 +80,6 @@ class MemoryMappedFile { private: // Mapped file content as a MemoryRange object. MemoryRange content_; - - DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); }; } // namespace google_breakpad diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc index b3fe4600f..742108205 100644 --- a/src/common/mac/arch_utilities.cc +++ b/src/common/mac/arch_utilities.cc @@ -39,7 +39,8 @@ #include #if defined(__APPLE__) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 || \ - __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000) + __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000 || \ + __TVOS_OS_VERSION_MAX_ALLOWED >= 160000) #include #endif @@ -97,8 +98,9 @@ ArchInfo GetLocalArchInfo(void) { std::optional GetArchInfoFromName(const char* arch_name) { #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 || \ - __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000) - if (__builtin_available(macOS 13.0, iOS 16.0, *)) { + __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000 || \ + __TVOS_OS_VERSION_MAX_ALLOWED >= 160000) + if (__builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, *)) { cpu_type_t type; cpu_subtype_t subtype; if (macho_cpu_type_for_arch_name(arch_name, &type, &subtype)) { @@ -124,8 +126,9 @@ std::optional GetArchInfoFromName(const char* arch_name) { const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { #if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 130000 || \ - __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000) - if (__builtin_available(macOS 13.0, iOS 16.0, *)) { + __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000 || \ + __TVOS_OS_VERSION_MAX_ALLOWED >= 160000) + if (__builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, *)) { const char* name = macho_arch_name_for_cpu_type(cpu_type, cpu_subtype); if (name) { return name; diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc index dd91196ae..c06945e48 100644 --- a/src/common/mac/dump_syms.cc +++ b/src/common/mac/dump_syms.cc @@ -424,14 +424,67 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr& module) { return true; } +void DumpSymbols::StartProcessSplitDwarf( + google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) const { + std::string split_file; + google_breakpad::SectionMap split_sections; + google_breakpad::ByteReader split_byte_reader(endianness); + uint64_t cu_offset = 0; + if (reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader, + cu_offset)) + return; + DwarfCUToModule::FileContext file_context(split_file, module, + handle_inter_cu_refs); + for (auto section : split_sections) + file_context.AddSectionToSectionMap(section.first, section.second.first, + section.second.second); + // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str, + // its debug info will refer to .debug_addr/.debug_line in the main binary. + if (file_context.section_map().find(".debug_addr") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(), + reader->GetAddrBufferLen()); + if (file_context.section_map().find(".debug_line") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(), + reader->GetLineBufferLen()); + if (file_context.section_map().find(".debug_line_str") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line_str", + reader->GetLineStrBuffer(), + reader->GetLineStrBufferLen()); + DumperRangesHandler ranges_handler(&split_byte_reader); + DumperLineToModule line_to_module(&split_byte_reader); + DwarfCUToModule::WarningReporter reporter(split_file, cu_offset); + DwarfCUToModule root_handler( + &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline, + reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(), + reader->GetSourceLineOffset()); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::CompilationUnit split_reader( + split_file, file_context.section_map(), cu_offset, &split_byte_reader, + &die_dispatcher); + split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID()); + split_reader.Start(); + // Normally, it won't happen unless we have transitive reference. + if (split_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&split_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } +} + void DumpSymbols::ReadDwarf(google_breakpad::Module* module, const mach_o::Reader& macho_reader, const mach_o::SectionMap& dwarf_sections, bool handle_inter_cu_refs) const { // Build a byte reader of the appropriate endianness. - ByteReader byte_reader(macho_reader.big_endian() - ? ENDIANNESS_BIG - : ENDIANNESS_LITTLE); + google_breakpad::Endianness endianness = + macho_reader.big_endian() ? ENDIANNESS_BIG : ENDIANNESS_LITTLE; + ByteReader byte_reader(endianness); // Construct a context for this file. DwarfCUToModule::FileContext file_context(selected_object_name_, @@ -467,14 +520,14 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module, // Walk the __debug_info section, one compilation unit at a time. uint64_t debug_info_length = debug_info_section.second; + bool handle_inline = symbol_data_ & INLINES; for (uint64_t offset = 0; offset < debug_info_length;) { // Make a handler for the root DIE that populates MODULE with the // debug info. DwarfCUToModule::WarningReporter reporter(selected_object_name_, offset); DwarfCUToModule root_handler(&file_context, &line_to_module, - &ranges_handler, &reporter, - symbol_data_ & INLINES); + &ranges_handler, &reporter, handle_inline); // Make a Dwarf2Handler that drives our DIEHandler. DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET. @@ -485,6 +538,11 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module, &die_dispatcher); // Process the entire compilation unit; get the offset of the next. offset += dwarf_reader.Start(); + // Start to process split dwarf file. + if (dwarf_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&dwarf_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } } } diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h index 5bcb0b58f..5ccf49e3e 100644 --- a/src/common/mac/dump_syms.h +++ b/src/common/mac/dump_syms.h @@ -43,6 +43,7 @@ #include #include "common/byte_cursor.h" +#include "common/dwarf/dwarf2reader.h" #include "common/mac/arch_utilities.h" #include "common/mac/macho_reader.h" #include "common/mac/super_fat_arch.h" @@ -143,6 +144,13 @@ class DumpSymbols { // Creates an empty module object. bool CreateEmptyModule(scoped_ptr& module); + // Process the split dwarf file referenced by reader. + void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) const; + // Read debugging information from |dwarf_sections|, which was taken from // |macho_reader|, and add it to |module|. void ReadDwarf(google_breakpad::Module* module, diff --git a/src/common/module.cc b/src/common/module.cc index 73c4a8b17..0eb5aad82 100644 --- a/src/common/module.cc +++ b/src/common/module.cc @@ -289,8 +289,7 @@ void Module::GetStackFrameEntries(vector* vec) const { } } -void Module::AssignSourceIds( - set& inline_origins) { +void Module::AssignSourceIds() { // First, give every source file an id of -1. for (FileByNameMap::iterator file_it = files_.begin(); file_it != files_.end(); ++file_it) { @@ -394,7 +393,7 @@ bool Module::Write(std::ostream& stream, SymbolData symbol_data) { // Get all referenced inline origins. set inline_origins; CreateInlineOrigins(inline_origins); - AssignSourceIds(inline_origins); + AssignSourceIds(); // Write out files. for (FileByNameMap::iterator file_it = files_.begin(); diff --git a/src/common/module.h b/src/common/module.h index d736701ff..28e8e9c50 100644 --- a/src/common/module.h +++ b/src/common/module.h @@ -146,10 +146,6 @@ class Module { // The inlined function's name. StringView name; - - File* file; - - int getFileID() const { return file ? file->source_id : -1; } }; // A inlined call site. @@ -228,7 +224,7 @@ class Module { map references_; }; - InlineOriginMap inline_origin_map; + map inline_origin_maps; // A source line. struct Line { @@ -407,7 +403,7 @@ class Module { // Set the source id numbers for all other files --- unused by the // source line data --- to -1. We do this before writing out the // symbol file, at which point we omit any unused files. - void AssignSourceIds(set& inline_origins); + void AssignSourceIds(); // This function should be called before AssignSourceIds() to get the set of // valid InlineOrigins*. diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc index 6a6762e53..c51162e52 100644 --- a/src/common/module_unittest.cc +++ b/src/common/module_unittest.cc @@ -198,9 +198,7 @@ TEST(Module, WriteOmitUnusedFiles) { function->lines.push_back(line1); function->lines.push_back(line2); m.AddFunction(function); - - std::set inline_origins; - m.AssignSourceIds(inline_origins); + m.AssignSourceIds(); vector vec; m.GetFiles(&vec); diff --git a/src/common/simple_string_dictionary.h b/src/common/simple_string_dictionary.h index f7253a34e..166d56c8d 100644 --- a/src/common/simple_string_dictionary.h +++ b/src/common/simple_string_dictionary.h @@ -32,8 +32,6 @@ #include #include -#include "common/basictypes.h" - namespace google_breakpad { // Opaque type for the serialized representation of a NonAllocatingMap. One is @@ -80,6 +78,8 @@ class NonAllocatingMap { : map_(map), current_(0) { } + Iterator(const Iterator&) = delete; + void operator=(const Iterator&) = delete; // Returns the next entry in the map, or NULL if at the end of the // collection. @@ -90,14 +90,12 @@ class NonAllocatingMap { return entry; } } - return NULL; + return nullptr; } private: const NonAllocatingMap& map_; size_t current_; - - DISALLOW_COPY_AND_ASSIGN(Iterator); }; NonAllocatingMap() : entries_() { diff --git a/src/common/windows/pe_source_line_writer.h b/src/common/windows/pe_source_line_writer.h index a37481459..324663bac 100644 --- a/src/common/windows/pe_source_line_writer.h +++ b/src/common/windows/pe_source_line_writer.h @@ -31,7 +31,6 @@ #include -#include "common/basictypes.h" #include "common/windows/module_info.h" namespace google_breakpad { @@ -44,6 +43,8 @@ using std::wstring; class PESourceLineWriter { public: explicit PESourceLineWriter(const wstring& pe_file); + PESourceLineWriter(const PESourceLineWriter&) = delete; + void operator=(const PESourceLineWriter&) = delete; ~PESourceLineWriter(); // Writes Breakpad symbols from the pe file to |symbol_file|. @@ -58,9 +59,7 @@ class PESourceLineWriter { bool GetPEInfo(PEModuleInfo* info); private: - const wstring pe_file_; - - DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter); + const wstring pe_file_; }; } // namespace google_breakpad diff --git a/src/config.h.in b/src/config.h.in index 8fd7b0aa3..9a4eb0de9 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -21,6 +21,9 @@ /* Define to 1 if you have the `rustc_demangle' library (-lrustc_demangle). */ #undef HAVE_LIBRUSTC_DEMANGLE +/* Define to 1 if you have the `zstd' library (-lzstd). */ +#undef HAVE_LIBZSTD + /* Define to 1 if you have the `memfd_create' function. */ #undef HAVE_MEMFD_CREATE diff --git a/src/google_breakpad/common/minidump_cpu_riscv.h b/src/google_breakpad/common/minidump_cpu_riscv.h index 94d061175..812cf5fda 100644 --- a/src/google_breakpad/common/minidump_cpu_riscv.h +++ b/src/google_breakpad/common/minidump_cpu_riscv.h @@ -39,28 +39,8 @@ #include "google_breakpad/common/breakpad_types.h" -#define MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT 32 -#if defined(__riscv) -# if __riscv_flen == 32 -typedef uint32_t riscv_fpr_size; -# elif __riscv_flen == 64 -typedef uint64_t riscv_fpr_size; -# elif __riscv_flen == 128 -typedef uint128_struct riscv_fpr_size; -# else -# error "Unexpected __riscv_flen" -# endif -#else -typedef uint32_t riscv_fpr_size; -#endif - #define MD_CONTEXT_RISCV_GPR_COUNT 32 - -typedef struct { - /* 32 floating point registers, f0 .. f31. */ - riscv_fpr_size regs[MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT]; - uint32_t fpcsr; -} MDFloatingSaveAreaRISCV; +#define MD_CONTEXT_RISCV_FPR_COUNT 32 enum MDRISCVRegisterNumbers { MD_CONTEXT_RISCV_REG_PC = 0, @@ -72,13 +52,14 @@ enum MDRISCVRegisterNumbers { * context stored in the structure. */ #define MD_CONTEXT_RISCV 0x00800000 #define MD_CONTEXT_RISCV_INTEGER (MD_CONTEXT_RISCV | 0x00000001) -#define MD_CONTEXT_RISCV_FLOATING_POINT (MD_CONTEXT_RISCV | 0x00000004) +#define MD_CONTEXT_RISCV_FLOATING_POINT (MD_CONTEXT_RISCV | 0x00000002) #define MD_CONTEXT_RISCV_FULL (MD_CONTEXT_RISCV_INTEGER | \ MD_CONTEXT_RISCV_FLOATING_POINT) typedef struct { /* Determines which fields of this struct are populated */ uint32_t context_flags; + uint32_t version; uint32_t pc; uint32_t ra; @@ -113,20 +94,24 @@ typedef struct { uint32_t t5; uint32_t t6; - MDFloatingSaveAreaRISCV float_save; + /* 32 floating point registers, f0 .. f31. Breakpad only supports RISCV32 + * with 32 bit floating point. */ + uint32_t fpregs[MD_CONTEXT_RISCV_FPR_COUNT]; + uint32_t fcsr; } MDRawContextRISCV; /* For (MDRawContextRISCV64).context_flags. These values indicate the type of * context stored in the structure. */ #define MD_CONTEXT_RISCV64 0x08000000 #define MD_CONTEXT_RISCV64_INTEGER (MD_CONTEXT_RISCV64 | 0x00000001) -#define MD_CONTEXT_RISCV64_FLOATING_POINT (MD_CONTEXT_RISCV64 | 0x00000004) +#define MD_CONTEXT_RISCV64_FLOATING_POINT (MD_CONTEXT_RISCV64 | 0x00000002) #define MD_CONTEXT_RISCV64_FULL (MD_CONTEXT_RISCV64_INTEGER | \ MD_CONTEXT_RISCV64_FLOATING_POINT) typedef struct { /* Determines which fields of this struct are populated */ uint32_t context_flags; + uint32_t version; uint64_t pc; uint64_t ra; @@ -161,7 +146,10 @@ typedef struct { uint64_t t5; uint64_t t6; - MDFloatingSaveAreaRISCV float_save; + /* 32 floating point registers, f0 .. f31. Breakpad only supports RISCV64 with + * 64 bit floating point. */ + uint64_t fpregs[MD_CONTEXT_RISCV_FPR_COUNT]; + uint32_t fcsr; } MDRawContextRISCV64; diff --git a/src/google_breakpad/common/minidump_exception_linux.h b/src/google_breakpad/common/minidump_exception_linux.h index 06d36fd15..a3bc000ee 100644 --- a/src/google_breakpad/common/minidump_exception_linux.h +++ b/src/google_breakpad/common/minidump_exception_linux.h @@ -157,6 +157,11 @@ typedef enum { MD_EXCEPTION_FLAG_LIN_SEGV_ACCERR = 2, MD_EXCEPTION_FLAG_LIN_SEGV_BNDERR = 3, MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR = 4, + MD_EXCEPTION_FLAG_LIN_SEGV_ACCADI = 5, + MD_EXCEPTION_FLAG_LIN_SEGV_ADIDERR = 6, + MD_EXCEPTION_FLAG_LIN_SEGV_ADIPERR = 7, + MD_EXCEPTION_FLAG_LIN_SEGV_MTEAERR = 8, + MD_EXCEPTION_FLAG_LIN_SEGV_MTESERR = 9, /* SIGBUS */ MD_EXCEPTION_FLAG_LIN_BUS_ADRALN = 1, diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h index 934a0e3ef..e523ab367 100644 --- a/src/google_breakpad/processor/minidump.h +++ b/src/google_breakpad/processor/minidump.h @@ -89,7 +89,6 @@ #include #include -#include "common/basictypes.h" #include "common/using_std_string.h" #include "google_breakpad/processor/code_module.h" #include "google_breakpad/processor/code_modules.h" @@ -114,7 +113,7 @@ template class RangeMap; // itself. class MinidumpObject : public DumpObject { public: - virtual ~MinidumpObject() {} + virtual ~MinidumpObject() = default; protected: explicit MinidumpObject(Minidump* minidump); @@ -136,7 +135,9 @@ class MinidumpObject : public DumpObject { // same interface, and may be derived from this class. class MinidumpStream : public MinidumpObject { public: - virtual ~MinidumpStream() {} + MinidumpStream(const MinidumpStream&) = delete; + void operator=(const MinidumpStream&) = delete; + ~MinidumpStream() override = default; protected: explicit MinidumpStream(Minidump* minidump); @@ -150,8 +151,6 @@ class MinidumpStream : public MinidumpObject { // that implements MinidumpStream can compare expected_size to a // known size as an integrity check. virtual bool Read(uint32_t expected_size) = 0; - - DISALLOW_COPY_AND_ASSIGN(MinidumpStream); }; @@ -167,7 +166,9 @@ class MinidumpStream : public MinidumpObject { // user wants). class MinidumpContext : public DumpContext { public: - virtual ~MinidumpContext(); + MinidumpContext(const MinidumpContext&) = delete; + void operator=(const MinidumpContext&) = delete; + ~MinidumpContext() override; protected: explicit MinidumpContext(Minidump* minidump); @@ -192,8 +193,6 @@ class MinidumpContext : public DumpContext { // for access to data about the minidump file itself, such as whether // it should be byte-swapped. Minidump* minidump_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpContext); }; @@ -208,7 +207,7 @@ class MinidumpContext : public DumpContext { class MinidumpMemoryRegion : public MinidumpObject, public MemoryRegion { public: - virtual ~MinidumpMemoryRegion(); + ~MinidumpMemoryRegion() override; static void set_max_bytes(uint32_t max_bytes) { max_bytes_ = max_bytes; } static uint32_t max_bytes() { return max_bytes_; } @@ -219,22 +218,22 @@ class MinidumpMemoryRegion : public MinidumpObject, const uint8_t* GetMemory() const; // The address of the base of the memory region. - uint64_t GetBase() const; + uint64_t GetBase() const override; // The size, in bytes, of the memory region. - uint32_t GetSize() const; + uint32_t GetSize() const override; // Frees the cached memory region, if cached. void FreeMemory(); // Obtains the value of memory at the pointer specified by address. - bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const; - bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const; - bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const; - bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const; + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const override; + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const override; + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const override; + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const override; // Print a human-readable representation of the object to stdout. - void Print() const; + void Print() const override; void SetPrintMode(bool hexdump, unsigned int width); protected: @@ -277,9 +276,9 @@ class MinidumpMemoryRegion : public MinidumpObject, // contain a memory region or context. class MinidumpThread : public MinidumpObject { public: - virtual ~MinidumpThread(); + ~MinidumpThread() override; - const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; } + const MDRawThread* thread() const { return valid_ ? &thread_ : nullptr; } // GetMemory may return NULL even if the MinidumpThread is valid, // if the thread memory cannot be read. virtual MinidumpMemoryRegion* GetMemory(); @@ -322,7 +321,9 @@ class MinidumpThread : public MinidumpObject { // a process. class MinidumpThreadList : public MinidumpStream { public: - virtual ~MinidumpThreadList(); + MinidumpThreadList(const MinidumpThreadList&) = delete; + void operator=(const MinidumpThreadList&) = delete; + ~MinidumpThreadList() override; static void set_max_threads(uint32_t max_threads) { max_threads_ = max_threads; @@ -364,18 +365,16 @@ class MinidumpThreadList : public MinidumpStream { // The list of threads. MinidumpThreads* threads_; - uint32_t thread_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpThreadList); + uint32_t thread_count_; }; // MinidumpThreadName contains the name of a thread. class MinidumpThreadName : public MinidumpObject { public: - virtual ~MinidumpThreadName(); + ~MinidumpThreadName() override; const MDRawThreadName* thread_name() const { - return valid_ ? &thread_name_ : NULL; + return valid_ ? &thread_name_ : nullptr; } // Gets the thread ID. @@ -419,7 +418,9 @@ class MinidumpThreadName : public MinidumpObject { // MinidumpThreadNames) in a process. class MinidumpThreadNameList : public MinidumpStream { public: - virtual ~MinidumpThreadNameList(); + MinidumpThreadNameList(const MinidumpThreadNameList&) = delete; + void operator=(const MinidumpThreadNameList&) = delete; + ~MinidumpThreadNameList() override; virtual unsigned int thread_name_count() const { return valid_ ? thread_name_count_ : 0; @@ -446,8 +447,6 @@ class MinidumpThreadNameList : public MinidumpStream { // The list of thread names. MinidumpThreadNames* thread_names_; uint32_t thread_name_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpThreadNameList); }; // MinidumpModule wraps MDRawModule, which contains information about loaded @@ -457,7 +456,7 @@ class MinidumpThreadNameList : public MinidumpStream { class MinidumpModule : public MinidumpObject, public CodeModule { public: - virtual ~MinidumpModule(); + ~MinidumpModule() override; static void set_max_cv_bytes(uint32_t max_cv_bytes) { max_cv_bytes_ = max_cv_bytes; @@ -469,27 +468,27 @@ class MinidumpModule : public MinidumpObject, } static uint32_t max_misc_bytes() { return max_misc_bytes_; } - const MDRawModule* module() const { return valid_ ? &module_ : NULL; } + const MDRawModule* module() const { return valid_ ? &module_ : nullptr; } // CodeModule implementation - virtual uint64_t base_address() const { + uint64_t base_address() const override { return valid_ ? module_.base_of_image : static_cast(-1); } - virtual uint64_t size() const { return valid_ ? module_.size_of_image : 0; } - virtual string code_file() const; - virtual string code_identifier() const; - virtual string debug_file() const; - virtual string debug_identifier() const; - virtual string version() const; - virtual CodeModule* Copy() const; - virtual bool is_unloaded() const { return false; } + uint64_t size() const override { return valid_ ? module_.size_of_image : 0; } + string code_file() const override; + string code_identifier() const override; + string debug_file() const override; + string debug_identifier() const override; + string version() const override; + CodeModule* Copy() const override; + bool is_unloaded() const override { return false; } // Getter and setter for shrink_down_delta. This is used when the address // range for a module is shrunk down due to address range conflicts with // other modules. The base_address and size fields are not updated and they // should always reflect the original values (reported in the minidump). - virtual uint64_t shrink_down_delta() const; - virtual void SetShrinkDownDelta(uint64_t shrink_down_delta); + uint64_t shrink_down_delta() const override; + void SetShrinkDownDelta(uint64_t shrink_down_delta) override; // The CodeView record, which contains information to locate the module's // debugging information (pdb). This is returned as uint8_t* because @@ -580,7 +579,9 @@ class MinidumpModule : public MinidumpObject, class MinidumpModuleList : public MinidumpStream, public CodeModules { public: - virtual ~MinidumpModuleList(); + MinidumpModuleList(const MinidumpModuleList&) = delete; + void operator=(const MinidumpModuleList&) = delete; + ~MinidumpModuleList() override; static void set_max_modules(uint32_t max_modules) { max_modules_ = max_modules; @@ -588,19 +589,19 @@ class MinidumpModuleList : public MinidumpStream, static uint32_t max_modules() { return max_modules_; } // CodeModules implementation. - virtual unsigned int module_count() const { + unsigned int module_count() const override { return valid_ ? module_count_ : 0; } - virtual const MinidumpModule* GetModuleForAddress(uint64_t address) const; - virtual const MinidumpModule* GetMainModule() const; - virtual const MinidumpModule* GetModuleAtSequence( - unsigned int sequence) const; - virtual const MinidumpModule* GetModuleAtIndex(unsigned int index) const; - virtual const CodeModules* Copy() const; + const MinidumpModule* GetModuleForAddress(uint64_t address) const override; + const MinidumpModule* GetMainModule() const override; + const MinidumpModule* GetModuleAtSequence( + unsigned int sequence) const override; + const MinidumpModule* GetModuleAtIndex(unsigned int index) const override; + const CodeModules* Copy() const override; // Returns a vector of all modules which address ranges needed to be shrunk // down due to address range conflicts with other modules. - virtual vector > GetShrunkRangeModules() const; + vector> GetShrunkRangeModules() const override; // Print a human-readable representation of the object to stdout. void Print(); @@ -615,7 +616,7 @@ class MinidumpModuleList : public MinidumpStream, static const uint32_t kStreamType = MD_MODULE_LIST_STREAM; - bool Read(uint32_t expected_size); + bool Read(uint32_t expected_size) override; bool StoreRange(const MinidumpModule& module, uint64_t base_address, @@ -632,8 +633,6 @@ class MinidumpModuleList : public MinidumpStream, MinidumpModules* modules_; uint32_t module_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpModuleList); }; @@ -648,7 +647,9 @@ class MinidumpModuleList : public MinidumpStream, // memory minidumps contain all of a process' mapped memory. class MinidumpMemoryList : public MinidumpStream { public: - virtual ~MinidumpMemoryList(); + MinidumpMemoryList(const MinidumpMemoryList&) = delete; + void operator=(const MinidumpMemoryList&) = delete; + ~MinidumpMemoryList() override; static void set_max_regions(uint32_t max_regions) { max_regions_ = max_regions; @@ -696,8 +697,6 @@ class MinidumpMemoryList : public MinidumpStream { // The list of regions. MemoryRegions* regions_; uint32_t region_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryList); }; @@ -709,10 +708,12 @@ class MinidumpMemoryList : public MinidumpStream { // occurred. class MinidumpException : public MinidumpStream { public: - virtual ~MinidumpException(); + MinidumpException(const MinidumpException&) = delete; + void operator=(const MinidumpException&) = delete; + ~MinidumpException() override; const MDRawExceptionStream* exception() const { - return valid_ ? &exception_ : NULL; + return valid_ ? &exception_ : nullptr; } // The thread ID is used to determine if a thread is the exception thread, @@ -736,19 +737,19 @@ class MinidumpException : public MinidumpStream { bool Read(uint32_t expected_size) override; MDRawExceptionStream exception_; - MinidumpContext* context_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpException); + MinidumpContext* context_; }; // MinidumpAssertion wraps MDRawAssertionInfo, which contains information // about an assertion that caused the minidump to be generated. class MinidumpAssertion : public MinidumpStream { public: - virtual ~MinidumpAssertion(); + MinidumpAssertion(const MinidumpAssertion&) = delete; + void operator=(const MinidumpAssertion&) = delete; + ~MinidumpAssertion() override; const MDRawAssertionInfo* assertion() const { - return valid_ ? &assertion_ : NULL; + return valid_ ? &assertion_ : nullptr; } string expression() const { @@ -779,8 +780,6 @@ class MinidumpAssertion : public MinidumpStream { string expression_; string function_; string file_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpAssertion); }; @@ -788,10 +787,12 @@ class MinidumpAssertion : public MinidumpStream { // the system on which the minidump was generated. See also MinidumpMiscInfo. class MinidumpSystemInfo : public MinidumpStream { public: - virtual ~MinidumpSystemInfo(); + MinidumpSystemInfo(const MinidumpSystemInfo&) = delete; + void operator=(const MinidumpSystemInfo&) = delete; + ~MinidumpSystemInfo() override; const MDRawSystemInfo* system_info() const { - return valid_ ? &system_info_ : NULL; + return valid_ ? &system_info_ : nullptr; } // GetOS and GetCPU return textual representations of the operating system @@ -834,8 +835,6 @@ class MinidumpSystemInfo : public MinidumpStream { // A string identifying the CPU vendor, if known. const string* cpu_vendor_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpSystemInfo); }; @@ -846,7 +845,7 @@ class MinidumpUnloadedModule : public MinidumpObject, ~MinidumpUnloadedModule() override; const MDRawUnloadedModule* module() const { - return valid_ ? &unloaded_module_ : NULL; + return valid_ ? &unloaded_module_ : nullptr; } // CodeModule implementation @@ -903,6 +902,8 @@ class MinidumpUnloadedModule : public MinidumpObject, class MinidumpUnloadedModuleList : public MinidumpStream, public CodeModules { public: + MinidumpUnloadedModuleList(const MinidumpUnloadedModuleList&) = delete; + void operator=(const MinidumpUnloadedModuleList&) = delete; ~MinidumpUnloadedModuleList() override; static void set_max_modules(uint32_t max_modules) { @@ -945,8 +946,6 @@ class MinidumpUnloadedModuleList : public MinidumpStream, MinidumpUnloadedModules* unloaded_modules_; uint32_t module_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpUnloadedModuleList); }; @@ -955,8 +954,11 @@ class MinidumpUnloadedModuleList : public MinidumpStream, // information. See also MinidumpSystemInfo. class MinidumpMiscInfo : public MinidumpStream { public: + MinidumpMiscInfo(const MinidumpMiscInfo&) = delete; + void operator=(const MinidumpMiscInfo&) = delete; + const MDRawMiscInfo* misc_info() const { - return valid_ ? &misc_info_ : NULL; + return valid_ ? &misc_info_ : nullptr; } // Print a human-readable representation of the object to stdout. @@ -980,8 +982,6 @@ class MinidumpMiscInfo : public MinidumpStream { string daylight_name_; string build_string_; string dbg_bld_str_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpMiscInfo); }; @@ -990,8 +990,11 @@ class MinidumpMiscInfo : public MinidumpStream { // at the time the minidump was generated. class MinidumpBreakpadInfo : public MinidumpStream { public: + MinidumpBreakpadInfo(const MinidumpBreakpadInfo&) = delete; + void operator=(const MinidumpBreakpadInfo&) = delete; + const MDRawBreakpadInfo* breakpad_info() const { - return valid_ ? &breakpad_info_ : NULL; + return valid_ ? &breakpad_info_ : nullptr; } // These thread IDs are used to determine if threads deserve special @@ -1014,8 +1017,6 @@ class MinidumpBreakpadInfo : public MinidumpStream { bool Read(uint32_t expected_size_) override; MDRawBreakpadInfo breakpad_info_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpBreakpadInfo); }; // MinidumpMemoryInfo wraps MDRawMemoryInfo, which provides information @@ -1023,7 +1024,9 @@ class MinidumpBreakpadInfo : public MinidumpStream { // and protection. class MinidumpMemoryInfo : public MinidumpObject { public: - const MDRawMemoryInfo* info() const { return valid_ ? &memory_info_ : NULL; } + const MDRawMemoryInfo* info() const { + return valid_ ? &memory_info_ : nullptr; + } // The address of the base of the memory region. uint64_t GetBase() const { return valid_ ? memory_info_.base_address : 0; } @@ -1060,7 +1063,9 @@ class MinidumpMemoryInfo : public MinidumpObject { // info corresponding to a specific address. class MinidumpMemoryInfoList : public MinidumpStream { public: - virtual ~MinidumpMemoryInfoList(); + MinidumpMemoryInfoList(const MinidumpMemoryInfoList&) = delete; + void operator=(const MinidumpMemoryInfoList&) = delete; + ~MinidumpMemoryInfoList() override; unsigned int info_count() const { return valid_ ? info_count_ : 0; } @@ -1086,14 +1091,15 @@ class MinidumpMemoryInfoList : public MinidumpStream { MinidumpMemoryInfos* infos_; uint32_t info_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryInfoList); }; // MinidumpLinuxMaps wraps information about a single mapped memory region // from /proc/self/maps. class MinidumpLinuxMaps : public MinidumpObject { public: + MinidumpLinuxMaps(const MinidumpLinuxMaps&) = delete; + void operator=(const MinidumpLinuxMaps&) = delete; + // The memory address of the base of the mapped region. uint64_t GetBase() const { return valid_ ? region_.start : 0; } // The size of the mapped region. @@ -1139,8 +1145,6 @@ class MinidumpLinuxMaps : public MinidumpObject { // The memory region struct that this class wraps. MappedMemoryRegion region_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMaps); }; // MinidumpLinuxMapsList corresponds to the Linux-exclusive MD_LINUX_MAPS @@ -1148,7 +1152,9 @@ class MinidumpLinuxMaps : public MinidumpObject { // the mapped memory regions and their access permissions. class MinidumpLinuxMapsList : public MinidumpStream { public: - virtual ~MinidumpLinuxMapsList(); + MinidumpLinuxMapsList(const MinidumpLinuxMapsList&) = delete; + void operator=(const MinidumpLinuxMapsList&) = delete; + ~MinidumpLinuxMapsList() override; // Get number of mappings. unsigned int get_maps_count() const { return valid_ ? maps_count_ : 0; } @@ -1180,8 +1186,6 @@ class MinidumpLinuxMapsList : public MinidumpStream { MinidumpLinuxMappings* maps_; // The number of mappings. uint32_t maps_count_; - - DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMapsList); }; // MinidumpCrashpadInfo wraps MDRawCrashpadInfo, which is an optional stream in @@ -1196,12 +1200,12 @@ class MinidumpCrashpadInfo : public MinidumpStream { }; const MDRawCrashpadInfo* crashpad_info() const { - return valid_ ? &crashpad_info_ : NULL; + return valid_ ? &crashpad_info_ : nullptr; } const std::vector>* GetModuleCrashpadInfoAnnotationObjects() const { - return valid_ ? &module_crashpad_info_annotation_objects_ : NULL; + return valid_ ? &module_crashpad_info_annotation_objects_ : nullptr; } // Print a human-readable representation of the object to stdout. @@ -1242,6 +1246,9 @@ class Minidump { // is valid as long as the Minidump object is. explicit Minidump(std::istream& input); + Minidump(const Minidump&) = delete; + void operator=(const Minidump&) = delete; + virtual ~Minidump(); // path may be empty if the minidump was not opened from a file @@ -1258,7 +1265,9 @@ class Minidump { } static uint32_t max_string_length() { return max_string_length_; } - virtual const MDRawHeader* header() const { return valid_ ? &header_ : NULL; } + virtual const MDRawHeader* header() const { + return valid_ ? &header_ : nullptr; + } // Reads the CPU information from the system info stream and generates the // appropriate CPU flags. The returned context_cpu_flags are the same as @@ -1374,7 +1383,7 @@ class Minidump { // the Minidump object locate interesting streams quickly, and // provides a convenient place to stash MinidumpStream objects. struct MinidumpStreamInfo { - MinidumpStreamInfo() : stream_index(0), stream(NULL) {} + MinidumpStreamInfo() : stream_index(0), stream(nullptr) {} ~MinidumpStreamInfo() { delete stream; } // Index into the MinidumpDirectoryEntries vector @@ -1436,8 +1445,6 @@ class Minidump { // Knobs for controlling display of memory printing. bool hexdump_; unsigned int hexdump_width_; - - DISALLOW_COPY_AND_ASSIGN(Minidump); }; diff --git a/src/google_breakpad/processor/minidump_processor.h b/src/google_breakpad/processor/minidump_processor.h index 137ef4444..8475407e7 100644 --- a/src/google_breakpad/processor/minidump_processor.h +++ b/src/google_breakpad/processor/minidump_processor.h @@ -126,8 +126,18 @@ class MinidumpProcessor { // does not exist or cannot be determined. static string GetAssertion(Minidump* dump); + // Sets the flag to enable/disable use of objdump during normal crash + // processing. This is independent from the flag for use of objdump during + // exploitability analysis. void set_enable_objdump(bool enabled) { enable_objdump_ = enabled; } + // Sets the flag to enable/disable use of objdump during exploitability + // analysis. This is independent from the flag for use of objdump during + // normal crash processing. + void set_enable_objdump_for_exploitability(bool enabled) { + enable_objdump_for_exploitability_ = enabled; + } + private: StackFrameSymbolizer* frame_symbolizer_; // Indicate whether resolver_helper_ is owned by this instance. @@ -138,9 +148,15 @@ class MinidumpProcessor { // memory corruption issue. bool enable_exploitability_; - // This flag permits the exploitability scanner to shell out to objdump - // for purposes of disassembly. + // This flag permits the processor to shell out to objdump for purposes of + // disassembly during normal crash processing, but not during exploitability + // analysis. bool enable_objdump_; + + // This flag permits the exploitability scanner to shell out to objdump for + // purposes of disassembly. This results in significantly more overhead than + // the enable_objdump_ flag. + bool enable_objdump_for_exploitability_; }; } // namespace google_breakpad diff --git a/src/processor/dump_context.cc b/src/processor/dump_context.cc index 93d826c4a..ab97930f9 100644 --- a/src/processor/dump_context.cc +++ b/src/processor/dump_context.cc @@ -776,24 +776,14 @@ void DumpContext::Print() { context_riscv->t6); #if defined(__riscv) - for (unsigned int freg_index = 0; - freg_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++freg_index) { - riscv_fpr_size fp_value = context_riscv->float_save.regs[freg_index]; -# if __riscv_flen == 32 - printf(" float_save.regs[%2d] = 0x%" PRIx32 "\n", - freg_index, fp_value); -# elif __riscv_flen == 64 - printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", - freg_index, fp_value); -# elif __riscv_flen == 128 - printf(" float_save.regs[%2d] = 0x%" PRIx64 "%" PRIx64 "\n", - freg_index, fp_value.high, fp_value.low); -# else -# error "Unexpected __riscv_flen" -# endif + for (unsigned int freg_index = 0; freg_index < MD_CONTEXT_RISCV_FPR_COUNT; + ++freg_index) { + // Breakpad only supports RISCV32 with 32 bit floating point. + uint32_t fp_value = context_riscv->fpregs[freg_index]; + printf(" fpregs[%2d] = 0x%" PRIx32 "\n", freg_index, + fp_value); } - printf(" float_save.fpcsr = 0x%" PRIx32 "\n", - context_riscv->float_save.fpcsr); + printf(" fcsr = 0x%" PRIx32 "\n", context_riscv->fcsr); #endif break; } @@ -870,25 +860,14 @@ void DumpContext::Print() { context_riscv64->t6); #if defined(__riscv) - for (unsigned int freg_index = 0; - freg_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++freg_index) { - riscv_fpr_size fp_value = context_riscv64->float_save.regs[freg_index]; -# if __riscv_flen == 32 - printf(" float_save.regs[%2d] = 0x%" PRIx32 "\n", - freg_index, fp_value); -# elif __riscv_flen == 64 - printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", - freg_index, fp_value); -# elif __riscv_flen == 128 - printf(" float_save.regs[%2d] = 0x%" - PRIx64 "%" PRIx64 "\n", - freg_index, fp_value.high, fp_value.low); -# else -# error "Unexpected __riscv_flen" -# endif + for (unsigned int freg_index = 0; freg_index < MD_CONTEXT_RISCV_FPR_COUNT; + ++freg_index) { + // Breakpad only supports RISCV64 with 64 bit floating point. + uint64_t fp_value = context_riscv64->fpregs[freg_index]; + printf(" fpregs[%2d] = 0x%" PRIx64 "\n", freg_index, + fp_value); } - printf(" float_save.fpcsr = 0x%" PRIx32 "\n", - context_riscv64->float_save.fpcsr); + printf(" fcsr = 0x%" PRIx32 "\n", context_riscv64->fcsr); #endif break; } diff --git a/src/processor/exploitability_unittest.cc b/src/processor/exploitability_unittest.cc index 5f8cee0ac..09e4690d5 100644 --- a/src/processor/exploitability_unittest.cc +++ b/src/processor/exploitability_unittest.cc @@ -84,7 +84,7 @@ ExploitabilityFor(const string& filename) { SimpleSymbolSupplier supplier(TestDataDir() + "/symbols"); BasicSourceLineResolver resolver; MinidumpProcessor processor(&supplier, &resolver, true); - processor.set_enable_objdump(true); + processor.set_enable_objdump_for_exploitability(true); ProcessState state; string minidump_file = TestDataDir() + "/" + filename; diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 45e4a5246..83f72b97b 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -1259,12 +1259,11 @@ bool MinidumpContext::Read(uint32_t expected_size) { Swap(&context_riscv->t5); Swap(&context_riscv->t6); - for (int fpr_index = 0; - fpr_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; + for (int fpr_index = 0; fpr_index < MD_CONTEXT_RISCV_FPR_COUNT; ++fpr_index) { - Swap(&context_riscv->float_save.regs[fpr_index]); + Swap(&context_riscv->fpregs[fpr_index]); } - Swap(&context_riscv->float_save.fpcsr); + Swap(&context_riscv->fcsr); } SetContextRISCV(context_riscv.release()); @@ -1338,12 +1337,11 @@ bool MinidumpContext::Read(uint32_t expected_size) { Swap(&context_riscv64->t5); Swap(&context_riscv64->t6); - for (int fpr_index = 0; - fpr_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; + for (int fpr_index = 0; fpr_index < MD_CONTEXT_RISCV_FPR_COUNT; ++fpr_index) { - Swap(&context_riscv64->float_save.regs[fpr_index]); + Swap(&context_riscv64->fpregs[fpr_index]); } - Swap(&context_riscv64->float_save.fpcsr); + Swap(&context_riscv64->fcsr); } SetContextRISCV64(context_riscv64.release()); @@ -5505,7 +5503,7 @@ void MinidumpCrashpadInfo::Print() { // Value represents something else. char buffer[3]; for (const uint8_t& v : annot.value) { - snprintf(buffer, sizeof(buffer), "%X", v); + snprintf(buffer, sizeof(buffer), "%02X", v); str_value.append(buffer); } } diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index 5ba6ff4f8..5d2dea6d8 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -63,7 +63,8 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), own_frame_symbolizer_(true), enable_exploitability_(false), - enable_objdump_(false) { + enable_objdump_(false), + enable_objdump_for_exploitability_(false) { } MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, @@ -72,7 +73,8 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), own_frame_symbolizer_(true), enable_exploitability_(enable_exploitability), - enable_objdump_(false) { + enable_objdump_(false), + enable_objdump_for_exploitability_(false) { } MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer, @@ -80,7 +82,8 @@ MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer, : frame_symbolizer_(frame_symbolizer), own_frame_symbolizer_(false), enable_exploitability_(enable_exploitability), - enable_objdump_(false) { + enable_objdump_(false), + enable_objdump_for_exploitability_(false) { assert(frame_symbolizer_); } @@ -375,9 +378,8 @@ ProcessResult MinidumpProcessor::Process( // rating. if (enable_exploitability_) { scoped_ptr exploitability( - Exploitability::ExploitabilityForPlatform(dump, - process_state, - enable_objdump_)); + Exploitability::ExploitabilityForPlatform( + dump, process_state, enable_objdump_for_exploitability_)); // The engine will be null if the platform is not supported if (exploitability != NULL) { process_state->exploitability_ = exploitability->CheckExploitability(); @@ -1796,6 +1798,21 @@ string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address, case MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR: reason.append("SEGV_PKUERR"); break; + case MD_EXCEPTION_FLAG_LIN_SEGV_ACCADI: + reason.append("SEGV_ACCADI"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_ADIDERR: + reason.append("SEGV_ADIDERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_ADIPERR: + reason.append("SEGV_ADIPERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_MTEAERR: + reason.append("SEGV_MTEAERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_MTESERR: + reason.append("SEGV_MTESERR"); + break; default: reason.append(flags_string); BPLOG(INFO) << "Unknown exception reason " << reason; diff --git a/src/processor/stackwalker_address_list.h b/src/processor/stackwalker_address_list.h index 28d377c3e..d27f3fb2d 100644 --- a/src/processor/stackwalker_address_list.h +++ b/src/processor/stackwalker_address_list.h @@ -36,7 +36,6 @@ #ifndef PROCESSOR_STACKWALKER_ADDRESS_LIST_H_ #define PROCESSOR_STACKWALKER_ADDRESS_LIST_H_ -#include "common/basictypes.h" #include "google_breakpad/common/breakpad_types.h" #include "google_breakpad/processor/stackwalker.h" @@ -53,6 +52,8 @@ class StackwalkerAddressList : public Stackwalker { size_t frame_count, const CodeModules* modules, StackFrameSymbolizer* frame_symbolizer); + StackwalkerAddressList(const StackwalkerAddressList&) = delete; + void operator=(const StackwalkerAddressList&) = delete; private: // Implementation of Stackwalker. @@ -62,8 +63,6 @@ class StackwalkerAddressList : public Stackwalker { const uint64_t* frames_; size_t frame_count_; - - DISALLOW_COPY_AND_ASSIGN(StackwalkerAddressList); }; } // namespace google_breakpad diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc index 9c09835fe..0fa02e04f 100644 --- a/src/processor/stackwalker_arm64.cc +++ b/src/processor/stackwalker_arm64.cc @@ -267,15 +267,25 @@ void StackwalkerARM64::CorrectRegLRByFramePointer( last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]) return; - StackFrameARM64* last_last_frame = - static_cast(*(frames.end() - 2)); - uint64_t last_last_fp = - last_last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP]; + // Searching for a real callee frame. Skipping inline frames since they + // don't contain context (and cannot be downcasted to StackFrameARM64). + size_t last_frame_callee_id = frames.size() - 2; + while (last_frame_callee_id >= 0 && frames[last_frame_callee_id]->trust == + StackFrame::FRAME_TRUST_INLINE) { + last_frame_callee_id--; + } + if (last_frame_callee_id < 0) return; + StackFrameARM64* last_frame_callee = + static_cast(frames[last_frame_callee_id]); + + uint64_t last_frame_callee_fp = + last_frame_callee->context.iregs[MD_CONTEXT_ARM64_REG_FP]; uint64_t last_fp = 0; - if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp, &last_fp)) { - BPLOG(ERROR) << "Unable to read last_fp from last_last_fp: 0x" - << std::hex << last_last_fp; + if (last_frame_callee_fp && + !memory_->GetMemoryAtAddress(last_frame_callee_fp, &last_fp)) { + BPLOG(ERROR) << "Unable to read last_fp from last_last_fp: 0x" << std::hex + << last_frame_callee_fp; return; } // Give up if STACK CFI doesn't agree with frame pointer. @@ -283,9 +293,10 @@ void StackwalkerARM64::CorrectRegLRByFramePointer( return; uint64_t last_lr = 0; - if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp + 8, &last_lr)) { + if (last_frame_callee_fp && + !memory_->GetMemoryAtAddress(last_frame_callee_fp + 8, &last_lr)) { BPLOG(ERROR) << "Unable to read last_lr from (last_last_fp + 8): 0x" - << std::hex << (last_last_fp + 8); + << std::hex << (last_frame_callee_fp + 8); return; } last_lr = PtrauthStrip(last_lr); diff --git a/src/third_party/libdisasm/x86_format.c b/src/third_party/libdisasm/x86_format.c index 0ec960dc8..bb547ad4c 100644 --- a/src/third_party/libdisasm/x86_format.c +++ b/src/third_party/libdisasm/x86_format.c @@ -29,7 +29,7 @@ } while( 0 ) #define STRNCATF( buf, fmt, data, len ) do { \ - char _tmp[MAX_OP_STRING]; \ + char _tmp[MAX_OP_XML_STRING]; \ \ snprintf( _tmp, sizeof _tmp, fmt, data ); \ STRNCAT( buf, _tmp, len ); \ diff --git a/src/tools/linux/md2core/minidump-2-core.cc b/src/tools/linux/md2core/minidump-2-core.cc index 9d5e5e3f9..3e310bc7d 100644 --- a/src/tools/linux/md2core/minidump-2-core.cc +++ b/src/tools/linux/md2core/minidump-2-core.cc @@ -583,25 +583,21 @@ ParseThreadRegisters(CrashedProcess::Thread* thread, thread->mcontext.__gregs[30] = rawregs->t5; thread->mcontext.__gregs[31] = rawregs->t6; -# if __riscv_flen == 32 - for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { - thread->mcontext.__fpregs.__f.__f[i] = rawregs->float_save.regs[i]; + // Breakpad only supports RISCV32 with 32 bit floating point. + // Breakpad only supports RISCV64 with 64 bit floating point. +#if __riscv_xlen == 32 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__f.__f[i] = rawregs->fpregs[i]; } - thread->mcontext.__fpregs.__f.__fcsr = rawregs->float_save.fpcsr; -# elif __riscv_flen == 64 - for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { - thread->mcontext.__fpregs.__d.__f[i] = rawregs->float_save.regs[i]; + thread->mcontext.__fpregs.__f.__fcsr = rawregs->fcsr; +#elif __riscv_xlen == 64 + for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__d.__f[i] = rawregs->fpregs[i]; } - thread->mcontext.__fpregs.__d.__fcsr = rawregs->float_save.fpcsr; -# elif __riscv_flen == 128 - for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { - thread->mcontext.__fpregs.__q.__f[2*i] = rawregs->float_save.regs[i].high; - thread->mcontext.__fpregs.__q.__f[2*i+1] = rawregs->float_save.regs[i].low; - } - thread->mcontext.__fpregs.__q.__fcsr = rawregs->float_save.fpcsr; -# else -# error "Unexpected __riscv_flen" -# endif + thread->mcontext.__fpregs.__d.__fcsr = rawregs->fcsr; +#else +#error "Unexpected __riscv_xlen" +#endif } #else #error "This code has not been ported to your platform yet" diff --git a/src/tools/mac/upload_system_symbols/upload_system_symbols.go b/src/tools/mac/upload_system_symbols/upload_system_symbols.go index ba0672763..f34c288ae 100644 --- a/src/tools/mac/upload_system_symbols/upload_system_symbols.go +++ b/src/tools/mac/upload_system_symbols/upload_system_symbols.go @@ -163,6 +163,29 @@ func main() { } } +// manglePath reduces an absolute filesystem path to a string suitable as the +// base for a file name which encodes some of the original path. The result +// concatenates the leading initial from each path component except the last to +// the last path component; for example /System/Library/Frameworks/AppKit +// becomes SLFAppKit. +// Assumes ASCII. +func manglePath(path string) string { + components := strings.Split(path, "/") + n := len(components) + builder := strings.Builder{} + for i, component := range components { + if len(component) == 0 { + continue + } + if i < n-1 { + builder.WriteString(component[:1]) + } else { + builder.WriteString(component) + } + } + return builder.String() +} + type WorkerPool struct { wg sync.WaitGroup } @@ -296,7 +319,7 @@ func (dq *DumpQueue) worker() { dumpSyms := path.Join(*breakpadTools, "dump_syms") for req := range dq.queue { - filebase := path.Join(dq.dumpPath, strings.Replace(req.path, "/", "_", -1)) + filebase := path.Join(dq.dumpPath, manglePath(req.path)) symfile := fmt.Sprintf("%s_%s.sym", filebase, req.arch) f, err := os.Create(symfile) if err != nil { diff --git a/src/tools/python/deps-to-manifest.py b/src/tools/python/deps-to-manifest.py index 2fcaf7717..b614f94fd 100755 --- a/src/tools/python/deps-to-manifest.py +++ b/src/tools/python/deps-to-manifest.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # Copyright 2016 Google LLC # # Redistribution and use in source and binary forms, with or without @@ -29,8 +29,6 @@ """Convert gclient's DEPS file to repo's manifest xml file.""" -from __future__ import print_function - import argparse import os import sys @@ -76,7 +74,8 @@ def ConvertDepsToManifest(deps, manifest): """Convert the |deps| file to the |manifest|.""" # Load the DEPS file data. ctx = {} - execfile(deps, ctx) + with open(deps, 'rb') as file: + exec(compile(file.read(), deps, 'exec'), ctx) new_contents = '' diff --git a/src/tools/python/filter_syms.py b/src/tools/python/filter_syms.py index caf3693a5..8537769e9 100644 --- a/src/tools/python/filter_syms.py +++ b/src/tools/python/filter_syms.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2012 Google LLC # # Redistribution and use in source and binary forms, with or without @@ -38,7 +38,6 @@ updating any references to the FILE records in the other record types. """ -import macpath import ntpath import optparse import os @@ -132,8 +131,8 @@ def _AdjustPath(self, path): Returns: The actual path to use when writing the FILE record. """ - return path[len(filter(path.startswith, - self.ignored_prefixes + [''])[0]):] + return path[len(next(filter(path.startswith, + self.ignored_prefixes + ['']))):] def _ParseFileRecord(self, file_record): """Parses and corrects a FILE record.""" @@ -193,7 +192,7 @@ def main(): symbol_parser = SymbolFileParser(sys.stdin, sys.stdout, options.prefixes, path_handler) symbol_parser.Process() - except BreakpadParseError, e: + except BreakpadParseError as e: print >> sys.stderr, 'Got an error while processing symbol file' print >> sys.stderr, str(e) return 1 diff --git a/src/tools/python/tests/filter_syms_unittest.py b/src/tools/python/tests/filter_syms_unittest.py index 1081fc731..f6364b8b3 100644 --- a/src/tools/python/tests/filter_syms_unittest.py +++ b/src/tools/python/tests/filter_syms_unittest.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2012 Google LLC # # Redistribution and use in source and binary forms, with or without @@ -29,10 +29,9 @@ """Unit tests for filter_syms.py""" -import cStringIO +import io import ntpath import os -import StringIO import sys import unittest @@ -44,8 +43,8 @@ class FilterSysmsTest(unittest.TestCase): def assertParsed(self, input_data, ignored_prefixes, expected): - input_io = cStringIO.StringIO(input_data) - output_io = cStringIO.StringIO() + input_io = io.StringIO(input_data) + output_io = io.StringIO() parser = filter_syms.SymbolFileParser(input_io, output_io, ignored_prefixes, ntpath) parser.Process() @@ -134,4 +133,4 @@ def testIgnoredPrefixesDuplicateFiles(self): self.assertParsed(INPUT, IGNORED_PREFIXES, EXPECTED_OUTPUT) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main()