зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1440282 - Update breakpad to revision 1459e5df74dd03b7d3d473e6d271413d7aa98a88 r=ted
This adds support for the DW_AT_ranges attribute when dumping out symbols and adds basic support for AArch64 (64-bit ARM) on Windows in the minidump processor. Differential Revision: https://phabricator.services.mozilla.com/D3443 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
3d5b81aef3
Коммит
5d2f9f8da7
|
@ -41,7 +41,7 @@ typedef MDRawContextAMD64 RawContextCPU;
|
|||
#elif defined(__ARM_EABI__)
|
||||
typedef MDRawContextARM RawContextCPU;
|
||||
#elif defined(__aarch64__)
|
||||
typedef MDRawContextARM64 RawContextCPU;
|
||||
typedef MDRawContextARM64_Old RawContextCPU;
|
||||
#elif defined(__mips__)
|
||||
typedef MDRawContextMIPS RawContextCPU;
|
||||
#else
|
||||
|
|
|
@ -214,7 +214,7 @@ uintptr_t ThreadInfo::GetInstructionPointer() const {
|
|||
}
|
||||
|
||||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
||||
out->context_flags = MD_CONTEXT_ARM64_FULL;
|
||||
out->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
|
||||
|
||||
out->cpsr = static_cast<uint32_t>(regs.pstate);
|
||||
for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
|
||||
|
|
|
@ -194,7 +194,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
|
|||
|
||||
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
|
||||
const struct fpsimd_context* fpregs) {
|
||||
out->context_flags = MD_CONTEXT_ARM64_FULL;
|
||||
out->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
|
||||
|
||||
out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate);
|
||||
for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
|
||||
|
|
|
@ -1041,7 +1041,7 @@ class MinidumpWriter {
|
|||
// processor_architecture should always be set, do this first
|
||||
sys_info->processor_architecture =
|
||||
#if defined(__aarch64__)
|
||||
MD_CPU_ARCHITECTURE_ARM64;
|
||||
MD_CPU_ARCHITECTURE_ARM64_OLD;
|
||||
#else
|
||||
MD_CPU_ARCHITECTURE_ARM;
|
||||
#endif
|
||||
|
|
|
@ -545,7 +545,7 @@ bool
|
|||
MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state,
|
||||
MDLocationDescriptor *register_location)
|
||||
{
|
||||
TypedMDRVA<MDRawContextARM64> context(&writer_);
|
||||
TypedMDRVA<MDRawContextARM64_Old> context(&writer_);
|
||||
arm_thread_state64_t *machine_state =
|
||||
reinterpret_cast<arm_thread_state64_t *>(state);
|
||||
|
||||
|
@ -553,8 +553,8 @@ MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state,
|
|||
return false;
|
||||
|
||||
*register_location = context.location();
|
||||
MDRawContextARM64 *context_ptr = context.get();
|
||||
context_ptr->context_flags = MD_CONTEXT_ARM64_FULL;
|
||||
MDRawContextARM64_Old *context_ptr = context.get();
|
||||
context_ptr->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
|
||||
|
||||
#define AddGPR(a) context_ptr->iregs[a] = \
|
||||
REGISTER_FROM_THREADSTATE(machine_state, x[a])
|
||||
|
@ -1191,7 +1191,7 @@ bool MinidumpGenerator::WriteSystemInfoStream(
|
|||
#endif
|
||||
#ifdef HAS_ARM64_SUPPORT
|
||||
case CPU_TYPE_ARM64:
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64;
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64_OLD;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_PPC_SUPPORT
|
||||
|
|
|
@ -51,7 +51,7 @@ deps = {
|
|||
# Linux syscall support.
|
||||
"src/src/third_party/lss":
|
||||
"https://chromium.googlesource.com/linux-syscall-support/" +
|
||||
"@e6527b0cd469e3ff5764785dadcb39bf7d787154",
|
||||
"@a89bf7903f3169e6bc7b8efc10a73a7571de21cf",
|
||||
}
|
||||
|
||||
hooks = [
|
||||
|
|
|
@ -1 +1 @@
|
|||
69c2c51dd89965d234eec16e3a9353634831916b
|
||||
1459e5df74dd03b7d3d473e6d271413d7aa98a88
|
||||
|
|
|
@ -233,6 +233,8 @@ src_libbreakpad_a_SOURCES = \
|
|||
src/processor/cfi_frame_info.h \
|
||||
src/processor/contained_range_map-inl.h \
|
||||
src/processor/contained_range_map.h \
|
||||
src/processor/convert_old_arm64_context.cc \
|
||||
src/processor/convert_old_arm64_context.h \
|
||||
src/processor/disassembler_x86.h \
|
||||
src/processor/disassembler_x86.cc \
|
||||
src/processor/dump_context.cc \
|
||||
|
@ -487,6 +489,7 @@ src_client_linux_linux_client_unittest_shlib_SOURCES = \
|
|||
src/common/tests/file_utils.cc \
|
||||
src/common/tests/file_utils.h \
|
||||
src/processor/basic_code_modules.cc \
|
||||
src/processor/convert_old_arm64_context.cc \
|
||||
src/processor/dump_context.cc \
|
||||
src/processor/dump_object.cc \
|
||||
src/processor/logging.cc \
|
||||
|
@ -571,6 +574,7 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \
|
|||
src/common/dwarf_cfi_to_module.cc \
|
||||
src/common/dwarf_cu_to_module.cc \
|
||||
src/common/dwarf_line_to_module.cc \
|
||||
src/common/dwarf_range_list_handler.cc \
|
||||
src/common/language.cc \
|
||||
src/common/module.cc \
|
||||
src/common/path_helper.cc \
|
||||
|
@ -619,6 +623,7 @@ src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \
|
|||
src/common/dwarf_cfi_to_module.cc \
|
||||
src/common/dwarf_cu_to_module.cc \
|
||||
src/common/dwarf_line_to_module.cc \
|
||||
src/common/dwarf_range_list_handler.cc \
|
||||
src/common/language.cc \
|
||||
src/common/md5.cc \
|
||||
src/common/module.cc \
|
||||
|
@ -658,6 +663,7 @@ src_common_dumper_unittest_SOURCES = \
|
|||
src/common/dwarf_cu_to_module_unittest.cc \
|
||||
src/common/dwarf_line_to_module.cc \
|
||||
src/common/dwarf_line_to_module_unittest.cc \
|
||||
src/common/dwarf_range_list_handler.cc \
|
||||
src/common/language.cc \
|
||||
src/common/memory_range_unittest.cc \
|
||||
src/common/module.cc \
|
||||
|
@ -811,6 +817,7 @@ src_processor_exploitability_unittest_SOURCES = \
|
|||
src_processor_exploitability_unittest_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) $(TEST_CFLAGS)
|
||||
src_processor_exploitability_unittest_LDADD = \
|
||||
src/processor/convert_old_arm64_context.o \
|
||||
src/processor/minidump_processor.o \
|
||||
src/processor/process_state.o \
|
||||
src/processor/disassembler_x86.o \
|
||||
|
@ -892,6 +899,7 @@ src_processor_microdump_processor_unittest_LDADD = \
|
|||
src/processor/basic_code_modules.o \
|
||||
src/processor/basic_source_line_resolver.o \
|
||||
src/processor/call_stack.o \
|
||||
src/processor/convert_old_arm64_context.o \
|
||||
src/processor/cfi_frame_info.o \
|
||||
src/processor/dump_context.o \
|
||||
src/processor/dump_object.o \
|
||||
|
@ -926,6 +934,7 @@ src_processor_minidump_processor_unittest_LDADD = \
|
|||
src/processor/basic_source_line_resolver.o \
|
||||
src/processor/call_stack.o \
|
||||
src/processor/cfi_frame_info.o \
|
||||
src/processor/convert_old_arm64_context.o \
|
||||
src/processor/disassembler_x86.o \
|
||||
src/processor/dump_context.o \
|
||||
src/processor/dump_object.o \
|
||||
|
@ -965,6 +974,7 @@ src_processor_minidump_unittest_CPPFLAGS = \
|
|||
$(AM_CPPFLAGS) $(TEST_CFLAGS)
|
||||
src_processor_minidump_unittest_LDADD = \
|
||||
src/processor/basic_code_modules.o \
|
||||
src/processor/convert_old_arm64_context.o \
|
||||
src/processor/dump_context.o \
|
||||
src/processor/dump_object.o \
|
||||
src/processor/logging.o \
|
||||
|
@ -1186,6 +1196,7 @@ src_processor_minidump_dump_SOURCES = \
|
|||
src/processor/minidump_dump.cc
|
||||
src_processor_minidump_dump_LDADD = \
|
||||
src/processor/basic_code_modules.o \
|
||||
src/processor/convert_old_arm64_context.o \
|
||||
src/processor/dump_context.o \
|
||||
src/processor/dump_object.o \
|
||||
src/processor/logging.o \
|
||||
|
@ -1200,6 +1211,7 @@ src_processor_microdump_stackwalk_LDADD = \
|
|||
src/processor/basic_code_modules.o \
|
||||
src/processor/basic_source_line_resolver.o \
|
||||
src/processor/call_stack.o \
|
||||
src/processor/convert_old_arm64_context.o \
|
||||
src/processor/cfi_frame_info.o \
|
||||
src/processor/disassembler_x86.o \
|
||||
src/processor/dump_context.o \
|
||||
|
@ -1235,6 +1247,7 @@ src_processor_minidump_stackwalk_LDADD = \
|
|||
src/processor/basic_source_line_resolver.o \
|
||||
src/processor/call_stack.o \
|
||||
src/processor/cfi_frame_info.o \
|
||||
src/processor/convert_old_arm64_context.o \
|
||||
src/processor/disassembler_x86.o \
|
||||
src/processor/dump_context.o \
|
||||
src/processor/dump_object.o \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# generated automatically by aclocal 1.15 -*- Autoconf -*-
|
||||
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -20,7 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to.
|
|||
If you have problems, you may need to regenerate the build system entirely.
|
||||
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
|
||||
|
||||
# Copyright (C) 2002-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2002-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -35,7 +35,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
|
|||
[am__api_version='1.15'
|
||||
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
|
||||
dnl require some minimum version. Point them to the right macro.
|
||||
m4_if([$1], [1.15], [],
|
||||
m4_if([$1], [1.15.1], [],
|
||||
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
|
||||
])
|
||||
|
||||
|
@ -51,12 +51,12 @@ m4_define([_AM_AUTOCONF_VERSION], [])
|
|||
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
|
||||
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.15])dnl
|
||||
[AM_AUTOMAKE_VERSION([1.15.1])dnl
|
||||
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
|
||||
|
||||
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2011-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -118,7 +118,7 @@ AC_SUBST([AR])dnl
|
|||
|
||||
# Figure out how to run the assembler. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -138,7 +138,7 @@ _AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl
|
|||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -190,7 +190,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd`
|
|||
|
||||
# AM_CONDITIONAL -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1997-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -221,7 +221,7 @@ AC_CONFIG_COMMANDS_PRE(
|
|||
Usually this means the macro was only invoked conditionally.]])
|
||||
fi])])
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1999-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -412,7 +412,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
|
|||
|
||||
# Generate code to set up dependency tracking. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1999-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -488,7 +488,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
|
|||
|
||||
# Do all the work for Automake. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -685,7 +685,7 @@ for _am_header in $config_headers :; do
|
|||
done
|
||||
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -706,7 +706,7 @@ if test x"${install_sh+set}" != xset; then
|
|||
fi
|
||||
AC_SUBST([install_sh])])
|
||||
|
||||
# Copyright (C) 2003-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2003-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -728,7 +728,7 @@ AC_SUBST([am__leading_dot])])
|
|||
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
|
||||
# From Jim Meyering
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -763,7 +763,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
|
|||
|
||||
# Check to see how 'make' treats includes. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -813,7 +813,7 @@ rm -f confinc confmf
|
|||
|
||||
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1997-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -854,7 +854,7 @@ fi
|
|||
# Obsolete and "removed" macros, that must however still report explicit
|
||||
# error messages when used, to smooth transition.
|
||||
#
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -881,7 +881,7 @@ AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES])
|
|||
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -910,7 +910,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
|
|||
AC_DEFUN([_AM_IF_OPTION],
|
||||
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1999-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -957,7 +957,7 @@ AC_LANG_POP([C])])
|
|||
# For backward compatibility.
|
||||
AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -976,7 +976,7 @@ AC_DEFUN([AM_RUN_LOG],
|
|||
|
||||
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -1057,7 +1057,7 @@ AC_CONFIG_COMMANDS_PRE(
|
|||
rm -f conftest.file
|
||||
])
|
||||
|
||||
# Copyright (C) 2009-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2009-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -1117,7 +1117,7 @@ AC_SUBST([AM_BACKSLASH])dnl
|
|||
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
|
||||
])
|
||||
|
||||
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -1145,7 +1145,7 @@ fi
|
|||
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
|
||||
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||
|
||||
# Copyright (C) 2006-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2006-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
@ -1164,7 +1164,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
|
|||
|
||||
# Check how to create a tarball. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2004-2014 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2004-2017 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
|
|
|
@ -6098,7 +6098,7 @@ else
|
|||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
|
@ -6144,7 +6144,7 @@ else
|
|||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
|
@ -6168,7 +6168,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
|||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
|
@ -6213,7 +6213,7 @@ else
|
|||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
|
@ -6237,7 +6237,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
|||
We can't simply define LARGE_OFF_T to be 9223372036854775807,
|
||||
since some C++ compilers masquerading as C compilers
|
||||
incorrectly reject 9223372036854775807. */
|
||||
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
|
||||
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
|
||||
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
|
||||
&& LARGE_OFF_T % 2147483647 == 1)
|
||||
? 1 : -1];
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
<project path='src/src/third_party/lss'
|
||||
name='linux-syscall-support/'
|
||||
revision='e6527b0cd469e3ff5764785dadcb39bf7d787154'
|
||||
revision='a89bf7903f3169e6bc7b8efc10a73a7571de21cf'
|
||||
remote='chromium' />
|
||||
|
||||
<project path='src/src/third_party/protobuf/protobuf'
|
||||
|
|
|
@ -1247,6 +1247,41 @@ void LineInfo::ReadLines() {
|
|||
after_header_ = lengthstart + header_.total_length;
|
||||
}
|
||||
|
||||
RangeListReader::RangeListReader(const uint8_t *buffer, uint64 size,
|
||||
ByteReader *reader, RangeListHandler *handler)
|
||||
: buffer_(buffer), size_(size), reader_(reader), handler_(handler) { }
|
||||
|
||||
bool RangeListReader::ReadRangeList(uint64 offset) {
|
||||
const uint64 max_address =
|
||||
(reader_->AddressSize() == 4) ? 0xffffffffUL
|
||||
: 0xffffffffffffffffULL;
|
||||
const uint64 entry_size = reader_->AddressSize() * 2;
|
||||
bool list_end = false;
|
||||
|
||||
do {
|
||||
if (offset > size_ - entry_size) {
|
||||
return false; // Invalid range detected
|
||||
}
|
||||
|
||||
uint64 start_address = reader_->ReadAddress(buffer_ + offset);
|
||||
uint64 end_address =
|
||||
reader_->ReadAddress(buffer_ + offset + reader_->AddressSize());
|
||||
|
||||
if (start_address == max_address) { // Base address selection
|
||||
handler_->SetBaseAddress(end_address);
|
||||
} else if (start_address == 0 && end_address == 0) { // End-of-list
|
||||
handler_->Finish();
|
||||
list_end = true;
|
||||
} else { // Add a range entry
|
||||
handler_->AddRange(start_address, end_address);
|
||||
}
|
||||
|
||||
offset += entry_size;
|
||||
} while (!list_end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// A DWARF rule for recovering the address or value of a register, or
|
||||
// computing the canonical frame address. There is one subclass of this for
|
||||
// each '*Rule' member function in CallFrameInfo::Handler.
|
||||
|
|
|
@ -187,6 +187,36 @@ class LineInfoHandler {
|
|||
uint32 file_num, uint32 line_num, uint32 column_num) { }
|
||||
};
|
||||
|
||||
class RangeListHandler {
|
||||
public:
|
||||
RangeListHandler() { }
|
||||
|
||||
virtual ~RangeListHandler() { }
|
||||
|
||||
// Add a range.
|
||||
virtual void AddRange(uint64 begin, uint64 end) { };
|
||||
|
||||
// A new base address must be set for computing the ranges' addresses.
|
||||
virtual void SetBaseAddress(uint64 base_address) { };
|
||||
|
||||
// Finish processing the range list.
|
||||
virtual void Finish() { };
|
||||
};
|
||||
|
||||
class RangeListReader {
|
||||
public:
|
||||
RangeListReader(const uint8_t *buffer, uint64 size, ByteReader *reader,
|
||||
RangeListHandler *handler);
|
||||
|
||||
bool ReadRangeList(uint64 offset);
|
||||
|
||||
private:
|
||||
const uint8_t *buffer_;
|
||||
uint64 size_;
|
||||
ByteReader* reader_;
|
||||
RangeListHandler *handler_;
|
||||
};
|
||||
|
||||
// This class is the main interface between the reader and the
|
||||
// client. The virtual functions inside this get called for
|
||||
// interesting events that happen during DWARF2 reading.
|
||||
|
|
|
@ -184,6 +184,9 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset,
|
|||
case DW_AT_decl_file:
|
||||
current_function_info_->file = files_->at(data).name;
|
||||
break;
|
||||
case DW_AT_ranges:
|
||||
current_function_info_->ranges = data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ struct FunctionInfo {
|
|||
uint64 lowpc;
|
||||
// End address for this function.
|
||||
uint64 highpc;
|
||||
// Ranges offset
|
||||
uint64 ranges;
|
||||
};
|
||||
|
||||
struct SourceFileInfo {
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
|
@ -51,6 +52,7 @@
|
|||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::accumulate;
|
||||
using std::map;
|
||||
using std::pair;
|
||||
using std::sort;
|
||||
|
@ -167,10 +169,15 @@ 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)
|
||||
CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg,
|
||||
RangesHandler *ranges_handler_arg)
|
||||
: file_context(file_context_arg),
|
||||
reporter(reporter_arg),
|
||||
language(Language::CPlusPlus) {}
|
||||
ranges_handler(ranges_handler_arg),
|
||||
language(Language::CPlusPlus),
|
||||
low_pc(0),
|
||||
high_pc(0),
|
||||
ranges(0) {}
|
||||
|
||||
~CUContext() {
|
||||
for (vector<Module::Function *>::iterator it = functions.begin();
|
||||
|
@ -185,9 +192,19 @@ struct DwarfCUToModule::CUContext {
|
|||
// For printing error messages.
|
||||
WarningReporter *reporter;
|
||||
|
||||
// For reading ranges from the .debug_ranges section
|
||||
RangesHandler *ranges_handler;
|
||||
|
||||
// The source language of this compilation unit.
|
||||
const Language *language;
|
||||
|
||||
// Addresses covered by this CU. If high_pc_ is non-zero then the CU covers
|
||||
// low_pc to high_pc, otherwise ranges is non-zero and low_pc represents
|
||||
// the base address of the ranges covered by the CU.
|
||||
uint64 low_pc;
|
||||
uint64 high_pc;
|
||||
uint64 ranges;
|
||||
|
||||
// The functions defined in this compilation unit. We accumulate
|
||||
// them here during parsing. Then, in DwarfCUToModule::Finish, we
|
||||
// assign them lines and add them to file_context->module.
|
||||
|
@ -445,7 +462,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
|
|||
uint64 offset)
|
||||
: GenericDIEHandler(cu_context, parent_context, offset),
|
||||
low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr),
|
||||
abstract_origin_(NULL), inline_(false) { }
|
||||
ranges_(0), abstract_origin_(NULL), inline_(false) { }
|
||||
void ProcessAttributeUnsigned(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 data);
|
||||
|
@ -465,6 +482,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
|
|||
string name_;
|
||||
uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc
|
||||
DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address.
|
||||
uint64 ranges_; // DW_AT_ranges
|
||||
const AbstractOrigin* abstract_origin_;
|
||||
bool inline_;
|
||||
};
|
||||
|
@ -484,6 +502,9 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned(
|
|||
high_pc_form_ = form;
|
||||
high_pc_ = data;
|
||||
break;
|
||||
case dwarf2reader::DW_AT_ranges:
|
||||
ranges_ = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data);
|
||||
|
@ -537,17 +558,48 @@ bool DwarfCUToModule::FuncHandler::EndAttributes() {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool IsEmptyRange(const vector<Module::Range>& ranges) {
|
||||
uint64 size = accumulate(ranges.cbegin(), ranges.cend(), 0,
|
||||
[](uint64 total, Module::Range entry) {
|
||||
return total + entry.size;
|
||||
}
|
||||
);
|
||||
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
void DwarfCUToModule::FuncHandler::Finish() {
|
||||
// Make high_pc_ an address, if it isn't already.
|
||||
if (high_pc_form_ != dwarf2reader::DW_FORM_addr) {
|
||||
high_pc_ += low_pc_;
|
||||
vector<Module::Range> ranges;
|
||||
|
||||
if (!ranges_) {
|
||||
// Make high_pc_ an address, if it isn't already.
|
||||
if (high_pc_form_ != dwarf2reader::DW_FORM_addr &&
|
||||
high_pc_form_ != dwarf2reader::DW_FORM_GNU_addr_index) {
|
||||
high_pc_ += low_pc_;
|
||||
}
|
||||
|
||||
Module::Range range(low_pc_, high_pc_ - low_pc_);
|
||||
ranges.push_back(range);
|
||||
} else {
|
||||
RangesHandler *ranges_handler = cu_context_->ranges_handler;
|
||||
|
||||
if (ranges_handler) {
|
||||
if (!ranges_handler->ReadRanges(ranges_, cu_context_->low_pc, &ranges)) {
|
||||
ranges.clear();
|
||||
cu_context_->reporter->MalformedRangeList(ranges_);
|
||||
}
|
||||
} else {
|
||||
cu_context_->reporter->MissingRanges();
|
||||
}
|
||||
}
|
||||
|
||||
// Did we collect the information we need? Not all DWARF function
|
||||
// entries have low and high addresses (for example, inlined
|
||||
// functions that were never used), but all the ones we're
|
||||
// interested in cover a non-empty range of bytes.
|
||||
if (low_pc_ < high_pc_) {
|
||||
// entries are non-empty (for example, inlined functions that were never
|
||||
// used), but all the ones we're interested in cover a non-empty range of
|
||||
// bytes.
|
||||
if (!IsEmptyRange(ranges)) {
|
||||
low_pc_ = ranges.front().address;
|
||||
|
||||
// Malformed DWARF may omit the name, but all Module::Functions must
|
||||
// have names.
|
||||
string name;
|
||||
|
@ -561,7 +613,7 @@ void DwarfCUToModule::FuncHandler::Finish() {
|
|||
// Create a Module::Function based on the data we've gathered, and
|
||||
// add it to the functions_ list.
|
||||
scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
|
||||
func->size = high_pc_ - low_pc_;
|
||||
func->ranges = ranges;
|
||||
func->parameter_size = 0;
|
||||
if (func->address) {
|
||||
// If the function address is zero this is a sign that this function
|
||||
|
@ -663,7 +715,7 @@ void DwarfCUToModule::WarningReporter::UncoveredFunction(
|
|||
return;
|
||||
UncoveredHeading();
|
||||
fprintf(stderr, " function%s: %s\n",
|
||||
function.size == 0 ? " (zero-length)" : "",
|
||||
IsEmptyRange(function.ranges) ? " (zero-length)" : "",
|
||||
function.name.c_str());
|
||||
}
|
||||
|
||||
|
@ -697,11 +749,25 @@ void DwarfCUToModule::WarningReporter::UnhandledInterCUReference(
|
|||
filename_.c_str(), offset, target);
|
||||
}
|
||||
|
||||
void DwarfCUToModule::WarningReporter::MalformedRangeList(uint64 offset) {
|
||||
CUHeading();
|
||||
fprintf(stderr, "%s: warning: the range list at offset 0x%llx falls out of "
|
||||
"the .debug_ranges section.\n",
|
||||
filename_.c_str(), offset);
|
||||
}
|
||||
|
||||
void DwarfCUToModule::WarningReporter::MissingRanges() {
|
||||
CUHeading();
|
||||
fprintf(stderr, "%s: warning: A DW_AT_ranges attribute was encountered but "
|
||||
"the .debug_ranges section is missing.\n", filename_.c_str());
|
||||
}
|
||||
|
||||
DwarfCUToModule::DwarfCUToModule(FileContext *file_context,
|
||||
LineToModuleHandler *line_reader,
|
||||
RangesHandler *ranges_handler,
|
||||
WarningReporter *reporter)
|
||||
: line_reader_(line_reader),
|
||||
cu_context_(new CUContext(file_context, reporter)),
|
||||
cu_context_(new CUContext(file_context, reporter, ranges_handler)),
|
||||
child_context_(new DIEContext()),
|
||||
has_source_line_info_(false) {
|
||||
}
|
||||
|
@ -732,6 +798,16 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr,
|
|||
case dwarf2reader::DW_AT_language: // source language of this CU
|
||||
SetLanguage(static_cast<DwarfLanguage>(data));
|
||||
break;
|
||||
case dwarf2reader::DW_AT_low_pc:
|
||||
cu_context_->low_pc = data;
|
||||
break;
|
||||
case dwarf2reader::DW_AT_high_pc:
|
||||
cu_context_->high_pc = data;
|
||||
break;
|
||||
case dwarf2reader::DW_AT_ranges:
|
||||
cu_context_->ranges = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -841,6 +917,46 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
class FunctionRange {
|
||||
public:
|
||||
FunctionRange(const Module::Range &range, Module::Function *function) :
|
||||
address(range.address), size(range.size), function(function) { }
|
||||
|
||||
void AddLine(Module::Line &line) {
|
||||
function->lines.push_back(line);
|
||||
}
|
||||
|
||||
Module::Address address;
|
||||
Module::Address size;
|
||||
Module::Function *function;
|
||||
};
|
||||
|
||||
// Fills an array of ranges with pointers to the functions which owns them.
|
||||
// The array is sorted in ascending order and the ranges are non-overlapping.
|
||||
|
||||
static void FillSortedFunctionRanges(vector<FunctionRange> &dest_ranges,
|
||||
vector<Module::Function *> *functions) {
|
||||
for (vector<Module::Function *>::const_iterator func_it = functions->cbegin();
|
||||
func_it != functions->cend();
|
||||
func_it++)
|
||||
{
|
||||
Module::Function *func = *func_it;
|
||||
vector<Module::Range> &ranges = func->ranges;
|
||||
for (vector<Module::Range>::const_iterator ranges_it = ranges.cbegin();
|
||||
ranges_it != ranges.cend();
|
||||
++ranges_it) {
|
||||
FunctionRange range(*ranges_it, func);
|
||||
dest_ranges.push_back(range);
|
||||
}
|
||||
}
|
||||
|
||||
sort(dest_ranges.begin(), dest_ranges.end(),
|
||||
[](const FunctionRange &fr1, const FunctionRange &fr2) {
|
||||
return fr1.address < fr2.address;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Return true if ADDRESS falls within the range of ITEM.
|
||||
template <class T>
|
||||
inline bool within(const T &item, Module::Address address) {
|
||||
|
@ -880,47 +996,50 @@ void DwarfCUToModule::AssignLinesToFunctions() {
|
|||
const Module::Function *last_function_cited = NULL;
|
||||
const Module::Line *last_line_cited = NULL;
|
||||
|
||||
// Make a single pass through both vectors from lower to higher
|
||||
// addresses, populating each Function's lines vector with lines
|
||||
// from our lines_ vector that fall within the function's address
|
||||
// range.
|
||||
vector<Module::Function *>::iterator func_it = functions->begin();
|
||||
// Prepare a sorted list of ranges with range-to-function mapping
|
||||
vector<FunctionRange> sorted_ranges;
|
||||
FillSortedFunctionRanges(sorted_ranges, functions);
|
||||
|
||||
// Make a single pass through both the range and line vectors from lower to
|
||||
// higher addresses, populating each range's function lines vector with lines
|
||||
// from our lines_ vector that fall within the range.
|
||||
vector<FunctionRange>::iterator range_it = sorted_ranges.begin();
|
||||
vector<Module::Line>::const_iterator line_it = lines_.begin();
|
||||
|
||||
Module::Address current;
|
||||
|
||||
// Pointers to the referents of func_it and line_it, or NULL if the
|
||||
// iterator is at the end of the sequence.
|
||||
Module::Function *func;
|
||||
FunctionRange *range;
|
||||
const Module::Line *line;
|
||||
|
||||
// Start current at the beginning of the first line or function,
|
||||
// whichever is earlier.
|
||||
if (func_it != functions->end() && line_it != lines_.end()) {
|
||||
func = *func_it;
|
||||
if (range_it != sorted_ranges.end() && line_it != lines_.end()) {
|
||||
range = &*range_it;
|
||||
line = &*line_it;
|
||||
current = std::min(func->address, line->address);
|
||||
current = std::min(range->address, line->address);
|
||||
} else if (line_it != lines_.end()) {
|
||||
func = NULL;
|
||||
range = NULL;
|
||||
line = &*line_it;
|
||||
current = line->address;
|
||||
} else if (func_it != functions->end()) {
|
||||
func = *func_it;
|
||||
} else if (range_it != sorted_ranges.end()) {
|
||||
range = &*range_it;
|
||||
line = NULL;
|
||||
current = (*func_it)->address;
|
||||
current = range->address;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
while (func || line) {
|
||||
while (range || line) {
|
||||
// This loop has two invariants that hold at the top.
|
||||
//
|
||||
// First, at least one of the iterators is not at the end of its
|
||||
// sequence, and those that are not refer to the earliest
|
||||
// function or line that contains or starts after CURRENT.
|
||||
// range or line that contains or starts after CURRENT.
|
||||
//
|
||||
// Note that every byte is in one of four states: it is covered
|
||||
// or not covered by a function, and, independently, it is
|
||||
// or not covered by a range, and, independently, it is
|
||||
// covered or not covered by a line.
|
||||
//
|
||||
// The second invariant is that CURRENT refers to a byte whose
|
||||
|
@ -930,7 +1049,7 @@ void DwarfCUToModule::AssignLinesToFunctions() {
|
|||
//
|
||||
// Note that, although each iteration advances CURRENT from one
|
||||
// transition address to the next in each iteration, it might
|
||||
// not advance the iterators. Suppose we have a function that
|
||||
// not advance the iterators. Suppose we have a range that
|
||||
// starts with a line, has a gap, and then a second line, and
|
||||
// suppose that we enter an iteration with CURRENT at the end of
|
||||
// the first line. The next transition address is the start of
|
||||
|
@ -938,11 +1057,11 @@ void DwarfCUToModule::AssignLinesToFunctions() {
|
|||
// advance CURRENT to that point. At the head of that iteration,
|
||||
// the invariants require that the line iterator be pointing at
|
||||
// the second line. But this is also true at the head of the
|
||||
// next. And clearly, the iteration must not change the function
|
||||
// next. And clearly, the iteration must not change the range
|
||||
// iterator. So neither iterator moves.
|
||||
|
||||
// Assert the first invariant (see above).
|
||||
assert(!func || current < func->address || within(*func, current));
|
||||
assert(!range || current < range->address || within(*range, current));
|
||||
assert(!line || current < line->address || within(*line, current));
|
||||
|
||||
// The next transition after CURRENT.
|
||||
|
@ -950,33 +1069,33 @@ void DwarfCUToModule::AssignLinesToFunctions() {
|
|||
|
||||
// Figure out which state we're in, add lines or warn, and compute
|
||||
// the next transition address.
|
||||
if (func && current >= func->address) {
|
||||
if (range && current >= range->address) {
|
||||
if (line && current >= line->address) {
|
||||
// Covered by both a line and a function.
|
||||
Module::Address func_left = func->size - (current - func->address);
|
||||
// Covered by both a line and a range.
|
||||
Module::Address range_left = range->size - (current - range->address);
|
||||
Module::Address line_left = line->size - (current - line->address);
|
||||
// This may overflow, but things work out.
|
||||
next_transition = current + std::min(func_left, line_left);
|
||||
next_transition = current + std::min(range_left, line_left);
|
||||
Module::Line l = *line;
|
||||
l.address = current;
|
||||
l.size = next_transition - current;
|
||||
func->lines.push_back(l);
|
||||
range->AddLine(l);
|
||||
last_line_used = line;
|
||||
} else {
|
||||
// Covered by a function, but no line.
|
||||
if (func != last_function_cited) {
|
||||
reporter->UncoveredFunction(*func);
|
||||
last_function_cited = func;
|
||||
// Covered by a range, but no line.
|
||||
if (range->function != last_function_cited) {
|
||||
reporter->UncoveredFunction(*(range->function));
|
||||
last_function_cited = range->function;
|
||||
}
|
||||
if (line && within(*func, line->address))
|
||||
if (line && within(*range, line->address))
|
||||
next_transition = line->address;
|
||||
else
|
||||
// If this overflows, we'll catch it below.
|
||||
next_transition = func->address + func->size;
|
||||
next_transition = range->address + range->size;
|
||||
}
|
||||
} else {
|
||||
if (line && current >= line->address) {
|
||||
// Covered by a line, but no function.
|
||||
// Covered by a line, but no range.
|
||||
//
|
||||
// If GCC emits padding after one function to align the start
|
||||
// of the next, then it will attribute the padding
|
||||
|
@ -988,27 +1107,27 @@ void DwarfCUToModule::AssignLinesToFunctions() {
|
|||
// start of the next function, then assume this is what
|
||||
// happened, and don't warn.
|
||||
if (line != last_line_cited
|
||||
&& !(func
|
||||
&& !(range
|
||||
&& line == last_line_used
|
||||
&& func->address - line->address == line->size)) {
|
||||
&& range->address - line->address == line->size)) {
|
||||
reporter->UncoveredLine(*line);
|
||||
last_line_cited = line;
|
||||
}
|
||||
if (func && within(*line, func->address))
|
||||
next_transition = func->address;
|
||||
if (range && within(*line, range->address))
|
||||
next_transition = range->address;
|
||||
else
|
||||
// If this overflows, we'll catch it below.
|
||||
next_transition = line->address + line->size;
|
||||
} else {
|
||||
// Covered by neither a function nor a line. By the invariant,
|
||||
// both func and line begin after CURRENT. The next transition
|
||||
// is the start of the next function or next line, whichever
|
||||
// Covered by neither a range nor a line. By the invariant,
|
||||
// both range and line begin after CURRENT. The next transition
|
||||
// is the start of the next range or next line, whichever
|
||||
// is earliest.
|
||||
assert(func || line);
|
||||
if (func && line)
|
||||
next_transition = std::min(func->address, line->address);
|
||||
else if (func)
|
||||
next_transition = func->address;
|
||||
assert(range || line);
|
||||
if (range && line)
|
||||
next_transition = std::min(range->address, line->address);
|
||||
else if (range)
|
||||
next_transition = range->address;
|
||||
else
|
||||
next_transition = line->address;
|
||||
}
|
||||
|
@ -1025,11 +1144,11 @@ void DwarfCUToModule::AssignLinesToFunctions() {
|
|||
// then we could go around more than once. We don't worry too much
|
||||
// about what result we produce in that case, just as long as we don't
|
||||
// hang or crash.
|
||||
while (func_it != functions->end()
|
||||
&& next_transition >= (*func_it)->address
|
||||
&& !within(**func_it, next_transition))
|
||||
func_it++;
|
||||
func = (func_it != functions->end()) ? *func_it : NULL;
|
||||
while (range_it != sorted_ranges.end()
|
||||
&& next_transition >= range_it->address
|
||||
&& !within(*range_it, next_transition))
|
||||
range_it++;
|
||||
range = (range_it != sorted_ranges.end()) ? &(*range_it) : NULL;
|
||||
while (line_it != lines_.end()
|
||||
&& next_transition >= line_it->address
|
||||
&& !within(*line_it, next_transition))
|
||||
|
|
|
@ -123,6 +123,22 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
|||
scoped_ptr<FilePrivate> file_private_;
|
||||
};
|
||||
|
||||
// An abstract base class for handlers that handle DWARF range lists for
|
||||
// DwarfCUToModule.
|
||||
class RangesHandler {
|
||||
public:
|
||||
RangesHandler() { }
|
||||
virtual ~RangesHandler() { }
|
||||
|
||||
// Called when finishing a function to populate the function's ranges.
|
||||
// The ranges' entries are read starting from offset in the .debug_ranges
|
||||
// section, base_address holds the base PC the range list values are
|
||||
// offsets off. Return false if the rangelist falls out of the
|
||||
// .debug_ranges section.
|
||||
virtual bool ReadRanges(uint64 offset, Module::Address base_address,
|
||||
vector<Module::Range>* ranges) = 0;
|
||||
};
|
||||
|
||||
// An abstract base class for handlers that handle DWARF line data
|
||||
// for DwarfCUToModule. DwarfCUToModule could certainly just use
|
||||
// dwarf2reader::LineInfo itself directly, but decoupling things
|
||||
|
@ -208,6 +224,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
|||
// FilePrivate did not retain the inter-CU specification data.
|
||||
virtual void UnhandledInterCUReference(uint64 offset, uint64 target);
|
||||
|
||||
// The DW_AT_ranges at offset is malformed (truncated or outside of the
|
||||
// .debug_ranges section's bound).
|
||||
virtual void MalformedRangeList(uint64 offset);
|
||||
|
||||
// A DW_AT_ranges attribute was encountered but the no .debug_ranges
|
||||
// section was found.
|
||||
virtual void MissingRanges();
|
||||
|
||||
uint64 cu_offset() const {
|
||||
return cu_offset_;
|
||||
}
|
||||
|
@ -235,6 +259,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
|||
// data we find.
|
||||
DwarfCUToModule(FileContext *file_context,
|
||||
LineToModuleHandler *line_reader,
|
||||
RangesHandler *ranges_handler,
|
||||
WarningReporter *reporter);
|
||||
~DwarfCUToModule();
|
||||
|
||||
|
|
|
@ -128,7 +128,8 @@ class CUFixtureBase {
|
|||
language_signed_(false),
|
||||
appender_(&lines_),
|
||||
reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL),
|
||||
root_handler_(&file_context_, &line_reader_, &reporter_),
|
||||
root_handler_(&file_context_, &line_reader_,
|
||||
/* ranges_reader */ nullptr, &reporter_),
|
||||
functions_filled_(false) {
|
||||
// By default, expect no warnings to be reported, and expect the
|
||||
// compilation unit's name to be provided. The test can override
|
||||
|
@ -597,7 +598,7 @@ void CUFixtureBase::TestFunction(int i, const string &name,
|
|||
Module::Function *function = functions_[i];
|
||||
EXPECT_EQ(name, function->name);
|
||||
EXPECT_EQ(address, function->address);
|
||||
EXPECT_EQ(size, function->size);
|
||||
EXPECT_EQ(size, function->ranges[0].size);
|
||||
EXPECT_EQ(0U, function->parameter_size);
|
||||
}
|
||||
|
||||
|
@ -1515,7 +1516,7 @@ TEST_F(Specifications, InterCU) {
|
|||
|
||||
// First CU. Declares class_A.
|
||||
{
|
||||
DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
|
||||
DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_);
|
||||
ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||
ASSERT_TRUE(root1_handler.StartRootDIE(1,
|
||||
dwarf2reader::DW_TAG_compile_unit));
|
||||
|
@ -1528,7 +1529,7 @@ TEST_F(Specifications, InterCU) {
|
|||
|
||||
// Second CU. Defines class_A, declares member_func_B.
|
||||
{
|
||||
DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
|
||||
DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_);
|
||||
ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||
ASSERT_TRUE(root2_handler.StartRootDIE(1,
|
||||
dwarf2reader::DW_TAG_compile_unit));
|
||||
|
@ -1545,7 +1546,7 @@ TEST_F(Specifications, InterCU) {
|
|||
|
||||
// Third CU. Defines member_func_B.
|
||||
{
|
||||
DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
|
||||
DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_);
|
||||
ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||
ASSERT_TRUE(root3_handler.StartRootDIE(1,
|
||||
dwarf2reader::DW_TAG_compile_unit));
|
||||
|
@ -1574,7 +1575,7 @@ TEST_F(Specifications, UnhandledInterCU) {
|
|||
|
||||
// First CU. Declares class_A.
|
||||
{
|
||||
DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
|
||||
DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_);
|
||||
ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||
ASSERT_TRUE(root1_handler.StartRootDIE(1,
|
||||
dwarf2reader::DW_TAG_compile_unit));
|
||||
|
@ -1587,7 +1588,7 @@ TEST_F(Specifications, UnhandledInterCU) {
|
|||
|
||||
// Second CU. Defines class_A, declares member_func_B.
|
||||
{
|
||||
DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
|
||||
DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_);
|
||||
ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||
ASSERT_TRUE(root2_handler.StartRootDIE(1,
|
||||
dwarf2reader::DW_TAG_compile_unit));
|
||||
|
@ -1605,7 +1606,7 @@ TEST_F(Specifications, UnhandledInterCU) {
|
|||
|
||||
// Third CU. Defines member_func_B.
|
||||
{
|
||||
DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
|
||||
DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_);
|
||||
ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
|
||||
ASSERT_TRUE(root3_handler.StartRootDIE(1,
|
||||
dwarf2reader::DW_TAG_compile_unit));
|
||||
|
@ -1791,7 +1792,8 @@ struct Reporter: public Test {
|
|||
file("source file name") {
|
||||
reporter.SetCUName("compilation-unit-name");
|
||||
|
||||
function.size = 0x89808a5bdfa0a6a3ULL;
|
||||
Module::Range range(0x19c45c30770c1eb0ULL, 0x89808a5bdfa0a6a3ULL);
|
||||
function.ranges.push_back(range);
|
||||
function.parameter_size = 0x6a329f18683dcd51ULL;
|
||||
|
||||
line.address = 0x3606ac6267aebeccULL;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2018 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Gabriele Svelto <gsvelto@mozilla.com>
|
||||
// <gabriele.svelto@gmail.com>
|
||||
|
||||
// dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class.
|
||||
// See dwarf_range_list_handler.h for details.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/dwarf_range_list_handler.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
void DwarfRangeListHandler::AddRange(uint64 begin, uint64 end) {
|
||||
Module::Range r(begin + base_address_, end - begin);
|
||||
|
||||
ranges_->push_back(r);
|
||||
}
|
||||
|
||||
void DwarfRangeListHandler::SetBaseAddress(uint64 base_address) {
|
||||
base_address_ = base_address;
|
||||
}
|
||||
|
||||
void DwarfRangeListHandler::Finish() {
|
||||
std::sort(ranges_->begin(), ranges_->end(),
|
||||
[](const Module::Range &a, const Module::Range &b) {
|
||||
return a.address < b.address;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,79 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2018 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Gabriele Svelto <gsvelto@mozilla.com>
|
||||
// <gabriele.svelto@gmail.com>
|
||||
|
||||
// The DwarfRangeListHandler class accepts rangelist data from a DWARF parser
|
||||
// and adds it to a google_breakpad::Function or other objects supporting
|
||||
// ranges.
|
||||
|
||||
#ifndef COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
|
||||
#define COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common/module.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A class for producing a vector of google_breakpad::Module::Range
|
||||
// instances from a parsed DWARF range list.
|
||||
|
||||
class DwarfRangeListHandler: public dwarf2reader::RangeListHandler {
|
||||
public:
|
||||
DwarfRangeListHandler(uint64 base_address, vector<Module::Range> *ranges)
|
||||
: base_address_(base_address), ranges_(ranges) { }
|
||||
|
||||
~DwarfRangeListHandler() { }
|
||||
|
||||
// Add a range to the list
|
||||
void AddRange(uint64 begin, uint64 end);
|
||||
|
||||
// Record the new base address and use it for the following entries
|
||||
void SetBaseAddress(uint64 base_address);
|
||||
|
||||
// Sort the ranges so that they are in ascending order of starting address
|
||||
void Finish();
|
||||
|
||||
private:
|
||||
// The current PC to add to every entry, this can be overridden by a special
|
||||
// list entry
|
||||
uint64 base_address_;
|
||||
|
||||
// The list of ranges to be populated
|
||||
vector<Module::Range> *ranges_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
|
|
@ -59,6 +59,7 @@
|
|||
#include "common/dwarf_cfi_to_module.h"
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
#include "common/dwarf_range_list_handler.h"
|
||||
#include "common/linux/crc32.h"
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/linux/elfutils.h"
|
||||
|
@ -87,6 +88,7 @@ using google_breakpad::DumpOptions;
|
|||
using google_breakpad::DwarfCFIToModule;
|
||||
using google_breakpad::DwarfCUToModule;
|
||||
using google_breakpad::DwarfLineToModule;
|
||||
using google_breakpad::DwarfRangeListHandler;
|
||||
using google_breakpad::ElfClass;
|
||||
using google_breakpad::ElfClass32;
|
||||
using google_breakpad::ElfClass64;
|
||||
|
@ -213,6 +215,30 @@ bool LoadStabs(const typename ElfClass::Ehdr* elf_header,
|
|||
}
|
||||
#endif // NO_STABS_SUPPORT
|
||||
|
||||
// A range handler that accepts rangelist data parsed by
|
||||
// dwarf2reader::RangeListReader and populates a range vector (typically
|
||||
// owned by a function) with the results.
|
||||
class DumperRangesHandler : public DwarfCUToModule::RangesHandler {
|
||||
public:
|
||||
DumperRangesHandler(const uint8_t *buffer, uint64 size,
|
||||
dwarf2reader::ByteReader* reader)
|
||||
: buffer_(buffer), size_(size), reader_(reader) { }
|
||||
|
||||
bool ReadRanges(uint64 offset, Module::Address base_address,
|
||||
vector<Module::Range>* ranges) {
|
||||
DwarfRangeListHandler handler(base_address, ranges);
|
||||
dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
|
||||
&handler);
|
||||
|
||||
return rangelist_reader.ReadRangeList(offset);
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t *buffer_;
|
||||
uint64 size_;
|
||||
dwarf2reader::ByteReader* reader_;
|
||||
};
|
||||
|
||||
// A line-to-module loader that accepts line number info parsed by
|
||||
// dwarf2reader::LineInfo and populates a Module and a line vector
|
||||
// with the results.
|
||||
|
@ -267,6 +293,18 @@ bool LoadDwarf(const string& dwarf_filename,
|
|||
file_context.AddSectionToSectionMap(name, contents, section->sh_size);
|
||||
}
|
||||
|
||||
// Optional .debug_ranges reader
|
||||
scoped_ptr<DumperRangesHandler> ranges_handler;
|
||||
dwarf2reader::SectionMap::const_iterator ranges_entry =
|
||||
file_context.section_map().find(".debug_ranges");
|
||||
if (ranges_entry != file_context.section_map().end()) {
|
||||
const std::pair<const uint8_t *, uint64>& ranges_section =
|
||||
ranges_entry->second;
|
||||
ranges_handler.reset(
|
||||
new DumperRangesHandler(ranges_section.first, ranges_section.second,
|
||||
&byte_reader));
|
||||
}
|
||||
|
||||
// Parse all the compilation units in the .debug_info section.
|
||||
DumperLineToModule line_to_module(&byte_reader);
|
||||
dwarf2reader::SectionMap::const_iterator debug_info_entry =
|
||||
|
@ -282,7 +320,8 @@ bool LoadDwarf(const string& dwarf_filename,
|
|||
// Make a handler for the root DIE that populates MODULE with the
|
||||
// data that was found.
|
||||
DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
|
||||
DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
|
||||
DwarfCUToModule root_handler(&file_context, &line_to_module,
|
||||
ranges_handler.get(), &reporter);
|
||||
// Make a Dwarf2Handler that drives the DIEHandler.
|
||||
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
|
||||
// Make a DWARF parser for the compilation unit at OFFSET.
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "common/dwarf_cfi_to_module.h"
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
#include "common/dwarf_range_list_handler.h"
|
||||
#include "common/mac/file_id.h"
|
||||
#include "common/mac/arch_utilities.h"
|
||||
#include "common/mac/macho_reader.h"
|
||||
|
@ -76,6 +77,7 @@
|
|||
using dwarf2reader::ByteReader;
|
||||
using google_breakpad::DwarfCUToModule;
|
||||
using google_breakpad::DwarfLineToModule;
|
||||
using google_breakpad::DwarfRangeListHandler;
|
||||
using google_breakpad::FileID;
|
||||
using google_breakpad::mach_o::FatReader;
|
||||
using google_breakpad::mach_o::Section;
|
||||
|
@ -303,6 +305,31 @@ string DumpSymbols::Identifier() {
|
|||
return compacted;
|
||||
}
|
||||
|
||||
// A range handler that accepts rangelist data parsed by
|
||||
// dwarf2reader::RangeListReader and populates a range vector (typically
|
||||
// owned by a function) with the results.
|
||||
class DumpSymbols::DumperRangesHandler:
|
||||
public DwarfCUToModule::RangesHandler {
|
||||
public:
|
||||
DumperRangesHandler(const uint8_t *buffer, uint64 size,
|
||||
dwarf2reader::ByteReader* reader)
|
||||
: buffer_(buffer), size_(size), reader_(reader) { }
|
||||
|
||||
bool ReadRanges(uint64 offset, Module::Address base_address,
|
||||
vector<Module::Range>* ranges) {
|
||||
DwarfRangeListHandler handler(base_address, ranges);
|
||||
dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
|
||||
&handler);
|
||||
|
||||
return rangelist_reader.ReadRangeList(offset);
|
||||
}
|
||||
|
||||
private:
|
||||
const uint8_t *buffer_;
|
||||
uint64 size_;
|
||||
dwarf2reader::ByteReader* reader_;
|
||||
};
|
||||
|
||||
// A line-to-module loader that accepts line number info parsed by
|
||||
// dwarf2reader::LineInfo and populates a Module and a line vector
|
||||
// with the results.
|
||||
|
@ -425,6 +452,18 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
|||
// Build a line-to-module loader for the root handler to use.
|
||||
DumperLineToModule line_to_module(&byte_reader);
|
||||
|
||||
// Optional .debug_ranges reader
|
||||
scoped_ptr<DumperRangesHandler> ranges_handler;
|
||||
dwarf2reader::SectionMap::const_iterator ranges_entry =
|
||||
file_context.section_map().find("__debug_ranges");
|
||||
if (ranges_entry != file_context.section_map().end()) {
|
||||
const std::pair<const uint8_t *, uint64>& ranges_section =
|
||||
ranges_entry->second;
|
||||
ranges_handler.reset(
|
||||
new DumperRangesHandler(ranges_section.first, ranges_section.second,
|
||||
&byte_reader));
|
||||
}
|
||||
|
||||
// Walk the __debug_info section, one compilation unit at a time.
|
||||
uint64 debug_info_length = debug_info_section.second;
|
||||
for (uint64 offset = 0; offset < debug_info_length;) {
|
||||
|
@ -432,7 +471,8 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
|||
// debug info.
|
||||
DwarfCUToModule::WarningReporter reporter(selected_object_name_,
|
||||
offset);
|
||||
DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
|
||||
DwarfCUToModule root_handler(&file_context, &line_to_module,
|
||||
ranges_handler.get(), &reporter);
|
||||
// Make a Dwarf2Handler that drives our DIEHandler.
|
||||
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
|
||||
// Make a DWARF parser for the compilation unit at OFFSET.
|
||||
|
|
|
@ -125,6 +125,7 @@ class DumpSymbols {
|
|||
private:
|
||||
// Used internally.
|
||||
class DumperLineToModule;
|
||||
class DumperRangesHandler;
|
||||
class LoadCommandDumper;
|
||||
|
||||
// This method behaves similarly to NXFindBestFatArch, but it supports
|
||||
|
|
|
@ -99,10 +99,12 @@ void Module::AddFunction(Function *function) {
|
|||
#if _DEBUG
|
||||
{
|
||||
// There should be no other PUBLIC symbols that overlap with the function.
|
||||
Extern debug_ext(function->address);
|
||||
ExternSet::iterator it_debug = externs_.lower_bound(&ext);
|
||||
assert(it_debug == externs_.end() ||
|
||||
(*it_debug)->address >= function->address + function->size);
|
||||
for (const Range& range : function->ranges) {
|
||||
Extern debug_ext(range.address);
|
||||
ExternSet::iterator it_debug = externs_.lower_bound(&ext);
|
||||
assert(it_debug == externs_.end() ||
|
||||
(*it_debug)->address >= range.address + range.size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -281,24 +283,33 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
|
|||
for (FunctionSet::const_iterator func_it = functions_.begin();
|
||||
func_it != functions_.end(); ++func_it) {
|
||||
Function *func = *func_it;
|
||||
stream << "FUNC " << hex
|
||||
<< (func->address - load_address_) << " "
|
||||
<< func->size << " "
|
||||
<< func->parameter_size << " "
|
||||
<< func->name << dec << "\n";
|
||||
if (!stream.good())
|
||||
return ReportError();
|
||||
vector<Line>::iterator line_it = func->lines.begin();
|
||||
for (auto range_it = func->ranges.cbegin();
|
||||
range_it != func->ranges.cend(); ++range_it) {
|
||||
stream << "FUNC " << hex
|
||||
<< (range_it->address - load_address_) << " "
|
||||
<< range_it->size << " "
|
||||
<< func->parameter_size << " "
|
||||
<< func->name << dec << "\n";
|
||||
|
||||
for (vector<Line>::iterator line_it = func->lines.begin();
|
||||
line_it != func->lines.end(); ++line_it) {
|
||||
stream << hex
|
||||
<< (line_it->address - load_address_) << " "
|
||||
<< line_it->size << " "
|
||||
<< dec
|
||||
<< line_it->number << " "
|
||||
<< line_it->file->source_id << "\n";
|
||||
if (!stream.good())
|
||||
return ReportError();
|
||||
|
||||
while ((line_it != func->lines.end()) &&
|
||||
(line_it->address >= range_it->address) &&
|
||||
(line_it->address < (range_it->address + range_it->size))) {
|
||||
stream << hex
|
||||
<< (line_it->address - load_address_) << " "
|
||||
<< line_it->size << " "
|
||||
<< dec
|
||||
<< line_it->number << " "
|
||||
<< line_it->file->source_id << "\n";
|
||||
|
||||
if (!stream.good())
|
||||
return ReportError();
|
||||
|
||||
++line_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,10 +85,19 @@ class Module {
|
|||
int source_id;
|
||||
};
|
||||
|
||||
// An address range.
|
||||
struct Range {
|
||||
Range(const Address address_input, const Address size_input) :
|
||||
address(address_input), size(size_input) { }
|
||||
|
||||
Address address;
|
||||
Address size;
|
||||
};
|
||||
|
||||
// A function.
|
||||
struct Function {
|
||||
Function(const string &name_input, const Address &address_input) :
|
||||
name(name_input), address(address_input), size(0), parameter_size(0) {}
|
||||
name(name_input), address(address_input), parameter_size(0) {}
|
||||
|
||||
// For sorting by address. (Not style-guide compliant, but it's
|
||||
// stupid not to put this in the struct.)
|
||||
|
@ -99,9 +108,9 @@ class Module {
|
|||
// The function's name.
|
||||
const string name;
|
||||
|
||||
// The start address and length of the function's code.
|
||||
// The start address and the address ranges covered by the function.
|
||||
const Address address;
|
||||
Address size;
|
||||
vector<Range> ranges;
|
||||
|
||||
// The function's parameter size.
|
||||
Address parameter_size;
|
||||
|
|
|
@ -55,7 +55,8 @@ static Module::Function *generate_duplicate_function(const string &name) {
|
|||
const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL;
|
||||
|
||||
Module::Function *function = new Module::Function(name, DUP_ADDRESS);
|
||||
function->size = DUP_SIZE;
|
||||
Module::Range range(DUP_ADDRESS, DUP_SIZE);
|
||||
function->ranges.push_back(range);
|
||||
function->parameter_size = DUP_PARAMETER_SIZE;
|
||||
return function;
|
||||
}
|
||||
|
@ -92,7 +93,8 @@ TEST(Write, OneLineFunc) {
|
|||
Module::File *file = m.FindFile("file_name.cc");
|
||||
Module::Function *function = new Module::Function(
|
||||
"function_name", 0xe165bf8023b9d9abLL);
|
||||
function->size = 0x1e4bb0eb1cbf5b09LL;
|
||||
Module::Range range(0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL);
|
||||
function->ranges.push_back(range);
|
||||
function->parameter_size = 0x772beee89114358aLL;
|
||||
Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL,
|
||||
file, 67519080 };
|
||||
|
@ -120,7 +122,8 @@ TEST(Write, RelativeLoadAddress) {
|
|||
// A function.
|
||||
Module::Function *function = new Module::Function(
|
||||
"A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL);
|
||||
function->size = 0x2922088f98d3f6fcLL;
|
||||
Module::Range range(0xbec774ea5dd935f3LL, 0x2922088f98d3f6fcLL);
|
||||
function->ranges.push_back(range);
|
||||
function->parameter_size = 0xe5e9aa008bd5f0d0LL;
|
||||
|
||||
// Some source lines. The module should not sort these.
|
||||
|
@ -177,13 +180,14 @@ TEST(Write, OmitUnusedFiles) {
|
|||
// Create a function.
|
||||
Module::Function *function = new Module::Function(
|
||||
"function_name", 0x9b926d464f0b9384LL);
|
||||
function->size = 0x4f524a4ba795e6a6LL;
|
||||
Module::Range range(0x9b926d464f0b9384LL, 0x4f524a4ba795e6a6LL);
|
||||
function->ranges.push_back(range);
|
||||
function->parameter_size = 0xbbe8133a6641c9b7LL;
|
||||
|
||||
// Source files that refer to some files, but not others.
|
||||
Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL,
|
||||
Module::Line line1 = { 0xab415089485e1a20LL, 0x126e3124979291f2LL,
|
||||
file1, 137850127 };
|
||||
Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL,
|
||||
Module::Line line2 = { 0xb2675b5c3c2ed33fLL, 0x1df77f5551dbd68cLL,
|
||||
file3, 28113549 };
|
||||
function->lines.push_back(line1);
|
||||
function->lines.push_back(line2);
|
||||
|
@ -210,8 +214,8 @@ TEST(Write, OmitUnusedFiles) {
|
|||
"FILE 1 filename3\n"
|
||||
"FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7"
|
||||
" function_name\n"
|
||||
"595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n"
|
||||
"401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n",
|
||||
"ab415089485e1a20 126e3124979291f2 137850127 0\n"
|
||||
"b2675b5c3c2ed33f 1df77f5551dbd68c 28113549 1\n",
|
||||
contents.c_str());
|
||||
}
|
||||
|
||||
|
@ -225,7 +229,8 @@ TEST(Write, NoCFI) {
|
|||
// A function.
|
||||
Module::Function *function = new Module::Function(
|
||||
"A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL);
|
||||
function->size = 0x2922088f98d3f6fcLL;
|
||||
Module::Range range(0xbec774ea5dd935f3LL, 0x2922088f98d3f6fcLL);
|
||||
function->ranges.push_back(range);
|
||||
function->parameter_size = 0xe5e9aa008bd5f0d0LL;
|
||||
|
||||
// Some source lines. The module should not sort these.
|
||||
|
@ -267,12 +272,14 @@ TEST(Construct, AddFunctions) {
|
|||
// Two functions.
|
||||
Module::Function *function1 = new Module::Function(
|
||||
"_without_form", 0xd35024aa7ca7da5cLL);
|
||||
function1->size = 0x200b26e605f99071LL;
|
||||
Module::Range r1(0xd35024aa7ca7da5cLL, 0x200b26e605f99071LL);
|
||||
function1->ranges.push_back(r1);
|
||||
function1->parameter_size = 0xf14ac4fed48c4a99LL;
|
||||
|
||||
Module::Function *function2 = new Module::Function(
|
||||
"_and_void", 0x2987743d0b35b13fLL);
|
||||
function2->size = 0xb369db048deb3010LL;
|
||||
Module::Range r2(0x2987743d0b35b13fLL, 0xb369db048deb3010LL);
|
||||
function2->ranges.push_back(r2);
|
||||
function2->parameter_size = 0x938e556cb5a79988LL;
|
||||
|
||||
// Put them in a vector.
|
||||
|
@ -504,7 +511,8 @@ TEST(Construct, FunctionsAndExternsWithSameAddress) {
|
|||
m.AddExtern(extern2);
|
||||
|
||||
Module::Function* function = new Module::Function("_xyz", 0xfff0);
|
||||
function->size = 0x10;
|
||||
Module::Range range(0xfff0, 0x10);
|
||||
function->ranges.push_back(range);
|
||||
function->parameter_size = 0;
|
||||
m.AddFunction(function);
|
||||
|
||||
|
@ -541,7 +549,8 @@ TEST(Construct, FunctionsAndThumbExternsWithSameAddress) {
|
|||
// The corresponding function from the DWARF debug data have the actual
|
||||
// address.
|
||||
Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0);
|
||||
function->size = 0x10;
|
||||
Module::Range range(0xfff0, 0x10);
|
||||
function->ranges.push_back(range);
|
||||
function->parameter_size = 0;
|
||||
m.AddFunction(function);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ if CONFIG['OS_ARCH'] != 'WINNT':
|
|||
'dwarf_cfi_to_module.cc',
|
||||
'dwarf_cu_to_module.cc',
|
||||
'dwarf_line_to_module.cc',
|
||||
'dwarf_range_list_handler.cc',
|
||||
'language.cc',
|
||||
'md5.cc',
|
||||
'module.cc',
|
||||
|
|
|
@ -91,7 +91,8 @@ bool StabsToModule::StartFunction(const string &name,
|
|||
uint64_t address) {
|
||||
assert(!current_function_);
|
||||
Module::Function *f = new Module::Function(Demangle(name), address);
|
||||
f->size = 0; // We compute this in StabsToModule::Finalize().
|
||||
Module::Range r(address, 0); // We compute this in StabsToModule::Finalize().
|
||||
f->ranges.push_back(r);
|
||||
f->parameter_size = 0; // We don't provide this information.
|
||||
current_function_ = f;
|
||||
boundaries_.push_back(static_cast<Module::Address>(address));
|
||||
|
@ -167,14 +168,14 @@ void StabsToModule::Finalize() {
|
|||
vector<Module::Address>::const_iterator boundary
|
||||
= std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address);
|
||||
if (boundary != boundaries_.end())
|
||||
f->size = *boundary - f->address;
|
||||
f->ranges[0].size = *boundary - f->address;
|
||||
else
|
||||
// If this is the last function in the module, and the STABS
|
||||
// reader was unable to give us its ending address, then assign
|
||||
// it a bogus, very large value. This will happen at most once
|
||||
// per module: since we've added all functions' addresses to the
|
||||
// boundary table, only one can be the last.
|
||||
f->size = kFallbackSize;
|
||||
f->ranges[0].size = kFallbackSize;
|
||||
|
||||
// Compute sizes for each of the function f's lines --- if it has any.
|
||||
if (!f->lines.empty()) {
|
||||
|
@ -185,7 +186,8 @@ void StabsToModule::Finalize() {
|
|||
line_it != last_line; line_it++)
|
||||
line_it[0].size = line_it[1].address - line_it[0].address;
|
||||
// Compute the size of the last line from f's end address.
|
||||
last_line->size = (f->address + f->size) - last_line->address;
|
||||
last_line->size =
|
||||
(f->ranges[0].address + f->ranges[0].size) - last_line->address;
|
||||
}
|
||||
}
|
||||
// Now that everything has a size, add our functions to the module, and
|
||||
|
|
|
@ -64,7 +64,7 @@ TEST(StabsToModule, SimpleCU) {
|
|||
Module::Function *function = functions[0];
|
||||
EXPECT_STREQ("function", function->name.c_str());
|
||||
EXPECT_EQ(0xfde4abbed390c394LL, function->address);
|
||||
EXPECT_EQ(0x10U, function->size);
|
||||
EXPECT_EQ(0x10U, function->ranges[0].size);
|
||||
EXPECT_EQ(0U, function->parameter_size);
|
||||
ASSERT_EQ((size_t) 1, function->lines.size());
|
||||
Module::Line *line = &function->lines[0];
|
||||
|
@ -130,7 +130,7 @@ TEST(StabsToModule, DuplicateFunctionNames) {
|
|||
|
||||
Module::Function *function = functions[0];
|
||||
EXPECT_EQ(0xf2cfda36ecf7f46dLL, function->address);
|
||||
EXPECT_LT(0U, function->size); // should have used dummy size
|
||||
EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size
|
||||
EXPECT_EQ(0U, function->parameter_size);
|
||||
ASSERT_EQ(0U, function->lines.size());
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ TEST(InferSizes, LineSize) {
|
|||
Module::Function *function = functions[0];
|
||||
EXPECT_STREQ("function", function->name.c_str());
|
||||
EXPECT_EQ(0xb4513962eff94e92LL, function->address);
|
||||
EXPECT_EQ(0x1000100000000ULL, function->size); // inferred from CU end
|
||||
EXPECT_EQ(0x1000100000000ULL, function->ranges[0].size); // inferred from CU end
|
||||
EXPECT_EQ(0U, function->parameter_size);
|
||||
ASSERT_EQ((size_t) 2, function->lines.size());
|
||||
|
||||
|
@ -216,7 +216,7 @@ TEST(FunctionNames, Mangled) {
|
|||
"push_back(unsigned long long const&)",
|
||||
function->name.c_str());
|
||||
EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address);
|
||||
EXPECT_LT(0U, function->size); // should have used dummy size
|
||||
EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size
|
||||
EXPECT_EQ(0U, function->parameter_size);
|
||||
ASSERT_EQ(0U, function->lines.size());
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
#include "util/hash/hash.h"
|
||||
|
||||
template <class T, class U, class H = __gnu_cxx::hash<T> >
|
||||
struct unordered_map : public hash_map<T, U, H> {};
|
||||
struct unordered_map : public __gnu_cxx::hash_map<T, U, H> {};
|
||||
template <class T, class H = __gnu_cxx::hash<T> >
|
||||
struct unordered_set : public hash_set<T, H> {};
|
||||
struct unordered_set : public __gnu_cxx::hash_set<T, H> {};
|
||||
|
||||
#elif defined(_LIBCPP_VERSION) // c++11
|
||||
#include <unordered_map>
|
||||
|
|
|
@ -66,7 +66,61 @@
|
|||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT 32
|
||||
#define MD_CONTEXT_ARM64_GPR_COUNT 33
|
||||
|
||||
typedef struct {
|
||||
/* 32 128-bit floating point registers, d0 .. d31. */
|
||||
uint128_struct regs[MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT];
|
||||
|
||||
uint32_t fpcr; /* FPU control register */
|
||||
uint32_t fpsr; /* FPU status register */
|
||||
} MDFloatingSaveAreaARM64;
|
||||
|
||||
/* For (MDRawContextARM64).context_flags. These values indicate the type of
|
||||
* context stored in the structure. */
|
||||
#define MD_CONTEXT_ARM64 0x00400000
|
||||
#define MD_CONTEXT_ARM64_CONTROL (MD_CONTEXT_ARM64 | 0x00000001)
|
||||
#define MD_CONTEXT_ARM64_INTEGER (MD_CONTEXT_ARM64 | 0x00000002)
|
||||
#define MD_CONTEXT_ARM64_FLOATING_POINT (MD_CONTEXT_ARM64 | 0x00000004)
|
||||
#define MD_CONTEXT_ARM64_DEBUG (MD_CONTEXT_ARM64 | 0x00000008)
|
||||
#define MD_CONTEXT_ARM64_FULL (MD_CONTEXT_ARM64_CONTROL | \
|
||||
MD_CONTEXT_ARM64_INTEGER | \
|
||||
MD_CONTEXT_ARM64_FLOATING_POINT)
|
||||
#define MD_CONTEXT_ARM64_ALL (MD_CONTEXT_ARM64_FULL | MD_CONTEXT_ARM64_DEBUG)
|
||||
|
||||
typedef struct {
|
||||
/* Determines which fields of this struct are populated */
|
||||
uint32_t context_flags;
|
||||
|
||||
/* CPSR (flags, basically): 32 bits:
|
||||
bit 31 - N (negative)
|
||||
bit 30 - Z (zero)
|
||||
bit 29 - C (carry)
|
||||
bit 28 - V (overflow)
|
||||
bit 27 - Q (saturation flag, sticky)
|
||||
All other fields -- ignore */
|
||||
uint32_t cpsr;
|
||||
|
||||
/* 33 64-bit integer registers, x0 .. x31 + the PC
|
||||
* Note the following fixed uses:
|
||||
* x29 is the frame pointer
|
||||
* x30 is the link register
|
||||
* x31 is the stack pointer
|
||||
* The PC is effectively x32.
|
||||
*/
|
||||
uint64_t iregs[MD_CONTEXT_ARM64_GPR_COUNT];
|
||||
|
||||
/* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */
|
||||
MDFloatingSaveAreaARM64 float_save;
|
||||
|
||||
uint32_t bcr[8];
|
||||
uint64_t bvr[8];
|
||||
uint32_t wcr[2];
|
||||
uint64_t wvr[2];
|
||||
} MDRawContextARM64;
|
||||
|
||||
typedef struct {
|
||||
uint32_t fpsr; /* FPU status register */
|
||||
|
@ -74,9 +128,7 @@ typedef struct {
|
|||
|
||||
/* 32 128-bit floating point registers, d0 .. d31. */
|
||||
uint128_struct regs[MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT];
|
||||
} MDFloatingSaveAreaARM64;
|
||||
|
||||
#define MD_CONTEXT_ARM64_GPR_COUNT 33
|
||||
} MDFloatingSaveAreaARM64_Old;
|
||||
|
||||
/* Use the same 32-bit alignment when accessing this structure from 64-bit code
|
||||
* as is used natively in 32-bit code. */
|
||||
|
@ -107,9 +159,9 @@ typedef struct {
|
|||
uint32_t cpsr;
|
||||
|
||||
/* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */
|
||||
MDFloatingSaveAreaARM64 float_save;
|
||||
MDFloatingSaveAreaARM64_Old float_save;
|
||||
|
||||
} MDRawContextARM64;
|
||||
} MDRawContextARM64_Old;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
@ -123,18 +175,18 @@ enum MDARM64RegisterNumbers {
|
|||
MD_CONTEXT_ARM64_REG_PC = 32
|
||||
};
|
||||
|
||||
/* For (MDRawContextARM64).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_ARM64 is Breakpad-defined.
|
||||
/* For (MDRawContextARM64_Old).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_ARM64_OLD is Breakpad-defined.
|
||||
* This value was chosen to avoid likely conflicts with MD_CONTEXT_*
|
||||
* for other CPUs. */
|
||||
#define MD_CONTEXT_ARM64 0x80000000
|
||||
#define MD_CONTEXT_ARM64_INTEGER (MD_CONTEXT_ARM64 | 0x00000002)
|
||||
#define MD_CONTEXT_ARM64_FLOATING_POINT (MD_CONTEXT_ARM64 | 0x00000004)
|
||||
#define MD_CONTEXT_ARM64_OLD 0x80000000
|
||||
#define MD_CONTEXT_ARM64_INTEGER_OLD (MD_CONTEXT_ARM64_OLD | 0x00000002)
|
||||
#define MD_CONTEXT_ARM64_FLOATING_POINT_OLD (MD_CONTEXT_ARM64_OLD | 0x00000004)
|
||||
|
||||
#define MD_CONTEXT_ARM64_FULL (MD_CONTEXT_ARM64_INTEGER | \
|
||||
MD_CONTEXT_ARM64_FLOATING_POINT)
|
||||
#define MD_CONTEXT_ARM64_FULL_OLD (MD_CONTEXT_ARM64_INTEGER_OLD | \
|
||||
MD_CONTEXT_ARM64_FLOATING_POINT_OLD)
|
||||
|
||||
#define MD_CONTEXT_ARM64_ALL (MD_CONTEXT_ARM64_INTEGER | \
|
||||
MD_CONTEXT_ARM64_FLOATING_POINT)
|
||||
#define MD_CONTEXT_ARM64_ALL_OLD (MD_CONTEXT_ARM64_INTEGER_OLD | \
|
||||
MD_CONTEXT_ARM64_FLOATING_POINT_OLD)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ */
|
||||
|
|
|
@ -654,9 +654,10 @@ typedef enum {
|
|||
MD_CPU_ARCHITECTURE_AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */
|
||||
MD_CPU_ARCHITECTURE_X86_WIN64 = 10,
|
||||
/* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
|
||||
MD_CPU_ARCHITECTURE_ARM64 = 12, /* PROCESSOR_ARCHITECTURE_ARM64 */
|
||||
MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */
|
||||
MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */
|
||||
MD_CPU_ARCHITECTURE_ARM64 = 0x8003, /* Breakpad-defined value for ARM64 */
|
||||
MD_CPU_ARCHITECTURE_ARM64_OLD = 0x8003, /* Breakpad-defined value for ARM64 */
|
||||
MD_CPU_ARCHITECTURE_MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */
|
||||
MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
|
||||
} MDCPUArchitecture;
|
||||
|
|
|
@ -541,6 +541,12 @@ class MinidumpModuleList : public MinidumpStream,
|
|||
|
||||
bool Read(uint32_t expected_size);
|
||||
|
||||
bool StoreRange(const MinidumpModule& module,
|
||||
uint64_t base_address,
|
||||
uint32_t module_index,
|
||||
uint32_t module_count,
|
||||
bool is_android);
|
||||
|
||||
// The largest number of modules that will be read from a minidump. The
|
||||
// default is 1024.
|
||||
static uint32_t max_modules_;
|
||||
|
@ -1254,6 +1260,8 @@ class Minidump {
|
|||
|
||||
bool swap() const { return valid_ ? swap_ : false; }
|
||||
|
||||
bool is_big_endian() const { return valid_ ? is_big_endian_ : false; }
|
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print();
|
||||
|
||||
|
@ -1319,6 +1327,9 @@ class Minidump {
|
|||
// same-endian, this will be false.
|
||||
bool swap_;
|
||||
|
||||
// true if the minidump was produced by a big-endian cpu.
|
||||
bool is_big_endian_;
|
||||
|
||||
// Validity of the Minidump structure, false immediately after
|
||||
// construction or after a failed Read(); true following a successful
|
||||
// Read().
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2018, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "processor/convert_old_arm64_context.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
void ConvertOldARM64Context(const MDRawContextARM64_Old& old,
|
||||
MDRawContextARM64* context) {
|
||||
context->context_flags = MD_CONTEXT_ARM64;
|
||||
if (old.context_flags & MD_CONTEXT_ARM64_INTEGER_OLD) {
|
||||
context->context_flags |=
|
||||
MD_CONTEXT_ARM64_INTEGER | MD_CONTEXT_ARM64_CONTROL;
|
||||
}
|
||||
if (old.context_flags & MD_CONTEXT_ARM64_FLOATING_POINT_OLD) {
|
||||
context->context_flags |= MD_CONTEXT_ARM64_FLOATING_POINT;
|
||||
}
|
||||
|
||||
context->cpsr = old.cpsr;
|
||||
|
||||
static_assert(sizeof(old.iregs) == sizeof(context->iregs),
|
||||
"iregs size mismatch");
|
||||
memcpy(context->iregs, old.iregs, sizeof(context->iregs));
|
||||
|
||||
static_assert(sizeof(old.float_save.regs) == sizeof(context->float_save.regs),
|
||||
"float_save.regs size mismatch");
|
||||
memcpy(context->float_save.regs,
|
||||
old.float_save.regs,
|
||||
sizeof(context->float_save.regs));
|
||||
context->float_save.fpcr = old.float_save.fpcr;
|
||||
context->float_save.fpsr = old.float_save.fpsr;
|
||||
|
||||
memset(context->bcr, 0, sizeof(context->bcr));
|
||||
memset(context->bvr, 0, sizeof(context->bvr));
|
||||
memset(context->wcr, 0, sizeof(context->wcr));
|
||||
memset(context->wvr, 0, sizeof(context->wvr));
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2018, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__
|
||||
#define PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__
|
||||
|
||||
#include "google_breakpad/common/minidump_cpu_arm64.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
void ConvertOldARM64Context(const MDRawContextARM64_Old& old,
|
||||
MDRawContextARM64* context);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__
|
|
@ -584,7 +584,7 @@ void DumpContext::Print() {
|
|||
case MD_CONTEXT_ARM64: {
|
||||
const MDRawContextARM64* context_arm64 = GetContextARM64();
|
||||
printf("MDRawContextARM64\n");
|
||||
printf(" context_flags = 0x%" PRIx64 "\n",
|
||||
printf(" context_flags = 0x%x\n",
|
||||
context_arm64->context_flags);
|
||||
for (unsigned int ireg_index = 0;
|
||||
ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
|
||||
|
@ -603,6 +603,7 @@ void DumpContext::Print() {
|
|||
printf(" float_save.regs[%2d] = 0x%" PRIx64 "%" PRIx64 "\n",
|
||||
freg_index, fp_value.high, fp_value.low);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "google_breakpad/common/minidump_cpu_arm.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "processor/basic_code_module.h"
|
||||
#include "processor/convert_old_arm64_context.h"
|
||||
#include "processor/linked_ptr.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/range_map-inl.h"
|
||||
|
@ -311,15 +312,22 @@ Microdump::Microdump(const string& contents)
|
|||
memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size());
|
||||
context_->SetContextARM(arm);
|
||||
} else if (strcmp(arch.c_str(), kArm64Architecture) == 0) {
|
||||
if (cpu_state_raw.size() != sizeof(MDRawContextARM64)) {
|
||||
if (cpu_state_raw.size() == sizeof(MDRawContextARM64)) {
|
||||
MDRawContextARM64* arm = new MDRawContextARM64();
|
||||
memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size());
|
||||
context_->SetContextARM64(arm);
|
||||
} else if (cpu_state_raw.size() == sizeof(MDRawContextARM64_Old)) {
|
||||
MDRawContextARM64_Old old_arm;
|
||||
memcpy(&old_arm, &cpu_state_raw[0], cpu_state_raw.size());
|
||||
MDRawContextARM64* new_arm = new MDRawContextARM64();
|
||||
ConvertOldARM64Context(old_arm, new_arm);
|
||||
context_->SetContextARM64(new_arm);
|
||||
} else {
|
||||
std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size()
|
||||
<< " bytes instead of " << sizeof(MDRawContextARM64)
|
||||
<< std::endl;
|
||||
continue;
|
||||
}
|
||||
MDRawContextARM64* arm = new MDRawContextARM64();
|
||||
memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size());
|
||||
context_->SetContextARM64(arm);
|
||||
} else if (strcmp(arch.c_str(), kX86Architecture) == 0) {
|
||||
if (cpu_state_raw.size() != sizeof(MDRawContextX86)) {
|
||||
std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size()
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "google_breakpad/processor/dump_context.h"
|
||||
#include "processor/basic_code_module.h"
|
||||
#include "processor/basic_code_modules.h"
|
||||
#include "processor/convert_old_arm64_context.h"
|
||||
#include "processor/logging.h"
|
||||
|
||||
// All intentional fallthroughs in breakpad are in this file, so define
|
||||
|
@ -79,17 +80,18 @@
|
|||
|
||||
namespace google_breakpad {
|
||||
|
||||
|
||||
using std::istream;
|
||||
using std::ifstream;
|
||||
using std::numeric_limits;
|
||||
using std::vector;
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns true iff |context_size| matches exactly one of the sizes of the
|
||||
// various MDRawContext* types.
|
||||
// TODO(blundell): This function can be removed once
|
||||
// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550 is fixed.
|
||||
static bool IsContextSizeUnique(uint32_t context_size) {
|
||||
bool IsContextSizeUnique(uint32_t context_size) {
|
||||
int num_matching_contexts = 0;
|
||||
if (context_size == sizeof(MDRawContextX86))
|
||||
num_matching_contexts++;
|
||||
|
@ -105,6 +107,8 @@ static bool IsContextSizeUnique(uint32_t context_size) {
|
|||
num_matching_contexts++;
|
||||
if (context_size == sizeof(MDRawContextARM64))
|
||||
num_matching_contexts++;
|
||||
if (context_size == sizeof(MDRawContextARM64_Old))
|
||||
num_matching_contexts++;
|
||||
if (context_size == sizeof(MDRawContextMIPS))
|
||||
num_matching_contexts++;
|
||||
return num_matching_contexts == 1;
|
||||
|
@ -122,9 +126,7 @@ static bool IsContextSizeUnique(uint32_t context_size) {
|
|||
// to account for certain templatized operations that require swapping for
|
||||
// wider types but handle uint8_t too
|
||||
// (MinidumpMemoryRegion::GetMemoryAtAddressInternal).
|
||||
static inline void Swap(uint8_t* value) {
|
||||
}
|
||||
|
||||
inline void Swap(uint8_t* value) {}
|
||||
|
||||
// Optimization: don't need to AND the furthest right shift, because we're
|
||||
// shifting an unsigned quantity. The standard requires zero-filling in this
|
||||
|
@ -132,22 +134,18 @@ static inline void Swap(uint8_t* value) {
|
|||
// right shift to avoid an arithmetic shift (which retains the sign bit).
|
||||
// The furthest left shift never needs to be ANDed bitmask.
|
||||
|
||||
|
||||
static inline void Swap(uint16_t* value) {
|
||||
*value = (*value >> 8) |
|
||||
(*value << 8);
|
||||
inline void Swap(uint16_t* value) {
|
||||
*value = (*value >> 8) | (*value << 8);
|
||||
}
|
||||
|
||||
|
||||
static inline void Swap(uint32_t* value) {
|
||||
inline void Swap(uint32_t* value) {
|
||||
*value = (*value >> 24) |
|
||||
((*value >> 8) & 0x0000ff00) |
|
||||
((*value << 8) & 0x00ff0000) |
|
||||
(*value << 24);
|
||||
}
|
||||
|
||||
|
||||
static inline void Swap(uint64_t* value) {
|
||||
inline void Swap(uint64_t* value) {
|
||||
uint32_t* value32 = reinterpret_cast<uint32_t*>(value);
|
||||
Swap(&value32[0]);
|
||||
Swap(&value32[1]);
|
||||
|
@ -159,7 +157,7 @@ static inline void Swap(uint64_t* value) {
|
|||
|
||||
// Given a pointer to a 128-bit int in the minidump data, set the "low"
|
||||
// and "high" fields appropriately.
|
||||
static void Normalize128(uint128_struct* value, bool is_big_endian) {
|
||||
void Normalize128(uint128_struct* value, bool is_big_endian) {
|
||||
// The struct format is [high, low], so if the format is big-endian,
|
||||
// the most significant bytes will already be in the high field.
|
||||
if (!is_big_endian) {
|
||||
|
@ -171,36 +169,34 @@ static void Normalize128(uint128_struct* value, bool is_big_endian) {
|
|||
|
||||
// This just swaps each int64 half of the 128-bit value.
|
||||
// The value should also be normalized by calling Normalize128().
|
||||
static void Swap(uint128_struct* value) {
|
||||
void Swap(uint128_struct* value) {
|
||||
Swap(&value->low);
|
||||
Swap(&value->high);
|
||||
}
|
||||
|
||||
// Swapping signed integers
|
||||
static inline void Swap(int32_t* value) {
|
||||
inline void Swap(int32_t* value) {
|
||||
Swap(reinterpret_cast<uint32_t*>(value));
|
||||
}
|
||||
|
||||
static inline void Swap(MDLocationDescriptor* location_descriptor) {
|
||||
inline void Swap(MDLocationDescriptor* location_descriptor) {
|
||||
Swap(&location_descriptor->data_size);
|
||||
Swap(&location_descriptor->rva);
|
||||
}
|
||||
|
||||
|
||||
static inline void Swap(MDMemoryDescriptor* memory_descriptor) {
|
||||
inline void Swap(MDMemoryDescriptor* memory_descriptor) {
|
||||
Swap(&memory_descriptor->start_of_memory_range);
|
||||
Swap(&memory_descriptor->memory);
|
||||
}
|
||||
|
||||
|
||||
static inline void Swap(MDGUID* guid) {
|
||||
inline void Swap(MDGUID* guid) {
|
||||
Swap(&guid->data1);
|
||||
Swap(&guid->data2);
|
||||
Swap(&guid->data3);
|
||||
// Don't swap guid->data4[] because it contains 8-bit quantities.
|
||||
}
|
||||
|
||||
static inline void Swap(MDSystemTime* system_time) {
|
||||
inline void Swap(MDSystemTime* system_time) {
|
||||
Swap(&system_time->year);
|
||||
Swap(&system_time->month);
|
||||
Swap(&system_time->day_of_week);
|
||||
|
@ -211,12 +207,12 @@ static inline void Swap(MDSystemTime* system_time) {
|
|||
Swap(&system_time->milliseconds);
|
||||
}
|
||||
|
||||
static inline void Swap(MDXStateFeature* xstate_feature) {
|
||||
inline void Swap(MDXStateFeature* xstate_feature) {
|
||||
Swap(&xstate_feature->offset);
|
||||
Swap(&xstate_feature->size);
|
||||
}
|
||||
|
||||
static inline void Swap(MDXStateConfigFeatureMscInfo* xstate_feature_info) {
|
||||
inline void Swap(MDXStateConfigFeatureMscInfo* xstate_feature_info) {
|
||||
Swap(&xstate_feature_info->size_of_info);
|
||||
Swap(&xstate_feature_info->context_size);
|
||||
Swap(&xstate_feature_info->enabled_features);
|
||||
|
@ -226,12 +222,12 @@ static inline void Swap(MDXStateConfigFeatureMscInfo* xstate_feature_info) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline void Swap(MDRawSimpleStringDictionaryEntry* entry) {
|
||||
inline void Swap(MDRawSimpleStringDictionaryEntry* entry) {
|
||||
Swap(&entry->key);
|
||||
Swap(&entry->value);
|
||||
}
|
||||
|
||||
static inline void Swap(uint16_t* data, size_t size_in_bytes) {
|
||||
inline void Swap(uint16_t* data, size_t size_in_bytes) {
|
||||
size_t data_length = size_in_bytes / sizeof(data[0]);
|
||||
for (size_t i = 0; i < data_length; i++) {
|
||||
Swap(&data[i]);
|
||||
|
@ -252,8 +248,7 @@ static inline void Swap(uint16_t* data, size_t size_in_bytes) {
|
|||
// parameter, a converter that uses iconv would also need to take the host
|
||||
// CPU's endianness into consideration. It doesn't seems worth the trouble
|
||||
// of making it a dependency when we don't care about anything but UTF-16.
|
||||
static string* UTF16ToUTF8(const vector<uint16_t>& in,
|
||||
bool swap) {
|
||||
string* UTF16ToUTF8(const vector<uint16_t>& in, bool swap) {
|
||||
scoped_ptr<string> out(new string());
|
||||
|
||||
// Set the string's initial capacity to the number of UTF-16 characters,
|
||||
|
@ -326,14 +321,14 @@ static string* UTF16ToUTF8(const vector<uint16_t>& in,
|
|||
|
||||
// Return the smaller of the number of code units in the UTF-16 string,
|
||||
// not including the terminating null word, or maxlen.
|
||||
static size_t UTF16codeunits(const uint16_t *string, size_t maxlen) {
|
||||
size_t UTF16codeunits(const uint16_t* string, size_t maxlen) {
|
||||
size_t count = 0;
|
||||
while (count < maxlen && string[count] != 0)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline void Swap(MDTimeZoneInformation* time_zone) {
|
||||
inline void Swap(MDTimeZoneInformation* time_zone) {
|
||||
Swap(&time_zone->bias);
|
||||
// Skip time_zone->standard_name. No need to swap UTF-16 fields.
|
||||
// The swap will be done as part of the conversion to UTF-8.
|
||||
|
@ -345,10 +340,10 @@ static inline void Swap(MDTimeZoneInformation* time_zone) {
|
|||
Swap(&time_zone->daylight_bias);
|
||||
}
|
||||
|
||||
static void ConvertUTF16BufferToUTF8String(const uint16_t* utf16_data,
|
||||
size_t max_length_in_bytes,
|
||||
string* utf8_result,
|
||||
bool swap) {
|
||||
void ConvertUTF16BufferToUTF8String(const uint16_t* utf16_data,
|
||||
size_t max_length_in_bytes,
|
||||
string* utf8_result,
|
||||
bool swap) {
|
||||
// Since there is no explicit byte length for each string, use
|
||||
// UTF16codeunits to calculate word length, then derive byte
|
||||
// length from that.
|
||||
|
@ -377,9 +372,9 @@ enum NumberFormat {
|
|||
kNumberFormatHexadecimal,
|
||||
};
|
||||
|
||||
static void PrintValueOrInvalid(bool valid,
|
||||
NumberFormat number_format,
|
||||
uint32_t value) {
|
||||
void PrintValueOrInvalid(bool valid,
|
||||
NumberFormat number_format,
|
||||
uint32_t value) {
|
||||
if (!valid) {
|
||||
printf("(invalid)\n");
|
||||
} else if (number_format == kNumberFormatDecimal) {
|
||||
|
@ -390,7 +385,7 @@ static void PrintValueOrInvalid(bool valid,
|
|||
}
|
||||
|
||||
// Converts a time_t to a string showing the time in UTC.
|
||||
static string TimeTToUTCString(time_t tt) {
|
||||
string TimeTToUTCString(time_t tt) {
|
||||
struct tm timestruct;
|
||||
#ifdef _WIN32
|
||||
gmtime_s(×truct, &tt);
|
||||
|
@ -407,8 +402,7 @@ static string TimeTToUTCString(time_t tt) {
|
|||
return string(timestr);
|
||||
}
|
||||
|
||||
|
||||
static string MDGUIDToString(const MDGUID& uuid) {
|
||||
string MDGUIDToString(const MDGUID& uuid) {
|
||||
char buf[37];
|
||||
snprintf(buf, sizeof(buf), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
uuid.data1,
|
||||
|
@ -425,6 +419,12 @@ static string MDGUIDToString(const MDGUID& uuid) {
|
|||
return std::string(buf);
|
||||
}
|
||||
|
||||
bool IsDevAshmem(const string& filename) {
|
||||
const string kDevAshmem("/dev/ashmem/");
|
||||
return filename.compare(0, kDevAshmem.length(), kDevAshmem) == 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//
|
||||
// MinidumpObject
|
||||
|
@ -474,8 +474,8 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
|||
<< "other raw context";
|
||||
return false;
|
||||
}
|
||||
if (!IsContextSizeUnique(sizeof(MDRawContextARM64))) {
|
||||
BPLOG(ERROR) << "sizeof(MDRawContextARM64) cannot match the size of any "
|
||||
if (!IsContextSizeUnique(sizeof(MDRawContextARM64_Old))) {
|
||||
BPLOG(ERROR) << "sizeof(MDRawContextARM64_Old) cannot match the size of any "
|
||||
<< "other raw context";
|
||||
return false;
|
||||
}
|
||||
|
@ -681,8 +681,8 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
|||
}
|
||||
|
||||
SetContextPPC64(context_ppc64.release());
|
||||
} else if (expected_size == sizeof(MDRawContextARM64)) {
|
||||
// |context_flags| of MDRawContextARM64 is 64 bits, but other MDRawContext
|
||||
} else if (expected_size == sizeof(MDRawContextARM64_Old)) {
|
||||
// |context_flags| of MDRawContextARM64_Old is 64 bits, but other MDRawContext
|
||||
// in the else case have 32 bits |context_flags|, so special case it here.
|
||||
uint64_t context_flags;
|
||||
|
||||
|
@ -695,7 +695,7 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
|||
if (minidump_->swap())
|
||||
Swap(&context_flags);
|
||||
|
||||
scoped_ptr<MDRawContextARM64> context_arm64(new MDRawContextARM64());
|
||||
scoped_ptr<MDRawContextARM64_Old> context_arm64(new MDRawContextARM64_Old());
|
||||
|
||||
uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
|
||||
if (cpu_type == 0) {
|
||||
|
@ -707,7 +707,7 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
|||
}
|
||||
}
|
||||
|
||||
if (cpu_type != MD_CONTEXT_ARM64) {
|
||||
if (cpu_type != MD_CONTEXT_ARM64_OLD) {
|
||||
// TODO: Fall through to switch below.
|
||||
// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550
|
||||
BPLOG(ERROR) << "MinidumpContext not actually arm64 context";
|
||||
|
@ -723,7 +723,7 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
|||
uint8_t* context_after_flags =
|
||||
reinterpret_cast<uint8_t*>(context_arm64.get()) + flags_size;
|
||||
if (!minidump_->ReadBytes(context_after_flags,
|
||||
sizeof(MDRawContextARM64) - flags_size)) {
|
||||
sizeof(MDRawContextARM64_Old) - flags_size)) {
|
||||
BPLOG(ERROR) << "MinidumpContext could not read arm64 context";
|
||||
return false;
|
||||
}
|
||||
|
@ -748,24 +748,16 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
|||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
// While ARM64 is bi-endian, iOS (currently the only platform
|
||||
// for which ARM64 support has been brought up) uses ARM64 exclusively
|
||||
// in little-endian mode.
|
||||
Normalize128(&context_arm64->float_save.regs[fpr_index], false);
|
||||
Normalize128(&context_arm64->float_save.regs[fpr_index],
|
||||
minidump_->is_big_endian());
|
||||
Swap(&context_arm64->float_save.regs[fpr_index]);
|
||||
}
|
||||
}
|
||||
SetContextFlags(static_cast<uint32_t>(context_arm64->context_flags));
|
||||
|
||||
// Check for data loss when converting context flags from uint64_t into
|
||||
// uint32_t
|
||||
if (static_cast<uint64_t>(GetContextFlags()) !=
|
||||
context_arm64->context_flags) {
|
||||
BPLOG(ERROR) << "Data loss detected when converting ARM64 context_flags";
|
||||
return false;
|
||||
}
|
||||
|
||||
SetContextARM64(context_arm64.release());
|
||||
scoped_ptr<MDRawContextARM64> new_context(new MDRawContextARM64());
|
||||
ConvertOldARM64Context(*context_arm64.get(), new_context.get());
|
||||
SetContextFlags(new_context->context_flags);
|
||||
SetContextARM64(new_context.release());
|
||||
} else {
|
||||
uint32_t context_flags;
|
||||
if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
|
||||
|
@ -1062,6 +1054,58 @@ bool MinidumpContext::Read(uint32_t expected_size) {
|
|||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_ARM64: {
|
||||
if (expected_size != sizeof(MDRawContextARM64)) {
|
||||
BPLOG(ERROR) << "MinidumpContext arm64 size mismatch, " <<
|
||||
expected_size << " != " << sizeof(MDRawContextARM64);
|
||||
return false;
|
||||
}
|
||||
|
||||
scoped_ptr<MDRawContextARM64> context_arm64(new MDRawContextARM64());
|
||||
|
||||
// Set the context_flags member, which has already been read, and
|
||||
// read the rest of the structure beginning with the first member
|
||||
// after context_flags.
|
||||
context_arm64->context_flags = context_flags;
|
||||
|
||||
size_t flags_size = sizeof(context_arm64->context_flags);
|
||||
uint8_t* context_after_flags =
|
||||
reinterpret_cast<uint8_t*>(context_arm64.get()) + flags_size;
|
||||
if (!minidump_->ReadBytes(context_after_flags,
|
||||
sizeof(*context_arm64) - flags_size)) {
|
||||
BPLOG(ERROR) << "MinidumpContext could not read arm64 context";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do this after reading the entire MDRawContext structure because
|
||||
// GetSystemInfo may seek minidump to a new position.
|
||||
if (!CheckAgainstSystemInfo(cpu_type)) {
|
||||
BPLOG(ERROR) << "MinidumpContext arm does not match system info";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (minidump_->swap()) {
|
||||
// context_arm64->context_flags was already swapped.
|
||||
for (unsigned int ireg_index = 0;
|
||||
ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
|
||||
++ireg_index) {
|
||||
Swap(&context_arm64->iregs[ireg_index]);
|
||||
}
|
||||
Swap(&context_arm64->cpsr);
|
||||
Swap(&context_arm64->float_save.fpsr);
|
||||
Swap(&context_arm64->float_save.fpcr);
|
||||
for (unsigned int fpr_index = 0;
|
||||
fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
|
||||
++fpr_index) {
|
||||
Normalize128(&context_arm64->float_save.regs[fpr_index],
|
||||
minidump_->is_big_endian());
|
||||
Swap(&context_arm64->float_save.regs[fpr_index]);
|
||||
}
|
||||
}
|
||||
SetContextARM64(context_arm64.release());
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_CONTEXT_MIPS:
|
||||
case MD_CONTEXT_MIPS64: {
|
||||
if (expected_size != sizeof(MDRawContextMIPS)) {
|
||||
|
@ -1207,6 +1251,11 @@ bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
|
|||
return_value = true;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_ARM64_OLD:
|
||||
if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64_OLD)
|
||||
return_value = true;
|
||||
break;
|
||||
|
||||
case MD_CONTEXT_MIPS:
|
||||
if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS)
|
||||
return_value = true;
|
||||
|
@ -2682,8 +2731,7 @@ bool MinidumpModuleList::Read(uint32_t expected_size) {
|
|||
scoped_ptr<MinidumpModules> modules(
|
||||
new MinidumpModules(module_count, MinidumpModule(minidump_)));
|
||||
|
||||
for (unsigned int module_index = 0;
|
||||
module_index < module_count;
|
||||
for (uint32_t module_index = 0; module_index < module_count;
|
||||
++module_index) {
|
||||
MinidumpModule* module = &(*modules)[module_index];
|
||||
|
||||
|
@ -2701,17 +2749,16 @@ bool MinidumpModuleList::Read(uint32_t expected_size) {
|
|||
// included in the loop above, additional seeks would be needed where
|
||||
// none are now to read contiguous data.
|
||||
uint64_t last_end_address = 0;
|
||||
for (unsigned int module_index = 0;
|
||||
module_index < module_count;
|
||||
for (uint32_t module_index = 0; module_index < module_count;
|
||||
++module_index) {
|
||||
MinidumpModule* module = &(*modules)[module_index];
|
||||
MinidumpModule& module = (*modules)[module_index];
|
||||
|
||||
// ReadAuxiliaryData fails if any data that the module indicates should
|
||||
// exist is missing, but we treat some such cases as valid anyway. See
|
||||
// issue #222: if a debugging record is of a format that's too large to
|
||||
// handle, it shouldn't render the entire dump invalid. Check module
|
||||
// validity before giving up.
|
||||
if (!module->ReadAuxiliaryData() && !module->valid()) {
|
||||
if (!module.ReadAuxiliaryData() && !module.valid()) {
|
||||
BPLOG(ERROR) << "MinidumpModuleList could not read required module "
|
||||
"auxiliary data for module " <<
|
||||
module_index << "/" << module_count;
|
||||
|
@ -2721,52 +2768,54 @@ bool MinidumpModuleList::Read(uint32_t expected_size) {
|
|||
// It is safe to use module->code_file() after successfully calling
|
||||
// module->ReadAuxiliaryData or noting that the module is valid.
|
||||
|
||||
uint64_t base_address = module->base_address();
|
||||
uint64_t module_size = module->size();
|
||||
uint64_t base_address = module.base_address();
|
||||
uint64_t module_size = module.size();
|
||||
if (base_address == static_cast<uint64_t>(-1)) {
|
||||
BPLOG(ERROR) << "MinidumpModuleList found bad base address "
|
||||
"for module " << module_index << "/" << module_count <<
|
||||
", " << module->code_file();
|
||||
BPLOG(ERROR) << "MinidumpModuleList found bad base address for module "
|
||||
<< module_index << "/" << module_count << ", "
|
||||
<< module.code_file();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!range_map_->StoreRange(base_address, module_size, module_index)) {
|
||||
// Android's shared memory implementation /dev/ashmem can contain
|
||||
// duplicate entries for JITted code, so ignore these.
|
||||
// TODO(wfh): Remove this code when Android is fixed.
|
||||
// See https://crbug.com/439531
|
||||
const string kDevAshmem("/dev/ashmem/");
|
||||
if (module->code_file().compare(
|
||||
0, kDevAshmem.length(), kDevAshmem) != 0) {
|
||||
if (base_address < last_end_address) {
|
||||
// If failed due to apparent range overlap the cause may be
|
||||
// the client correction applied for Android packed relocations.
|
||||
// If this is the case, back out the client correction and retry.
|
||||
module_size -= last_end_address - base_address;
|
||||
base_address = last_end_address;
|
||||
if (!range_map_->StoreRange(base_address,
|
||||
module_size, module_index)) {
|
||||
BPLOG(ERROR) << "MinidumpModuleList could not store module " <<
|
||||
module_index << "/" << module_count << ", " <<
|
||||
module->code_file() << ", " <<
|
||||
HexString(base_address) << "+" <<
|
||||
HexString(module_size) << ", after adjusting";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
BPLOG(ERROR) << "MinidumpModuleList could not store module " <<
|
||||
module_index << "/" << module_count << ", " <<
|
||||
module->code_file() << ", " <<
|
||||
HexString(base_address) << "+" <<
|
||||
HexString(module_size);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
BPLOG(INFO) << "MinidumpModuleList ignoring overlapping module " <<
|
||||
module_index << "/" << module_count << ", " <<
|
||||
module->code_file() << ", " <<
|
||||
HexString(base_address) << "+" <<
|
||||
HexString(module_size);
|
||||
// Some minidumps have additional modules in the list that are duplicates.
|
||||
// Ignore them. See https://crbug.com/838322
|
||||
uint32_t existing_module_index;
|
||||
if (range_map_->RetrieveRange(base_address, &existing_module_index,
|
||||
nullptr, nullptr, nullptr) &&
|
||||
existing_module_index < module_count) {
|
||||
const MinidumpModule& existing_module =
|
||||
(*modules)[existing_module_index];
|
||||
if (existing_module.base_address() == module.base_address() &&
|
||||
existing_module.size() == module.size() &&
|
||||
existing_module.code_file() == module.code_file() &&
|
||||
existing_module.code_identifier() == module.code_identifier()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const bool is_android = minidump_->IsAndroid();
|
||||
if (!StoreRange(module, base_address, module_index, module_count,
|
||||
is_android)) {
|
||||
if (!is_android || base_address >= last_end_address) {
|
||||
BPLOG(ERROR) << "MinidumpModuleList could not store module "
|
||||
<< module_index << "/" << module_count << ", "
|
||||
<< module.code_file() << ", " << HexString(base_address)
|
||||
<< "+" << HexString(module_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If failed due to apparent range overlap the cause may be the client
|
||||
// correction applied for Android packed relocations. If this is the
|
||||
// case, back out the client correction and retry.
|
||||
assert(is_android);
|
||||
module_size -= last_end_address - base_address;
|
||||
base_address = last_end_address;
|
||||
if (!range_map_->StoreRange(base_address, module_size, module_index)) {
|
||||
BPLOG(ERROR) << "MinidumpModuleList could not store module "
|
||||
<< module_index << "/" << module_count << ", "
|
||||
<< module.code_file() << ", " << HexString(base_address)
|
||||
<< "+" << HexString(module_size) << ", after adjusting";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
last_end_address = base_address + module_size;
|
||||
|
@ -2781,6 +2830,28 @@ bool MinidumpModuleList::Read(uint32_t expected_size) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MinidumpModuleList::StoreRange(const MinidumpModule& module,
|
||||
uint64_t base_address,
|
||||
uint32_t module_index,
|
||||
uint32_t module_count,
|
||||
bool is_android) {
|
||||
if (range_map_->StoreRange(base_address, module.size(), module_index))
|
||||
return true;
|
||||
|
||||
// Android's shared memory implementation /dev/ashmem can contain duplicate
|
||||
// entries for JITted code, so ignore these.
|
||||
// TODO(wfh): Remove this code when Android is fixed.
|
||||
// See https://crbug.com/439531
|
||||
if (is_android && IsDevAshmem(module.code_file())) {
|
||||
BPLOG(INFO) << "MinidumpModuleList ignoring overlapping module "
|
||||
<< module_index << "/" << module_count << ", "
|
||||
<< module.code_file() << ", " << HexString(base_address) << "+"
|
||||
<< HexString(module.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
|
||||
uint64_t address) const {
|
||||
|
@ -3469,6 +3540,7 @@ string MinidumpSystemInfo::GetCPU() {
|
|||
break;
|
||||
|
||||
case MD_CPU_ARCHITECTURE_ARM64:
|
||||
case MD_CPU_ARCHITECTURE_ARM64_OLD:
|
||||
cpu = "arm64";
|
||||
break;
|
||||
|
||||
|
@ -4975,6 +5047,7 @@ Minidump::Minidump(const string& path, bool hexdump, unsigned int hexdump_width)
|
|||
path_(path),
|
||||
stream_(NULL),
|
||||
swap_(false),
|
||||
is_big_endian_(false),
|
||||
valid_(false),
|
||||
hexdump_(hexdump),
|
||||
hexdump_width_(hexdump_width) {
|
||||
|
@ -4987,6 +5060,7 @@ Minidump::Minidump(istream& stream)
|
|||
path_(),
|
||||
stream_(&stream),
|
||||
swap_(false),
|
||||
is_big_endian_(false),
|
||||
valid_(false),
|
||||
hexdump_(false),
|
||||
hexdump_width_(0) {
|
||||
|
@ -5070,6 +5144,9 @@ bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) {
|
|||
case MD_CPU_ARCHITECTURE_ARM64:
|
||||
*context_cpu_flags = MD_CONTEXT_ARM64;
|
||||
break;
|
||||
case MD_CPU_ARCHITECTURE_ARM64_OLD:
|
||||
*context_cpu_flags = MD_CONTEXT_ARM64_OLD;
|
||||
break;
|
||||
case MD_CPU_ARCHITECTURE_IA64:
|
||||
*context_cpu_flags = MD_CONTEXT_IA64;
|
||||
break;
|
||||
|
@ -5142,6 +5219,13 @@ bool Minidump::Read() {
|
|||
swap_ = false;
|
||||
}
|
||||
|
||||
#if defined(__BIG_ENDIAN__) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
is_big_endian_ = !swap_;
|
||||
#else
|
||||
is_big_endian_ = swap_;
|
||||
#endif
|
||||
|
||||
BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") <<
|
||||
"byte-swapping minidump";
|
||||
|
||||
|
@ -5817,5 +5901,4 @@ T* Minidump::GetStream(T** stream) {
|
|||
return *stream;
|
||||
}
|
||||
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -535,7 +535,7 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
|
|||
break;
|
||||
}
|
||||
|
||||
case MD_CPU_ARCHITECTURE_ARM64: {
|
||||
case MD_CPU_ARCHITECTURE_ARM64_OLD: {
|
||||
info->cpu = "arm64";
|
||||
break;
|
||||
}
|
||||
|
@ -735,7 +735,7 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
|
|||
if (raw_system_info->processor_architecture ==
|
||||
MD_CPU_ARCHITECTURE_ARM ||
|
||||
raw_system_info->processor_architecture ==
|
||||
MD_CPU_ARCHITECTURE_ARM64) {
|
||||
MD_CPU_ARCHITECTURE_ARM64_OLD) {
|
||||
switch (exception_flags) {
|
||||
case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
|
||||
reason.append("EXC_ARM_DA_ALIGN");
|
||||
|
@ -789,7 +789,7 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
|
|||
reason = "EXC_BAD_INSTRUCTION / ";
|
||||
switch (raw_system_info->processor_architecture) {
|
||||
case MD_CPU_ARCHITECTURE_ARM:
|
||||
case MD_CPU_ARCHITECTURE_ARM64: {
|
||||
case MD_CPU_ARCHITECTURE_ARM64_OLD: {
|
||||
switch (exception_flags) {
|
||||
case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED:
|
||||
reason.append("EXC_ARM_UNDEFINED");
|
||||
|
@ -972,7 +972,7 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
|
|||
reason = "EXC_BREAKPOINT / ";
|
||||
switch (raw_system_info->processor_architecture) {
|
||||
case MD_CPU_ARCHITECTURE_ARM:
|
||||
case MD_CPU_ARCHITECTURE_ARM64: {
|
||||
case MD_CPU_ARCHITECTURE_ARM64_OLD: {
|
||||
switch (exception_flags) {
|
||||
case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
|
||||
reason.append("EXC_ARM_DA_ALIGN");
|
||||
|
|
|
@ -27,6 +27,7 @@ UNIFIED_SOURCES += [
|
|||
'basic_source_line_resolver.cc',
|
||||
'call_stack.cc',
|
||||
'cfi_frame_info.cc',
|
||||
'convert_old_arm64_context.cc',
|
||||
'dump_context.cc',
|
||||
'dump_object.cc',
|
||||
'exploitability.cc',
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
'cfi_frame_info.h',
|
||||
'contained_range_map-inl.h',
|
||||
'contained_range_map.h',
|
||||
'convert_old_arm64_context.cc',
|
||||
'convert_old_arm64_context.h',
|
||||
'disassembler_x86.cc',
|
||||
'disassembler_x86.h',
|
||||
'dump_context.cc',
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "google_breakpad/processor/memory_region.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "google_breakpad/processor/system_info.h"
|
||||
#include "processor/cfi_frame_info.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/stackwalker_arm.h"
|
||||
|
@ -249,10 +250,14 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack,
|
|||
scoped_ptr<StackFrameARM> frame;
|
||||
|
||||
// See if there is DWARF call frame information covering this address.
|
||||
scoped_ptr<CFIFrameInfo> cfi_frame_info(
|
||||
frame_symbolizer_->FindCFIFrameInfo(last_frame));
|
||||
if (cfi_frame_info.get())
|
||||
frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
|
||||
// TODO(jperaza): Ignore iOS CFI info until it is properly collected.
|
||||
// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=764
|
||||
if (!system_info_ || system_info_->os != "iOS") {
|
||||
scoped_ptr<CFIFrameInfo> cfi_frame_info(
|
||||
frame_symbolizer_->FindCFIFrameInfo(last_frame));
|
||||
if (cfi_frame_info.get())
|
||||
frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
|
||||
}
|
||||
|
||||
// If CFI failed, or there wasn't CFI available, fall back
|
||||
// to frame pointer, if this is configured.
|
||||
|
|
|
@ -782,8 +782,12 @@ TEST_F(CFI, RejectBadExpressions) {
|
|||
class StackwalkerARMFixtureIOS : public StackwalkerARMFixture {
|
||||
public:
|
||||
StackwalkerARMFixtureIOS() {
|
||||
system_info.os = "iOS";
|
||||
system_info.os_short = "ios";
|
||||
// iOS_test is used instead of iOS because the stackwalker has a check to
|
||||
// avoid using CFI for iOS dumps. This is a workaround for bad CFI being
|
||||
// produced by dump_syms for iOS.
|
||||
// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=764
|
||||
system_info.os = "iOS_test";
|
||||
system_info.os_short = "ios_test";
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4334,26 +4334,6 @@ struct kernel_statfs {
|
|||
return LSS_NAME(setpgid)(0, 0);
|
||||
}
|
||||
|
||||
LSS_INLINE int LSS_NAME(sysconf)(int name) {
|
||||
extern int __getpagesize(void);
|
||||
switch (name) {
|
||||
case _SC_OPEN_MAX: {
|
||||
struct kernel_rlimit limit;
|
||||
#if defined(__ARM_EABI__)
|
||||
return LSS_NAME(ugetrlimit)(RLIMIT_NOFILE, &limit) < 0
|
||||
? 8192 : limit.rlim_cur;
|
||||
#else
|
||||
return LSS_NAME(getrlimit)(RLIMIT_NOFILE, &limit) < 0
|
||||
? 8192 : limit.rlim_cur;
|
||||
#endif
|
||||
}
|
||||
case _SC_PAGESIZE:
|
||||
return __getpagesize();
|
||||
default:
|
||||
LSS_ERRNO = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#if defined(__x86_64__)
|
||||
/* Need to make sure loff_t isn't truncated to 32-bits under x32. */
|
||||
LSS_INLINE ssize_t LSS_NAME(pread64)(int f, void *b, size_t c, loff_t o) {
|
||||
|
@ -4464,7 +4444,7 @@ struct kernel_statfs {
|
|||
#endif
|
||||
|
||||
#if !defined(__NR_pipe)
|
||||
LSS_INLINE pid_t LSS_NAME(pipe)(int *pipefd) {
|
||||
LSS_INLINE int LSS_NAME(pipe)(int *pipefd) {
|
||||
return LSS_NAME(pipe2)(pipefd, 0);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -480,17 +480,28 @@ ParseThreadRegisters(CrashedProcess::Thread* thread,
|
|||
static void
|
||||
ParseThreadRegisters(CrashedProcess::Thread* thread,
|
||||
const MinidumpMemoryRange& range) {
|
||||
const MDRawContextARM64* rawregs = range.GetData<MDRawContextARM64>(0);
|
||||
#define COPY_REGS(rawregs) \
|
||||
do { \
|
||||
for (int i = 0; i < 31; ++i) \
|
||||
thread->regs.regs[i] = rawregs->iregs[i]; \
|
||||
thread->regs.sp = rawregs->iregs[MD_CONTEXT_ARM64_REG_SP]; \
|
||||
thread->regs.pc = rawregs->iregs[MD_CONTEXT_ARM64_REG_PC]; \
|
||||
thread->regs.pstate = rawregs->cpsr; \
|
||||
\
|
||||
memcpy(thread->fpregs.vregs, rawregs->float_save.regs, 8 * 32); \
|
||||
thread->fpregs.fpsr = rawregs->float_save.fpsr; \
|
||||
thread->fpregs.fpcr = rawregs->float_save.fpcr; \
|
||||
} while (false)
|
||||
|
||||
for (int i = 0; i < 31; ++i)
|
||||
thread->regs.regs[i] = rawregs->iregs[i];
|
||||
thread->regs.sp = rawregs->iregs[MD_CONTEXT_ARM64_REG_SP];
|
||||
thread->regs.pc = rawregs->iregs[MD_CONTEXT_ARM64_REG_PC];
|
||||
thread->regs.pstate = rawregs->cpsr;
|
||||
|
||||
memcpy(thread->fpregs.vregs, rawregs->float_save.regs, 8 * 32);
|
||||
thread->fpregs.fpsr = rawregs->float_save.fpsr;
|
||||
thread->fpregs.fpcr = rawregs->float_save.fpcr;
|
||||
if (range.length() == sizeof(MDRawContextARM64_Old)) {
|
||||
const MDRawContextARM64_Old* rawregs =
|
||||
range.GetData<MDRawContextARM64_Old>(0);
|
||||
COPY_REGS(rawregs);
|
||||
} else {
|
||||
const MDRawContextARM64* rawregs = range.GetData<MDRawContextARM64>(0);
|
||||
COPY_REGS(rawregs);
|
||||
}
|
||||
#undef COPY_REGS
|
||||
}
|
||||
#elif defined(__mips__)
|
||||
static void
|
||||
|
@ -590,7 +601,7 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo,
|
|||
exit(1);
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64) {
|
||||
if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD) {
|
||||
fprintf(stderr,
|
||||
"This version of minidump-2-core only supports ARM (64bit).\n");
|
||||
exit(1);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */; };
|
||||
4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */; };
|
||||
4247E6402110D5A500482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4247E63F2110D5A500482558 /* path_helper.cc */; };
|
||||
4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */; };
|
||||
4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721E126F9ADE00B43EAF /* exploitability.cc */; };
|
||||
4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */; };
|
||||
|
@ -81,6 +83,10 @@
|
|||
08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; };
|
||||
162F64FD161C5ECB00CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; };
|
||||
4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_old_arm64_context.cc; path = ../../../processor/convert_old_arm64_context.cc; sourceTree = "<group>"; };
|
||||
4214B7FF211109A600B769FA /* convert_old_arm64_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert_old_arm64_context.h; path = ../../../processor/convert_old_arm64_context.h; sourceTree = "<group>"; };
|
||||
4247E63E2110D5A500482558 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; };
|
||||
4247E63F2110D5A500482558 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; };
|
||||
4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = source_line_resolver_base.cc; path = ../../../processor/source_line_resolver_base.cc; sourceTree = SOURCE_ROOT; };
|
||||
4D2C721E126F9ADE00B43EAF /* exploitability.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability.cc; path = ../../../processor/exploitability.cc; sourceTree = SOURCE_ROOT; };
|
||||
4D2C7222126F9AF900B43EAF /* exploitability_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_win.cc; path = ../../../processor/exploitability_win.cc; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -215,6 +221,10 @@
|
|||
08FB7794FE84155DC02AAC07 /* crash_report */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */,
|
||||
4214B7FF211109A600B769FA /* convert_old_arm64_context.h */,
|
||||
4247E63F2110D5A500482558 /* path_helper.cc */,
|
||||
4247E63E2110D5A500482558 /* path_helper.h */,
|
||||
8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */,
|
||||
8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */,
|
||||
8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */,
|
||||
|
@ -446,8 +456,11 @@
|
|||
/* Begin PBXProject section */
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
};
|
||||
buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */;
|
||||
compatibilityVersion = "Xcode 3.1";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
|
@ -517,6 +530,7 @@
|
|||
4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */,
|
||||
4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */,
|
||||
F407DC48185773C10064622B /* exploitability_linux.cc in Sources */,
|
||||
4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */,
|
||||
4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */,
|
||||
4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */,
|
||||
4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */,
|
||||
|
@ -526,6 +540,7 @@
|
|||
4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */,
|
||||
4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */,
|
||||
4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */,
|
||||
4247E6402110D5A500482558 /* path_helper.cc in Sources */,
|
||||
F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */,
|
||||
4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */,
|
||||
4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */,
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
/* Begin PBXBuildFile section */
|
||||
162F64FA161C591500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F8161C591500CD68D5 /* arch_utilities.cc */; };
|
||||
162F6500161C5F2200CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F8161C591500CD68D5 /* arch_utilities.cc */; };
|
||||
4247E63D2110D4B200482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = EB06C7511FEBC515000214D9 /* path_helper.cc */; };
|
||||
4D72CAF513DFBAC2006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CAF413DFBAC2006CABE3 /* md5.cc */; };
|
||||
8BCAAA4C1CE3A7980046090B /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */; };
|
||||
8BCAAA4D1CE3B1260046090B /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */; };
|
||||
|
@ -105,6 +106,7 @@
|
|||
D21F97D711CBA12300239E38 /* test_assembler_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */; };
|
||||
D21F97D811CBA13D00239E38 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; };
|
||||
D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE0911665B5700407530 /* test_assembler.cc */; };
|
||||
EB06C7531FEBC516000214D9 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = EB06C7511FEBC515000214D9 /* path_helper.cc */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -341,12 +343,14 @@
|
|||
B89E0E701166573700DD08C9 /* macho_dump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_dump.cc; sourceTree = "<group>"; };
|
||||
B89E0E741166575200DD08C9 /* macho_dump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_dump; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B89E0E9511665A6400DD08C9 /* macho_reader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_reader_unittest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B89E0E9F11665AC300DD08C9 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gtest_main.cc; path = ../../../testing/gtest/src/gtest_main.cc; sourceTree = SOURCE_ROOT; };
|
||||
B89E0EA011665AC300DD08C9 /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gtest-all.cc"; path = "../../../testing/gtest/src/gtest-all.cc"; sourceTree = SOURCE_ROOT; };
|
||||
B89E0EA311665AEA00DD08C9 /* gmock-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gmock-all.cc"; path = "../../../testing/src/gmock-all.cc"; sourceTree = SOURCE_ROOT; };
|
||||
B89E0E9F11665AC300DD08C9 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gtest_main.cc; path = ../../../testing/googletest/src/gtest_main.cc; sourceTree = SOURCE_ROOT; };
|
||||
B89E0EA011665AC300DD08C9 /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gtest-all.cc"; path = "../../../testing/googletest/src/gtest-all.cc"; sourceTree = SOURCE_ROOT; };
|
||||
B89E0EA311665AEA00DD08C9 /* gmock-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gmock-all.cc"; path = "../../../testing/googlemock/src/gmock-all.cc"; sourceTree = SOURCE_ROOT; };
|
||||
B8C5B5111166531A00D34F4E /* dump_syms */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dump_syms; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B8E8CA0C1156C854009E61B2 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = SOURCE_ROOT; };
|
||||
D21F97D211CBA0F200239E38 /* test_assembler_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_assembler_unittest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EB06C7511FEBC515000214D9 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; };
|
||||
EB06C7521FEBC516000214D9 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; };
|
||||
F95B422B0E0E22D100DBDE83 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = SOURCE_ROOT; };
|
||||
F95B422C0E0E22D100DBDE83 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; };
|
||||
F95B422D0E0E22D100DBDE83 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -501,6 +505,8 @@
|
|||
9BDF186E0B1BB43700F8391B /* dump_syms_tool.cc */,
|
||||
B89E0E701166573700DD08C9 /* macho_dump.cc */,
|
||||
4D72CAF413DFBAC2006CABE3 /* md5.cc */,
|
||||
EB06C7511FEBC515000214D9 /* path_helper.cc */,
|
||||
EB06C7521FEBC516000214D9 /* path_helper.h */,
|
||||
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */,
|
||||
);
|
||||
|
@ -1059,6 +1065,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4247E63D2110D4B200482558 /* path_helper.cc in Sources */,
|
||||
162F6500161C5F2200CD68D5 /* arch_utilities.cc in Sources */,
|
||||
B89E0E781166576C00DD08C9 /* macho_reader.cc in Sources */,
|
||||
B89E0E7A1166576C00DD08C9 /* macho_dump.cc in Sources */,
|
||||
|
@ -1082,6 +1089,7 @@
|
|||
B88FAE2C1166606200407530 /* macho_reader.cc in Sources */,
|
||||
8BCAAA4C1CE3A7980046090B /* elf_reader.cc in Sources */,
|
||||
B8C5B5171166534700D34F4E /* dwarf2reader.cc in Sources */,
|
||||
EB06C7531FEBC516000214D9 /* path_helper.cc in Sources */,
|
||||
B8C5B5181166534700D34F4E /* bytereader.cc in Sources */,
|
||||
B8C5B5191166534700D34F4E /* macho_utilities.cc in Sources */,
|
||||
B8C5B51A1166534700D34F4E /* file_id.cc in Sources */,
|
||||
|
@ -1260,10 +1268,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = stabs_to_module_unittest;
|
||||
};
|
||||
|
@ -1274,10 +1282,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = stabs_to_module_unittest;
|
||||
};
|
||||
|
@ -1288,10 +1296,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -1307,10 +1315,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -1341,10 +1349,10 @@
|
|||
GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = stabs_reader_unittest;
|
||||
};
|
||||
|
@ -1356,10 +1364,10 @@
|
|||
GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = stabs_reader_unittest;
|
||||
};
|
||||
|
@ -1370,10 +1378,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = gtestmockall;
|
||||
};
|
||||
|
@ -1384,10 +1392,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = gtestmockall;
|
||||
};
|
||||
|
@ -1398,10 +1406,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = module_unittest;
|
||||
};
|
||||
|
@ -1412,10 +1420,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = module_unittest;
|
||||
};
|
||||
|
@ -1426,10 +1434,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = dwarf2diehandler_unittest;
|
||||
};
|
||||
|
@ -1440,10 +1448,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = dwarf2diehandler_unittest;
|
||||
};
|
||||
|
@ -1454,10 +1462,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = dwarf_line_to_module_unittest;
|
||||
};
|
||||
|
@ -1468,10 +1476,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = dwarf_line_to_module_unittest;
|
||||
};
|
||||
|
@ -1482,10 +1490,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = dwarf_cu_to_module_unittest;
|
||||
};
|
||||
|
@ -1496,10 +1504,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = dwarf_cu_to_module_unittest;
|
||||
};
|
||||
|
@ -1510,10 +1518,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = dwarf_cfi_to_module_unittest;
|
||||
};
|
||||
|
@ -1524,10 +1532,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = dwarf_cfi_to_module_unittest;
|
||||
};
|
||||
|
@ -1538,10 +1546,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = bytereader_unittest;
|
||||
};
|
||||
|
@ -1552,10 +1560,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
);
|
||||
PRODUCT_NAME = bytereader_unittest;
|
||||
};
|
||||
|
@ -1566,10 +1574,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
);
|
||||
PRODUCT_NAME = byte_cursor_unittest;
|
||||
};
|
||||
|
@ -1580,10 +1588,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
);
|
||||
PRODUCT_NAME = byte_cursor_unittest;
|
||||
};
|
||||
|
@ -1608,10 +1616,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
);
|
||||
PRODUCT_NAME = macho_reader_unittest;
|
||||
};
|
||||
|
@ -1622,10 +1630,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
);
|
||||
PRODUCT_NAME = macho_reader_unittest;
|
||||
};
|
||||
|
@ -1654,10 +1662,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
);
|
||||
PRODUCT_NAME = test_assembler_unittest;
|
||||
};
|
||||
|
@ -1668,10 +1676,10 @@
|
|||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
$inherited,
|
||||
../../../testing,
|
||||
../../../testing/include,
|
||||
../../../testing/gtest,
|
||||
../../../testing/gtest/include,
|
||||
../../../testing/googletest,
|
||||
../../../testing/googletest/include,
|
||||
../../../testing/googlemock,
|
||||
../../../testing/googlemock/include,
|
||||
);
|
||||
PRODUCT_NAME = test_assembler_unittest;
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@ BROWSER_CHROME_MANIFESTS += ['browser/browser.ini']
|
|||
|
||||
UNIFIED_SOURCES += [
|
||||
'../google-breakpad/src/processor/basic_code_modules.cc',
|
||||
'../google-breakpad/src/processor/convert_old_arm64_context.cc',
|
||||
'../google-breakpad/src/processor/dump_context.cc',
|
||||
'../google-breakpad/src/processor/dump_object.cc',
|
||||
'../google-breakpad/src/processor/logging.cc',
|
||||
|
@ -60,4 +61,4 @@ if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
|
|||
CXXFLAGS += ['-wd4334']
|
||||
|
||||
if CONFIG['CC_TYPE'] == 'clang-cl':
|
||||
AllowCompilerWarnings() # workaround for bug 1090497
|
||||
AllowCompilerWarnings() # workaround for bug 1090497
|
||||
|
|
Загрузка…
Ссылка в новой задаче