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:
Gabriele Svelto 2018-08-21 10:34:11 +00:00
Родитель 3d5b81aef3
Коммит 5d2f9f8da7
48 изменённых файлов: 1211 добавлений и 439 удалений

Просмотреть файл

@ -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(&timestruct, &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