Compare commits

..

No commits in common. "unowhy2" and "main" have entirely different histories.

163 changed files with 1423 additions and 5745 deletions

12
.gitignore vendored
View File

@ -27,7 +27,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Ignore other VCSs.
.repo/
.svn/
# Ignore common compiled artifacts.
@ -48,7 +47,6 @@ lib*.a
/src/tools/linux/symupload/minidump_upload
/src/tools/linux/symupload/sym_upload
/src/tools/mac/dump_syms/dump_syms
/src/tools/mac/dump_syms/dump_syms_mac
# Ignore autotools generated artifacts.
.deps
@ -78,8 +76,8 @@ src/Makefile
*.pyc
# Ignore directories gclient syncs.
#src/testing
#src/third_party/glog
#src/third_party/lss
#src/third_party/protobuf
#src/tools/gyp
src/testing
src/third_party/glog
src/third_party/lss
src/third_party/protobuf
src/tools/gyp

15
.gitmodules vendored
View File

@ -1,15 +0,0 @@
[submodule "src/third_party/glog"]
path = src/third_party/glog
url = https://github.com/google/glog.git
[submodule "src/testing"]
path = src/testing
url = https://github.com/google/googletest.git
[submodule "src/third_party/protobuf/protobuf"]
path = src/third_party/protobuf/protobuf
url = https://github.com/google/protobuf.git
[submodule "src/tools/gyp"]
path = src/tools/gyp
url = https://chromium.googlesource.com/external/gyp
[submodule "src/third_party/lss"]
path = src/third_party/lss
url = https://chromium.googlesource.com/linux-syscall-support/

View File

@ -1,32 +1,26 @@
# Travis build integration.
# https://docs.travis-ci.com/
language: cpp
# TODO: add a clang build as well.
compiler:
- gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- clang
- gcc-4.8
- g++-4.8
# Travis sets CC/CXX to the system toolchain based on the `compiler`
# selection. If clang is added, this should move to be set inside the
# matrix.
env:
global:
- secure: "FPczJ1u7FWGXOtUVf5AONeexfQDYnKRtuNs3phLwlPPAbgAlIc/WeTRSHC8DAb1T8IyPdN3Zi7cqLz0dvPol0iX1fWSfr8YdtW0ea8nUYH5ldmmp6H75FEUJUcISmYwL4WN7TldC6Hnzrlbw/0xmBH8gtAgddtBXKc9P9SwEZvM4OiFMHbMPwZEhRj+D95rfH12lgh3D16nbXGnx3rSNbHszvIxrU2VvlLo9Aa+hbmVj5CsBiNJjhDS64ie+VMTkuzcWNqLRYaGOCQ8ftKAlj/fjGfoKjPDN9dSJg9gW1FjOMPeQo93qhSc/hCmTq7sWxBJu48telinUgESdE5q/8gRf5J05ImWPntZAkC/wQkA20K7Kp/fH1CRaYXQMWKjts8c6dQZ5R4WxE4WXUo5rz573Ti9uyVTLys9whnzaib3YbqYv04irkhpgzo3rd8PF8SXpgK99ySQCcv/Dh7UQuXPpcaknOk2mBySXjQDgpQHHXDN2uUek1HEo5xit8fQuQw3TdPIZ9ZgzQ/c5/Dx6sLWAGEfVH9MN+hy6AiZnJ1JI+XF82kAf1pnf8WddHtlE7pAdWRFQt0iOj9T9esV1/o0VCJVzJLRdpKecF0sTpJxDuan6cFI0tNCkNjHFA5wJKYAvdOPAmYkqre7aIIqSOKy3Fjh9JP9CBJFy7eals9U="
# TODO: Add an OS X config.
matrix:
include:
- os: linux
compiler: gcc
env: USE_CC=gcc-4.8 USE_CXX=g++-4.8 COVERITY_SCAN=true
- os: linux
compiler: clang
- USE_CC=gcc-4.8 USE_CXX=g++-4.8
before_install: ./scripts/travis-checkout.sh
script: ./scripts/travis-build.sh
# TODO: add mac support
os:
- linux
notifications:
email:
- google-breakpad-dev@googlegroups.com

19
DEPS
View File

@ -40,8 +40,11 @@ deps = {
# Testing libraries and utilities.
"src/src/testing":
"https://github.com/google/googlemock.git" +
"@release-1.7.0",
"src/src/testing/gtest":
"https://github.com/google/googletest.git" +
"@release-1.8.0",
"@release-1.7.0",
# Protobuf.
"src/src/third_party/protobuf/protobuf":
@ -56,7 +59,7 @@ deps = {
# Linux syscall support.
"src/src/third_party/lss":
"https://chromium.googlesource.com/linux-syscall-support/" +
"@3f6478ac95edf86cd3da300c2c0d34a438f5dbeb",
"@9292030109847793f7a6689adac1ddafb412fe14"
}
hooks = [
@ -69,16 +72,4 @@ hooks = [
"--no-circular-check",
"src/src/client/windows/breakpad_client.gyp"],
},
{
# XXX: this and above should all be wired into build/all.gyp ?
"action": ["python",
"src/src/tools/gyp/gyp_main.py",
"--no-circular-check",
"src/src/tools/windows/tools_windows.gyp"],
},
{
# Keep the manifest up to date.
"action": ["python", "src/src/tools/python/deps-to-manifest.py",
"src/DEPS", "src/default.xml"],
},
]

View File

@ -43,7 +43,17 @@ AM_CXXFLAGS += -I$(top_srcdir)/src/common/android/include
AM_CXXFLAGS += -I$(top_srcdir)/src/common/android/testing/include
endif
AM_CXXFLAGS += $(WARN_CXXFLAGS)
if GCC
# These are good warnings to be treated as errors
AM_CXXFLAGS += \
-Werror=missing-braces \
-Werror=non-virtual-dtor \
-Werror=overloaded-virtual \
-Werror=reorder \
-Werror=sign-compare \
-Werror=unused-variable \
-Werror=vla
endif
if LINUX_HOST
# Build as PIC on Linux, for linux_client_unittest_shlib
@ -110,10 +120,8 @@ TEST_DEPS =
else
TEST_CFLAGS = \
-I$(top_srcdir)/src/testing/include \
-I$(top_srcdir)/src/testing/googletest/include \
-I$(top_srcdir)/src/testing/googletest \
-I$(top_srcdir)/src/testing/googlemock/include \
-I$(top_srcdir)/src/testing/googlemock \
-I$(top_srcdir)/src/testing/gtest/include \
-I$(top_srcdir)/src/testing/gtest \
-I$(top_srcdir)/src/testing
TEST_LIBS = src/testing/libtesting.a
TEST_DEPS = $(TEST_LIBS)
@ -133,9 +141,9 @@ check_LIBRARIES += src/testing/libtesting.a
if !SYSTEM_TEST_LIBS
src_testing_libtesting_a_SOURCES = \
src/breakpad_googletest_includes.h \
src/testing/googletest/src/gtest-all.cc \
src/testing/googletest/src/gtest_main.cc \
src/testing/googlemock/src/gmock-all.cc
src/testing/gtest/src/gtest-all.cc \
src/testing/gtest/src/gtest_main.cc \
src/testing/src/gmock-all.cc
src_testing_libtesting_a_CPPFLAGS = \
$(AM_CPPFLAGS) $(TEST_CFLAGS)
endif
@ -185,8 +193,7 @@ src_client_linux_libbreakpad_client_a_SOURCES = \
src/common/linux/guid_creator.h \
src/common/linux/linux_libc_support.cc \
src/common/linux/memory_mapped_file.cc \
src/common/linux/safe_readlink.cc \
src/common/linux/http_upload.cc
src/common/linux/safe_readlink.cc
if ANDROID_HOST
src_client_linux_libbreakpad_client_a_SOURCES += \
src/common/android/breakpad_getcontext.S
@ -586,10 +593,6 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \
src/common/linux/memory_mapped_file.cc \
src/common/linux/safe_readlink.cc \
src/tools/linux/dump_syms/dump_syms.cc
src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \
$(RUST_DEMANGLE_CFLAGS)
src_tools_linux_dump_syms_dump_syms_LDADD = \
$(RUST_DEMANGLE_LIBS)
src_tools_linux_md2core_minidump_2_core_SOURCES = \
src/common/linux/memory_mapped_file.cc \
@ -638,10 +641,7 @@ src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \
src/tools/mac/dump_syms/dump_syms_tool.cc
src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS= \
-I$(top_srcdir)/src/third_party/mac_headers \
$(RUST_DEMANGLE_CFLAGS) \
-DHAVE_MACH_O_NLIST_H
src_tools_mac_dump_syms_dump_syms_mac_LDADD= \
$(RUST_DEMANGLE_LIBS)
src_common_dumper_unittest_SOURCES = \
src/common/byte_cursor_unittest.cc \
@ -698,11 +698,9 @@ src_common_dumper_unittest_SOURCES = \
src/common/tests/file_utils.cc
src_common_dumper_unittest_CPPFLAGS = \
$(AM_CPPFLAGS) $(TEST_CFLAGS) \
$(RUST_DEMANGLE_CFLAGS) \
$(PTHREAD_CFLAGS)
src_common_dumper_unittest_LDADD = \
$(TEST_LIBS) \
$(RUST_DEMANGLE_LIBS) \
$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
src_common_mac_macho_reader_unittest_SOURCES = \
@ -1323,7 +1321,6 @@ EXTRA_DIST = \
src/common/windows/pdb_source_line_writer.h \
src/common/windows/string_utils-inl.h \
src/common/windows/string_utils.cc \
src/processor/microdump_stackwalk_test_vars \
src/processor/stackwalk_common.cc \
src/processor/stackwalk_common.h \
src/processor/stackwalker_selftest_sol.s \
@ -1350,7 +1347,6 @@ EXTRA_DIST = \
src/processor/testdata/linux_raise_sigabrt.dmp \
src/processor/testdata/linux_stack_pointer_in_module.dmp \
src/processor/testdata/linux_stack_pointer_in_stack.dmp \
src/processor/testdata/linux_stack_pointer_in_stack_alt_name.dmp \
src/processor/testdata/linux_stacksmash.dmp \
src/processor/testdata/linux_write_to_nonwritable_module.dmp \
src/processor/testdata/linux_write_to_nonwritable_region_math.dmp \
@ -1395,61 +1391,54 @@ EXTRA_DIST = \
src/processor/testdata/symbols/overflow/B0E1FC01EF48E39CAF5C881D2DF0C3840/overflow.sym \
src/processor/testdata/symbols/test_app.pdb/5A9832E5287241C1838ED98914E9B7FF1/test_app.sym \
src/processor/testdata/test_app.cc \
src/testing/googletest/include/gtest/gtest.h \
src/testing/googletest/include/gtest/gtest-death-test.h \
src/testing/googletest/include/gtest/gtest-message.h \
src/testing/googletest/include/gtest/gtest-param-test.h \
src/testing/googletest/include/gtest/gtest-printers.h \
src/testing/googletest/include/gtest/gtest-spi.h \
src/testing/googletest/include/gtest/gtest-test-part.h \
src/testing/googletest/include/gtest/gtest-typed-test.h \
src/testing/googletest/include/gtest/gtest_pred_impl.h \
src/testing/googletest/include/gtest/gtest_prod.h \
src/testing/googletest/include/gtest/internal/custom/gtest-port.h \
src/testing/googletest/include/gtest/internal/custom/gtest-printers.h \
src/testing/googletest/include/gtest/internal/custom/gtest.h \
src/testing/googletest/include/gtest/internal/gtest-death-test-internal.h \
src/testing/googletest/include/gtest/internal/gtest-filepath.h \
src/testing/googletest/include/gtest/internal/gtest-internal.h \
src/testing/googletest/include/gtest/internal/gtest-linked_ptr.h \
src/testing/googletest/include/gtest/internal/gtest-param-util-generated.h \
src/testing/googletest/include/gtest/internal/gtest-param-util.h \
src/testing/googletest/include/gtest/internal/gtest-port-arch.h \
src/testing/googletest/include/gtest/internal/gtest-port.h \
src/testing/googletest/include/gtest/internal/gtest-string.h \
src/testing/googletest/include/gtest/internal/gtest-tuple.h \
src/testing/googletest/include/gtest/internal/gtest-type-util.h \
src/testing/googletest/src/gtest.cc \
src/testing/googletest/src/gtest-death-test.cc \
src/testing/googletest/src/gtest-filepath.cc \
src/testing/googletest/src/gtest-internal-inl.h \
src/testing/googletest/src/gtest-port.cc \
src/testing/googletest/src/gtest-printers.cc \
src/testing/googletest/src/gtest-test-part.cc \
src/testing/googletest/src/gtest-typed-test.cc \
src/testing/googlemock/include/gmock/gmock.h \
src/testing/googlemock/include/gmock/gmock-actions.h \
src/testing/googlemock/include/gmock/gmock-cardinalities.h \
src/testing/googlemock/include/gmock/gmock-generated-actions.h \
src/testing/googlemock/include/gmock/gmock-generated-function-mockers.h \
src/testing/googlemock/include/gmock/gmock-generated-matchers.h \
src/testing/googlemock/include/gmock/gmock-generated-nice-strict.h \
src/testing/googlemock/include/gmock/gmock-matchers.h \
src/testing/googlemock/include/gmock/gmock-more-actions.h \
src/testing/googlemock/include/gmock/gmock-more-matchers.h \
src/testing/googlemock/include/gmock/gmock-spec-builders.h \
src/testing/googlemock/include/gmock/internal/custom/gmock-generated-actions.h \
src/testing/googlemock/include/gmock/internal/custom/gmock-matchers.h \
src/testing/googlemock/include/gmock/internal/custom/gmock-port.h \
src/testing/googlemock/include/gmock/internal/gmock-generated-internal-utils.h \
src/testing/googlemock/include/gmock/internal/gmock-internal-utils.h \
src/testing/googlemock/include/gmock/internal/gmock-port.h \
src/testing/googlemock/src/gmock.cc \
src/testing/googlemock/src/gmock-cardinalities.cc \
src/testing/googlemock/src/gmock-internal-utils.cc \
src/testing/googlemock/src/gmock-matchers.cc \
src/testing/googlemock/src/gmock-spec-builders.cc \
src/testing/googlemock/src/gmock_main.cc \
src/testing/gtest/include/gtest/gtest.h \
src/testing/gtest/include/gtest/gtest-death-test.h \
src/testing/gtest/include/gtest/gtest-message.h \
src/testing/gtest/include/gtest/gtest-param-test.h \
src/testing/gtest/include/gtest/gtest-printers.h \
src/testing/gtest/include/gtest/gtest-spi.h \
src/testing/gtest/include/gtest/gtest-test-part.h \
src/testing/gtest/include/gtest/gtest-typed-test.h \
src/testing/gtest/include/gtest/gtest_pred_impl.h \
src/testing/gtest/include/gtest/gtest_prod.h \
src/testing/gtest/include/gtest/internal/gtest-death-test-internal.h \
src/testing/gtest/include/gtest/internal/gtest-filepath.h \
src/testing/gtest/include/gtest/internal/gtest-internal.h \
src/testing/gtest/include/gtest/internal/gtest-linked_ptr.h \
src/testing/gtest/include/gtest/internal/gtest-param-util-generated.h \
src/testing/gtest/include/gtest/internal/gtest-param-util.h \
src/testing/gtest/include/gtest/internal/gtest-port.h \
src/testing/gtest/include/gtest/internal/gtest-string.h \
src/testing/gtest/include/gtest/internal/gtest-tuple.h \
src/testing/gtest/include/gtest/internal/gtest-type-util.h \
src/testing/gtest/src/gtest.cc \
src/testing/gtest/src/gtest-death-test.cc \
src/testing/gtest/src/gtest-filepath.cc \
src/testing/gtest/src/gtest-internal-inl.h \
src/testing/gtest/src/gtest-port.cc \
src/testing/gtest/src/gtest-printers.cc \
src/testing/gtest/src/gtest-test-part.cc \
src/testing/gtest/src/gtest-typed-test.cc \
src/testing/include/gmock/gmock.h \
src/testing/include/gmock/gmock-actions.h \
src/testing/include/gmock/gmock-cardinalities.h \
src/testing/include/gmock/gmock-generated-actions.h \
src/testing/include/gmock/gmock-generated-function-mockers.h \
src/testing/include/gmock/gmock-generated-matchers.h \
src/testing/include/gmock/gmock-generated-nice-strict.h \
src/testing/include/gmock/gmock-matchers.h \
src/testing/include/gmock/gmock-more-actions.h \
src/testing/include/gmock/gmock-more-matchers.h \
src/testing/include/gmock/gmock-spec-builders.h \
src/testing/include/gmock/internal/gmock-generated-internal-utils.h \
src/testing/include/gmock/internal/gmock-internal-utils.h \
src/testing/include/gmock/internal/gmock-port.h \
src/testing/src/gmock.cc \
src/testing/src/gmock-cardinalities.cc \
src/testing/src/gmock-internal-utils.cc \
src/testing/src/gmock-matchers.cc \
src/testing/src/gmock-spec-builders.cc \
src/testing/src/gmock_main.cc \
src/third_party/curl/COPYING \
src/third_party/curl/curlbuild.h \
src/third_party/curl/curl.h \

File diff suppressed because it is too large Load Diff

View File

@ -8,13 +8,12 @@ crash-reporting system.
* [Bugs](https://bugs.chromium.org/p/google-breakpad/)
* Discussion/Questions: [google-breakpad-discuss@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-discuss)
* Developer/Reviews: [google-breakpad-dev@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-dev)
* Tests: [![Build Status](https://travis-ci.org/google/breakpad.svg?branch=master)](https://travis-ci.org/google/breakpad) [![Build status](https://ci.appveyor.com/api/projects/status/eguv4emv2rhq68u2?svg=true)](https://ci.appveyor.com/project/vapier/breakpad)
* Coverage [![Coverity Status](https://scan.coverity.com/projects/9215/badge.svg)](https://scan.coverity.com/projects/google-breakpad)
* Tests: [![Build Status](https://travis-ci.org/google/breakpad.svg?branch=master)](https://travis-ci.org/google/breakpad)
## Getting started (from master)
1. First, [download depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools)
and ensure that theyre in your `PATH`.
and ensure that they're in your `PATH`.
2. Create a new directory for checking out the source code (it must be named
breakpad).
@ -76,7 +75,6 @@ dependent repos are up-to-date.
e.g. `git commit ... && git cl upload ...`
You will be prompted for credential and a description.
4. At https://chromium-review.googlesource.com/ you'll find your issue listed;
click on it, then “Add reviewer”, and enter in the code reviewer. Depending
on your settings, you may not see an email, but the reviewer has been
notified with google-breakpad-dev@googlegroups.com always CCd.
4. At https://codereview.chromium.org/ you'll find your issue listed; click on
it, and select Publish+Mail, and enter in the code reviewer and CC
google-breakpad-dev@googlegroups.com

6
aclocal.m4 vendored
View File

@ -1295,9 +1295,3 @@ AC_SUBST([am__tar])
AC_SUBST([am__untar])
]) # _AM_PROG_TAR
m4_include([m4/ax_append_compile_flags.m4])
m4_include([m4/ax_append_flag.m4])
m4_include([m4/ax_check_compile_flag.m4])
m4_include([m4/ax_cxx_compile_stdcxx.m4])
m4_include([m4/ax_pthread.m4])
m4_include([m4/ax_require_defined.m4])

View File

@ -1,42 +0,0 @@
version: '{build}'
environment:
GYP_MSVS_VERSION: 2013
platform:
- Win32
configuration:
- Debug
- Release
# Use the source dir expected by gclient.
clone_folder: c:\projects\breakpad\src
# Before checkout.
init:
- cd %APPVEYOR_BUILD_FOLDER%\..\..
- appveyor DownloadFile https://storage.googleapis.com/chrome-infra/depot_tools.zip
- 7z -bd x depot_tools.zip -odepot_tools
- depot_tools\update_depot_tools
- cd %APPVEYOR_BUILD_FOLDER%
# After checkout.
install:
- PATH C:\projects\depot_tools;%PATH%
- cd %APPVEYOR_BUILD_FOLDER%\..
- gclient config https://%APPVEYOR_REPO_PROVIDER%.com/%APPVEYOR_REPO_NAME% --unmanaged --name=src
- gclient sync
build_script:
- cd %APPVEYOR_BUILD_FOLDER%
- msbuild src\client\windows\breakpad_client.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /m /verbosity:normal
- msbuild src\tools\windows\tools_windows.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /m /verbosity:normal
test_script:
- src\client\windows\%CONFIGURATION%\client_tests.exe
- src\tools\windows\%CONFIGURATION%\dump_syms_unittest.exe
artifacts:
- path: '**\*.exe'
- path: '**\*.lib'

126
autotools/config.guess vendored
View File

@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2017 Free Software Foundation, Inc.
# Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2017-02-07'
timestamp='2016-01-01'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2017 Free Software Foundation, Inc.
Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -186,12 +186,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently (or will in the future) and ABI.
# to ELF recently, or will in the future.
case "${UNAME_MACHINE_ARCH}" in
earm*)
os=netbsdelf
;;
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
@ -240,10 +237,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
exit ;;
*:LibertyBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
exit ;;
*:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;;
@ -275,42 +268,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
UNAME_MACHINE=alpha ;;
UNAME_MACHINE="alpha" ;;
"EV4.5 (21064)")
UNAME_MACHINE=alpha ;;
UNAME_MACHINE="alpha" ;;
"LCA4 (21066/21068)")
UNAME_MACHINE=alpha ;;
UNAME_MACHINE="alpha" ;;
"EV5 (21164)")
UNAME_MACHINE=alphaev5 ;;
UNAME_MACHINE="alphaev5" ;;
"EV5.6 (21164A)")
UNAME_MACHINE=alphaev56 ;;
UNAME_MACHINE="alphaev56" ;;
"EV5.6 (21164PC)")
UNAME_MACHINE=alphapca56 ;;
UNAME_MACHINE="alphapca56" ;;
"EV5.7 (21164PC)")
UNAME_MACHINE=alphapca57 ;;
UNAME_MACHINE="alphapca57" ;;
"EV6 (21264)")
UNAME_MACHINE=alphaev6 ;;
UNAME_MACHINE="alphaev6" ;;
"EV6.7 (21264A)")
UNAME_MACHINE=alphaev67 ;;
UNAME_MACHINE="alphaev67" ;;
"EV6.8CB (21264C)")
UNAME_MACHINE=alphaev68 ;;
UNAME_MACHINE="alphaev68" ;;
"EV6.8AL (21264B)")
UNAME_MACHINE=alphaev68 ;;
UNAME_MACHINE="alphaev68" ;;
"EV6.8CX (21264D)")
UNAME_MACHINE=alphaev68 ;;
UNAME_MACHINE="alphaev68" ;;
"EV6.9A (21264/EV69A)")
UNAME_MACHINE=alphaev69 ;;
UNAME_MACHINE="alphaev69" ;;
"EV7 (21364)")
UNAME_MACHINE=alphaev7 ;;
UNAME_MACHINE="alphaev7" ;;
"EV7.9 (21364A)")
UNAME_MACHINE=alphaev79 ;;
UNAME_MACHINE="alphaev79" ;;
esac
# A Pn.n version is a patched version.
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
@ -383,16 +376,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build
SUN_ARCH=i386
SUN_ARCH="i386"
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH=x86_64
SUN_ARCH="x86_64"
fi
fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@ -417,7 +410,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
echo m68k-sun-sunos${UNAME_RELEASE}
@ -642,13 +635,13 @@ EOF
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in
523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in
32) HP_ARCH=hppa2.0n ;;
64) HP_ARCH=hppa2.0w ;;
'') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
32) HP_ARCH="hppa2.0n" ;;
64) HP_ARCH="hppa2.0w" ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
esac ;;
esac
fi
@ -687,11 +680,11 @@ EOF
exit (0);
}
EOF
(CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
if [ ${HP_ARCH} = hppa2.0w ]
if [ ${HP_ARCH} = "hppa2.0w" ]
then
eval $set_cc_for_build
@ -704,12 +697,12 @@ EOF
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__
then
HP_ARCH=hppa2.0w
HP_ARCH="hppa2.0w"
else
HP_ARCH=hppa64
HP_ARCH="hppa64"
fi
fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@ -814,14 +807,14 @@ EOF
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@ -903,7 +896,7 @@ EOF
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
@ -926,7 +919,7 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arc:Linux:*:* | arceb:Linux:*:*)
@ -1000,9 +993,6 @@ EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
mips64el:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
openrisc*:Linux:*:*)
echo or1k-unknown-linux-${LIBC}
exit ;;
@ -1035,9 +1025,6 @@ EOF
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-${LIBC}
exit ;;
riscv32:Linux:*:* | riscv64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
exit ;;
@ -1285,9 +1272,6 @@ EOF
SX-8R:SUPER-UX:*:*)
echo sx8r-nec-superux${UNAME_RELEASE}
exit ;;
SX-ACE:SUPER-UX:*:*)
echo sxace-nec-superux${UNAME_RELEASE}
exit ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit ;;
@ -1301,9 +1285,9 @@ EOF
UNAME_PROCESSOR=powerpc
fi
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
@ -1325,7 +1309,7 @@ EOF
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = x86; then
if test "$UNAME_PROCESSOR" = "x86"; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
@ -1343,9 +1327,6 @@ EOF
NSR-?:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit ;;
NSX-?:NONSTOP_KERNEL:*:*)
echo nsx-tandem-nsk${UNAME_RELEASE}
exit ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
exit ;;
@ -1359,7 +1340,7 @@ EOF
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
if test "$cputype" = 386; then
if test "$cputype" = "386"; then
UNAME_MACHINE=i386
else
UNAME_MACHINE="$cputype"
@ -1401,7 +1382,7 @@ EOF
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
exit ;;
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
@ -1420,17 +1401,18 @@ esac
cat >&2 <<EOF
$0: unable to guess system type
This script (version $timestamp), has failed to recognize the
operating system you are using. If your script is old, overwrite
config.guess and config.sub with the latest versions from:
This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
and
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
If $0 has already been updated, send the following data and any
information you think might be pertinent to config-patches@gnu.org to
provide the necessary information to handle your system.
If the version you run ($0) is already up to date, please
send the following data and any information you think might be
pertinent to <config-patches@gnu.org> in order to provide the needed
information to handle your system.
config.guess timestamp = $timestamp

38
autotools/config.sub vendored
View File

@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2017 Free Software Foundation, Inc.
# Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2017-02-07'
timestamp='2016-01-01'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@ -67,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright 1992-2017 Free Software Foundation, Inc.
Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -117,7 +117,7 @@ case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
kopensolaris*-gnu* | cloudabi*-eabi* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
@ -301,7 +301,6 @@ case $basic_machine in
| open8 | or1k | or1knd | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| pru \
| pyramid \
| riscv32 | riscv64 \
| rl78 | rx \
@ -429,7 +428,6 @@ case $basic_machine in
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pru-* \
| pyramid-* \
| riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
@ -645,14 +643,6 @@ case $basic_machine in
basic_machine=m68k-bull
os=-sysv3
;;
e500v[12])
basic_machine=powerpc-unknown
os=$os"spe"
;;
e500v[12]-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
os=$os"spe"
;;
ebmon29k)
basic_machine=a29k-amd
os=-ebmon
@ -948,9 +938,6 @@ case $basic_machine in
nsr-tandem)
basic_machine=nsr-tandem
;;
nsx-tandem)
basic_machine=nsx-tandem
;;
op50n-* | op60c-*)
basic_machine=hppa1.1-oki
os=-proelf
@ -1035,7 +1022,7 @@ case $basic_machine in
ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle)
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
;;
ppcle-* | powerpclittle-*)
@ -1045,7 +1032,7 @@ case $basic_machine in
;;
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppc64le | powerpc64little)
ppc64le | powerpc64little | ppc64-le | powerpc64-little)
basic_machine=powerpc64le-unknown
;;
ppc64le-* | powerpc64little-*)
@ -1395,14 +1382,14 @@ case $os in
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
| -bitrig* | -openbsd* | -solidbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
| -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
@ -1412,7 +1399,7 @@ case $os in
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
| -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*)
| -onefs* | -tirtos*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@ -1544,8 +1531,6 @@ case $os in
;;
-nacl*)
;;
-ios)
;;
-none)
;;
*)
@ -1641,9 +1626,6 @@ case $basic_machine in
sparc-* | *-sun)
os=-sunos4.1.1
;;
pru-*)
os=-elf
;;
*-be)
os=-beos
;;

View File

@ -1,4 +1,5 @@
GERRIT_HOST: True
GERRIT_SQUASH_UPLOADS: True
CODE_REVIEW_SERVER: chromium-review.googlesource.com
# This file is used by gcl to get repository specific information.
CODE_REVIEW_SERVER: codereview.chromium.org
CC_LIST: google-breakpad-dev@googlegroups.com
TRY_ON_UPLOAD: False
VIEW_VC: https://chromium.googlesource.com/breakpad/breakpad/+/

349
configure vendored
View File

@ -626,8 +626,6 @@ ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
RUST_DEMANGLE_LIBS
RUST_DEMANGLE_CFLAGS
SELFTEST_FALSE
SELFTEST_TRUE
GTEST_LIBS
@ -648,7 +646,6 @@ ANDROID_HOST_FALSE
ANDROID_HOST_TRUE
LINUX_HOST_FALSE
LINUX_HOST_TRUE
WARN_CXXFLAGS
HAVE_CXX11
PTHREAD_CFLAGS
PTHREAD_LIBS
@ -656,6 +653,8 @@ PTHREAD_CC
ax_pthread_config
EGREP
GREP
GCC_FALSE
GCC_TRUE
RANLIB
am__fastdepCXX_FALSE
am__fastdepCXX_TRUE
@ -776,7 +775,6 @@ enable_processor
enable_tools
enable_system_test_libs
enable_selftest
with_rust_demangle
'
ac_precious_vars='build_alias
host_alias
@ -797,9 +795,7 @@ GMOCK_CFLAGS
GMOCK_LIBS
GTEST_CONFIG
GTEST_CFLAGS
GTEST_LIBS
RUST_DEMANGLE_CFLAGS
RUST_DEMANGLE_LIBS'
GTEST_LIBS'
# Initialize some variables set by options.
@ -1437,14 +1433,6 @@ Optional Features:
--enable-selftest Run extra tests with "make check" (may conflict with
optimizations) (default is no)
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-rust-demangle=/path/to/rust-demangle-capi
Link against the rust-demangle library to demangle
Rust language symbols during symbol dumping (default
is no) Pass the path to the crate root.
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
@ -1468,10 +1456,6 @@ Some influential environment variables:
GTEST_CFLAGS
Compiler flags for gtest
GTEST_LIBS Linker flags for gtest
RUST_DEMANGLE_CFLAGS
Compiler flags for rust-demangle
RUST_DEMANGLE_LIBS
Linker flags for rust-demangle
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@ -5736,6 +5720,14 @@ else
RANLIB="$ac_cv_prog_RANLIB"
fi
if test "$GCC" = yes; then
GCC_TRUE=
GCC_FALSE='#'
else
GCC_TRUE='#'
GCC_FALSE=
fi
# let the Makefile know if we're gcc
# Check whether --enable-m32 was given.
if test "${enable_m32+set}" = set; then :
@ -6200,6 +6192,104 @@ rm -rf conftest*
fi
# ===========================================================================
# http://www.nongnu.org/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
# This is what autoupdate's m4 run will expand. It fires
# the warning (with _au_warn_XXX), outputs it into the
# updated configure.ac (with AC_DIAGNOSE), and then outputs
# the replacement expansion.
# This is an auxiliary macro that is also run when
# autoupdate runs m4. It simply calls m4_warning, but
# we need a wrapper so that each warning is emitted only
# once. We break the quoting in m4_warning's argument in
# order to expand this macro's arguments, not AU_DEFUN's.
# Finally, this is the expansion that is picked up by
# autoconf. It tells the user to run autoupdate, and
# then outputs the replacement expansion. We do not care
# about autoupdate's warning because that contains
# information on what to do *after* running autoupdate.
@ -6585,6 +6675,68 @@ fi
done
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXXFLAGS to
# enable support. VERSION may be '11' (for the C++11 standard) or '14'
# (for the C++14 standard).
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# required and that the macro should error out if no mode with that
# support is found. If specified 'optional', then configuration proceeds
# regardless, after defining HAVE_CXX${VERSION} if and only if a
# supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
ax_cxx_compile_cxx11_required=true
ac_ext=cpp
@ -7245,136 +7397,6 @@ $as_echo "#define HAVE_CXX11 1" >>confdefs.h
fi
WARN_CXXFLAGS=
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -Werror=unknown-warning-option" >&5
$as_echo_n "checking whether C++ compiler accepts -Werror=unknown-warning-option... " >&6; }
if ${ax_cv_check_cxxflags___Werror_unknown_warning_option+:} false; then :
$as_echo_n "(cached) " >&6
else
ax_check_save_flags=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -Werror=unknown-warning-option"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
ax_cv_check_cxxflags___Werror_unknown_warning_option=yes
else
ax_cv_check_cxxflags___Werror_unknown_warning_option=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CXXFLAGS=$ax_check_save_flags
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___Werror_unknown_warning_option" >&5
$as_echo "$ax_cv_check_cxxflags___Werror_unknown_warning_option" >&6; }
if test "x$ax_cv_check_cxxflags___Werror_unknown_warning_option" = xyes; then :
ax_compiler_flags_test="-Werror=unknown-warning-option"
else
ax_compiler_flags_test=""
fi
for flag in -Wmissing-braces -Wnon-virtual-dtor -Woverloaded-virtual -Wreorder -Wsign-compare -Wunused-variable -Wvla ; do
as_CACHEVAR=`$as_echo "ax_cv_check_cxxflags_${ax_compiler_flags_test}_$flag" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5
$as_echo_n "checking whether C++ compiler accepts $flag... " >&6; }
if eval \${$as_CACHEVAR+:} false; then :
$as_echo_n "(cached) " >&6
else
ax_check_save_flags=$CXXFLAGS
CXXFLAGS="$CXXFLAGS ${ax_compiler_flags_test} $flag"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
eval "$as_CACHEVAR=yes"
else
eval "$as_CACHEVAR=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CXXFLAGS=$ax_check_save_flags
fi
eval ac_res=\$$as_CACHEVAR
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
if ${WARN_CXXFLAGS+:} false; then :
case " $WARN_CXXFLAGS " in #(
*" $flag "*) :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS already contains \$flag"; } >&5
(: WARN_CXXFLAGS already contains $flag) 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } ;; #(
*) :
as_fn_append WARN_CXXFLAGS " $flag"
{ { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5
(: WARN_CXXFLAGS="$WARN_CXXFLAGS") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
;;
esac
else
WARN_CXXFLAGS=$flag
{ { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5
(: WARN_CXXFLAGS="$WARN_CXXFLAGS") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
fi
else
:
fi
done
as_fn_append WARN_CXXFLAGS " -Werror"
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
# Only build Linux client libs when compiling for Linux
case $host in
*-*-linux* | *-android* )
@ -7725,31 +7747,6 @@ else
fi
# Check whether --with-rust-demangle was given.
if test "${with_rust_demangle+set}" = set; then :
withval=$with_rust_demangle; case "${withval}" in
yes)
as_fn_error $? "You must pass the path to the rust-demangle-capi crate for --with-rust-demangle" "$LINENO" 5
;;
no)
rust_demangle=false
;;
*)
if ! test -f "${withval}/Cargo.toml"; then
as_fn_error $? "You must pass the path to the rust-demangle-capi crate for --with-rust-demangle" "$LINENO" 5
fi
RUST_DEMANGLE_CFLAGS="-DHAVE_RUST_DEMANGLE -I${withval}/target/include"
RUST_DEMANGLE_LIBS="-L${withval}/target/release -lrust_demangle -lpthread -ldl"
;;
esac
else
rust_demangle=false
fi
ac_config_files="$ac_config_files breakpad.pc breakpad-client.pc Makefile"
@ -7901,6 +7898,10 @@ if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
as_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${GCC_TRUE}" && test -z "${GCC_FALSE}"; then
as_fn_error $? "conditional \"GCC\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${LINUX_HOST_TRUE}" && test -z "${LINUX_HOST_FALSE}"; then
as_fn_error $? "conditional \"LINUX_HOST\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5

View File

@ -28,7 +28,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
AC_PREREQ(2.64)
AC_PREREQ(2.57)
AC_INIT(breakpad, 0.1, google-breakpad-dev@googlegroups.com)
dnl Sanity check: the argument is just a file that should exist.
@ -48,6 +48,7 @@ AM_PROG_CC_C_O
AC_PROG_CPP
AC_PROG_CXX
AC_PROG_RANLIB
AM_CONDITIONAL(GCC, test "$GCC" = yes) # let the Makefile know if we're gcc
dnl This must come before all the feature tests below.
AC_ARG_ENABLE(m32,
@ -71,34 +72,13 @@ AC_ARG_ENABLE(m32,
AC_HEADER_STDC
AC_SYS_LARGEFILE
m4_include(m4/ax_pthread.m4)
AX_PTHREAD
AC_CHECK_HEADERS([a.out.h])
m4_include(m4/ax_cxx_compile_stdcxx.m4)
AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
dnl Test supported warning flags.
WARN_CXXFLAGS=
dnl This warning flag is used by clang. Its default behavior is to warn when
dnl given an unknown flag rather than error out.
AC_LANG_PUSH([C++])
AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[
ax_compiler_flags_test="-Werror=unknown-warning-option"
],[
ax_compiler_flags_test=""
])
AX_APPEND_COMPILE_FLAGS(m4_flatten([
-Wmissing-braces
-Wnon-virtual-dtor
-Woverloaded-virtual
-Wreorder
-Wsign-compare
-Wunused-variable
-Wvla
]), [WARN_CXXFLAGS], [${ax_compiler_flags_test}])
AS_VAR_APPEND([WARN_CXXFLAGS], " -Werror")
AC_LANG_POP([C++])
AC_SUBST([WARN_CXXFLAGS])
# Only build Linux client libs when compiling for Linux
case $host in
*-*-linux* | *-android* )
@ -215,31 +195,6 @@ AC_ARG_ENABLE(selftest,
[selftest=false])
AM_CONDITIONAL(SELFTEST, test x$selftest = xtrue)
AC_ARG_WITH(rust-demangle,
AS_HELP_STRING([--with-rust-demangle=/path/to/rust-demangle-capi],
[Link against the rust-demangle library]
[to demangle Rust language symbols during]
[symbol dumping (default is no)]
[Pass the path to the crate root.]),
[case "${withval}" in
yes)
AC_MSG_ERROR(You must pass the path to the rust-demangle-capi crate for --with-rust-demangle)
;;
no)
rust_demangle=false
;;
*)
if ! test -f "${withval}/Cargo.toml"; then
AC_MSG_ERROR(You must pass the path to the rust-demangle-capi crate for --with-rust-demangle)
fi
RUST_DEMANGLE_CFLAGS="-DHAVE_RUST_DEMANGLE -I${withval}/target/include"
RUST_DEMANGLE_LIBS="-L${withval}/target/release -lrust_demangle -lpthread -ldl"
;;
esac],
[rust_demangle=false])
AC_ARG_VAR([RUST_DEMANGLE_CFLAGS], [Compiler flags for rust-demangle])
AC_ARG_VAR([RUST_DEMANGLE_LIBS], [Linker flags for rust-demangle])
AC_CONFIG_FILES(m4_flatten([
breakpad.pc
breakpad-client.pc

View File

@ -1,48 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- AUTOGENERATED BY deps-to-manifest.py; DO NOT EDIT -->
<manifest>
<default revision='refs/heads/master'
remote='chromium'
sync-c='true'
sync-j='8' />
<remote name='github'
fetch='https://github.com/'
review='' />
<remote name='chromium'
fetch='https://chromium.googlesource.com/'
review='https://chromium-review.googlesource.com' />
<project path='src'
name='breakpad/breakpad'
revision='refs/heads/master'
remote='chromium' />
<project path='src/src/tools/gyp'
name='external/gyp/'
revision='e8ab0833a42691cd2184bd4c45d779e43821d3e0'
remote='chromium' />
<project path='src/src/third_party/glog'
name='google/glog.git'
revision='refs/tags/v0.3.4'
remote='github' />
<project path='src/src/testing'
name='google/googletest.git'
revision='refs/tags/release-1.8.0'
remote='github' />
<project path='src/src/third_party/lss'
name='linux-syscall-support/'
revision='3f6478ac95edf86cd3da300c2c0d34a438f5dbeb'
remote='chromium' />
<project path='src/src/third_party/protobuf/protobuf'
name='google/protobuf.git'
revision='cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac'
remote='github' />
</manifest>

View File

@ -69,8 +69,8 @@ amount of work from a crashed process.
The mechanisms for installing an exception handler vary between operating
systems. On Windows, its a relatively simple matter of making one call to
register a [top-level exception
filter](http://msdn.microsoft.com/library/en-us/debug/base/setunhandledexceptionfilter.asp)
register a [top-level exception filter]
(http://msdn.microsoft.com/library/en-us/debug/base/setunhandledexceptionfilter.asp)
callback function. On most Unix-like systems such as Linux, processes are
informed of exceptions by the delivery of a signal, so an exception handler
takes the form of a signal handler. The native mechanism to catch exceptions on
@ -178,8 +178,9 @@ didnt actually handle an exception. This function may be useful for developer
who want to test their applications with Breakpad enabled but still retain the
ability to use traditional debugging techniques. It also allows a
Breakpad-enabled application to coexist with a platforms native crash reporting
system, such as Mac OS X [CrashReporter](http://developer.apple.com/technotes/tn2004/tn2123.html)
and [Windows Error Reporting](http://msdn.microsoft.com/isv/resources/wer/).
system, such as Mac OS X [CrashReporter]
(http://developer.apple.com/technotes/tn2004/tn2123.html) and [Windows Error
Reporting](http://msdn.microsoft.com/isv/resources/wer/).
Typically, when Breakpad handles an exception fully and no debuggers are
involved, the crashed process will terminate.

View File

@ -9,7 +9,8 @@ minidumps on request for programs that have not crashed.
Breakpad is currently used by Google Chrome, Firefox, Google Picasa, Camino,
Google Earth, and other projects.
![Workflow](breakpad.png)
![http://google-breakpad.googlecode.com/svn/wiki/breakpad.png]
(http://google-breakpad.googlecode.com/svn/wiki/breakpad.png)
Breakpad has three main components:
@ -89,7 +90,7 @@ known as "out-of-process" exception handling.
## Breakpad Code Overview
All the client-side code is found by visiting the Google Project at
https://chromium.googlesource.com/breakpad/breakpad. The following directory structure is
http://code.google.com/p/google-breakpad. The following directory structure is
present in the `src` directory:
* `processor` Contains minidump-processing code that is used on the server
@ -100,9 +101,14 @@ present in the `src` directory:
(Among other directories)
* [Windows Integration Guide](windows_client_integration.md)
* [Mac Integration Guide](mac_breakpad_starter_guide.md)
* [Linux Integration Guide](linux_starter_guide.md)
* <a
href='http://code.google.com/p/google-breakpad/wiki/WindowsClientIntegration'>Windows
Integration Guide</a>
* <a
href='http://code.google.com/p/google-breakpad/wiki/MacBreakpadStarterGuide'>Mac
Integration Guide</a>
* <a href='http://code.google.com/p/google-breakpad/wiki/LinuxStarterGuide'>
Linux Integration Guide</a>
## Build process specifics(symbol generation)

View File

@ -75,8 +75,10 @@
## More Information
* Project home: https://chromium.googlesource.com/breakpad/breakpad
* Project home: http://code.google.com/p/google-breakpad/
* Mailing lists
* [google-breakpad-dev@googlegroups.com](http://groups.google.com/group/google-breakpad-dev/)
* [google-breakpad-discuss@googlegroups.com](http://groups.google.com/group/google-breakpad-discuss/)
* [google-breakpad-dev@googlegroups.com]
(http://groups.google.com/group/google-breakpad-dev/)
* [google-breakpad-discuss@googlegroups.com]
(http://groups.google.com/group/google-breakpad-discuss/)
* Ask me (irc.mozilla.org: mento)

View File

@ -13,9 +13,8 @@ The Breakpad processor is intended to sit at the core of a comprehensive
crash-reporting system that does not require debugging information to be
provided to those running applications being monitored. Some existing
crash-reporting systems, such as [GNOME](http://www.gnome.org/)s Bug-Buddy and
[Apple](http://www.apple.com/)s
[CrashReporter](http://developer.apple.com/technotes/tn2004/tn2123.html),
require symbolic
[Apple](http://www.apple.com/)s [CrashReporter]
(http://developer.apple.com/technotes/tn2004/tn2123.html), require symbolic
information to be present on the end users computer; in the case of
CrashReporter, the reports are transmitted only to Apple, not to third-party
developers. Other systems, such as [Microsoft](http://www.microsoft.com/)s
@ -82,12 +81,13 @@ set to produce dumps at any time a developer deems appropriate. The Breakpad
processor can handle dumps in the minidump format, either generated by an
[Breakpad client “handler”](client_design.md) implementation, or by another
implementation that produces dumps in this format. The
[DbgHelp.dll!MiniDumpWriteDump](http://msdn2.microsoft.com/en-us/library/ms680360.aspx)
function on Windows
[DbgHelp.dll!MiniDumpWriteDump]
(http://msdn2.microsoft.com/en-us/library/ms680360.aspx) function on Windows
produces dumps in this format, and is the basis for the Breakpad handler
implementation on that platform.
The [minidump format](http://msdn.microsoft.com/en-us/library/ms679293%28VS.85%29.aspx) is
The [minidump format]
(http://msdn.microsoft.com/en-us/library/ms679293%28VS.85%29.aspx) is
essentially a simple container format, organized as a series of streams. Each
stream contains some type of data relevant to the crash. A typical “normal”
minidump contains streams for the thread list, the module list, the CPU context
@ -155,12 +155,11 @@ storage needs.
Breakpads symbol file format is text-based, and was defined to be fairly
human-readable and to encompass the needs of multiple platforms. The Breakpad
processor itself does not operate directly with native symbol formats
([DWARF](http://dwarf.freestandards.org/) and
[STABS](http://sourceware.org/gdb/current/onlinedocs/stabs.html)
on most Unix-like systems,
[.pdb files](http://msdn2.microsoft.com/en-us/library/yd4f8bd1(VS.80).aspx)
on Windows),
processor itself does not operate directly with native symbol formats ([DWARF]
(http://dwarf.freestandards.org/) and [STABS]
(http://sourceware.org/gdb/current/onlinedocs/stabs.html) on most Unix-like
systems, [.pdb files]
(http://msdn2.microsoft.com/en-us/library/yd4f8bd1(VS.80).aspx) on Windows),
because of the complications in accessing potentially complex symbol formats
with slight variations between platforms, stored within different types of
binary formats. In the case of `.pdb` files, the debugging format is not even

View File

@ -8,12 +8,16 @@ traces from the information contained within a minidump file.
## Starting the Process
Typically the stack walking process is initiated by instantiating the
[MinidumpProcessor](../src/processor/minidump_processor.cc)
class and calling the [MinidumpProcessor::Process](../src/processor/minidump_processor.cc#61)
[MinidumpProcessor]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/minidump_processor.cc)
class and calling the [MinidumpProcessor::Process]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/minidump_processor.cc#61)
method, providing it a minidump file to process. To produce a useful stack
trace, the MinidumpProcessor requires two other objects which are passed in its
constructor: a [SymbolSupplier](../src/google_breakpad/processor/symbol_supplier.h)
and a [SourceLineResolverInterface](../src/google_breakpad/processor/source_line_resolver_interface.h).
constructor: a [SymbolSupplier]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/symbol_supplier.h)
and a [SourceLineResolverInterface]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h).
The SymbolSupplier object is responsible for locating and providing SymbolFiles
that match modules from the minidump. The SourceLineResolverInterface is
responsible for loading the symbol files and using the information contained
@ -22,26 +26,29 @@ information on how to unwind from a stack frame to its caller. More detail will
be provided on these interactions later.
A number of data streams are extracted from the minidump to begin stack walking:
the list of threads from the process
([MinidumpThreadList](../src/google_breakpad/processor/minidump.h#335)),
the list of modules loaded in the process
([MinidumpModuleList](../src/google_breakpad/processor/minidump.h#501)),
the list of threads from the process ([MinidumpThreadList]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#335)),
the list of modules loaded in the process ([MinidumpModuleList]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#501)),
and information about the exception that caused the process to crash
([MinidumpException](../src/google_breakpad/processor/minidump.h#615)).
([MinidumpException]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#615)).
## Enumerating Threads
For each thread in the thread list
([MinidumpThread](../src/google_breakpad/processor/minidump.h#299)),
the thread memory containing the stack for the thread
([MinidumpMemoryRegion](../src/google_breakpad/processor/minidump.h#236))
For each thread in the thread list ([MinidumpThread]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#299)),
the thread memory containing the stack for the thread ([MinidumpMemoryRegion]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#236))
and the CPU context representing the CPU state of the thread at the time the
dump was written ([MinidumpContext](../src/google_breakpad/processor/minidump.h#171))
dump was written ([MinidumpContext]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#171))
are extracted from the minidump. If the thread being processed is the thread
that produced the exception then a CPU context is obtained from the
MinidumpException object instead, which represents the CPU state of the thread
at the point of the exception. A stack walker is then instantiated by calling
the [Stackwalker::StackwalkerForCPU](../src/google_breakpad/processor/stackwalker.h#77)
the [Stackwalker::StackwalkerForCPU]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/stackwalker.h#77)
method and passing it the CPU context, the thread memory, the module list, as
well as the SymbolSupplier and SourceLineResolverInterface. This method selects
the specific !Stackwalker subclass based on the CPU architecture of the provided
@ -50,7 +57,8 @@ CPU context and returns an instance of that subclass.
## Walking a thread's stack
Once a !Stackwalker instance has been obtained, the processor calls the
[Stackwalker::Walk](../src/google_breakpad/processor/source_line_resolver_interface.h)
[Stackwalker::Walk]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h)
method to obtain a list of frames representing the stack of this thread. The
!Stackwalker starts by calling the GetContextFrame method which returns a
StackFrame representing the top of the stack, with CPU state provided by the
@ -61,24 +69,28 @@ for each frame in turn:
The address of the instruction pointer of the current frame is used to determine
which module contains the current frame by calling the module list's
[GetModuleForAddress](../src/google_breakpad/processor/code_modules.h#56) method.
[GetModuleForAddress]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/code_modules.h#56)
method.
### Locating Symbols
If a module is located, the SymbolSupplier is asked to locate symbols
corresponding to the module by calling its
[GetCStringSymbolData](../src/google_breakpad/processor/symbol_supplier.h#87)
corresponding to the module by calling its [GetCStringSymbolData]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/symbol_supplier.h#87)
method. Typically this is implemented by using the module's debug filename (the
PDB filename for Windows dumps) and debug identifier (a GUID plus one extra
digit) as a lookup key. The [SimpleSymbolSupplier](../src/processor/simple_symbol_supplier.cc)
digit) as a lookup key. The [SimpleSymbolSupplier]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/simple_symbol_supplier.cc)
class simply uses these as parts of a file path to locate a flat file on disk.
### Loading Symbols
If a symbol file is located, the SourceLineResolverInterface is then asked to
load the symbol file by calling its
[LoadModuleUsingMemoryBuffer](../src/google_breakpad/processor/source_line_resolver_interface.h#71)
method. The [BasicSourceLineResolver](../src/processor/basic_source_line_resolver.cc)
load the symbol file by calling its [LoadModuleUsingMemoryBuffer]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h#71)
method. The [BasicSourceLineResolver]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/basic_source_line_resolver.cc)
implementation parses the text-format [symbol file](symbol_files.md) into
in-memory data structures to make lookups by address of function names, source
line information, and unwind information easy.
@ -86,7 +98,8 @@ line information, and unwind information easy.
### Getting source line information
If a symbol file has been successfully loaded, the SourceLineResolverInterface's
[FillSourceLineInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#89)
[FillSourceLineInfo]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h#89)
method is called to provide a function name and source line information for the
current frame. This is done by subtracting the base address of the module
containing the current frame from the instruction pointer of the current frame
@ -106,15 +119,17 @@ nearest symbol that is less than the provided RVA.
### Finding the caller frame
To find the next frame in the stack, the !Stackwalker calls its
[GetCallerFrame](../src/google_breakpad/processor/stackwalker.h#186)
To find the next frame in the stack, the !Stackwalker calls its [GetCallerFrame]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/stackwalker.h#186)
method, passing in the current frame. Each !Stackwalker subclass implements
GetCallerFrame differently, but there are common patterns.
Typically the first step is to query the SourceLineResolverInterface for the
presence of detailed unwind information. This is done using its
[FindWindowsFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#96)
and [FindCFIFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#102)
[FindWindowsFrameInfo]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h#96)
and [FindCFIFrameInfo]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h#102)
methods. These methods look for Windows unwind info extracted from a PDB file
([STACK WIN](SymbolFiles#STACK_WIN_records.md) lines from the symbol file), or
DWARF CFI extracted from a binary ([STACK CFI](SymbolFiles#STACK_CFI_records.md)
@ -133,11 +148,12 @@ to produce the caller frame.
If no caller frame was found by any other method most !Stackwalker
implementations resort to stack scanning by looking at each word on the stack
down to a fixed depth (implemented in the
[Stackwalker::ScanForReturnAddress](../src/google_breakpad/processor/stackwalker.h#131)
down to a fixed depth (implemented in the [Stackwalker::ScanForReturnAddress]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/stackwalker.h#131)
method) and using a heuristic to attempt to find a reasonable return address
(implemented in the
[Stackwalker::InstructionAddressSeemsValid](../src/google_breakpad/processor/stackwalker.h#111) method).
(implemented in the [Stackwalker::InstructionAddressSeemsValid]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/stackwalker.h#111)
method).
If no caller frame is found or the caller frame seems invalid, stack walking
stops. If a caller frame was found then these steps repeat using the new frame

View File

@ -197,10 +197,10 @@ All fields of a `STACK WIN` record, except for the last, are hexadecimal
numbers.
The _type_ field indicates what sort of stack frame data this record holds. Its
value should be one of the values of the
[StackFrameTypeEnum](http://msdn.microsoft.com/en-us/library/bc5207xw%28VS.100%29.aspx)
type in Microsoft's
[Debug Interface Access (DIA)](http://msdn.microsoft.com/en-us/library/x93ctkx8%28VS.100%29.aspx) API.
value should be one of the values of the [StackFrameTypeEnum]
(http://msdn.microsoft.com/en-us/library/bc5207xw%28VS.100%29.aspx) type in
Microsoft's [Debug Interface Access (DIA)]
(http://msdn.microsoft.com/en-us/library/x93ctkx8%28VS.100%29.aspx) API.
Breakpad uses only records of type 4 (`FrameTypeFrameData`) and 0
(`FrameTypeFPO`); it ignores others. These types differ only in whether the last
field is an _allocates\_base\_pointer_ flag (`FrameTypeFPO`) or a program string
@ -274,7 +274,8 @@ follows:
* If the _has\_program\_string_ field of a `STACK WIN` record is not zero,
then the record's final field is a string containing a program to be
interpreted to recover the caller's frame. The comments in the
[postfix\_evaluator.h](../src/processor/postfix_evaluator.h#40)
[postfix\_evaluator.h]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/postfix_evaluator.h#40)
header file explain the language in which the program is written. You should
place the following variables in the dictionary before interpreting the
program:

View File

@ -1,67 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# For every FLAG1, FLAG2 it is checked whether the compiler works with the
# flag. If it does, the flag is added FLAGS-VARIABLE
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. During the check the flag is always added to the
# current language's flags.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: This macro depends on the AX_APPEND_FLAG and
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
# AX_APPEND_LINK_FLAGS.
#
# LICENSE
#
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 5
AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
for flag in $1; do
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
done
])dnl AX_APPEND_COMPILE_FLAGS

View File

@ -1,71 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
#
# DESCRIPTION
#
# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
# added in between.
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
# FLAG.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
AC_DEFUN([AX_APPEND_FLAG],
[dnl
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
AS_VAR_SET_IF(FLAGS,[
AS_CASE([" AS_VAR_GET(FLAGS) "],
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
[
AS_VAR_APPEND(FLAGS,[" $1"])
AC_RUN_LOG([: FLAGS="$FLAGS"])
])
],
[
AS_VAR_SET(FLAGS,[$1])
AC_RUN_LOG([: FLAGS="$FLAGS"])
])
AS_VAR_POPDEF([FLAGS])dnl
])dnl AX_APPEND_FLAG

View File

@ -1,74 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 4
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

View File

@ -280,4 +280,4 @@ else
$2
fi
AC_LANG_RESTORE
])dnl AX_PTHREAD
])dnl AX_PTHREAD

View File

@ -1,37 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_REQUIRE_DEFINED(MACRO)
#
# DESCRIPTION
#
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
# been defined and thus are available for use. This avoids random issues
# where a macro isn't expanded. Instead the configure script emits a
# non-fatal:
#
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
#
# It's like AC_REQUIRE except it doesn't expand the required macro.
#
# Here's an example:
#
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
#
# LICENSE
#
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
])dnl AX_REQUIRE_DEFINED

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
set -ex
@ -19,28 +19,6 @@ setup_env() {
export JOBS=$(( $NCPUS < 4 ? $NCPUS : 4 ))
}
# We have to do this by hand rather than use the coverity addon because of
# matrix explosion: https://github.com/travis-ci/travis-ci/issues/1975
# We also do it by hand because when we're throttled, the addon will exit
# the build immediately and skip the main script!
coverity_scan() {
if [ "${COVERITY_SCAN}" != "true" ] || \
[ -n "${TRAVIS_TAG}" ] || \
[ "${TRAVIS_PULL_REQUEST}" = "true" ]
then
echo "Skipping coverity scan."
return
fi
export COVERITY_SCAN_PROJECT_NAME="${TRAVIS_REPO_SLUG}"
export COVERITY_SCAN_NOTIFICATION_EMAIL="google-breakpad-dev@googlegroups.com"
export COVERITY_SCAN_BUILD_COMMAND="make -j${JOBS}"
export COVERITY_SCAN_BUILD_COMMAND_PREPEND="git clean -q -x -d -f; git checkout -f; ./configure"
export COVERITY_SCAN_BRANCH_PATTERN="master"
curl -s "https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh" | bash || :
}
# Do an in-tree build and make sure tests pass.
build() {
./configure
@ -51,20 +29,15 @@ build() {
# Do an out-of-tree build and make sure we can create a release tarball.
build_out_of_tree() {
mkdir -p build/native
pushd build/native >/dev/null
cd build/native
../../configure
make -j${JOBS} distcheck VERBOSE=1
popd >/dev/null
}
main() {
setup_env
build
build_out_of_tree
# Do scans last as they like to dirty the tree and some tests
# expect a clean tree (like code style checks).
coverity_scan
}
main "$@"

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
set -ex
get_depot_tools() {

View File

@ -1,131 +0,0 @@
#!/usr/bin/env python
import os
import argparse
import shutil
import string
import sys
# parse args
parser = argparse.ArgumentParser()
parser.add_argument('src', help='google_breakpad root directory where build was done')
parser.add_argument('dst', help='destination root directory where google_breakpad have to be installed')
args = parser.parse_args()
# test args
if not os.path.isdir(args.src):
print(args.src + ' not such directory')
sys.exit(1)
# customize args
google_breakpad_src_dir = os.path.join( args.src, 'src' )
dst_dir = os.path.join( args.dst )
# function to define src and dst in copy function
def convertSrcAndDst( srcFile, dstFile, subDir ):
src = os.path.join(google_breakpad_src_dir, srcFile.replace('/', os.path.sep))
dst = os.path.join(dst_dir, subDir, dstFile.replace('/', os.path.sep))
return src, dst
def copyFile(src, dst):
# print what we will doing
print (src + ' ==>> ' + dst )
# be sure dst directory exist or create it
dst_dir = os.path.dirname(dst)
if not os.path.exists(dst_dir):
os.makedirs(dst_dir)
# copy
shutil.copy2(src, dst)
google_breakpad_header_files = [
'client/windows/common/ipc_protocol.h',
'client/windows/crash_generation/client_info.h',
'client/windows/crash_generation/crash_generation_client.h',
'client/windows/crash_generation/crash_generation_server.h',
'client/windows/crash_generation/minidump_generator.h',
'client/windows/handler/exception_handler.h',
'common/scoped_ptr.h',
'common/windows/string_utils-inl.h',
'common/windows/http_upload.h',
'google_breakpad/common/breakpad_types.h',
'google_breakpad/common/minidump_format.h',
'google_breakpad/common/minidump_cpu_amd64.h',
'google_breakpad/common/minidump_cpu_arm.h',
'google_breakpad/common/minidump_cpu_arm64.h',
'google_breakpad/common/minidump_cpu_mips.h',
'google_breakpad/common/minidump_cpu_ppc.h',
'google_breakpad/common/minidump_cpu_ppc64.h',
'google_breakpad/common/minidump_cpu_sparc.h',
'google_breakpad/common/minidump_cpu_x86.h',
'google_breakpad/common/minidump_exception_linux.h',
'google_breakpad/common/minidump_exception_mac.h',
'google_breakpad/common/minidump_exception_ps3.h',
'google_breakpad/common/minidump_exception_solaris.h',
'google_breakpad/common/minidump_exception_win32.h'
]
# copy headers
for f in google_breakpad_header_files:
src, dst = convertSrcAndDst(f, f, os.path.join('include', 'breakpad'))
copyFile(src, dst)
google_breakpad_library_dir_base = [
'client/windows',
'client/windows/crash_generation',
'client/windows/handler'
]
google_breakpad_library_dir_end = 'lib'
google_breakpad_library_files = [
'crash_generation_client.lib',
'crash_generation_server.lib',
'common.lib',
'exception_handler.lib'
]
build_type = [
'Debug',
'Release'
]
# copy libraries
for dir in google_breakpad_library_dir_base:
for buildType in build_type:
for file in google_breakpad_library_files:
path = os.path.join(dir, buildType, 'lib', file)
src, dst = convertSrcAndDst(path, os.path.basename(path), os.path.join('lib', buildType))
if os.path.exists(src):
copyFile(src, dst)
google_breakpad_binary_dir_base = [
'tools/windows/dump_syms'
]
google_breakpad_binary_files = [
'dump_syms.exe'
]
for dir in google_breakpad_binary_dir_base:
for buildType in build_type:
for file in google_breakpad_binary_files:
path = os.path.join(dir, buildType, file)
src, dst = convertSrcAndDst(path, os.path.basename(path), 'bin')
if os.path.exists(src):
copyFile(src, dst)

View File

@ -251,8 +251,8 @@
'win_release_Optimization%': '2', # 2 = /Os
'win_debug_Optimization%': '0', # 0 = /Od
# See http://msdn.microsoft.com/en-us/library/aa652367(VS.71).aspx
'win_release_RuntimeLibrary%': '2', # 2 = /MD (nondebug dynamic)
'win_debug_RuntimeLibrary%': '3', # 3 = /MDd (debug dynamic)
'win_release_RuntimeLibrary%': '0', # 0 = /MT (nondebug static)
'win_debug_RuntimeLibrary%': '1', # 1 = /MTd (debug static)
'release_extra_cflags%': '',
'debug_extra_cflags%': '',
@ -894,7 +894,7 @@
],
'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'],
'msvs_disabled_warnings': [
4091, 4100, 4127, 4396, 4503, 4512, 4819, 4995, 4702
4100, 4127, 4396, 4503, 4512, 4819, 4995, 4702
],
'msvs_settings': {
'VCCLCompilerTool': {

View File

@ -93,12 +93,11 @@ NSString* GetPlatform() {
@implementation BreakpadController
+ (BreakpadController*)sharedInstance {
static dispatch_once_t onceToken;
static BreakpadController* sharedInstance ;
dispatch_once(&onceToken, ^{
sharedInstance = [[BreakpadController alloc] initSingleton];
});
return sharedInstance;
@synchronized(self) {
static BreakpadController* sharedInstance_ =
[[BreakpadController alloc] initSingleton];
return sharedInstance_;
}
}
- (id)init {
@ -180,9 +179,10 @@ NSString* GetPlatform() {
enableUploads_ = YES;
[self sendStoredCrashReports];
} else {
// disable the enableUpload_ flag.
// sendDelay checks this flag and disables the upload of logs by sendStoredCrashReports
enableUploads_ = NO;
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(sendStoredCrashReports)
object:nil];
}
});
}
@ -317,35 +317,38 @@ NSString* GetPlatform() {
[userDefaults synchronize];
}
// This method must be called from the breakpad queue.
- (void)sendStoredCrashReports {
if (BreakpadGetCrashReportCount(breakpadRef_) == 0)
return;
dispatch_async(queue_, ^{
if (BreakpadGetCrashReportCount(breakpadRef_) == 0)
return;
int timeToWait = [self sendDelay];
int timeToWait = [self sendDelay];
// Unable to ever send report.
if (timeToWait == -1)
return;
// Unable to ever send report.
if (timeToWait == -1)
return;
// A report can be sent now.
if (timeToWait == 0) {
[self reportWillBeSent];
BreakpadUploadNextReportWithParameters(breakpadRef_,
uploadTimeParameters_);
// A report can be sent now.
if (timeToWait == 0) {
[self reportWillBeSent];
BreakpadUploadNextReportWithParameters(breakpadRef_,
uploadTimeParameters_);
// If more reports must be sent, make sure this method is called again.
if (BreakpadGetCrashReportCount(breakpadRef_) > 0)
timeToWait = uploadIntervalInSeconds_;
}
// If more reports must be sent, make sure this method is called again.
if (BreakpadGetCrashReportCount(breakpadRef_) > 0)
timeToWait = uploadIntervalInSeconds_;
}
// A report must be sent later.
if (timeToWait > 0) {
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeToWait * NSEC_PER_SEC));
dispatch_after(delay, queue_, ^{
[self sendStoredCrashReports];
});
}
// A report must be sent later.
if (timeToWait > 0) {
// performSelector: doesn't work on queue_
dispatch_async(dispatch_get_main_queue(), ^{
[self performSelector:@selector(sendStoredCrashReports)
withObject:nil
afterDelay:timeToWait];
});
}
});
}
@end

View File

@ -255,7 +255,7 @@ CrashGenerationServer::ClientEvent(short revents)
}
if (crashing_pid == -1 || signal_fd == -1) {
if (signal_fd != -1)
if (signal_fd)
close(signal_fd);
return true;
}

View File

@ -41,21 +41,8 @@ namespace google_breakpad {
// One of these is produced for each mapping in the process (i.e. line in
// /proc/$x/maps).
struct MappingInfo {
// On Android, relocation packing can mean that the reported start
// address of the mapping must be adjusted by a bias in order to
// compensate for the compression of the relocation section. The
// following two members hold (after LateInit) the adjusted mapping
// range. See crbug.com/606972 for more information.
uintptr_t start_addr;
size_t size;
// When Android relocation packing causes |start_addr| and |size| to
// be modified with a load bias, we need to remember the unbiased
// address range. The following structure holds the original mapping
// address range as reported by the operating system.
struct {
uintptr_t start_addr;
uintptr_t end_addr;
} system_mapping_info;
size_t offset; // offset into the backed file.
bool exec; // true if the mapping has the execute bit set.
char name[NAME_MAX];

View File

@ -36,19 +36,19 @@ namespace google_breakpad {
// Minidump defines register structures which are different from the raw
// structures which we get from the kernel. These are platform specific
// functions to juggle the ucontext_t and user structures into minidump format.
// functions to juggle the ucontext and user structures into minidump format.
#if defined(__i386__)
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
return uc->uc_mcontext.gregs[REG_ESP];
}
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
return uc->uc_mcontext.gregs[REG_EIP];
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
const struct _libc_fpstate* fp) {
const greg_t* regs = uc->uc_mcontext.gregs;
@ -88,15 +88,15 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
#elif defined(__x86_64)
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
return uc->uc_mcontext.gregs[REG_RSP];
}
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
return uc->uc_mcontext.gregs[REG_RIP];
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
const struct _libc_fpstate* fpregs) {
const greg_t* regs = uc->uc_mcontext.gregs;
@ -145,15 +145,15 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
#elif defined(__ARM_EABI__)
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
return uc->uc_mcontext.arm_sp;
}
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
return uc->uc_mcontext.arm_pc;
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) {
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
out->context_flags = MD_CONTEXT_ARM_FULL;
out->iregs[0] = uc->uc_mcontext.arm_r0;
@ -184,15 +184,15 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) {
#elif defined(__aarch64__)
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
return uc->uc_mcontext.sp;
}
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
return uc->uc_mcontext.pc;
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
const struct fpsimd_context* fpregs) {
out->context_flags = MD_CONTEXT_ARM64_FULL;
@ -210,15 +210,15 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
#elif defined(__mips__)
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP];
}
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
return uc->uc_mcontext.pc;
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) {
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
#if _MIPS_SIM == _ABI64
out->context_flags = MD_CONTEXT_MIPS64_FULL;
#elif _MIPS_SIM == _ABIO32

View File

@ -39,23 +39,23 @@
namespace google_breakpad {
// Wraps platform-dependent implementations of accessors to ucontext_t structs.
// Wraps platform-dependent implementations of accessors to ucontext structs.
struct UContextReader {
static uintptr_t GetStackPointer(const ucontext_t* uc);
static uintptr_t GetStackPointer(const struct ucontext* uc);
static uintptr_t GetInstructionPointer(const ucontext_t* uc);
static uintptr_t GetInstructionPointer(const struct ucontext* uc);
// Juggle a arch-specific ucontext_t into a minidump format
// Juggle a arch-specific ucontext into a minidump format
// out: the minidump structure
// info: the collection of register structures.
#if defined(__i386__) || defined(__x86_64)
static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
static void FillCPUContext(RawContextCPU *out, const ucontext *uc,
const struct _libc_fpstate* fp);
#elif defined(__aarch64__)
static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
static void FillCPUContext(RawContextCPU *out, const ucontext *uc,
const struct fpsimd_context* fpregs);
#else
static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc);
static void FillCPUContext(RawContextCPU *out, const ucontext *uc);
#endif
};

View File

@ -424,7 +424,7 @@ int ExceptionHandler::ThreadEntry(void *arg) {
// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) {
bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
if (filter_ && !filter_(callback_context_))
return false;
@ -439,9 +439,9 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) {
// Fill in all the holes in the struct to make Valgrind happy.
memset(&g_crash_context_, 0, sizeof(g_crash_context_));
memcpy(&g_crash_context_.siginfo, info, sizeof(siginfo_t));
memcpy(&g_crash_context_.context, uc, sizeof(ucontext_t));
memcpy(&g_crash_context_.context, uc, sizeof(struct ucontext));
#if defined(__aarch64__)
ucontext_t* uc_ptr = (ucontext_t*)uc;
struct ucontext* uc_ptr = (struct ucontext*)uc;
struct fpsimd_context* fp_ptr =
(struct fpsimd_context*)&uc_ptr->uc_mcontext.__reserved;
if (fp_ptr->head.magic == FPSIMD_MAGIC) {
@ -450,9 +450,9 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) {
}
#elif !defined(__ARM_EABI__) && !defined(__mips__)
// FP state is not part of user ABI on ARM Linux.
// In case of MIPS Linux FP state is already part of ucontext_t
// In case of MIPS Linux FP state is already part of struct ucontext
// and 'float_state' is not a member of CrashContext.
ucontext_t* uc_ptr = (ucontext_t*)uc;
struct ucontext* uc_ptr = (struct ucontext*)uc;
if (uc_ptr->uc_mcontext.fpregs) {
memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fpregs,
sizeof(g_crash_context_.float_state));
@ -476,7 +476,7 @@ bool ExceptionHandler::SimulateSignalDelivery(int sig) {
// ExceptionHandler::HandleSignal().
siginfo.si_code = SI_USER;
siginfo.si_pid = getpid();
ucontext_t context;
struct ucontext context;
getcontext(&context);
return HandleSignal(sig, &siginfo, &context);
}
@ -586,20 +586,12 @@ void ExceptionHandler::WaitForContinueSignal() {
// Runs on the cloned process.
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
size_t context_size) {
const bool may_skip_dump =
minidump_descriptor_.skip_dump_if_principal_mapping_not_referenced();
const uintptr_t principal_mapping_address =
minidump_descriptor_.address_within_principal_mapping();
const bool sanitize_stacks = minidump_descriptor_.sanitize_stacks();
if (minidump_descriptor_.IsMicrodumpOnConsole()) {
return google_breakpad::WriteMicrodump(
crashing_process,
context,
context_size,
mapping_list_,
may_skip_dump,
principal_mapping_address,
sanitize_stacks,
*minidump_descriptor_.microdump_extra_info());
}
if (minidump_descriptor_.IsFD()) {
@ -609,10 +601,7 @@ bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
context,
context_size,
mapping_list_,
app_memory_list_,
may_skip_dump,
principal_mapping_address,
sanitize_stacks);
app_memory_list_);
}
return google_breakpad::WriteMinidump(minidump_descriptor_.path(),
minidump_descriptor_.size_limit(),
@ -620,10 +609,7 @@ bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
context,
context_size,
mapping_list_,
app_memory_list_,
may_skip_dump,
principal_mapping_address,
sanitize_stacks);
app_memory_list_);
}
// static

View File

@ -191,11 +191,11 @@ class ExceptionHandler {
struct CrashContext {
siginfo_t siginfo;
pid_t tid; // the crashing thread.
ucontext_t context;
struct ucontext context;
#if !defined(__ARM_EABI__) && !defined(__mips__)
// #ifdef this out because FP state is not part of user ABI for Linux ARM.
// In case of MIPS Linux FP state is already part of ucontext_t so
// 'float_state' is not required.
// In case of MIPS Linux FP state is already part of struct
// ucontext so 'float_state' is not required.
fpstate_t float_state;
#endif
};

View File

@ -38,13 +38,9 @@ struct MicrodumpExtraInfo {
const char* build_fingerprint;
const char* product_info;
const char* gpu_fingerprint;
const char* process_type;
MicrodumpExtraInfo()
: build_fingerprint(NULL),
product_info(NULL),
gpu_fingerprint(NULL),
process_type(NULL) {}
: build_fingerprint(NULL), product_info(NULL), gpu_fingerprint(NULL) {}
};
}

View File

@ -45,11 +45,6 @@ MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor)
directory_(descriptor.directory_),
c_path_(NULL),
size_limit_(descriptor.size_limit_),
address_within_principal_mapping_(
descriptor.address_within_principal_mapping_),
skip_dump_if_principal_mapping_not_referenced_(
descriptor.skip_dump_if_principal_mapping_not_referenced_),
sanitize_stacks_(descriptor.sanitize_stacks_),
microdump_extra_info_(descriptor.microdump_extra_info_) {
// The copy constructor is not allowed to be called on a MinidumpDescriptor
// with a valid path_, as getting its c_path_ would require the heap which
@ -71,11 +66,6 @@ MinidumpDescriptor& MinidumpDescriptor::operator=(
UpdatePath();
}
size_limit_ = descriptor.size_limit_;
address_within_principal_mapping_ =
descriptor.address_within_principal_mapping_;
skip_dump_if_principal_mapping_not_referenced_ =
descriptor.skip_dump_if_principal_mapping_not_referenced_;
sanitize_stacks_ = descriptor.sanitize_stacks_;
microdump_extra_info_ = descriptor.microdump_extra_info_;
return *this;
}

View File

@ -53,19 +53,14 @@ class MinidumpDescriptor {
MinidumpDescriptor()
: mode_(kUninitialized),
fd_(-1),
size_limit_(-1),
address_within_principal_mapping_(0),
skip_dump_if_principal_mapping_not_referenced_(false) {}
size_limit_(-1) {}
explicit MinidumpDescriptor(const string& directory)
: mode_(kWriteMinidumpToFile),
fd_(-1),
directory_(directory),
c_path_(NULL),
size_limit_(-1),
address_within_principal_mapping_(0),
skip_dump_if_principal_mapping_not_referenced_(false),
sanitize_stacks_(false) {
size_limit_(-1) {
assert(!directory.empty());
}
@ -73,20 +68,14 @@ class MinidumpDescriptor {
: mode_(kWriteMinidumpToFd),
fd_(fd),
c_path_(NULL),
size_limit_(-1),
address_within_principal_mapping_(0),
skip_dump_if_principal_mapping_not_referenced_(false),
sanitize_stacks_(false) {
size_limit_(-1) {
assert(fd != -1);
}
explicit MinidumpDescriptor(const MicrodumpOnConsole&)
: mode_(kWriteMicrodumpToConsole),
fd_(-1),
size_limit_(-1),
address_within_principal_mapping_(0),
skip_dump_if_principal_mapping_not_referenced_(false),
sanitize_stacks_(false) {}
size_limit_(-1) {}
explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor);
MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor);
@ -112,28 +101,6 @@ class MinidumpDescriptor {
off_t size_limit() const { return size_limit_; }
void set_size_limit(off_t limit) { size_limit_ = limit; }
uintptr_t address_within_principal_mapping() const {
return address_within_principal_mapping_;
}
void set_address_within_principal_mapping(
uintptr_t address_within_principal_mapping) {
address_within_principal_mapping_ = address_within_principal_mapping;
}
bool skip_dump_if_principal_mapping_not_referenced() {
return skip_dump_if_principal_mapping_not_referenced_;
}
void set_skip_dump_if_principal_mapping_not_referenced(
bool skip_dump_if_principal_mapping_not_referenced) {
skip_dump_if_principal_mapping_not_referenced_ =
skip_dump_if_principal_mapping_not_referenced;
}
bool sanitize_stacks() const { return sanitize_stacks_; }
void set_sanitize_stacks(bool sanitize_stacks) {
sanitize_stacks_ = sanitize_stacks;
}
MicrodumpExtraInfo* microdump_extra_info() {
assert(IsMicrodumpOnConsole());
return &microdump_extra_info_;
@ -165,23 +132,6 @@ class MinidumpDescriptor {
off_t size_limit_;
// This member points somewhere into the main module for this
// process (the module that is considerered interesting for the
// purposes of debugging crashes).
uintptr_t address_within_principal_mapping_;
// If set, threads that do not reference the address range
// associated with |address_within_principal_mapping_| will not have their
// stacks logged.
bool skip_dump_if_principal_mapping_not_referenced_;
// If set, stacks are sanitized to remove PII. This involves
// overwriting any pointer-aligned words that are not either
// pointers into a process mapping or small integers (+/-4096). This
// leaves enough information to unwind stacks, and preserve some
// register values, but elides strings and other program data.
bool sanitize_stacks_;
// The extra microdump data (e.g. product name/version, build
// fingerprint, gpu fingerprint) that should be appended to the dump
// (microdump only). Microdumps don't have the ability of appending

View File

@ -132,9 +132,6 @@ class MicrodumpWriter {
public:
MicrodumpWriter(const ExceptionHandler::CrashContext* context,
const MappingList& mappings,
bool skip_dump_if_principal_mapping_not_referenced,
uintptr_t address_within_principal_mapping,
bool sanitize_stack,
const MicrodumpExtraInfo& microdump_extra_info,
LinuxDumper* dumper)
: ucontext_(context ? &context->context : NULL),
@ -143,16 +140,8 @@ class MicrodumpWriter {
#endif
dumper_(dumper),
mapping_list_(mappings),
skip_dump_if_principal_mapping_not_referenced_(
skip_dump_if_principal_mapping_not_referenced),
address_within_principal_mapping_(address_within_principal_mapping),
sanitize_stack_(sanitize_stack),
microdump_extra_info_(microdump_extra_info),
log_line_(NULL),
stack_copy_(NULL),
stack_len_(0),
stack_lower_bound_(0),
stack_pointer_(0) {
log_line_(NULL) {
log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize));
if (log_line_)
log_line_[0] = '\0'; // Clear out the log line buffer.
@ -170,31 +159,24 @@ class MicrodumpWriter {
return dumper_->ThreadsSuspend() && dumper_->LateInit();
}
void Dump() {
CaptureResult stack_capture_result = CaptureCrashingThreadStack(-1);
if (stack_capture_result == CAPTURE_UNINTERESTING) {
LogLine("Microdump skipped (uninteresting)");
return;
}
bool Dump() {
bool success;
LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
DumpProductInformation();
DumpOSInformation();
DumpProcessType();
DumpGPUInformation();
#if !defined(__LP64__)
DumpFreeSpace();
#endif
if (stack_capture_result == CAPTURE_OK)
DumpThreadStack();
DumpCPUState();
DumpMappings();
success = DumpCrashingThread();
if (success)
success = DumpMappings();
LogLine("-----END BREAKPAD MICRODUMP-----");
dumper_->ThreadsResume();
return success;
}
private:
enum CaptureResult { CAPTURE_OK, CAPTURE_FAILED, CAPTURE_UNINTERESTING };
// Writes one line to the system log.
void LogLine(const char* msg) {
#if defined(__ANDROID__)
@ -238,44 +220,7 @@ class MicrodumpWriter {
// Writes out the current line buffer on the system log.
void LogCommitLine() {
LogLine(log_line_);
log_line_[0] = 0;
}
CaptureResult CaptureCrashingThreadStack(int max_stack_len) {
stack_pointer_ = UContextReader::GetStackPointer(ucontext_);
if (!dumper_->GetStackInfo(reinterpret_cast<const void**>(&stack_lower_bound_),
&stack_len_, stack_pointer_)) {
return CAPTURE_FAILED;
}
if (max_stack_len >= 0 &&
stack_len_ > static_cast<size_t>(max_stack_len)) {
stack_len_ = max_stack_len;
}
stack_copy_ = reinterpret_cast<uint8_t*>(Alloc(stack_len_));
dumper_->CopyFromProcess(stack_copy_, dumper_->crash_thread(),
reinterpret_cast<const void*>(stack_lower_bound_),
stack_len_);
if (!skip_dump_if_principal_mapping_not_referenced_) return CAPTURE_OK;
const MappingInfo* principal_mapping =
dumper_->FindMappingNoBias(address_within_principal_mapping_);
if (!principal_mapping) return CAPTURE_UNINTERESTING;
uintptr_t low_addr = principal_mapping->system_mapping_info.start_addr;
uintptr_t high_addr = principal_mapping->system_mapping_info.end_addr;
uintptr_t pc = UContextReader::GetInstructionPointer(ucontext_);
if (low_addr <= pc && pc <= high_addr) return CAPTURE_OK;
if (dumper_->StackHasPointerToMapping(stack_copy_, stack_len_,
stack_pointer_ - stack_lower_bound_,
*principal_mapping)) {
return CAPTURE_OK;
}
return CAPTURE_UNINTERESTING;
my_strlcpy(log_line_, "", kLineBufferSize);
}
void DumpProductInformation() {
@ -288,16 +233,6 @@ class MicrodumpWriter {
LogCommitLine();
}
void DumpProcessType() {
LogAppend("P ");
if (microdump_extra_info_.process_type) {
LogAppend(microdump_extra_info_.process_type);
} else {
LogAppend("UNKNOWN");
}
LogCommitLine();
}
void DumpOSInformation() {
const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF));
@ -369,42 +304,87 @@ class MicrodumpWriter {
LogCommitLine();
}
void DumpThreadStack() {
if (sanitize_stack_) {
dumper_->SanitizeStackCopy(stack_copy_, stack_len_, stack_pointer_,
stack_pointer_ - stack_lower_bound_);
bool DumpThreadStack(uint32_t thread_id,
uintptr_t stack_pointer,
int max_stack_len,
uint8_t** stack_copy) {
*stack_copy = NULL;
const void* stack;
size_t stack_len;
if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
// The stack pointer might not be available. In this case we don't hard
// fail, just produce a (almost useless) microdump w/o a stack section.
return true;
}
LogAppend("S 0 ");
LogAppend(stack_pointer_);
LogAppend(stack_pointer);
LogAppend(" ");
LogAppend(stack_lower_bound_);
LogAppend(reinterpret_cast<uintptr_t>(stack));
LogAppend(" ");
LogAppend(stack_len_);
LogAppend(stack_len);
LogCommitLine();
if (max_stack_len >= 0 &&
stack_len > static_cast<unsigned int>(max_stack_len)) {
stack_len = max_stack_len;
}
*stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
dumper_->CopyFromProcess(*stack_copy, thread_id, stack, stack_len);
// Dump the content of the stack, splicing it into chunks which size is
// compatible with the max logcat line size (see LOGGER_ENTRY_MAX_PAYLOAD).
const size_t STACK_DUMP_CHUNK_SIZE = 384;
for (size_t stack_off = 0; stack_off < stack_len_;
for (size_t stack_off = 0; stack_off < stack_len;
stack_off += STACK_DUMP_CHUNK_SIZE) {
LogAppend("S ");
LogAppend(stack_lower_bound_ + stack_off);
LogAppend(reinterpret_cast<uintptr_t>(stack) + stack_off);
LogAppend(" ");
LogAppend(stack_copy_ + stack_off,
std::min(STACK_DUMP_CHUNK_SIZE, stack_len_ - stack_off));
LogAppend(*stack_copy + stack_off,
std::min(STACK_DUMP_CHUNK_SIZE, stack_len - stack_off));
LogCommitLine();
}
return true;
}
void DumpCPUState() {
RawContextCPU cpu;
my_memset(&cpu, 0, sizeof(RawContextCPU));
// Write information about the crashing thread.
bool DumpCrashingThread() {
const unsigned num_threads = dumper_->threads().size();
for (unsigned i = 0; i < num_threads; ++i) {
MDRawThread thread;
my_memset(&thread, 0, sizeof(thread));
thread.thread_id = dumper_->threads()[i];
// Dump only the crashing thread.
if (static_cast<pid_t>(thread.thread_id) != dumper_->crash_thread())
continue;
assert(ucontext_);
assert(!dumper_->IsPostMortem());
uint8_t* stack_copy;
const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
if (!DumpThreadStack(thread.thread_id, stack_ptr, -1, &stack_copy))
return false;
RawContextCPU cpu;
my_memset(&cpu, 0, sizeof(RawContextCPU));
#if !defined(__ARM_EABI__) && !defined(__mips__)
UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
#else
UContextReader::FillCPUContext(&cpu, ucontext_);
UContextReader::FillCPUContext(&cpu, ucontext_);
#endif
DumpCPUState(&cpu);
}
return true;
}
void DumpCPUState(RawContextCPU* cpu) {
LogAppend("C ");
LogAppend(&cpu, sizeof(cpu));
LogAppend(cpu, sizeof(*cpu));
LogCommitLine();
}
@ -556,7 +536,7 @@ class MicrodumpWriter {
#endif
// Write information about the mappings in effect.
void DumpMappings() {
bool DumpMappings() {
// First write all the mappings from the dumper
for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
const MappingInfo& mapping = *dumper_->mappings()[i];
@ -575,35 +555,19 @@ class MicrodumpWriter {
++iter) {
DumpModule(iter->first, false, 0, iter->second);
}
return true;
}
void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); }
const ucontext_t* const ucontext_;
const struct ucontext* const ucontext_;
#if !defined(__ARM_EABI__) && !defined(__mips__)
const google_breakpad::fpstate_t* const float_state_;
#endif
LinuxDumper* dumper_;
const MappingList& mapping_list_;
bool skip_dump_if_principal_mapping_not_referenced_;
uintptr_t address_within_principal_mapping_;
bool sanitize_stack_;
const MicrodumpExtraInfo microdump_extra_info_;
char* log_line_;
// The local copy of crashed process stack memory, beginning at
// |stack_lower_bound_|.
uint8_t* stack_copy_;
// The length of crashed process stack copy.
size_t stack_len_;
// The address of the page containing the stack pointer in the
// crashed process. |stack_lower_bound_| <= |stack_pointer_|
uintptr_t stack_lower_bound_;
// The stack pointer in the crashed process.
uintptr_t stack_pointer_;
};
} // namespace
@ -613,9 +577,6 @@ bool WriteMicrodump(pid_t crashing_process,
const void* blob,
size_t blob_size,
const MappingList& mappings,
bool skip_dump_if_principal_mapping_not_referenced,
uintptr_t address_within_principal_mapping,
bool sanitize_stack,
const MicrodumpExtraInfo& microdump_extra_info) {
LinuxPtraceDumper dumper(crashing_process);
const ExceptionHandler::CrashContext* context = NULL;
@ -628,14 +589,10 @@ bool WriteMicrodump(pid_t crashing_process,
dumper.set_crash_signal(context->siginfo.si_signo);
dumper.set_crash_thread(context->tid);
}
MicrodumpWriter writer(context, mappings,
skip_dump_if_principal_mapping_not_referenced,
address_within_principal_mapping, sanitize_stack,
microdump_extra_info, &dumper);
MicrodumpWriter writer(context, mappings, microdump_extra_info, &dumper);
if (!writer.Init())
return false;
writer.Dump();
return true;
return writer.Dump();
}
} // namespace google_breakpad

View File

@ -58,9 +58,6 @@ bool WriteMicrodump(pid_t crashing_process,
const void* blob,
size_t blob_size,
const MappingList& mappings,
bool skip_dump_if_main_module_not_referenced,
uintptr_t address_within_main_module,
bool sanitize_stack,
const MicrodumpExtraInfo& microdump_extra_info);
} // namespace google_breakpad

View File

@ -31,7 +31,6 @@
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <ucontext.h>
#include <sstream>
#include <string>
@ -48,11 +47,6 @@
using namespace google_breakpad;
extern "C" {
extern char __executable_start;
extern char __etext;
}
namespace {
typedef testing::Test MicrodumpWriterTest;
@ -68,19 +62,10 @@ MicrodumpExtraInfo MakeMicrodumpExtraInfo(
return info;
}
bool ContainsMicrodump(const std::string& buf) {
return std::string::npos != buf.find("-----BEGIN BREAKPAD MICRODUMP-----") &&
std::string::npos != buf.find("-----END BREAKPAD MICRODUMP-----");
}
const char kIdentifiableString[] = "_IDENTIFIABLE_";
void CrashAndGetMicrodump(const MappingList& mappings,
const MicrodumpExtraInfo& microdump_extra_info,
std::string* microdump,
bool skip_dump_if_principal_mapping_not_referenced = false,
uintptr_t address_within_principal_mapping = 0,
bool sanitize_stack = false) {
void CrashAndGetMicrodump(
const MappingList& mappings,
const MicrodumpExtraInfo& microdump_extra_info,
scoped_array<char>* buf) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
@ -89,14 +74,6 @@ void CrashAndGetMicrodump(const MappingList& mappings,
int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ASSERT_NE(-1, err_fd);
char identifiable_string[sizeof(kIdentifiableString)];
// This string should not appear in the resulting microdump if it
// has been sanitized.
strcpy(identifiable_string, kIdentifiableString);
// Force the strcpy to not be optimized away.
IGNORE_RET(write(STDOUT_FILENO, identifiable_string, 0));
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
@ -109,10 +86,7 @@ void CrashAndGetMicrodump(const MappingList& mappings,
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
// Pretend the current context is the child context (which is
// approximately right) so that we have a valid stack pointer, and
// can fetch child stack data via ptrace.
getcontext(&context.context);
// Set a non-zero tid to avoid tripping asserts.
context.tid = child;
@ -122,8 +96,6 @@ void CrashAndGetMicrodump(const MappingList& mappings,
ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO));
ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings,
skip_dump_if_principal_mapping_not_referenced,
address_within_principal_mapping, sanitize_stack,
microdump_extra_info));
// Revert stderr back to the console.
@ -133,38 +105,17 @@ void CrashAndGetMicrodump(const MappingList& mappings,
// Read back the stderr file and check for the microdump marker.
fsync(err_fd);
lseek(err_fd, 0, SEEK_SET);
const size_t kBufSize = 64 * 1024;
buf->reset(new char[kBufSize]);
ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0);
microdump->clear();
char buf[1024];
while (true) {
int bytes_read = IGNORE_EINTR(read(err_fd, buf, 1024));
if (bytes_read <= 0) break;
microdump->append(buf, buf + bytes_read);
}
close(err_fd);
close(fds[1]);
}
void ExtractMicrodumpStackContents(const string& microdump_content,
string* result) {
std::istringstream iss(microdump_content);
result->clear();
for (string line; std::getline(iss, line);) {
if (line.find("S ") == 0) {
std::istringstream stack_data(line);
std::string key;
std::string addr;
std::string data;
stack_data >> key >> addr >> data;
EXPECT_TRUE((data.size() & 1u) == 0u);
result->reserve(result->size() + data.size() / 2);
for (size_t i = 0; i < data.size(); i += 2) {
std::string byte = data.substr(i, 2);
result->push_back(static_cast<char>(strtoul(byte.c_str(), NULL, 16)));
}
}
}
ASSERT_NE(static_cast<char*>(0), strstr(
buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----"));
ASSERT_NE(static_cast<char*>(0), strstr(
buf->get(), "-----END BREAKPAD MICRODUMP-----"));
}
void CheckMicrodumpContents(const string& microdump_content,
@ -208,13 +159,6 @@ void CheckMicrodumpContents(const string& microdump_content,
ASSERT_TRUE(did_find_gpu_info);
}
bool MicrodumpStackContains(const string& microdump_content,
const string& expected_content) {
string result;
ExtractMicrodumpStackContents(microdump_content, &result);
return result.find(kIdentifiableString) != string::npos;
}
void CheckMicrodumpContents(const string& microdump_content,
const string& expected_fingerprint,
const string& expected_product_info,
@ -247,101 +191,23 @@ TEST(MicrodumpWriterTest, BasicWithMappings) {
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
mappings.push_back(mapping);
std::string buf;
scoped_array<char> buf;
CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf);
ASSERT_TRUE(ContainsMicrodump(buf));
#ifdef __LP64__
ASSERT_NE(std::string::npos,
buf.find("M 0000000000001000 000000000000002A 0000000000001000 "
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
ASSERT_NE(static_cast<char*>(0), strstr(
buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 "
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
#else
ASSERT_NE(std::string::npos,
buf.find("M 00001000 0000002A 00001000 "
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
ASSERT_NE(static_cast<char*>(0), strstr(
buf.get(), "M 00001000 0000002A 00001000 "
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
#endif
// In absence of a product info in the minidump, the writer should just write
// an unknown marker.
ASSERT_NE(std::string::npos, buf.find("V UNKNOWN:0.0.0.0"));
}
// Ensure that no output occurs if the interest region is set, but
// doesn't overlap anything on the stack.
TEST(MicrodumpWriterTest, NoOutputIfUninteresting) {
const char kProductInfo[] = "MockProduct:42.0.2311.99";
const char kBuildFingerprint[] =
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
const char kGPUFingerprint[] =
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
const MicrodumpExtraInfo kMicrodumpExtraInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
std::string buf;
MappingList no_mappings;
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, true, 0);
ASSERT_FALSE(ContainsMicrodump(buf));
}
// Ensure that stack content does not contain an identifiable string if the
// stack is sanitized.
TEST(MicrodumpWriterTest, StringRemovedBySanitization) {
const char kProductInfo[] = "MockProduct:42.0.2311.99";
const char kBuildFingerprint[] =
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
const char kGPUFingerprint[] =
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
const MicrodumpExtraInfo kMicrodumpExtraInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
std::string buf;
MappingList no_mappings;
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, false, 0u, true);
ASSERT_TRUE(ContainsMicrodump(buf));
ASSERT_FALSE(MicrodumpStackContains(buf, kIdentifiableString));
}
// Ensure that stack content does contain an identifiable string if the
// stack is not sanitized.
TEST(MicrodumpWriterTest, StringPresentIfNotSanitized) {
const char kProductInfo[] = "MockProduct:42.0.2311.99";
const char kBuildFingerprint[] =
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
const char kGPUFingerprint[] =
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
const MicrodumpExtraInfo kMicrodumpExtraInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
std::string buf;
MappingList no_mappings;
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, false, 0u, false);
ASSERT_TRUE(ContainsMicrodump(buf));
ASSERT_TRUE(MicrodumpStackContains(buf, kIdentifiableString));
}
// Ensure that output occurs if the interest region is set, and
// does overlap something on the stack.
TEST(MicrodumpWriterTest, OutputIfInteresting) {
const char kProductInfo[] = "MockProduct:42.0.2311.99";
const char kBuildFingerprint[] =
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
const char kGPUFingerprint[] =
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
const MicrodumpExtraInfo kMicrodumpExtraInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
std::string buf;
MappingList no_mappings;
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, true,
reinterpret_cast<uintptr_t>(CrashAndGetMicrodump));
ASSERT_TRUE(ContainsMicrodump(buf));
ASSERT_NE(static_cast<char*>(0), strstr(
buf.get(), "V UNKNOWN:0.0.0.0"));
}
// Ensure that the product info and build fingerprint metadata show up in the
@ -354,40 +220,38 @@ TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) {
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
const MicrodumpExtraInfo kMicrodumpExtraInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
std::string buf;
scoped_array<char> buf;
MappingList no_mappings;
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf);
ASSERT_TRUE(ContainsMicrodump(buf));
CheckMicrodumpContents(buf, kMicrodumpExtraInfo);
CheckMicrodumpContents(string(buf.get()), kMicrodumpExtraInfo);
}
TEST(MicrodumpWriterTest, NoProductInfo) {
const char kBuildFingerprint[] = "foobar";
const char kGPUFingerprint[] = "bazqux";
std::string buf;
scoped_array<char> buf;
MappingList no_mappings;
const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint));
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf);
ASSERT_TRUE(ContainsMicrodump(buf));
CheckMicrodumpContents(buf, kBuildFingerprint, "UNKNOWN:0.0.0.0",
kGPUFingerprint);
CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
"UNKNOWN:0.0.0.0", kGPUFingerprint);
}
TEST(MicrodumpWriterTest, NoGPUInfo) {
const char kProductInfo[] = "bazqux";
const char kBuildFingerprint[] = "foobar";
std::string buf;
scoped_array<char> buf;
MappingList no_mappings;
const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL));
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf);
ASSERT_TRUE(ContainsMicrodump(buf));
CheckMicrodumpContents(buf, kBuildFingerprint, kProductInfo, "UNKNOWN");
CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
kProductInfo, "UNKNOWN");
}
} // namespace

View File

@ -41,7 +41,7 @@ using namespace google_breakpad;
TEST(LinuxCoreDumperTest, GetMappingAbsolutePath) {
const LinuxCoreDumper dumper(getpid(), "core", "/tmp", "/mnt/root");
const MappingInfo mapping = {0, 0, {0, 0}, 0, false, "/usr/lib/libc.so"};
const MappingInfo mapping = { 0, 0, 0, false, "/usr/lib/libc.so" };
char path[PATH_MAX];
dumper.GetMappingAbsolutePath(mapping, path);

View File

@ -84,179 +84,6 @@ inline static bool IsMappedFileOpenUnsafe(
namespace google_breakpad {
namespace {
bool MappingContainsAddress(const MappingInfo& mapping, uintptr_t address) {
return mapping.system_mapping_info.start_addr <= address &&
address < mapping.system_mapping_info.end_addr;
}
#if defined(__CHROMEOS__)
// Recover memory mappings before writing dump on ChromeOS
//
// On Linux, breakpad relies on /proc/[pid]/maps to associate symbols from
// addresses. ChromeOS' hugepage implementation replaces some segments with
// anonymous private pages, which is a restriction of current implementation
// in Linux kernel at the time of writing. Thus, breakpad can no longer
// symbolize addresses from those text segments replaced with hugepages.
//
// This postprocess tries to recover the mappings. Because hugepages are always
// inserted in between some .text sections, it tries to infer the names and
// offsets of the segments, by looking at segments immediately precede and
// succeed them.
//
// For example, a text segment before hugepage optimization
// 02001000-03002000 r-xp /opt/google/chrome/chrome
//
// can be broken into
// 02001000-02200000 r-xp /opt/google/chrome/chrome
// 02200000-03000000 r-xp
// 03000000-03002000 r-xp /opt/google/chrome/chrome
//
// For more details, see:
// crbug.com/628040 ChromeOS' use of hugepages confuses crash symbolization
// Copied from CrOS' hugepage implementation, which is unlikely to change.
// The hugepage size is 2M.
const unsigned int kHpageShift = 21;
const size_t kHpageSize = (1 << kHpageShift);
const size_t kHpageMask = (~(kHpageSize - 1));
// Find and merge anonymous r-xp segments with surrounding named segments.
// There are two cases:
// Case 1: curr, next
// curr is anonymous
// curr is r-xp
// curr.size >= 2M
// curr.size is a multiple of 2M.
// next is backed by some file.
// curr and next are contiguous.
// offset(next) == sizeof(curr)
void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) {
// Merged segments are marked with size = 0.
if (curr->size == 0 || next->size == 0)
return;
if (curr->size >= kHpageSize &&
curr->exec &&
(curr->size & kHpageMask) == curr->size &&
(curr->start_addr & kHpageMask) == curr->start_addr &&
curr->name[0] == '\0' &&
next->name[0] != '\0' &&
curr->start_addr + curr->size == next->start_addr &&
curr->size == next->offset) {
// matched
my_strlcpy(curr->name, next->name, NAME_MAX);
if (next->exec) {
// (curr, next)
curr->size += next->size;
next->size = 0;
}
}
}
// Case 2: prev, curr, next
// curr is anonymous
// curr is r-xp
// curr.size >= 2M
// curr.size is a multiple of 2M.
// next and prev are backed by the same file.
// prev, curr and next are contiguous.
// offset(next) == offset(prev) + sizeof(prev) + sizeof(curr)
void TryRecoverMappings(MappingInfo *prev, MappingInfo *curr,
MappingInfo *next) {
// Merged segments are marked with size = 0.
if (prev->size == 0 || curr->size == 0 || next->size == 0)
return;
if (curr->size >= kHpageSize &&
curr->exec &&
(curr->size & kHpageMask) == curr->size &&
(curr->start_addr & kHpageMask) == curr->start_addr &&
curr->name[0] == '\0' &&
next->name[0] != '\0' &&
curr->start_addr + curr->size == next->start_addr &&
prev->start_addr + prev->size == curr->start_addr &&
my_strncmp(prev->name, next->name, NAME_MAX) == 0 &&
next->offset == prev->offset + prev->size + curr->size) {
// matched
my_strlcpy(curr->name, prev->name, NAME_MAX);
if (prev->exec) {
curr->offset = prev->offset;
curr->start_addr = prev->start_addr;
if (next->exec) {
// (prev, curr, next)
curr->size += prev->size + next->size;
prev->size = 0;
next->size = 0;
} else {
// (prev, curr), next
curr->size += prev->size;
prev->size = 0;
}
} else {
curr->offset = prev->offset + prev->size;
if (next->exec) {
// prev, (curr, next)
curr->size += next->size;
next->size = 0;
} else {
// prev, curr, next
}
}
}
}
// mappings_ is sorted excepted for the first entry.
// This function tries to merge segemnts into the first entry,
// then check for other sorted entries.
// See LinuxDumper::EnumerateMappings().
void CrOSPostProcessMappings(wasteful_vector<MappingInfo*>& mappings) {
// Find the candidate "next" to first segment, which is the only one that
// could be out-of-order.
size_t l = 1;
size_t r = mappings.size();
size_t next = mappings.size();
while (l < r) {
int m = (l + r) / 2;
if (mappings[m]->start_addr > mappings[0]->start_addr)
r = next = m;
else
l = m + 1;
}
// Try to merge segments into the first.
if (next < mappings.size()) {
TryRecoverMappings(mappings[0], mappings[next]);
if (next - 1 > 0)
TryRecoverMappings(mappings[next - 1], mappings[0], mappings[next]);
}
// Iterate through normal, sorted cases.
// Normal case 1.
for (size_t i = 1; i < mappings.size() - 1; i++)
TryRecoverMappings(mappings[i], mappings[i + 1]);
// Normal case 2.
for (size_t i = 1; i < mappings.size() - 2; i++)
TryRecoverMappings(mappings[i], mappings[i + 1], mappings[i + 2]);
// Collect merged (size == 0) segments.
size_t f, e;
for (f = e = 0; e < mappings.size(); e++)
if (mappings[e]->size > 0)
mappings[f++] = mappings[e];
mappings.resize(f);
}
#endif // __CHROMEOS__
} // namespace
// All interesting auvx entry types are below AT_SYSINFO_EHDR
#define AT_MAX AT_SYSINFO_EHDR
@ -286,11 +113,6 @@ bool LinuxDumper::LateInit() {
#if defined(__ANDROID__)
LatePostprocessMappings();
#endif
#if defined(__CHROMEOS__)
CrOSPostProcessMappings(mappings_);
#endif
return true;
}
@ -536,8 +358,6 @@ bool LinuxDumper::EnumerateMappings() {
}
MappingInfo* const module = new(allocator_) MappingInfo;
my_memset(module, 0, sizeof(MappingInfo));
module->system_mapping_info.start_addr = start_addr;
module->system_mapping_info.end_addr = end_addr;
module->start_addr = start_addr;
module->size = end_addr - start_addr;
module->offset = offset;
@ -711,126 +531,6 @@ bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
return true;
}
void LinuxDumper::SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len,
uintptr_t stack_pointer,
uintptr_t sp_offset) {
// We optimize the search for containing mappings in three ways:
// 1) We expect that pointers into the stack mapping will be common, so
// we cache that address range.
// 2) The last referenced mapping is a reasonable predictor for the next
// referenced mapping, so we test that first.
// 3) We precompute a bitfield based upon bits 32:32-n of the start and
// stop addresses, and use that to short circuit any values that can
// not be pointers. (n=11)
const uintptr_t defaced =
#if defined(__LP64__)
0x0defaced0defaced;
#else
0x0defaced;
#endif
// the bitfield length is 2^test_bits long.
const unsigned int test_bits = 11;
// byte length of the corresponding array.
const unsigned int array_size = 1 << (test_bits - 3);
const unsigned int array_mask = array_size - 1;
// The amount to right shift pointers by. This captures the top bits
// on 32 bit architectures. On 64 bit architectures this would be
// uninformative so we take the same range of bits.
const unsigned int shift = 32 - 11;
const MappingInfo* last_hit_mapping = nullptr;
const MappingInfo* hit_mapping = nullptr;
const MappingInfo* stack_mapping = FindMappingNoBias(stack_pointer);
// The magnitude below which integers are considered to be to be
// 'small', and not constitute a PII risk. These are included to
// avoid eliding useful register values.
const ssize_t small_int_magnitude = 4096;
char could_hit_mapping[array_size];
my_memset(could_hit_mapping, 0, array_size);
// Initialize the bitfield such that if the (pointer >> shift)'th
// bit, modulo the bitfield size, is not set then there does not
// exist a mapping in mappings_ that would contain that pointer.
for (size_t i = 0; i < mappings_.size(); ++i) {
if (!mappings_[i]->exec) continue;
// For each mapping, work out the (unmodulo'ed) range of bits to
// set.
uintptr_t start = mappings_[i]->start_addr;
uintptr_t end = start + mappings_[i]->size;
start >>= shift;
end >>= shift;
for (size_t bit = start; bit <= end; ++bit) {
// Set each bit in the range, applying the modulus.
could_hit_mapping[(bit >> 3) & array_mask] |= 1 << (bit & 7);
}
}
// Zero memory that is below the current stack pointer.
const uintptr_t offset =
(sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
if (offset) {
my_memset(stack_copy, 0, offset);
}
// Apply sanitization to each complete pointer-aligned word in the
// stack.
uint8_t* sp;
for (sp = stack_copy + offset;
sp <= stack_copy + stack_len - sizeof(uintptr_t);
sp += sizeof(uintptr_t)) {
uintptr_t addr;
my_memcpy(&addr, sp, sizeof(uintptr_t));
if (static_cast<intptr_t>(addr) <= small_int_magnitude &&
static_cast<intptr_t>(addr) >= -small_int_magnitude) {
continue;
}
if (stack_mapping && MappingContainsAddress(*stack_mapping, addr)) {
continue;
}
if (last_hit_mapping && MappingContainsAddress(*last_hit_mapping, addr)) {
continue;
}
uintptr_t test = addr >> shift;
if (could_hit_mapping[(test >> 3) & array_mask] & (1 << (test & 7)) &&
(hit_mapping = FindMappingNoBias(addr)) != nullptr &&
hit_mapping->exec) {
last_hit_mapping = hit_mapping;
continue;
}
my_memcpy(sp, &defaced, sizeof(uintptr_t));
}
// Zero any partial word at the top of the stack, if alignment is
// such that that is required.
if (sp < stack_copy + stack_len) {
my_memset(sp, 0, stack_copy + stack_len - sp);
}
}
bool LinuxDumper::StackHasPointerToMapping(const uint8_t* stack_copy,
size_t stack_len,
uintptr_t sp_offset,
const MappingInfo& mapping) {
// Loop over all stack words that would have been on the stack in
// the target process (i.e. are word aligned, and at addresses >=
// the stack pointer). Regardless of the alignment of |stack_copy|,
// the memory starting at |stack_copy| + |offset| represents an
// aligned word in the target process.
const uintptr_t low_addr = mapping.system_mapping_info.start_addr;
const uintptr_t high_addr = mapping.system_mapping_info.end_addr;
const uintptr_t offset =
(sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
for (const uint8_t* sp = stack_copy + offset;
sp <= stack_copy + stack_len - sizeof(uintptr_t);
sp += sizeof(uintptr_t)) {
uintptr_t addr;
my_memcpy(&addr, sp, sizeof(uintptr_t));
if (low_addr <= addr && addr <= high_addr)
return true;
}
return false;
}
// Find the mapping which the given memory address falls in.
const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
const uintptr_t addr = (uintptr_t) address;
@ -844,19 +544,6 @@ const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
return NULL;
}
// Find the mapping which the given memory address falls in. Uses the
// unadjusted mapping address range from the kernel, rather than the
// biased range.
const MappingInfo* LinuxDumper::FindMappingNoBias(uintptr_t address) const {
for (size_t i = 0; i < mappings_.size(); ++i) {
if (address >= mappings_[i]->system_mapping_info.start_addr &&
address < mappings_[i]->system_mapping_info.end_addr) {
return mappings_[i];
}
}
return NULL;
}
bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;

View File

@ -103,11 +103,6 @@ class LinuxDumper {
const wasteful_vector<pid_t> &threads() { return threads_; }
const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
const MappingInfo* FindMapping(const void* address) const;
// Find the mapping which the given memory address falls in. Unlike
// FindMapping, this method uses the unadjusted mapping address
// ranges from the kernel, rather than the ranges that have had the
// load bias applied.
const MappingInfo* FindMappingNoBias(uintptr_t address) const;
const wasteful_vector<elf_aux_val_t>& auxv() { return auxv_; }
// Find a block of memory to take as the stack given the top of stack pointer.
@ -116,32 +111,6 @@ class LinuxDumper {
// stack_top: the current top of the stack
bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
// Sanitize a copy of the stack by overwriting words that are not
// pointers with a sentinel (0x0defaced).
// stack_copy: a copy of the stack to sanitize. |stack_copy| might
// not be word aligned, but it represents word aligned
// data copied from another location.
// stack_len: the length of the allocation pointed to by |stack_copy|.
// stack_pointer: the address of the stack pointer (used to locate
// the stack mapping, as an optimization).
// sp_offset: the offset relative to stack_copy that reflects the
// current value of the stack pointer.
void SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len,
uintptr_t stack_pointer, uintptr_t sp_offset);
// Test whether |stack_copy| contains a pointer-aligned word that
// could be an address within a given mapping.
// stack_copy: a copy of the stack to check. |stack_copy| might
// not be word aligned, but it represents word aligned
// data copied from another location.
// stack_len: the length of the allocation pointed to by |stack_copy|.
// sp_offset: the offset relative to stack_copy that reflects the
// current value of the stack pointer.
// mapping: the mapping against which to test stack words.
bool StackHasPointerToMapping(const uint8_t* stack_copy, size_t stack_len,
uintptr_t sp_offset,
const MappingInfo& mapping);
PageAllocator* allocator() { return &allocator_; }
// Copy content of |length| bytes from a given process |child|,

View File

@ -57,15 +57,14 @@
void *thread_function(void *data) {
int pipefd = *static_cast<int *>(data);
volatile pid_t* thread_id = new pid_t;
*thread_id = syscall(__NR_gettid);
volatile pid_t thread_id = syscall(__NR_gettid);
// Signal parent that a thread has started.
uint8_t byte = 1;
if (write(pipefd, &byte, sizeof(byte)) != sizeof(byte)) {
perror("ERROR: parent notification failed");
return NULL;
}
register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = thread_id;
register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
while (true)
asm volatile ("" : : "r" (thread_id_ptr));
return NULL;

View File

@ -66,63 +66,6 @@ using namespace google_breakpad;
namespace {
pid_t SetupChildProcess(int number_of_threads) {
char kNumberOfThreadsArgument[2];
sprintf(kNumberOfThreadsArgument, "%d", number_of_threads);
int fds[2];
EXPECT_NE(-1, pipe(fds));
pid_t child_pid = fork();
if (child_pid == 0) {
// In child process.
close(fds[0]);
string helper_path(GetHelperBinary());
if (helper_path.empty()) {
fprintf(stderr, "Couldn't find helper binary\n");
_exit(1);
}
// Pass the pipe fd and the number of threads as arguments.
char pipe_fd_string[8];
sprintf(pipe_fd_string, "%d", fds[1]);
execl(helper_path.c_str(),
"linux_dumper_unittest_helper",
pipe_fd_string,
kNumberOfThreadsArgument,
NULL);
// Kill if we get here.
printf("Errno from exec: %d", errno);
std::string err_str = "Exec of " + helper_path + " failed";
perror(err_str.c_str());
_exit(1);
}
close(fds[1]);
// Wait for all child threads to indicate that they have started
for (int threads = 0; threads < number_of_threads; threads++) {
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
EXPECT_EQ(1, r);
EXPECT_TRUE(pfd.revents & POLLIN);
uint8_t junk;
EXPECT_EQ(read(fds[0], &junk, sizeof(junk)),
static_cast<ssize_t>(sizeof(junk)));
}
close(fds[0]);
// There is a race here because we may stop a child thread before
// it is actually running the busy loop. Empirically this sleep
// is sufficient to avoid the race.
usleep(100000);
return child_pid;
}
typedef wasteful_vector<uint8_t> id_vector;
typedef testing::Test LinuxPtraceDumperTest;
@ -427,9 +370,58 @@ TEST_F(LinuxPtraceDumperChildTest, FileIDsMatch) {
TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
static const int kNumberOfThreadsInHelperProgram = 5;
char kNumberOfThreadsArgument[2];
sprintf(kNumberOfThreadsArgument, "%d", kNumberOfThreadsInHelperProgram);
pid_t child_pid = SetupChildProcess(kNumberOfThreadsInHelperProgram);
ASSERT_NE(child_pid, -1);
int fds[2];
ASSERT_NE(-1, pipe(fds));
pid_t child_pid = fork();
if (child_pid == 0) {
// In child process.
close(fds[0]);
string helper_path(GetHelperBinary());
if (helper_path.empty()) {
FAIL() << "Couldn't find helper binary";
exit(1);
}
// Pass the pipe fd and the number of threads as arguments.
char pipe_fd_string[8];
sprintf(pipe_fd_string, "%d", fds[1]);
execl(helper_path.c_str(),
"linux_dumper_unittest_helper",
pipe_fd_string,
kNumberOfThreadsArgument,
NULL);
// Kill if we get here.
printf("Errno from exec: %d", errno);
FAIL() << "Exec of " << helper_path << " failed: " << strerror(errno);
exit(0);
}
close(fds[1]);
// Wait for all child threads to indicate that they have started
for (int threads = 0; threads < kNumberOfThreadsInHelperProgram; threads++) {
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fds[0];
pfd.events = POLLIN | POLLERR;
const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
ASSERT_EQ(1, r);
ASSERT_TRUE(pfd.revents & POLLIN);
uint8_t junk;
ASSERT_EQ(read(fds[0], &junk, sizeof(junk)),
static_cast<ssize_t>(sizeof(junk)));
}
close(fds[0]);
// There is a race here because we may stop a child thread before
// it is actually running the busy loop. Empirically this sleep
// is sufficient to avoid the race.
usleep(100000);
// Children are ready now.
LinuxPtraceDumper dumper(child_pid);
@ -476,99 +468,3 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
ASSERT_TRUE(WIFSIGNALED(status));
ASSERT_EQ(SIGKILL, WTERMSIG(status));
}
TEST_F(LinuxPtraceDumperTest, SanitizeStackCopy) {
static const int kNumberOfThreadsInHelperProgram = 1;
pid_t child_pid = SetupChildProcess(kNumberOfThreadsInHelperProgram);
ASSERT_NE(child_pid, -1);
LinuxPtraceDumper dumper(child_pid);
ASSERT_TRUE(dumper.Init());
EXPECT_TRUE(dumper.ThreadsSuspend());
ThreadInfo thread_info;
EXPECT_TRUE(dumper.GetThreadInfoByIndex(0, &thread_info));
const uintptr_t defaced =
#if defined(__LP64__)
0x0defaced0defaced;
#else
0x0defaced;
#endif
uintptr_t simulated_stack[2];
// Pointers into the stack shouldn't be sanitized.
memset(simulated_stack, 0xff, sizeof(simulated_stack));
simulated_stack[1] = thread_info.stack_pointer;
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
sizeof(simulated_stack), thread_info.stack_pointer,
sizeof(uintptr_t));
ASSERT_NE(simulated_stack[1], defaced);
// Memory prior to the stack pointer should be cleared.
ASSERT_EQ(simulated_stack[0], 0u);
// Small integers should not be sanitized.
for (int i = -4096; i <= 4096; ++i) {
memset(simulated_stack, 0, sizeof(simulated_stack));
simulated_stack[0] = static_cast<uintptr_t>(i);
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
sizeof(simulated_stack), thread_info.stack_pointer,
0u);
ASSERT_NE(simulated_stack[0], defaced);
}
// The instruction pointer definitely should point into an executable mapping.
const MappingInfo* mapping_info = dumper.FindMappingNoBias(
reinterpret_cast<uintptr_t>(thread_info.GetInstructionPointer()));
ASSERT_NE(mapping_info, nullptr);
ASSERT_TRUE(mapping_info->exec);
// Pointers to code shouldn't be sanitized.
memset(simulated_stack, 0, sizeof(simulated_stack));
simulated_stack[1] = thread_info.GetInstructionPointer();
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
sizeof(simulated_stack), thread_info.stack_pointer,
0u);
ASSERT_NE(simulated_stack[0], defaced);
// String fragments should be sanitized.
memcpy(simulated_stack, "abcdefghijklmnop", sizeof(simulated_stack));
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
sizeof(simulated_stack), thread_info.stack_pointer,
0u);
ASSERT_EQ(simulated_stack[0], defaced);
ASSERT_EQ(simulated_stack[1], defaced);
// Heap pointers should be sanititzed.
#if defined(__ARM_EABI__)
uintptr_t heap_addr = thread_info.regs.uregs[3];
#elif defined(__aarch64__)
uintptr_t heap_addr = thread_info.regs.regs[3];
#elif defined(__i386)
uintptr_t heap_addr = thread_info.regs.ecx;
#elif defined(__x86_64)
uintptr_t heap_addr = thread_info.regs.rcx;
#elif defined(__mips__)
uintptr_t heap_addr = thread_info.mcontext.gregs[1];
#else
#error This test has not been ported to this platform.
#endif
memset(simulated_stack, 0, sizeof(simulated_stack));
simulated_stack[0] = heap_addr;
dumper.SanitizeStackCopy(reinterpret_cast<uint8_t*>(&simulated_stack),
sizeof(simulated_stack), thread_info.stack_pointer,
0u);
ASSERT_EQ(simulated_stack[0], defaced);
EXPECT_TRUE(dumper.ThreadsResume());
kill(child_pid, SIGKILL);
// Reap child.
int status;
ASSERT_NE(-1, HANDLE_EINTR(waitpid(child_pid, &status, 0)));
ASSERT_TRUE(WIFSIGNALED(status));
ASSERT_EQ(SIGKILL, WTERMSIG(status));
}

View File

@ -129,9 +129,6 @@ class MinidumpWriter {
const ExceptionHandler::CrashContext* context,
const MappingList& mappings,
const AppMemoryList& appmem,
bool skip_stacks_if_mapping_unreferenced,
uintptr_t principal_mapping_address,
bool sanitize_stacks,
LinuxDumper* dumper)
: fd_(minidump_fd),
path_(minidump_path),
@ -143,12 +140,7 @@ class MinidumpWriter {
minidump_size_limit_(-1),
memory_blocks_(dumper_->allocator()),
mapping_list_(mappings),
app_memory_list_(appmem),
skip_stacks_if_mapping_unreferenced_(
skip_stacks_if_mapping_unreferenced),
principal_mapping_address_(principal_mapping_address),
principal_mapping_(nullptr),
sanitize_stacks_(sanitize_stacks) {
app_memory_list_(appmem) {
// Assert there should be either a valid fd or a valid path, not both.
assert(fd_ != -1 || minidump_path);
assert(fd_ == -1 || !minidump_path);
@ -158,22 +150,12 @@ class MinidumpWriter {
if (!dumper_->Init())
return false;
if (!dumper_->ThreadsSuspend() || !dumper_->LateInit())
return false;
if (skip_stacks_if_mapping_unreferenced_) {
principal_mapping_ =
dumper_->FindMappingNoBias(principal_mapping_address_);
if (!CrashingThreadReferencesPrincipalMapping())
return false;
}
if (fd_ != -1)
minidump_writer_.SetFile(fd_);
else if (!minidump_writer_.Open(path_))
return false;
return true;
return dumper_->ThreadsSuspend() && dumper_->LateInit();
}
~MinidumpWriter() {
@ -184,38 +166,6 @@ class MinidumpWriter {
dumper_->ThreadsResume();
}
bool CrashingThreadReferencesPrincipalMapping() {
if (!ucontext_ || !principal_mapping_)
return false;
const uintptr_t low_addr =
principal_mapping_->system_mapping_info.start_addr;
const uintptr_t high_addr =
principal_mapping_->system_mapping_info.end_addr;
const uintptr_t stack_pointer = UContextReader::GetStackPointer(ucontext_);
const uintptr_t pc = UContextReader::GetInstructionPointer(ucontext_);
if (pc >= low_addr && pc < high_addr)
return true;
uint8_t* stack_copy;
const void* stack;
size_t stack_len;
if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer))
return false;
stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
dumper_->CopyFromProcess(stack_copy, GetCrashThread(), stack, stack_len);
uintptr_t stack_pointer_offset =
stack_pointer - reinterpret_cast<uintptr_t>(stack);
return dumper_->StackHasPointerToMapping(
stack_copy, stack_len, stack_pointer_offset, *principal_mapping_);
}
bool Dump() {
// A minidump file contains a number of tagged streams. This is the number
// of stream which we write.
@ -316,16 +266,12 @@ class MinidumpWriter {
}
bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer,
uintptr_t pc, int max_stack_len, uint8_t** stack_copy) {
int max_stack_len, uint8_t** stack_copy) {
*stack_copy = NULL;
const void* stack;
size_t stack_len;
thread->stack.start_of_memory_range = stack_pointer;
thread->stack.memory.data_size = 0;
thread->stack.memory.rva = minidump_writer_.position();
if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
UntypedMDRVA memory(&minidump_writer_);
if (max_stack_len >= 0 &&
stack_len > static_cast<unsigned int>(max_stack_len)) {
stack_len = max_stack_len;
@ -338,38 +284,20 @@ class MinidumpWriter {
}
stack = reinterpret_cast<const void*>(int_stack);
}
if (!memory.Allocate(stack_len))
return false;
*stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack,
stack_len);
uintptr_t stack_pointer_offset =
stack_pointer - reinterpret_cast<uintptr_t>(stack);
if (skip_stacks_if_mapping_unreferenced_) {
if (!principal_mapping_) {
return true;
}
uintptr_t low_addr = principal_mapping_->system_mapping_info.start_addr;
uintptr_t high_addr = principal_mapping_->system_mapping_info.end_addr;
if ((pc < low_addr || pc > high_addr) &&
!dumper_->StackHasPointerToMapping(*stack_copy, stack_len,
stack_pointer_offset,
*principal_mapping_)) {
return true;
}
}
if (sanitize_stacks_) {
dumper_->SanitizeStackCopy(*stack_copy, stack_len, stack_pointer,
stack_pointer_offset);
}
UntypedMDRVA memory(&minidump_writer_);
if (!memory.Allocate(stack_len))
return false;
memory.Copy(*stack_copy, stack_len);
thread->stack.start_of_memory_range = reinterpret_cast<uintptr_t>(stack);
thread->stack.start_of_memory_range =
reinterpret_cast<uintptr_t>(stack);
thread->stack.memory = memory.location();
memory_blocks_.push_back(thread->stack);
} else {
thread->stack.start_of_memory_range = stack_pointer;
thread->stack.memory.data_size = 0;
thread->stack.memory.rva = minidump_writer_.position();
}
return true;
}
@ -416,9 +344,7 @@ class MinidumpWriter {
!dumper_->IsPostMortem()) {
uint8_t* stack_copy;
const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
if (!FillThreadStack(&thread, stack_ptr,
UContextReader::GetInstructionPointer(ucontext_),
-1, &stack_copy))
if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy))
return false;
// Copy 256 bytes around crashing instruction pointer to minidump.
@ -484,9 +410,8 @@ class MinidumpWriter {
int max_stack_len = -1; // default to no maximum for this thread
if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount)
max_stack_len = extra_thread_stack_len;
if (!FillThreadStack(&thread, info.stack_pointer,
info.GetInstructionPointer(), max_stack_len,
&stack_copy))
if (!FillThreadStack(&thread, info.stack_pointer, max_stack_len,
&stack_copy))
return false;
TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
@ -1323,7 +1248,7 @@ class MinidumpWriter {
const int fd_; // File descriptor where the minidum should be written.
const char* path_; // Path to the file where the minidum should be written.
const ucontext_t* const ucontext_; // also from the signal handler
const struct ucontext* const ucontext_; // also from the signal handler
#if !defined(__ARM_EABI__) && !defined(__mips__)
const google_breakpad::fpstate_t* const float_state_; // ditto
#endif
@ -1340,13 +1265,6 @@ class MinidumpWriter {
// Additional memory regions to be included in the dump,
// provided by the caller.
const AppMemoryList& app_memory_list_;
// If set, skip recording any threads that do not reference the
// mapping containing principal_mapping_address_.
bool skip_stacks_if_mapping_unreferenced_;
uintptr_t principal_mapping_address_;
const MappingInfo* principal_mapping_;
// If true, apply stack sanitization to stored stack data.
bool sanitize_stacks_;
};
@ -1356,10 +1274,7 @@ bool WriteMinidumpImpl(const char* minidump_path,
pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appmem,
bool skip_stacks_if_mapping_unreferenced,
uintptr_t principal_mapping_address,
bool sanitize_stacks) {
const AppMemoryList& appmem) {
LinuxPtraceDumper dumper(crashing_process);
const ExceptionHandler::CrashContext* context = NULL;
if (blob) {
@ -1372,8 +1287,7 @@ bool WriteMinidumpImpl(const char* minidump_path,
dumper.set_crash_thread(context->tid);
}
MinidumpWriter writer(minidump_path, minidump_fd, context, mappings,
appmem, skip_stacks_if_mapping_unreferenced,
principal_mapping_address, sanitize_stacks, &dumper);
appmem, &dumper);
// Set desired limit for file size of minidump (-1 means no limit).
writer.set_minidump_size_limit(minidump_size_limit);
if (!writer.Init())
@ -1386,29 +1300,17 @@ bool WriteMinidumpImpl(const char* minidump_path,
namespace google_breakpad {
bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
const void* blob, size_t blob_size,
bool skip_stacks_if_mapping_unreferenced,
uintptr_t principal_mapping_address,
bool sanitize_stacks) {
const void* blob, size_t blob_size) {
return WriteMinidumpImpl(minidump_path, -1, -1,
crashing_process, blob, blob_size,
MappingList(), AppMemoryList(),
skip_stacks_if_mapping_unreferenced,
principal_mapping_address,
sanitize_stacks);
MappingList(), AppMemoryList());
}
bool WriteMinidump(int minidump_fd, pid_t crashing_process,
const void* blob, size_t blob_size,
bool skip_stacks_if_mapping_unreferenced,
uintptr_t principal_mapping_address,
bool sanitize_stacks) {
const void* blob, size_t blob_size) {
return WriteMinidumpImpl(NULL, minidump_fd, -1,
crashing_process, blob, blob_size,
MappingList(), AppMemoryList(),
skip_stacks_if_mapping_unreferenced,
principal_mapping_address,
sanitize_stacks);
MappingList(), AppMemoryList());
}
bool WriteMinidump(const char* minidump_path, pid_t process,
@ -1418,7 +1320,7 @@ bool WriteMinidump(const char* minidump_path, pid_t process,
dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED);
dumper.set_crash_thread(process_blamed_thread);
MinidumpWriter writer(minidump_path, -1, NULL, MappingList(),
AppMemoryList(), false, 0, false, &dumper);
AppMemoryList(), &dumper);
if (!writer.Init())
return false;
return writer.Dump();
@ -1427,71 +1329,46 @@ bool WriteMinidump(const char* minidump_path, pid_t process,
bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appmem,
bool skip_stacks_if_mapping_unreferenced,
uintptr_t principal_mapping_address,
bool sanitize_stacks) {
const AppMemoryList& appmem) {
return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process,
blob, blob_size,
mappings, appmem,
skip_stacks_if_mapping_unreferenced,
principal_mapping_address,
sanitize_stacks);
mappings, appmem);
}
bool WriteMinidump(int minidump_fd, pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appmem,
bool skip_stacks_if_mapping_unreferenced,
uintptr_t principal_mapping_address,
bool sanitize_stacks) {
const AppMemoryList& appmem) {
return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process,
blob, blob_size,
mappings, appmem,
skip_stacks_if_mapping_unreferenced,
principal_mapping_address,
sanitize_stacks);
mappings, appmem);
}
bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit,
pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appmem,
bool skip_stacks_if_mapping_unreferenced,
uintptr_t principal_mapping_address,
bool sanitize_stacks) {
const AppMemoryList& appmem) {
return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit,
crashing_process, blob, blob_size,
mappings, appmem,
skip_stacks_if_mapping_unreferenced,
principal_mapping_address,
sanitize_stacks);
mappings, appmem);
}
bool WriteMinidump(int minidump_fd, off_t minidump_size_limit,
pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appmem,
bool skip_stacks_if_mapping_unreferenced,
uintptr_t principal_mapping_address,
bool sanitize_stacks) {
const AppMemoryList& appmem) {
return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit,
crashing_process, blob, blob_size,
mappings, appmem,
skip_stacks_if_mapping_unreferenced,
principal_mapping_address,
sanitize_stacks);
mappings, appmem);
}
bool WriteMinidump(const char* filename,
const MappingList& mappings,
const AppMemoryList& appmem,
LinuxDumper* dumper) {
MinidumpWriter writer(filename, -1, NULL, mappings, appmem,
false, 0, false, dumper);
MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper);
if (!writer.Init())
return false;
return writer.Dump();

View File

@ -78,16 +78,10 @@ typedef std::list<AppMemory> AppMemoryList;
//
// Returns true iff successful.
bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
const void* blob, size_t blob_size,
bool skip_stacks_if_mapping_unreferenced = false,
uintptr_t principal_mapping_address = 0,
bool sanitize_stacks = false);
const void* blob, size_t blob_size);
// Same as above but takes an open file descriptor instead of a path.
bool WriteMinidump(int minidump_fd, pid_t crashing_process,
const void* blob, size_t blob_size,
bool skip_stacks_if_mapping_unreferenced = false,
uintptr_t principal_mapping_address = 0,
bool sanitize_stacks = false);
const void* blob, size_t blob_size);
// Alternate form of WriteMinidump() that works with processes that
// are not expected to have crashed. If |process_blamed_thread| is
@ -102,35 +96,23 @@ bool WriteMinidump(const char* minidump_path, pid_t process,
bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appdata,
bool skip_stacks_if_mapping_unreferenced = false,
uintptr_t principal_mapping_address = 0,
bool sanitize_stacks = false);
const AppMemoryList& appdata);
bool WriteMinidump(int minidump_fd, pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appdata,
bool skip_stacks_if_mapping_unreferenced = false,
uintptr_t principal_mapping_address = 0,
bool sanitize_stacks = false);
const AppMemoryList& appdata);
// These overloads also allow passing a file size limit for the minidump.
bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit,
pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appdata,
bool skip_stacks_if_mapping_unreferenced = false,
uintptr_t principal_mapping_address = 0,
bool sanitize_stacks = false);
const AppMemoryList& appdata);
bool WriteMinidump(int minidump_fd, off_t minidump_size_limit,
pid_t crashing_process,
const void* blob, size_t blob_size,
const MappingList& mappings,
const AppMemoryList& appdata,
bool skip_stacks_if_mapping_unreferenced = false,
uintptr_t principal_mapping_address = 0,
bool sanitize_stacks = false);
const AppMemoryList& appdata);
bool WriteMinidump(const char* filename,
const MappingList& mappings,

View File

@ -169,7 +169,6 @@ TEST(MinidumpWriterTest, MappingInfo) {
info.start_addr = kMemoryAddress;
info.size = memory_size;
info.offset = 0;
info.exec = false;
strcpy(info.name, kMemoryName);
MappingList mappings;
@ -179,7 +178,7 @@ TEST(MinidumpWriterTest, MappingInfo) {
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
mappings.push_back(mapping);
ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
mappings, memory_list, false, 0, false));
mappings, memory_list));
// Read the minidump. Load the module list, and ensure that
// the mmap'ed |memory| is listed with the given module name
@ -215,146 +214,6 @@ TEST(MinidumpWriterTest, MappingInfo) {
close(fds[1]);
}
// Test that minidumping is skipped while writing minidumps if principal mapping
// is not referenced.
TEST(MinidumpWriterTest, MinidumpSkippedIfRequested) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
char b;
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
ASSERT_EQ(0, getcontext(&context.context));
context.tid = child;
AutoTempDir temp_dir;
string templ = temp_dir.path() + kMDWriterUnitTestFileName;
// pass an invalid principal mapping address, which will force
// WriteMinidump to not write a minidump.
ASSERT_FALSE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
true, static_cast<uintptr_t>(0x0102030405060708ull),
false));
close(fds[1]);
}
// Test that minidumping is skipped while writing minidumps if principal mapping
// is not referenced.
TEST(MinidumpWriterTest, MinidumpStacksSkippedIfRequested) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
// Create a thread that does not return, and only references libc (not the
// current executable). This thread should not be captured in the minidump.
pthread_t thread;
pthread_attr_t thread_attributes;
pthread_attr_init(&thread_attributes);
pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
sigset_t sigset;
sigemptyset(&sigset);
pthread_create(&thread, &thread_attributes,
reinterpret_cast<void* (*)(void*)>(&sigsuspend), &sigset);
char b;
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
ASSERT_EQ(0, getcontext(&context.context));
context.tid = child;
AutoTempDir temp_dir;
string templ = temp_dir.path() + kMDWriterUnitTestFileName;
// Pass an invalid principal mapping address, which will force
// WriteMinidump to not dump any thread stacks.
ASSERT_TRUE(WriteMinidump(
templ.c_str(), child, &context, sizeof(context), true,
reinterpret_cast<uintptr_t>(google_breakpad::WriteFile), false));
// Read the minidump. And ensure that thread memory was dumped only for the
// main thread.
Minidump minidump(templ);
ASSERT_TRUE(minidump.Read());
MinidumpThreadList *threads = minidump.GetThreadList();
int threads_with_stacks = 0;
for (unsigned int i = 0; i < threads->thread_count(); ++i) {
MinidumpThread *thread = threads->GetThreadAtIndex(i);
if (thread->GetMemory()) {
++threads_with_stacks;
}
}
ASSERT_EQ(1, threads_with_stacks);
close(fds[1]);
}
// Test that stacks can be sanitized while writing minidumps.
TEST(MinidumpWriterTest, StacksAreSanitizedIfRequested) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
char b;
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
ASSERT_EQ(0, getcontext(&context.context));
context.tid = child;
AutoTempDir temp_dir;
string templ = temp_dir.path() + kMDWriterUnitTestFileName;
// pass an invalid principal mapping address, which will force
// WriteMinidump to not dump any thread stacks.
ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
false, 0, true));
// Read the minidump. And ensure that thread memory contains a defaced value.
Minidump minidump(templ);
ASSERT_TRUE(minidump.Read());
const uintptr_t defaced =
#if defined(__LP64__)
0x0defaced0defaced;
#else
0x0defaced;
#endif
MinidumpThreadList *threads = minidump.GetThreadList();
for (unsigned int i = 0; i < threads->thread_count(); ++i) {
MinidumpThread *thread = threads->GetThreadAtIndex(i);
MinidumpMemoryRegion *mem = thread->GetMemory();
ASSERT_TRUE(mem != nullptr);
uint32_t sz = mem->GetSize();
const uint8_t *data = mem->GetMemory();
ASSERT_TRUE(memmem(data, sz, &defaced, sizeof(defaced)) != nullptr);
}
close(fds[1]);
}
// Test that a binary with a longer-than-usual build id note
// makes its way all the way through to the minidump unscathed.
// The linux_client_unittest is linked with an explicit --build-id
@ -464,7 +323,6 @@ TEST(MinidumpWriterTest, MappingInfoContained) {
info.start_addr = kMemoryAddress - memory_size;
info.size = memory_size * 3;
info.offset = 0;
info.exec = false;
strcpy(info.name, kMemoryName);
MappingList mappings;

View File

@ -126,7 +126,7 @@ extern "C" {
mach_msg_header_t* reply);
// This symbol must be visible to dlsym() - see
// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=345 for details.
// http://code.google.com/p/google-breakpad/issues/detail?id=345 for details.
kern_return_t catch_exception_raise(mach_port_t target_port,
mach_port_t failed_thread,
mach_port_t task,
@ -356,11 +356,6 @@ bool ExceptionHandler::WriteMinidumpWithException(
bool report_current_thread) {
bool result = false;
#if TARGET_OS_IPHONE
// _exit() should never be called on iOS.
exit_after_write = false;
#endif
if (directCallback_) {
if (directCallback_(callback_context_,
exception_type,
@ -464,7 +459,7 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
kern_return_t result;
// TODO: Handle the case where |target_behavior| has MACH_EXCEPTION_CODES
// set. https://bugs.chromium.org/p/google-breakpad/issues/detail?id=551
// set. https://code.google.com/p/google-breakpad/issues/detail?id=551
switch (target_behavior) {
case EXCEPTION_DEFAULT:
result = exception_raise(target_port, failed_thread, task, exception,

View File

@ -68,7 +68,7 @@
F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; };
F93A88800E8B4C8C0026AF89 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FA0BEF947200920385 /* file_id.cc */; };
F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F310E8B07E800D7E813 /* dwarftests.mm */; };
F93A88870E8B4C9A0026AF89 /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F390E8B0D0D00D7E813 /* dump_syms.cc */; };
F93A88870E8B4C9A0026AF89 /* dump_syms.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F390E8B0D0D00D7E813 /* dump_syms.mm */; };
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F760E8B0DC700D7E813 /* bytereader.cc */; };
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */; };
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F780E8B0DC700D7E813 /* functioninfo.cc */; };
@ -151,7 +151,7 @@
F9721F300E8B07E800D7E813 /* dwarftests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dwarftests.h; sourceTree = "<group>"; };
F9721F310E8B07E800D7E813 /* dwarftests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = dwarftests.mm; sourceTree = "<group>"; };
F9721F380E8B0CFC00D7E813 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; };
F9721F390E8B0D0D00D7E813 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = SOURCE_ROOT; };
F9721F390E8B0D0D00D7E813 /* dump_syms.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.mm; path = ../../../common/mac/dump_syms.mm; sourceTree = SOURCE_ROOT; };
F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
F9721F760E8B0DC700D7E813 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; };
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
@ -240,7 +240,7 @@
F9721F760E8B0DC700D7E813 /* bytereader.cc */,
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */,
F9721F780E8B0DC700D7E813 /* functioninfo.cc */,
F9721F390E8B0D0D00D7E813 /* dump_syms.cc */,
F9721F390E8B0D0D00D7E813 /* dump_syms.mm */,
F9721F380E8B0CFC00D7E813 /* dump_syms.h */,
F917C4F70E03265A00F86017 /* breakpad_exc_server.c */,
F917C4F80E03265A00F86017 /* breakpad_exc_server.h */,
@ -597,7 +597,7 @@
buildActionMask = 2147483647;
files = (
F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */,
F93A88870E8B4C9A0026AF89 /* dump_syms.cc in Sources */,
F93A88870E8B4C9A0026AF89 /* dump_syms.mm in Sources */,
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */,
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */,
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */,

View File

@ -36,7 +36,6 @@
#include "breakpad_googletest_includes.h"
#include "client/mac/handler/exception_handler.h"
#include "common/linux/ignore_ret.h"
#include "common/mac/MachIPC.h"
#include "common/tests/auto_tempdir.h"
#include "google_breakpad/processor/minidump.h"
@ -94,7 +93,7 @@ static bool MDCallback(const char *dump_dir, const char *file_name,
path.append(".dmp");
int fd = *reinterpret_cast<int*>(context);
IGNORE_RET(write(fd, path.c_str(), path.length() + 1));
(void)write(fd, path.c_str(), path.length() + 1);
close(fd);
exit(0);
// not reached
@ -294,7 +293,7 @@ TEST_F(ExceptionHandlerTest, DumpChildProcess) {
// Unblock child process
uint8_t data = 1;
IGNORE_RET(write(fds[1], &data, 1));
(void)write(fds[1], &data, 1);
// Child process should have exited with a zero status.
int ret;

View File

@ -42,7 +42,6 @@
#include "breakpad_googletest_includes.h"
#include "client/mac/handler/minidump_generator.h"
#include "client/mac/tests/spawn_child_process.h"
#include "common/linux/ignore_ret.h"
#include "common/mac/MachIPC.h"
#include "common/tests/auto_tempdir.h"
#include "google_breakpad/processor/minidump.h"
@ -191,7 +190,7 @@ TEST_F(MinidumpGeneratorTest, OutOfProcess) {
// Unblock child process
uint8_t data = 1;
IGNORE_RET(write(fds[1], &data, 1));
(void)write(fds[1], &data, 1);
// Child process should have exited with a zero status.
int ret;

View File

@ -41,17 +41,18 @@
namespace google_breakpad {
static const int kWaitForHandlerThreadMs = 60000;
static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
// As documented on MSDN, on failure SuspendThread returns (DWORD) -1
static const DWORD kFailedToSuspendThread = static_cast<DWORD>(-1);
// This is passed as the context to the MinidumpWriteDump callback.
typedef struct {
AppMemoryList::const_iterator iter;
AppMemoryList::const_iterator end;
} MinidumpCallbackContext;
// This define is new to Windows 10.
#ifndef DBG_PRINTEXCEPTION_WIDE_C
#define DBG_PRINTEXCEPTION_WIDE_C ((DWORD)0x4001000A)
#endif
vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
LONG ExceptionHandler::handler_stack_index_ = 0;
CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
@ -216,7 +217,6 @@ void ExceptionHandler::Initialize(
// Don't attempt to create the thread if we could not create the semaphores.
if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) {
DWORD thread_id;
const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
handler_thread_ = CreateThread(NULL, // lpThreadAttributes
kExceptionHandlerThreadInitialStackSize,
ExceptionHandlerThreadMain,
@ -353,7 +353,6 @@ ExceptionHandler::~ExceptionHandler() {
// inside DllMain.
is_shutdown_ = true;
ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
const int kWaitForHandlerThreadMs = 60000;
WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);
#else
TerminateThread(handler_thread_, 1);
@ -481,9 +480,7 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
DWORD code = exinfo->ExceptionRecord->ExceptionCode;
LONG action;
bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
(code == EXCEPTION_SINGLE_STEP) ||
(code == DBG_PRINTEXCEPTION_C) ||
(code == DBG_PRINTEXCEPTION_WIDE_C);
(code == EXCEPTION_SINGLE_STEP);
if (code == EXCEPTION_INVALID_HANDLE &&
current_handler->consume_invalid_handle_exceptions_) {
@ -767,10 +764,9 @@ bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {
// static
bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
MinidumpCallback callback,
void* callback_context,
MINIDUMP_TYPE dump_type) {
void* callback_context) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context,
HANDLER_NONE, dump_type, (HANDLE)NULL, NULL);
HANDLER_NONE);
return handler.WriteMinidump();
}
@ -779,13 +775,10 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child,
DWORD child_blamed_thread,
const wstring& dump_path,
MinidumpCallback callback,
void* callback_context,
MINIDUMP_TYPE dump_type) {
void* callback_context) {
EXCEPTION_RECORD ex;
CONTEXT ctx;
EXCEPTION_POINTERS exinfo = { NULL, NULL };
// As documented on MSDN, on failure SuspendThread returns (DWORD) -1
const DWORD kFailedToSuspendThread = static_cast<DWORD>(-1);
DWORD last_suspend_count = kFailedToSuspendThread;
HANDLE child_thread_handle = OpenThread(THREAD_GET_CONTEXT |
THREAD_QUERY_INFORMATION |
@ -813,7 +806,7 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child,
}
ExceptionHandler handler(dump_path, NULL, callback, callback_context,
HANDLER_NONE, dump_type, (HANDLE)NULL, NULL);
HANDLER_NONE);
bool success = handler.WriteMinidumpWithExceptionForProcess(
child_blamed_thread,
exinfo.ExceptionRecord ? &exinfo : NULL,

View File

@ -238,8 +238,7 @@ class ExceptionHandler {
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
static bool WriteMinidump(const wstring &dump_path,
MinidumpCallback callback, void* callback_context,
MINIDUMP_TYPE dump_type = MiniDumpNormal);
MinidumpCallback callback, void* callback_context);
// Write a minidump of |child| immediately. This can be used to
// capture the execution state of |child| independently of a crash.
@ -250,8 +249,7 @@ class ExceptionHandler {
DWORD child_blamed_thread,
const wstring& dump_path,
MinidumpCallback callback,
void* callback_context,
MINIDUMP_TYPE dump_type = MiniDumpNormal);
void* callback_context);
// Get the thread ID of the thread requesting the dump (either the exception
// thread or any other thread that called WriteMinidump directly). This

View File

@ -28,7 +28,9 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "breakpad_googletest_includes.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/include/gmock/gmock.h"
#include "client/windows/crash_generation/crash_generation_server.h"
#include "client/windows/common/ipc_protocol.h"

View File

@ -31,8 +31,8 @@
#include <objbase.h>
#include <dbghelp.h>
#include "breakpad_googletest_includes.h"
#include "client/windows/unittests/dump_analysis.h" // NOLINT
#include "testing/gtest/include/gtest/gtest.h"
DumpAnalysis::~DumpAnalysis() {
if (dump_file_view_ != NULL) {

View File

@ -31,10 +31,11 @@
#include <objbase.h>
#include <dbghelp.h>
#include "breakpad_googletest_includes.h"
#include "client/windows/crash_generation/minidump_generator.h"
#include "client/windows/unittests/dump_analysis.h" // NOLINT
#include "gtest/gtest.h"
namespace {
// Minidump with stacks, PEB, TEB, and unloaded module list.

View File

@ -38,12 +38,11 @@
'type': 'static_library',
'include_dirs': [
'<(DEPTH)/testing/include',
'<(DEPTH)/testing/googletest/include',
'<(DEPTH)/testing/googletest',
'<(DEPTH)/testing',
'<(DEPTH)/testing/gtest',
'<(DEPTH)/testing/gtest/include',
],
'sources': [
'<(DEPTH)/testing/googletest/src/gtest-all.cc',
'<(DEPTH)/testing/gtest/src/gtest-all.cc',
],
'direct_dependent_settings': {
'include_dirs': [
@ -62,24 +61,18 @@
'type': 'static_library',
'include_dirs': [
'<(DEPTH)/testing/include',
'<(DEPTH)/testing/googletest/include',
'<(DEPTH)/testing/googletest',
'<(DEPTH)/testing/googlemock/include',
'<(DEPTH)/testing/googlemock',
'<(DEPTH)/testing',
'<(DEPTH)/testing/',
'<(DEPTH)/testing/gtest',
'<(DEPTH)/testing/gtest/include',
],
'sources': [
'<(DEPTH)/testing/googlemock/src/gmock-all.cc',
'<(DEPTH)/testing/googletest/src/gtest_main.cc',
'<(DEPTH)/testing/src/gmock-all.cc',
'<(DEPTH)/testing/src/gmock_main.cc',
],
'direct_dependent_settings': {
'include_dirs': [
'<(DEPTH)/testing/include',
'<(DEPTH)/testing/googletest/include',
'<(DEPTH)/testing/googletest',
'<(DEPTH)/testing/googlemock/include',
'<(DEPTH)/testing/googlemock',
'<(DEPTH)/testing',
'<(DEPTH)/testing/gtest/include',
],
'defines': ['_VARIADIC_MAX=10'],
},

View File

@ -34,20 +34,12 @@
// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code.
// The following quirks are currently handled by this file:
// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct.
// - aarch64:
// - NDK r10: Add missing user_regs_struct and user_fpsimd_struct structs.
// - NDK r11+: Add missing <stdint.h> include
// - aarch64: Add missing user_regs_struct and user_fpsimd_struct structs.
// - Other platforms: Just use the Android NDK unchanged.
// TODO(primiano): remove these changes after Chromium has stably rolled to
// an NDK with the appropriate fixes.
#if defined(ANDROID_NDK_MAJOR_VERSION) && ANDROID_NDK_MAJOR_VERSION > 10
#ifdef __aarch64__
#include <stdint.h>
#endif // __aarch64__
#endif // defined(ANDROID_NDK_MAJOR_VERSION) && ANDROID_NDK_MAJOR_VERSION > 10
#include_next <sys/user.h>
#ifdef __i386__
@ -60,7 +52,6 @@ typedef struct user_fxsr_struct user_fpxregs_struct;
#endif // __cplusplus
#endif // __i386__
#if !defined(ANDROID_NDK_MAJOR_VERSION) || ANDROID_NDK_MAJOR_VERSION == 10
#ifdef __aarch64__
#ifdef __cplusplus
extern "C" {
@ -80,6 +71,5 @@ struct user_fpsimd_struct {
} // extern "C"
#endif // __cplusplus
#endif // __aarch64__
#endif // defined(ANDROID_NDK_VERSION) && ANDROID_NDK_MAJOR_VERSION == 10
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H

View File

@ -46,9 +46,7 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
unsigned return_address_register,
uint8_t version,
const string &augmentation,
bool dwarf64,
uint8_t address_size,
uint8_t segment_size) {
bool dwarf64) {
assert(!entry_length_);
entry_length_ = new PendingLength();
in_fde_ = false;
@ -65,10 +63,6 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
}
D8(version);
AppendCString(augmentation);
if (version >= 4) {
D8(address_size);
D8(segment_size);
}
ULEB128(code_alignment_factor);
LEB128(data_alignment_factor);
if (version == 1)

View File

@ -138,9 +138,7 @@ class CFISection: public Section {
unsigned return_address_register,
uint8_t version = 3,
const string &augmentation = "",
bool dwarf64 = false,
uint8_t address_size = 8,
uint8_t segment_size = 0);
bool dwarf64 = false);
// Append a Frame Description Entry header to this section with the
// given values. If dwarf64 is true, use the 64-bit DWARF initial

View File

@ -232,8 +232,6 @@ enum DwarfAttribute {
DW_AT_call_column = 0x57,
DW_AT_call_file = 0x58,
DW_AT_call_line = 0x59,
// DWARF 4
DW_AT_linkage_name = 0x6e,
// SGI/MIPS extensions.
DW_AT_MIPS_fde = 0x2001,
DW_AT_MIPS_loop_begin = 0x2002,
@ -501,7 +499,7 @@ enum DwarfOpcode {
DW_OP_call_frame_cfa =0x9c,
DW_OP_bit_piece =0x9d,
DW_OP_lo_user =0xe0,
DW_OP_hi_user =0xff,
DW_OP_hi_user =0xff,
// GNU extensions
DW_OP_GNU_push_tls_address =0xe0,
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
@ -544,8 +542,6 @@ enum DwarfLanguage
DW_LANG_ObjC_plus_plus =0x0011,
DW_LANG_UPC =0x0012,
DW_LANG_D =0x0013,
DW_LANG_Rust =0x001c,
DW_LANG_Swift =0x001e,
// Implementation-defined language code range.
DW_LANG_lo_user = 0x8000,
DW_LANG_hi_user = 0xffff,
@ -672,7 +668,7 @@ enum DwarfPointerEncoding
// encoding (except DW_EH_PE_aligned), and indicates that the
// encoded value represents the address at which the true address
// is stored, not the true address itself.
DW_EH_PE_indirect = 0x80
DW_EH_PE_indirect = 0x80
};
} // namespace dwarf2reader

View File

@ -2253,11 +2253,11 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
cursor++;
// If we don't recognize the version, we can't parse any more fields of the
// CIE. For DWARF CFI, we handle versions 1 through 4 (there was never a
// version 2 of CFI data). For .eh_frame, we handle versions 1 and 4 as well;
// CIE. For DWARF CFI, we handle versions 1 through 3 (there was never a
// version 2 of CFI data). For .eh_frame, we handle versions 1 and 3 as well;
// the difference between those versions seems to be the same as for
// .debug_frame.
if (cie->version < 1 || cie->version > 4) {
if (cie->version < 1 || cie->version > 3) {
reporter_->UnrecognizedVersion(cie->offset, cie->version);
return false;
}
@ -2287,36 +2287,16 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
}
}
if (cie->version >= 4) {
uint8_t address_size = *cursor++;
if (address_size != 8) {
// TODO(scottmg): Only supporting x64 for now.
reporter_->UnexpectedAddressSize(cie->offset, address_size);
return false;
}
uint8_t segment_size = *cursor++;
if (segment_size != 0) {
// TODO(scottmg): Only supporting x64 for now.
// I would have perhaps expected 4 here, but LLVM emits a 0, near
// http://llvm.org/docs/doxygen/html/MCDwarf_8cpp_source.html#l00606. As
// we are not using the value, only succeed for now if it's the expected
// 0.
reporter_->UnexpectedSegmentSize(cie->offset, segment_size);
return false;
}
}
// Parse the code alignment factor.
cie->code_alignment_factor = reader_->ReadUnsignedLEB128(cursor, &len);
if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie);
cursor += len;
// Parse the data alignment factor.
cie->data_alignment_factor = reader_->ReadSignedLEB128(cursor, &len);
if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie);
cursor += len;
// Parse the return address register. This is a ubyte in version 1, and
// a ULEB128 in version 3.
if (cie->version == 1) {
@ -2427,7 +2407,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
return true;
}
bool CallFrameInfo::ReadFDEFields(FDE *fde) {
const uint8_t *cursor = fde->fields;
size_t size;
@ -2668,22 +2648,6 @@ void CallFrameInfo::Reporter::BadCIEId(uint64 offset, uint64 cie_offset) {
filename_.c_str(), offset, section_.c_str(), cie_offset);
}
void CallFrameInfo::Reporter::UnexpectedAddressSize(uint64 offset,
uint8_t address_size) {
fprintf(stderr,
"%s: CFI frame description entry at offset 0x%llx in '%s':"
" CIE specifies unexpected address size: %d\n",
filename_.c_str(), offset, section_.c_str(), address_size);
}
void CallFrameInfo::Reporter::UnexpectedSegmentSize(uint64 offset,
uint8_t segment_size) {
fprintf(stderr,
"%s: CFI frame description entry at offset 0x%llx in '%s':"
" CIE specifies unexpected segment size: %d\n",
filename_.c_str(), offset, section_.c_str(), segment_size);
}
void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) {
fprintf(stderr,
"%s: CFI frame description entry at offset 0x%llx in '%s':"

View File

@ -1227,14 +1227,6 @@ class CallFrameInfo::Reporter {
// there is not a CIE.
virtual void BadCIEId(uint64 offset, uint64 cie_offset);
// The FDE at OFFSET refers to a CIE with an address size we don't know how
// to handle.
virtual void UnexpectedAddressSize(uint64 offset, uint8_t address_size);
// The FDE at OFFSET refers to a CIE with an segment descriptor size we
// don't know how to handle.
virtual void UnexpectedSegmentSize(uint64 offset, uint8_t segment_size);
// The FDE at OFFSET refers to a CIE with version number VERSION,
// which we don't recognize. We cannot parse DWARF CFI if it uses
// a version number we don't recognize.

View File

@ -126,8 +126,6 @@ class MockCallFrameErrorReporter: public CallFrameInfo::Reporter {
MOCK_METHOD1(EarlyEHTerminator, void(uint64));
MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64));
MOCK_METHOD2(BadCIEId, void(uint64, uint64));
MOCK_METHOD2(UnexpectedAddressSize, void(uint64, uint8_t));
MOCK_METHOD2(UnexpectedSegmentSize, void(uint64, uint8_t));
MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version));
MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &));
MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8));
@ -607,91 +605,6 @@ TEST_F(CFI, CIEVersion3ReturnColumn) {
EXPECT_TRUE(parser.Start());
}
TEST_F(CFI, CIEVersion4AdditionalFields) {
CFISection section(kBigEndian, 4);
Label cie;
section
.Mark(&cie)
// CIE version 4 with expected address and segment size.
.CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 4, "", true, 8, 0)
.FinishEntry()
// FDE, citing that CIE.
.FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section);
{
InSequence s;
EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 4, "", 0x89))
.WillOnce(Return(true));
EXPECT_CALL(handler, End()).WillOnce(Return(true));
}
string contents;
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
}
TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedAddressSize) {
CFISection section(kBigEndian, 4);
Label cie;
section
.Mark(&cie)
// Unexpected address size.
.CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 4, "", true, 3, 0)
.FinishEntry()
// FDE, citing that CIE.
.FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedAddress", section);
EXPECT_CALL(reporter, UnexpectedAddressSize(_, 3))
.WillOnce(Return());
string contents;
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(8);
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
}
TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedSegmentSize) {
CFISection section(kBigEndian, 4);
Label cie;
section
.Mark(&cie)
.CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 4, "", true, 8, 7)
.FinishEntry()
.FDEHeader(cie, 0x7bf0fda0, 0xcbcd28d8)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedSegment", section);
EXPECT_CALL(reporter, UnexpectedSegmentSize(_, 7))
.WillOnce(Return());
string contents;
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(8);
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
}
struct CFIInsnFixture: public CFIFixture {
CFIInsnFixture() : CFIFixture() {
data_factor = 0xb6f;

View File

@ -47,8 +47,7 @@
#include "third_party/musl/include/elf.h"
#include "elf_reader.h"
#include "common/using_std_string.h"
//#include "using_std_string.h"
// EM_AARCH64 is not defined by elf.h of GRTE v3 on x86.
// TODO(dougkwan): Remove this when v17 is retired.
#if !defined(EM_AARCH64)
@ -75,6 +74,7 @@
//DEFINE_bool(elfreader_process_dynsyms, true,
// "Activate PLT function processing");
using std::string;
using std::vector;
namespace {

View File

@ -19,8 +19,8 @@
#include <vector>
#include "common/dwarf/types.h"
#include "common/using_std_string.h"
using std::string;
using std::vector;
using std::pair;

View File

@ -195,7 +195,7 @@ void DwarfCFIToModule::Record(Module::Address address, int reg,
// Place the name in our global set of strings, and then use the string
// from the set. Even though the assignment looks like a copy, all the
// major string implementations use reference counting internally,
// major std::string implementations use reference counting internally,
// so the effect is to have all our data structures share copies of rules
// whenever possible. Since register names are drawn from a
// vector<string>, register names are already shared.

View File

@ -181,7 +181,7 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
// The names of the return address and canonical frame address. Putting
// these here instead of using string literals allows us to share their
// texts in reference-counted string implementations (all the
// texts in reference-counted std::string implementations (all the
// popular ones). Many, many rules cite these strings.
string cfa_name_, ra_name_;
@ -189,7 +189,7 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
// our data structures, insert it into this set, and then use the string
// from the set.
//
// Because string uses reference counting internally, simply using
// Because std::string uses reference counting internally, simply using
// strings from this set, even if passed by value, assigned, or held
// directly in structures and containers (map<string, ...>, for example),
// causes those strings to share a single instance of each distinct piece

View File

@ -39,6 +39,9 @@
#include "common/dwarf_cu_to_module.h"
#include <assert.h>
#if !defined(__ANDROID__)
#include <cxxabi.h>
#endif
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
@ -261,7 +264,7 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
uint64 offset_;
// Place the name in the global set of strings. Even though this looks
// like a copy, all the major string implementations use reference
// like a copy, all the major std::string implementations use reference
// counting internally, so the effect is to have all the data structures
// share copies of strings whenever possible.
// FIXME: Should this return something like a string_ref to avoid the
@ -347,22 +350,20 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
case dwarf2reader::DW_AT_name:
name_attribute_ = AddStringToPool(data);
break;
case dwarf2reader::DW_AT_MIPS_linkage_name:
case dwarf2reader::DW_AT_linkage_name: {
string demangled;
Language::DemangleResult result =
cu_context_->language->DemangleName(data, &demangled);
switch (result) {
case Language::kDemangleSuccess:
demangled_name_ = AddStringToPool(demangled);
break;
case Language::kDemangleFailure:
cu_context_->reporter->DemangleError(data);
// fallthrough
case Language::kDontDemangle:
demangled_name_.clear();
break;
case dwarf2reader::DW_AT_MIPS_linkage_name: {
char* demangled = NULL;
int status = -1;
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, &status);
#endif
if (status != 0) {
cu_context_->reporter->DemangleError(data, status);
demangled_name_ = "";
break;
}
if (demangled) {
demangled_name_ = AddStringToPool(demangled);
free(reinterpret_cast<void*>(demangled));
}
break;
}
@ -675,10 +676,11 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
filename_.c_str(), offset);
}
void DwarfCUToModule::WarningReporter::DemangleError(const string &input) {
void DwarfCUToModule::WarningReporter::DemangleError(
const string &input, int error) {
CUHeading();
fprintf(stderr, "%s: warning: failed to demangle %s\n",
filename_.c_str(), input.c_str());
fprintf(stderr, "%s: warning: failed to demangle %s with error %d\n",
filename_.c_str(), input.c_str(), error);
}
void DwarfCUToModule::WarningReporter::UnhandledInterCUReference(
@ -759,7 +761,6 @@ dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
case dwarf2reader::DW_TAG_class_type:
case dwarf2reader::DW_TAG_structure_type:
case dwarf2reader::DW_TAG_union_type:
case dwarf2reader::DW_TAG_module:
return new NamedScopeHandler(cu_context_.get(), child_context_.get(),
offset);
default:
@ -773,14 +774,6 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
cu_context_->language = Language::Java;
break;
case dwarf2reader::DW_LANG_Swift:
cu_context_->language = Language::Swift;
break;
case dwarf2reader::DW_LANG_Rust:
cu_context_->language = Language::Rust;
break;
// DWARF has no generic language code for assembly language; this is
// what the GNU toolchain uses.
case dwarf2reader::DW_LANG_Mips_Assembler:

View File

@ -202,7 +202,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
virtual void UnnamedFunction(uint64 offset);
// __cxa_demangle() failed to demangle INPUT.
virtual void DemangleError(const string &input);
virtual void DemangleError(const string &input, int error);
// The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
// FilePrivate did not retain the inter-CU specification data.

View File

@ -83,7 +83,7 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter {
MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
MOCK_METHOD1(DemangleError, void(const string &input));
MOCK_METHOD2(DemangleError, void(const string &input, int error));
MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target));
};
@ -1205,7 +1205,6 @@ TEST_F(Specifications, Function) {
}
TEST_F(Specifications, MangledName) {
// Language defaults to C++, so no need to set it here.
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
StartCU();
@ -1222,53 +1221,6 @@ TEST_F(Specifications, MangledName) {
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
}
TEST_F(Specifications, MangledNameSwift) {
// Swift mangled names should pass through untouched.
SetLanguage(dwarf2reader::DW_LANG_Swift);
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
StartCU();
const string kName = "_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si";
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
dwarf2reader::DW_TAG_subprogram, "declaration-name",
kName);
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
0xcd3c51b946fb1eeeLL, "",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
root_handler_.Finish();
TestFunctionCount(1);
TestFunction(0, kName,
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
}
TEST_F(Specifications, MangledNameRust) {
SetLanguage(dwarf2reader::DW_LANG_Rust);
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
StartCU();
const string kName = "_ZN14rustc_demangle8demangle17h373defa94bffacdeE";
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
dwarf2reader::DW_TAG_subprogram, "declaration-name",
kName);
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
0xcd3c51b946fb1eeeLL, "",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
root_handler_.Finish();
TestFunctionCount(1);
TestFunction(0,
#ifndef HAVE_RUST_DEMANGLE
// Rust mangled names should pass through untouched if not
// using rust-demangle.
kName,
#else
// If rust-demangle is available this should be properly
// demangled.
"rustc_demangle::demangle",
#endif
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
}
TEST_F(Specifications, MemberFunction) {
PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691);

View File

@ -34,70 +34,18 @@
#include "common/language.h"
#include <stdlib.h>
#if !defined(__ANDROID__)
#include <cxxabi.h>
#endif
#if defined(HAVE_RUST_DEMANGLE)
#include <rust_demangle.h>
#endif
#include <limits>
namespace {
string MakeQualifiedNameWithSeparator(const string& parent_name,
const char* separator,
const string& name) {
if (parent_name.empty()) {
return name;
}
return parent_name + separator + name;
}
} // namespace
namespace google_breakpad {
// C++ language-specific operations.
class CPPLanguage: public Language {
public:
CPPLanguage() {}
string MakeQualifiedName(const string &parent_name,
const string &name) const {
return MakeQualifiedNameWithSeparator(parent_name, "::", name);
}
virtual DemangleResult DemangleName(const string& mangled,
string* demangled) const {
#if defined(__ANDROID__)
// Android NDK doesn't provide abi::__cxa_demangle.
demangled->clear();
return kDontDemangle;
#else
int status;
char* demangled_c =
abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
DemangleResult result;
if (status == 0) {
result = kDemangleSuccess;
demangled->assign(demangled_c);
} else {
result = kDemangleFailure;
demangled->clear();
}
if (demangled_c) {
free(reinterpret_cast<void*>(demangled_c));
}
return result;
#endif
if (parent_name.empty())
return name;
else
return parent_name + "::" + name;
}
};
@ -106,79 +54,19 @@ CPPLanguage CPPLanguageSingleton;
// Java language-specific operations.
class JavaLanguage: public Language {
public:
JavaLanguage() {}
string MakeQualifiedName(const string &parent_name,
const string &name) const {
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
if (parent_name.empty())
return name;
else
return parent_name + "." + name;
}
};
JavaLanguage JavaLanguageSingleton;
// Swift language-specific operations.
class SwiftLanguage: public Language {
public:
SwiftLanguage() {}
string MakeQualifiedName(const string &parent_name,
const string &name) const {
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
}
virtual DemangleResult DemangleName(const string& mangled,
string* demangled) const {
// There is no programmatic interface to a Swift demangler. Pass through the
// mangled form because it encodes more information than the qualified name
// that would have been built by MakeQualifiedName(). The output can be
// post-processed by xcrun swift-demangle to transform mangled Swift names
// into something more readable.
demangled->assign(mangled);
return kDemangleSuccess;
}
};
SwiftLanguage SwiftLanguageSingleton;
// Rust language-specific operations.
class RustLanguage: public Language {
public:
RustLanguage() {}
string MakeQualifiedName(const string &parent_name,
const string &name) const {
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
}
virtual DemangleResult DemangleName(const string& mangled,
std::string* demangled) const {
// Rust names use GCC C++ name mangling, but demangling them with
// abi_demangle doesn't produce stellar results due to them having
// another layer of encoding.
// If callers provide rustc-demangle, use that.
#if defined(HAVE_RUST_DEMANGLE)
char* rust_demangled = rust_demangle(mangled.c_str());
if (rust_demangled == nullptr) {
return kDemangleFailure;
}
demangled->assign(rust_demangled);
free_rust_demangled_name(rust_demangled);
#else
// Otherwise, pass through the mangled name so callers can demangle
// after the fact.
demangled->assign(mangled);
#endif
return kDemangleSuccess;
}
};
RustLanguage RustLanguageSingleton;
// Assembler language-specific operations.
class AssemblerLanguage: public Language {
public:
AssemblerLanguage() {}
bool HasFunctions() const { return false; }
string MakeQualifiedName(const string &parent_name,
const string &name) const {
@ -190,8 +78,6 @@ AssemblerLanguage AssemblerLanguageSingleton;
const Language * const Language::CPlusPlus = &CPPLanguageSingleton;
const Language * const Language::Java = &JavaLanguageSingleton;
const Language * const Language::Swift = &SwiftLanguageSingleton;
const Language * const Language::Rust = &RustLanguageSingleton;
const Language * const Language::Assembler = &AssemblerLanguageSingleton;
} // namespace google_breakpad

View File

@ -77,26 +77,9 @@ class Language {
virtual string MakeQualifiedName (const string &parent_name,
const string &name) const = 0;
enum DemangleResult {
// Demangling was not performed because its not appropriate to attempt.
kDontDemangle = -1,
kDemangleSuccess,
kDemangleFailure,
};
// Wraps abi::__cxa_demangle() or similar for languages where appropriate.
virtual DemangleResult DemangleName(const string& mangled,
string* demangled) const {
demangled->clear();
return kDontDemangle;
}
// Instances for specific languages.
static const Language * const CPlusPlus,
* const Java,
* const Swift,
* const Rust,
* const Assembler;
};

View File

@ -926,10 +926,8 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
// number appended to the end of the file identifier; this isn't
// really used or necessary on other platforms, but be consistent.
string id = FileID::ConvertIdentifierToUUIDString(identifier) + "0";
// This is just the raw Build ID in hex.
string code_id = FileID::ConvertIdentifierToString(identifier);
module.reset(new Module(name, os, architecture, id, code_id));
module.reset(new Module(name, os, architecture, id));
return true;
}

View File

@ -40,8 +40,6 @@
#include <vector>
#include "breakpad_googletest_includes.h"
#include "common/linux/elf_gnu_compat.h"
#include "common/linux/elfutils.h"
#include "common/linux/dump_symbols.h"
#include "common/linux/synth_elf.h"
#include "common/module.h"
@ -56,7 +54,6 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file,
Module** module);
using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::Notes;
using google_breakpad::synth_elf::StringTable;
using google_breakpad::synth_elf::SymbolTable;
using google_breakpad::test_assembler::kLittleEndian;
@ -64,9 +61,7 @@ using google_breakpad::test_assembler::Section;
using std::stringstream;
using std::vector;
using ::testing::Test;
using ::testing::Types;
template<typename ElfClass>
class DumpSymbols : public Test {
public:
void GetElfContents(ELF& elf) {
@ -83,11 +78,7 @@ class DumpSymbols : public Test {
uint8_t* elfdata;
};
typedef Types<ElfClass32, ElfClass64> ElfClasses;
TYPED_TEST_CASE(DumpSymbols, ElfClasses);
TYPED_TEST(DumpSymbols, Invalid) {
TEST_F(DumpSymbols, Invalid) {
Elf32_Ehdr header;
memset(&header, 0, sizeof(header));
Module* module;
@ -99,8 +90,8 @@ TYPED_TEST(DumpSymbols, Invalid) {
&module));
}
TYPED_TEST(DumpSymbols, SimplePublic) {
ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian);
TEST_F(DumpSymbols, SimplePublic32) {
ELF elf(EM_386, ELFCLASS32, kLittleEndian);
// Zero out text section for simplicity.
Section text(kLittleEndian);
text.Append(4096, 0);
@ -108,11 +99,8 @@ TYPED_TEST(DumpSymbols, SimplePublic) {
// Add a public symbol.
StringTable table(kLittleEndian);
SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table);
syms.AddSymbol("superfunc",
(typename TypeParam::Addr)0x1000,
(typename TypeParam::Addr)0x10,
// ELF32_ST_INFO works for 32-or 64-bit.
SymbolTable syms(kLittleEndian, 4, table);
syms.AddSymbol("superfunc", (uint32_t)0x1000, (uint32_t)0x10,
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
SHN_UNDEF + 1);
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
@ -121,14 +109,14 @@ TYPED_TEST(DumpSymbols, SimplePublic) {
SHF_ALLOC, // flags
0, // addr
index, // link
sizeof(typename TypeParam::Sym)); // entsize
sizeof(Elf32_Sym)); // entsize
elf.Finish();
this->GetElfContents(elf);
GetElfContents(elf);
Module* module;
DumpOptions options(ALL_SYMBOL_DATA, true);
EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
"foo",
vector<string>(),
options,
@ -136,40 +124,24 @@ TYPED_TEST(DumpSymbols, SimplePublic) {
stringstream s;
module->Write(s, ALL_SYMBOL_DATA);
const string expected =
string("MODULE Linux ") + TypeParam::kMachineName
+ " 000000000000000000000000000000000 foo\n"
"INFO CODE_ID 00000000000000000000000000000000\n"
"PUBLIC 1000 0 superfunc\n";
EXPECT_EQ(expected, s.str());
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n",
s.str());
delete module;
}
TYPED_TEST(DumpSymbols, SimpleBuildID) {
ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian);
TEST_F(DumpSymbols, SimplePublic64) {
ELF elf(EM_X86_64, ELFCLASS64, kLittleEndian);
// Zero out text section for simplicity.
Section text(kLittleEndian);
text.Append(4096, 0);
elf.AddSection(".text", text, SHT_PROGBITS);
// Add a Build ID
const uint8_t kExpectedIdentifierBytes[] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13};
Notes notes(kLittleEndian);
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
sizeof(kExpectedIdentifierBytes));
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
// Add a public symbol.
StringTable table(kLittleEndian);
SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table);
syms.AddSymbol("superfunc",
(typename TypeParam::Addr)0x1000,
(typename TypeParam::Addr)0x10,
// ELF32_ST_INFO works for 32-or 64-bit.
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
SymbolTable syms(kLittleEndian, 8, table);
syms.AddSymbol("superfunc", (uint64_t)0x1000, (uint64_t)0x10,
ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
SHN_UNDEF + 1);
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
elf.AddSection(".dynsym", syms,
@ -177,14 +149,14 @@ TYPED_TEST(DumpSymbols, SimpleBuildID) {
SHF_ALLOC, // flags
0, // addr
index, // link
sizeof(typename TypeParam::Sym)); // entsize
sizeof(Elf64_Sym)); // entsize
elf.Finish();
this->GetElfContents(elf);
GetElfContents(elf);
Module* module;
DumpOptions options(ALL_SYMBOL_DATA, true);
EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
"foo",
vector<string>(),
options,
@ -192,13 +164,9 @@ TYPED_TEST(DumpSymbols, SimpleBuildID) {
stringstream s;
module->Write(s, ALL_SYMBOL_DATA);
const string expected =
string("MODULE Linux ") + TypeParam::kMachineName
+ " 030201000504070608090A0B0C0D0E0F0 foo\n"
"INFO CODE_ID 000102030405060708090A0B0C0D0E0F10111213\n"
"PUBLIC 1000 0 superfunc\n";
EXPECT_EQ(expected, s.str());
delete module;
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n",
s.str());
}
} // namespace google_breakpad

View File

@ -49,13 +49,9 @@ struct ElfClass32 {
typedef Elf32_Shdr Shdr;
typedef Elf32_Half Half;
typedef Elf32_Off Off;
typedef Elf32_Sym Sym;
typedef Elf32_Word Word;
static const int kClass = ELFCLASS32;
static const uint16_t kMachine = EM_386;
static const size_t kAddrSize = sizeof(Elf32_Addr);
static constexpr const char* kMachineName = "x86";
};
struct ElfClass64 {
@ -66,13 +62,9 @@ struct ElfClass64 {
typedef Elf64_Shdr Shdr;
typedef Elf64_Half Half;
typedef Elf64_Off Off;
typedef Elf64_Sym Sym;
typedef Elf64_Word Word;
static const int kClass = ELFCLASS64;
static const uint16_t kMachine = EM_X86_64;
static const size_t kAddrSize = sizeof(Elf64_Addr);
static constexpr const char* kMachineName = "x86_64";
};
bool IsValidElf(const void* elf_header);

View File

@ -45,9 +45,10 @@
#include "common/linux/elfutils.h"
#include "common/linux/linux_libc_support.h"
#include "common/linux/memory_mapped_file.h"
#include "common/using_std_string.h"
#include "third_party/lss/linux_syscall_support.h"
using std::string;
namespace google_breakpad {
// Used in a few places for backwards-compatibility.
@ -163,18 +164,8 @@ bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) {
return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
}
// These three functions are not ever called in an unsafe context, so it's OK
// This function is not ever called in an unsafe context, so it's OK
// to allocate memory and use libc.
static string bytes_to_hex_string(const uint8_t* bytes, size_t count) {
string result;
for (unsigned int idx = 0; idx < count; ++idx) {
char buf[3];
snprintf(buf, sizeof(buf), "%02X", bytes[idx]);
result.append(buf);
}
return result;
}
// static
string FileID::ConvertIdentifierToUUIDString(
const wasteful_vector<uint8_t>& identifier) {
@ -190,13 +181,13 @@ string FileID::ConvertIdentifierToUUIDString(
uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
*data3 = htons(*data3);
return bytes_to_hex_string(identifier_swapped, kMDGUIDSize);
}
// static
string FileID::ConvertIdentifierToString(
const wasteful_vector<uint8_t>& identifier) {
return bytes_to_hex_string(&identifier[0], identifier.size());
string result;
for (unsigned int idx = 0; idx < kMDGUIDSize; ++idx) {
char buf[3];
snprintf(buf, sizeof(buf), "%02X", identifier_swapped[idx]);
result.append(buf);
}
return result;
}
} // namespace google_breakpad

View File

@ -38,7 +38,6 @@
#include "common/linux/guid_creator.h"
#include "common/memory.h"
#include "common/using_std_string.h"
namespace google_breakpad {
@ -71,16 +70,12 @@ class FileID {
// Convert the |identifier| data to a string. The string will
// be formatted as a UUID in all uppercase without dashes.
// (e.g., 22F065BBFC9C49F780FE26A7CEBD7BCE).
static string ConvertIdentifierToUUIDString(
const wasteful_vector<uint8_t>& identifier);
// Convert the entire |identifier| data to a hex string.
static string ConvertIdentifierToString(
static std::string ConvertIdentifierToUUIDString(
const wasteful_vector<uint8_t>& identifier);
private:
// Storage for the path specified
string path_;
std::string path_;
};
} // namespace google_breakpad

View File

@ -319,20 +319,3 @@ TYPED_TEST(FileIDTest, UniqueHashes) {
EXPECT_NE(identifier_string_1, identifier_string_2);
}
TYPED_TEST(FileIDTest, ConvertIdentifierToString) {
const uint8_t kIdentifierBytes[] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
const char* kExpected =
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F";
id_vector identifier(this->make_vector());
identifier.insert(identifier.end(),
kIdentifierBytes,
kIdentifierBytes + sizeof(kIdentifierBytes));
ASSERT_EQ(kExpected,
FileID::ConvertIdentifierToString(identifier));
}

View File

@ -87,7 +87,18 @@ bool MemoryMappedFile::Map(const char* path, size_t offset) {
return true;
}
#if defined(__x86_64__) || defined(__aarch64__) || \
(defined(__mips__) && _MIPS_SIM == _ABI64)
void* data = sys_mmap(NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset);
#else
if ((offset & 4095) != 0) {
// Not page aligned.
sys_close(fd);
return false;
}
void* data = sys_mmap2(
NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset >> 12);
#endif
sys_close(fd);
if (data == MAP_FAILED) {
return false;

View File

@ -202,7 +202,7 @@ bool CrashGenerator::CreateChildCrash(
// On Android the signal sometimes doesn't seem to get sent even though
// tkill returns '0'. Retry a couple of times if the signal doesn't get
// through on the first go:
// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=579
// https://code.google.com/p/google-breakpad/issues/detail?id=579
#if defined(__ANDROID__)
const int kRetries = 60;
const unsigned int kSleepTimeInSeconds = 1;

View File

@ -117,7 +117,7 @@
// developer level errors. This implementation simply macros to NSLog/NSAssert.
// It is not intended to be a general logging/reporting system.
//
// Please see https://github.com/google/google-toolbox-for-mac/wiki/DevLogNAssert
// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert
// for a little more background on the usage of these macros.
//
// _GTMDevLog log some error/problem in debug builds

View File

@ -31,7 +31,7 @@
// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
// dump_syms.cc: Create a symbol file for use with minidumps
// dump_syms.mm: Create a symbol file for use with minidumps
#include "common/mac/dump_syms.h"

View File

@ -1114,7 +1114,7 @@ TEST_F(LoadCommand, SegmentBE32) {
Return(true)));
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
EXPECT_FALSE(actual_segment.bits_64);
EXPECT_EQ(false, actual_segment.bits_64);
EXPECT_EQ("froon", actual_segment.name);
EXPECT_EQ(0x1891139cU, actual_segment.vmaddr);
EXPECT_EQ(0xcb76584fU, actual_segment.vmsize);
@ -1151,7 +1151,7 @@ TEST_F(LoadCommand, SegmentLE32) {
Return(true)));
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
EXPECT_FALSE(actual_segment.bits_64);
EXPECT_EQ(false, actual_segment.bits_64);
EXPECT_EQ("sixteenprecisely", actual_segment.name);
EXPECT_EQ(0x4b877866U, actual_segment.vmaddr);
EXPECT_EQ(0xcb76584fU, actual_segment.vmsize);

View File

@ -138,8 +138,8 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
memcpy(&ctx->in[14], &ctx->bits[0], sizeof(u32));
memcpy(&ctx->in[15], &ctx->bits[1], sizeof(u32));
((u32 *) ctx->in)[14] = ctx->bits[0];
((u32 *) ctx->in)[15] = ctx->bits[1];
MD5Transform(ctx->buf, (u32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);

View File

@ -44,6 +44,7 @@
#ifdef __APPLE__
#define sys_mmap mmap
#define sys_mmap2 mmap
#define sys_munmap munmap
#define MAP_ANONYMOUS MAP_ANON
#else
@ -116,8 +117,14 @@ class PageAllocator {
private:
uint8_t *GetNPages(size_t num_pages) {
#if defined(__x86_64__) || defined(__aarch64__) || defined(__aarch64__) || \
((defined(__mips__) && _MIPS_SIM == _ABI64))
void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#else
void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#endif
if (a == MAP_FAILED)
return NULL;

View File

@ -49,13 +49,11 @@ using std::hex;
Module::Module(const string &name, const string &os,
const string &architecture, const string &id,
const string &code_id /* = "" */) :
const string &architecture, const string &id) :
name_(name),
os_(os),
architecture_(architecture),
id_(id),
code_id_(code_id),
load_address_(0) { }
Module::~Module() {
@ -237,10 +235,6 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
if (!stream.good())
return ReportError();
if (!code_id_.empty()) {
stream << "INFO CODE_ID " << code_id_ << endl;
}
if (symbol_data != ONLY_CFI) {
AssignSourceIds();

View File

@ -179,7 +179,7 @@ class Module {
// Create a new module with the given name, operating system,
// architecture, and ID string.
Module(const string &name, const string &os, const string &architecture,
const string &id, const string &code_id = "");
const string &id);
~Module();
// Set the module's load address to LOAD_ADDRESS; addresses given
@ -281,7 +281,6 @@ class Module {
string os() const { return os_; }
string architecture() const { return architecture_; }
string identifier() const { return id_; }
string code_identifier() const { return code_id_; }
private:
// Report an error that has occurred writing the symbol file, using
@ -294,7 +293,7 @@ class Module {
static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream);
// Module header entries.
string name_, os_, architecture_, id_, code_id_;
string name_, os_, architecture_, id_;
// The module's nominal load address. Addresses for functions and
// lines are absolute, assuming the module is loaded at this

View File

@ -64,7 +64,6 @@ static Module::Function *generate_duplicate_function(const string &name) {
#define MODULE_OS "os-name"
#define MODULE_ARCH "architecture"
#define MODULE_ID "id-string"
#define MODULE_CODE_ID "code-id-string"
TEST(Write, Header) {
stringstream s;
@ -75,16 +74,6 @@ TEST(Write, Header) {
contents.c_str());
}
TEST(Write, HeaderCodeId) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, MODULE_CODE_ID);
m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"INFO CODE_ID code-id-string\n",
contents.c_str());
}
TEST(Write, OneLineFunc) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);

View File

@ -57,9 +57,9 @@ void UTF8ToUTF16(const char *in, vector<uint16_t> *out) {
int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) {
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
const UTF8 *source_end_ptr = source_ptr + 1;
const UTF8 *source_end_ptr = source_ptr + sizeof(char);
uint16_t *target_ptr = out;
uint16_t *target_end_ptr = target_ptr + 2;
uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t);
out[0] = out[1] = 0;
// Process one character at a time
@ -103,7 +103,7 @@ void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) {
const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(&in);
const UTF32 *source_end_ptr = source_ptr + 1;
uint16_t *target_ptr = out;
uint16_t *target_end_ptr = target_ptr + 2;
uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t);
out[0] = out[1] = 0;
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,

View File

@ -449,27 +449,6 @@ void BuildEndpointIndexMap(ImageMap* image_map) {
}
}
void BuildSubsequentRVAMap(const OmapData &omap_data,
std::map<DWORD, DWORD> *subsequent) {
assert(subsequent->empty());
const OmapFromTable &orig2tran =
reinterpret_cast<const OmapFromTable &>(omap_data.omap_from);
if (orig2tran.empty())
return;
for (size_t i = 0; i < orig2tran.size() - 1; ++i) {
// Expect that orig2tran is sorted.
if (orig2tran[i].rva_original >= orig2tran[i + 1].rva_original) {
fprintf(stderr, "OMAP 'from' table unexpectedly unsorted\n");
subsequent->clear();
return;
}
subsequent->insert(std::make_pair(orig2tran[i].rva_original,
orig2tran[i + 1].rva_original));
}
}
// Clips the given mapped range.
void ClipMappedRangeOriginal(const AddressRange& clip_range,
MappedRange* mapped_range) {
@ -597,7 +576,6 @@ void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) {
BuildMapping(omap_data, &image_map->mapping);
BuildEndpointIndexMap(image_map);
BuildSubsequentRVAMap(omap_data, &image_map->subsequent_rva_block);
}
void MapAddressRange(const ImageMap& image_map,
@ -713,4 +691,4 @@ void MapAddressRange(const ImageMap& image_map,
return;
}
} // namespace google_breakpad
} // namespace google_breakpad

View File

@ -35,7 +35,6 @@
#include <windows.h>
#include <dia2.h>
#include <map>
#include <vector>
namespace google_breakpad {
@ -131,8 +130,6 @@ struct ImageMap {
// an interval in |mapping| that contains the endpoint. Useful for doing
// interval intersection queries.
EndpointIndexMap endpoint_index_map;
std::map<DWORD, DWORD> subsequent_rva_block;
};
} // namespace google_breakpad

View File

@ -30,7 +30,8 @@
#include "common/windows/omap.h"
#include "breakpad_googletest_includes.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace google_breakpad {

View File

@ -122,16 +122,6 @@ class AutoImage {
PLOADED_IMAGE img_;
};
bool SymbolsMatch(IDiaSymbol* a, IDiaSymbol* b) {
DWORD a_section, a_offset, b_section, b_offset;
if (FAILED(a->get_addressSection(&a_section)) ||
FAILED(a->get_addressOffset(&a_offset)) ||
FAILED(b->get_addressSection(&b_section)) ||
FAILED(b->get_addressOffset(&b_offset)))
return false;
return a_section == b_section && a_offset == b_offset;
}
bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
if (SUCCEEDED(data_source.CoCreateInstance(CLSID_DiaSource))) {
return true;
@ -866,39 +856,6 @@ bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) {
stack_param_size > 0 ? stack_param_size : 0,
name.m_str);
}
// Now walk the function in the original untranslated space, asking DIA
// what function is at that location, stepping through OMAP blocks. If
// we're still in the same function, emit another entry, because the
// symbol could have been split into multiple pieces. If we've gotten to
// another symbol in the original address space, then we're done for
// this symbol. See https://crbug.com/678874.
for (;;) {
// This steps to the next block in the original image. Simply doing
// rva++ would also be correct, but would emit tons of unnecessary
// entries.
rva = image_map_.subsequent_rva_block[rva];
if (rva == 0)
break;
CComPtr<IDiaSymbol> next_sym = NULL;
LONG displacement;
if (FAILED(session_->findSymbolByRVAEx(rva, SymTagPublicSymbol, &next_sym,
&displacement))) {
break;
}
if (!SymbolsMatch(symbol, next_sym))
break;
AddressRangeVector next_ranges;
MapAddressRange(image_map_, AddressRange(rva, 1), &next_ranges);
for (size_t i = 0; i < next_ranges.size(); ++i) {
fprintf(output_, "PUBLIC %x %x %ws\n", next_ranges[i].rva,
stack_param_size > 0 ? stack_param_size : 0, name.m_str);
}
}
return true;
}

View File

@ -34,7 +34,7 @@
*
* Author: Mark Mentovai
* Split into its own file: Neal Sidhwaney */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
@ -65,10 +65,8 @@ typedef enum {
/* EXC_SYSCALL */
MD_EXCEPTION_MAC_MACH_SYSCALL = 8,
/* EXC_MACH_SYSCALL */
MD_EXCEPTION_MAC_RPC_ALERT = 9,
MD_EXCEPTION_MAC_RPC_ALERT = 9
/* EXC_RPC_ALERT */
MD_EXCEPTION_MAC_SIMULATED = 0x43507378
/* Fake exception code used by Crashpad's SimulateCrash ('CPsx'). */
} MDExceptionMac;
/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X

View File

@ -94,23 +94,15 @@ typedef enum {
/* EXCEPTION_PRIV_INSTRUCTION */
MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd,
/* EXCEPTION_STACK_OVERFLOW */
MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE = 0xc00000ff,
/* EXCEPTION_BAD_FUNCTION_TABLE */
MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194,
/* EXCEPTION_POSSIBLE_DEADLOCK */
MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN = 0xc0000409,
/* STATUS_STACK_BUFFER_OVERRUN */
MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION = 0xc0000374,
/* STATUS_HEAP_CORRUPTION */
MD_EXCEPTION_OUT_OF_MEMORY = 0xe0000008,
/* Exception thrown by Chromium allocators to indicate OOM.
See base/process/memory.h in Chromium for rationale. */
MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363,
MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363
/* Per http://support.microsoft.com/kb/185294,
generated by Visual C++ compiler */
MD_EXCEPTION_CODE_WIN_SIMULATED = 0x0517a7ed
/* Fake exception code used by Crashpad's
CrashpadClient::DumpWithoutCrash. */
} MDExceptionCodeWin;

Some files were not shown because too many files have changed in this diff Show More