Compare commits

...

38 Commits
main ... unowhy

Author SHA1 Message Date
Mark Mentovai
89a54adbec Replace remaining references to 'struct ucontext' with 'ucontext_t'
This relands
e3035bc406,
which was accidentally committed to breakpad/breakpad/src, the read-only
mirror of src in breakpad/breakpad. (Well, it should have been
read-only.) See https://crbug.com/766164.

This fixes issues with glibc-2.26.

See https://bugs.gentoo.org/show_bug.cgi?id=628782 ,
https://sourceware.org/git/?p=glibc.git;h=251287734e89a52da3db682a8241eb6bccc050c9 , and
https://sourceware.org/ml/libc-alpha/2017-08/msg00010.html for context.
Change-Id: Id66f474d636dd2afa450bab925c5514a800fdd6f
Reviewed-on: https://chromium-review.googlesource.com/674304
Reviewed-by: Mark Mentovai <mark@chromium.org>
2017-11-16 11:30:55 +01:00
David Callu
25d9bef21d fix(script): change dump_syms source directory 2017-04-22 01:10:23 +02:00
Bilal Afkir
ec9650bde3 fix(install): fix install script on windows to handle debug mode 2017-02-10 10:47:22 +01:00
David Callu
43b476ba46 feat(GoogleBreakpad): disable warning 4091 on msvc 2017-02-04 23:46:26 +01:00
David Callu
85998ab1f3 chore(gyp): update to last available version to have msvc 2015 support 2017-02-04 22:37:59 +01:00
David Callu
e406e6433c chore(scripts): move windows install script in scripts dir 2017-02-02 11:09:16 +01:00
David Callu
3c80b703d7 feat(submodule): update submodule 2017-02-02 10:40:04 +01:00
David Callu
8c2c0d2b2a chore(gyp): change runtime library option on MSVC 2017-02-02 10:39:22 +01:00
David Callu
72aaf6d8fb fix(windows installer): change path to search library 2017-02-02 10:39:19 +01:00
David Callu
acc23b8972 chore(windows installer): remove check of dst dir 2017-02-02 10:39:14 +01:00
David Callu
81456eb33d chore(windows installer): adapt script from sqool_manager to external lib 2017-02-02 10:39:12 +01:00
David Callu
dd3cb8b446 chore(windows install): add script to install required file on windows 2017-02-02 10:39:08 +01:00
David Callu
291e9d94c6 fix(common): add http_upload in common target 2017-02-02 10:39:04 +01:00
David Callu
1ef219527e chore(cmake): add dependencies as submodule 2017-02-02 10:39:00 +01:00
Scott Graham
bbebd8d5e7 Basic handling of CIE version 4 in dwarf reading
CIE looks like it's been emitted by clang since ~May 2015 [1]. This
means that we didn't have any CFI because this parse aborted, which
meant that all stack walks reverted to stack scanning. Allow expected
values for address size and segment descriptor size through so that
dump_syms can generate at least somewhat reasonable data.

[1]: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20150518/277292.html

R=mark@chromium.org
BUG=chromium:627529

Change-Id: I6dc92f51c4afd25c2adff92c09ccb8bb03bf9112
Reviewed-on: https://chromium-review.googlesource.com/406012
Reviewed-by: Mark Mentovai <mark@chromium.org>
2016-11-15 15:10:56 -05:00
Sylvain Defresne
13c634f6a1 Revert "Don't define |r_debug| and |link_map| on Android releases 21 and later"
This reverts commit 0fc6d0c8df because it
does not compile in Chromium due to the following error:

In file included from ../../breakpad/src/client/linux/minidump_writer/linux_dumper.h:43:0,
                 from ../../breakpad/src/client/linux/minidump_writer/minidump_writer.h:41,
                 from ../../breakpad/src/client/linux/handler/exception_handler.h:42,
                 from ../../components/crash/content/app/breakpad_linux.cc:44:
../../breakpad/src/common/android/include/link.h:46:9: error: multi-line comment [-Werror=comment]
 #endif  // !defined(__aarch64__) && !defined(__x86_64__) && \
         ^

> Don't define |r_debug| and |link_map| on Android releases 21 and later
>
> NDKs for Android 21 and later have the data structures |r_debug| and
> |link_map| defined in their header files. Defining them multiple times
> generates a compiler error.
>
> This patch protects both data structures from definition on Android 21
> and later.
>
> BUG=629088
> R=rmcilroy@chromium.org
>
> Review URL: https://codereview.chromium.org/2156173002 .
>
> Patch from Thomas Zimmermann <tzimmermann@mozilla.com>.
>
> Committed: 0ebdc4a10a

BUG=629088

Change-Id: Ia8d7d0eff060d661113e544d732813820bcb69e0
Reviewed-on: https://chromium-review.googlesource.com/367717
Reviewed-by: Mark Mentovai <mark@chromium.org>
2016-08-10 22:01:39 +00:00
Sylvain Defresne
600ec35c5b Fail with a proper error message if input file is not found.
Previously, if the input file was missing, the symupload tool on Mac
would happily process, try to parse it (calling a method on nil) and
fail when trying to create the payload to send to the server as one
of the method raised a NSInvalidArgumentException when receiving a
nil value.

Change to code to instead check the file for existence which makes it
easier to understand what is happening when part of the build system
is misconfigured and invoke symupload without first creating the symbol
file.

BUG=449348

Change-Id: Icc0f08958114da4be0cbbd7a7c2aeef905bc0db1
Reviewed-on: https://chromium-review.googlesource.com/367260
Reviewed-by: Mark Mentovai <mark@chromium.org>
2016-08-09 23:13:07 +00:00
Thomas Zimmermann
0fc6d0c8df Don't define |r_debug| and |link_map| on Android releases 21 and later
NDKs for Android 21 and later have the data structures |r_debug| and
|link_map| defined in their header files. Defining them multiple times
generates a compiler error.

This patch protects both data structures from definition on Android 21
and later.

BUG=629088
R=rmcilroy@chromium.org

Review URL: https://codereview.chromium.org/2156173002 .

Patch from Thomas Zimmermann <tzimmermann@mozilla.com>.

Committed: 0ebdc4a10a
2016-08-03 15:28:43 +01:00
Andrew Bonventre
f7be4815a2 Switch to Gerrit for code reviews
BUG=629128

Change-Id: I687659d9fc78ed31dcd3be3b9268f30c17dd9c01
Reviewed-on: https://chromium-review.googlesource.com/362370
Reviewed-by: Mark Mentovai <mark@chromium.org>
2016-07-27 20:07:49 +00:00
Mark Mentovai
f5638b8c2e Test Gerrit
Change-Id: If335bec0a5079dececc0452b88a77d80f775ea97
Reviewed-on: https://chromium-review.googlesource.com/362660
Reviewed-by: Will Harris <wfh@chromium.org>
2016-07-25 13:44:49 +00:00
Aaron Gable
0e4af9d8f9 Add Breakpad codereview.settings entry for Gerrit
R=mark@chromium.org
BUG=629864

Review URL: https://codereview.chromium.org/2166193003 .
2016-07-21 12:45:20 -07:00
Mark Mentovai
5f638d5323 Remove DISALLOW_COPY_AND_ASSIGN from MinidumpStreamInfo
DISALLOW_COPY_AND_ASSIGN was inadvertently added to
Minidump::MinidumpStreamInfo in f04a010f71f6, but this class is used as
the value side of the Minidump::stream_map_ map and must be copyable
(with an old enough C++ library).

This broke:

https://build.chromium.org/p/tryserver.chromium.linux/builders/linux_chromium_chromeos_rel_ng/builds/247141/steps/compile%20%28with%20patch%29/logs/stdio

TBR=ivanpe@chromium.org

Review URL: https://codereview.chromium.org/2158423003 .
2016-07-20 10:08:14 -04:00
Ross McIlroy
b5200a97b7 Revert "Don't define |r_debug| and |link_map| on Android releases 21 and later"
This reverts commit 0fc10739232ac803f7304d01522db6051c7454ff.

Reason: breaks 64bit Android architectures.

BUG=629088
R=primiano@chromium.org

Review URL: https://codereview.chromium.org/2163923002 .
2016-07-20 11:27:11 +01:00
Will Harris
c99d374dde Add new exception code for OOM generated from Chromium.
See also https://codereview.chromium.org/2130293003/ for Chromium-side change and go/internal_cl_for_2130293003 for internal change.

BUG=chromium:614440
R=mark@chromium.org

Review URL: https://codereview.chromium.org/2160373002 .
2016-07-19 14:41:53 -07:00
Primiano Tucci
5adeef6117 Add process type to MicroDumpExtraInfo
BUG=616774
R=primiano@chromium.org, torne@chromium.org

Review URL: https://codereview.chromium.org/2087413002 .
2016-07-19 17:44:10 +01:00
Thomas Zimmermann
0ebdc4a10a Don't define |r_debug| and |link_map| on Android releases 21 and later
NDKs for Android 21 and later have the data structures |r_debug| and
|link_map| defined in their header files. Defining them multiple times
generates a compiler error.

This patch protects both data structures from definition on Android 21
and later.

BUG=629088
R=rmcilroy@chromium.org

Review URL: https://codereview.chromium.org/2156173002 .

Patch from Thomas Zimmermann <tzimmermann@mozilla.com>.
2016-07-19 17:00:51 +01:00
Ting-Yuan (Leo) Huang
41b91d064e 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 by
hugepages.

This patch 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

BUG=crbug.com/628040
R=mark@chromium.org

Review URL: https://codereview.chromium.org/2161713002 .

Patch from Ting-Yuan (Leo) Huang <laszio@chromium.org>.
2016-07-18 20:11:07 -04:00
John Budorick
965424f183 [Android] Guard some NDK workarounds by major version.
BUG=599327
R=mark@chromium.org

Review URL: https://codereview.chromium.org/2152153003 .
2016-07-15 12:49:44 -07:00
Ting-Yu Chou
dfd2da7979 Add a new argument to specify the minidump type to write on Windows.
R=ted.mielczarek@gmail.com
BUG=https://bugzilla.mozilla.org/show_bug.cgi?id=1267329

Review URL: https://codereview.chromium.org/2107083002/ .
2016-06-29 06:48:26 -04:00
Mike Frysinger
e0f2c17988 travis: note misbehavior by coverity addon when throttled
Example here: https://travis-ci.org/libgd/libgd/builds/139971212
The last line in the log is just the throttle notice.
2016-06-24 05:09:28 -04:00
Mike Frysinger
af8840d910 travis: move configure step to the prepare phase
The main command is more strict in that it has to be a single command.
2016-06-24 04:40:03 -04:00
Mike Frysinger
1600b6054e travis: make build scripts use bash
These are development scripts, so no need for them to be fast or
super portable.  Switch them to bash rather than POSIX shell.
2016-06-22 09:02:23 -04:00
Mike Frysinger
f140a0339f travis: fix cwd when running tests
Make sure we don't go messing with the cwd when running different tests.
This way we can always assume we start in the top level source dir.
2016-06-21 16:55:02 -04:00
Mike Frysinger
5325fd5162 travis: tweak coverity build command
The `build` shell func isn't in scope of the coverity shell script.
2016-06-21 15:10:31 -04:00
Mike Frysinger
83a5552060 travis: add coverity scan integration
R=ted.mielczarek@gmail.com

Review URL: https://codereview.chromium.org/2078283002 .
2016-06-21 11:14:28 -04:00
Ivan Penkov
24f5931c5e Server-side workaround to handle overlapping modules.
This change is resolving an issue that was caused by the combination of:
 - Android system libraries being relro packed in N+.
 - Breakpad dealing with relro packed libraries in a hack way.

This is a fix for http://crbug/611824.

I also found an use-after-free issue (bug in Minidump::SeekToStreamType).  I disallowed the MinidumpStreamInfo copy and assign constructors and the compiler detected another similar issue in Minidump::Print.  Then I disabled the copy and assign constructors for most classes in minidump.h (just in case).  There are a couple of classes where I couldn't disallow them (since assign is used).  This will require a small refactor so I left it out of this CL.

R=mark@chromium.org

Review URL: https://codereview.chromium.org/2060663002 .
2016-06-20 11:14:47 -07:00
Mike Frysinger
67f738b7ad linux-syscall-support: pull in latest version
The sys_mmap/sys_mmap2 weirdness has been cleaned up in lss now and there
is only one API now for everyone -- sys_mmap.

R=mseaborn@chromium.org

Review URL: https://codereview.chromium.org/2065493006 .
2016-06-14 14:17:56 -04:00
Ted Mielczarek
c44217f646 Dump INFO CODE_ID containing Build ID in Linux dump_syms
I'd like to have the Build ID available for our symbol server
uploading, and this will make it easy.

Most of this change is me rewriting dump_symbols_unittest to be
typed tests so I could add a new test there.

R=mark@chromium.org
BUG=

Review URL: https://codereview.chromium.org/2052263002 .
2016-06-10 13:23:29 -04:00
65 changed files with 998 additions and 170 deletions

10
.gitignore vendored
View File

@ -76,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 Normal file
View File

@ -0,0 +1,15 @@
[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,6 +1,9 @@
# Travis build integration.
# https://docs.travis-ci.com/
language: cpp
# Order here matters for implicit matrix generation and coverity scan.
# See scripts/travis-build.sh for details.
# TODO: add a clang build as well.
compiler:
- gcc
@ -15,9 +18,14 @@ addons:
# selection. If clang is added, this should move to be set inside the
# matrix.
env:
- USE_CC=gcc-4.8 USE_CXX=g++-4.8
global:
- secure: "FPczJ1u7FWGXOtUVf5AONeexfQDYnKRtuNs3phLwlPPAbgAlIc/WeTRSHC8DAb1T8IyPdN3Zi7cqLz0dvPol0iX1fWSfr8YdtW0ea8nUYH5ldmmp6H75FEUJUcISmYwL4WN7TldC6Hnzrlbw/0xmBH8gtAgddtBXKc9P9SwEZvM4OiFMHbMPwZEhRj+D95rfH12lgh3D16nbXGnx3rSNbHszvIxrU2VvlLo9Aa+hbmVj5CsBiNJjhDS64ie+VMTkuzcWNqLRYaGOCQ8ftKAlj/fjGfoKjPDN9dSJg9gW1FjOMPeQo93qhSc/hCmTq7sWxBJu48telinUgESdE5q/8gRf5J05ImWPntZAkC/wQkA20K7Kp/fH1CRaYXQMWKjts8c6dQZ5R4WxE4WXUo5rz573Ti9uyVTLys9whnzaib3YbqYv04irkhpgzo3rd8PF8SXpgK99ySQCcv/Dh7UQuXPpcaknOk2mBySXjQDgpQHHXDN2uUek1HEo5xit8fQuQw3TdPIZ9ZgzQ/c5/Dx6sLWAGEfVH9MN+hy6AiZnJ1JI+XF82kAf1pnf8WddHtlE7pAdWRFQt0iOj9T9esV1/o0VCJVzJLRdpKecF0sTpJxDuan6cFI0tNCkNjHFA5wJKYAvdOPAmYkqre7aIIqSOKy3Fjh9JP9CBJFy7eals9U="
matrix:
- USE_CC=gcc-4.8 USE_CXX=g++-4.8
before_install: ./scripts/travis-checkout.sh
script: ./scripts/travis-build.sh
# Order here matters; see compiler comment above.
# TODO: add mac support
os:
- linux

2
DEPS
View File

@ -59,7 +59,7 @@ deps = {
# Linux syscall support.
"src/src/third_party/lss":
"https://chromium.googlesource.com/linux-syscall-support/" +
"@9292030109847793f7a6689adac1ddafb412fe14"
"@3f6478ac95edf86cd3da300c2c0d34a438f5dbeb",
}
hooks = [

View File

@ -193,7 +193,8 @@ 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/safe_readlink.cc \
src/common/linux/http_upload.cc
if ANDROID_HOST
src_client_linux_libbreakpad_client_a_SOURCES += \
src/common/android/breakpad_getcontext.S

View File

@ -321,6 +321,7 @@ am__src_client_linux_libbreakpad_client_a_SOURCES_DIST = \
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/android/breakpad_getcontext.S
am__dirstamp = $(am__leading_dot)dirstamp
@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__objects_1 = src/common/android/breakpad_getcontext.$(OBJEXT)
@ -347,6 +348,7 @@ am__dirstamp = $(am__leading_dot)dirstamp
@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.$(OBJEXT) \
@LINUX_HOST_TRUE@ src/common/linux/http_upload.$(OBJEXT) \
@LINUX_HOST_TRUE@ $(am__objects_1)
src_client_linux_libbreakpad_client_a_OBJECTS = \
$(am_src_client_linux_libbreakpad_client_a_OBJECTS)
@ -2105,6 +2107,7 @@ CLEANFILES = $(am__append_13)
@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.cc \
@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \
@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.cc \
@LINUX_HOST_TRUE@ src/common/linux/http_upload.cc \
@LINUX_HOST_TRUE@ $(am__append_10)
@DISABLE_PROCESSOR_FALSE@src_libbreakpad_a_SOURCES = \
@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/common/breakpad_types.h \
@ -3556,6 +3559,9 @@ src/common/linux/memory_mapped_file.$(OBJEXT): \
src/common/linux/safe_readlink.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/common/linux/http_upload.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/common/android/$(am__dirstamp):
@$(MKDIR_P) src/common/android
@: > src/common/android/$(am__dirstamp)
@ -4495,9 +4501,6 @@ src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidum
src/tools/linux/md2core/minidump_2_core_unittest$(EXEEXT): $(src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS) $(src_tools_linux_md2core_minidump_2_core_unittest_DEPENDENCIES) $(EXTRA_src_tools_linux_md2core_minidump_2_core_unittest_DEPENDENCIES) src/tools/linux/md2core/$(am__dirstamp)
@rm -f src/tools/linux/md2core/minidump_2_core_unittest$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS) $(src_tools_linux_md2core_minidump_2_core_unittest_LDADD) $(LIBS)
src/common/linux/http_upload.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/tools/linux/symupload/$(am__dirstamp):
@$(MKDIR_P) src/tools/linux/symupload
@: > src/tools/linux/symupload/$(am__dirstamp)

View File

@ -9,11 +9,12 @@ crash-reporting system.
* 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)
* Coverage [![Coverity Status](https://scan.coverity.com/projects/9215/badge.svg)](https://scan.coverity.com/projects/google-breakpad)
## Getting started (from master)
1. First, [download depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools)
and ensure that they're in your `PATH`.
and ensure that theyre in your `PATH`.
2. Create a new directory for checking out the source code (it must be named
breakpad).
@ -75,6 +76,7 @@ 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://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
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.

View File

@ -1,5 +1,4 @@
# 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
GERRIT_HOST: True
GERRIT_SQUASH_UPLOADS: True
CODE_REVIEW_SERVER: chromium-review.googlesource.com
VIEW_VC: https://chromium.googlesource.com/breakpad/breakpad/+/

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -ex
@ -19,6 +19,28 @@ 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 [ "${TRAVIS_JOB_NUMBER##*.}" != "1" ] || \
[ -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
@ -29,15 +51,20 @@ build() {
# Do an out-of-tree build and make sure we can create a release tarball.
build_out_of_tree() {
mkdir -p build/native
cd build/native
pushd build/native >/dev/null
../../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/sh
#!/bin/bash
set -ex
get_depot_tools() {

View File

@ -0,0 +1,131 @@
#!/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%': '0', # 0 = /MT (nondebug static)
'win_debug_RuntimeLibrary%': '1', # 1 = /MTd (debug static)
'win_release_RuntimeLibrary%': '2', # 2 = /MD (nondebug dynamic)
'win_debug_RuntimeLibrary%': '3', # 3 = /MDd (debug dynamic)
'release_extra_cflags%': '',
'debug_extra_cflags%': '',
@ -894,7 +894,7 @@
],
'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'],
'msvs_disabled_warnings': [
4100, 4127, 4396, 4503, 4512, 4819, 4995, 4702
4091, 4100, 4127, 4396, 4503, 4512, 4819, 4995, 4702
],
'msvs_settings': {
'VCCLCompilerTool': {

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 and user structures into minidump format.
// functions to juggle the ucontext_t and user structures into minidump format.
#if defined(__i386__)
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
return uc->uc_mcontext.gregs[REG_ESP];
}
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.gregs[REG_EIP];
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *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 *uc,
#elif defined(__x86_64)
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
return uc->uc_mcontext.gregs[REG_RSP];
}
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.gregs[REG_RIP];
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *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 *uc,
#elif defined(__ARM_EABI__)
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
return uc->uc_mcontext.arm_sp;
}
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.arm_pc;
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *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 *uc) {
#elif defined(__aarch64__)
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
return uc->uc_mcontext.sp;
}
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.pc;
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
const struct fpsimd_context* fpregs) {
out->context_flags = MD_CONTEXT_ARM64_FULL;
@ -210,15 +210,15 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc,
#elif defined(__mips__)
uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP];
}
uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.pc;
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *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 structs.
// Wraps platform-dependent implementations of accessors to ucontext_t structs.
struct UContextReader {
static uintptr_t GetStackPointer(const struct ucontext* uc);
static uintptr_t GetStackPointer(const ucontext_t* uc);
static uintptr_t GetInstructionPointer(const struct ucontext* uc);
static uintptr_t GetInstructionPointer(const ucontext_t* uc);
// Juggle a arch-specific ucontext into a minidump format
// Juggle a arch-specific ucontext_t 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 *uc,
static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
const struct _libc_fpstate* fp);
#elif defined(__aarch64__)
static void FillCPUContext(RawContextCPU *out, const ucontext *uc,
static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
const struct fpsimd_context* fpregs);
#else
static void FillCPUContext(RawContextCPU *out, const ucontext *uc);
static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc);
#endif
};

View File

@ -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(struct ucontext));
memcpy(&g_crash_context_.context, uc, sizeof(ucontext_t));
#if defined(__aarch64__)
struct ucontext* uc_ptr = (struct ucontext*)uc;
ucontext_t* uc_ptr = (ucontext_t*)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 struct ucontext
// In case of MIPS Linux FP state is already part of ucontext_t
// and 'float_state' is not a member of CrashContext.
struct ucontext* uc_ptr = (struct ucontext*)uc;
ucontext_t* uc_ptr = (ucontext_t*)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();
struct ucontext context;
ucontext_t context;
getcontext(&context);
return HandleSignal(sig, &siginfo, &context);
}

View File

@ -191,11 +191,11 @@ class ExceptionHandler {
struct CrashContext {
siginfo_t siginfo;
pid_t tid; // the crashing thread.
struct ucontext context;
ucontext_t 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 struct
// ucontext so 'float_state' is not required.
// In case of MIPS Linux FP state is already part of ucontext_t so
// 'float_state' is not required.
fpstate_t float_state;
#endif
};

View File

@ -38,9 +38,13 @@ 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) {}
: build_fingerprint(NULL),
product_info(NULL),
gpu_fingerprint(NULL),
process_type(NULL) {}
};
}

View File

@ -164,6 +164,7 @@ class MicrodumpWriter {
LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
DumpProductInformation();
DumpOSInformation();
DumpProcessType();
DumpGPUInformation();
#if !defined(__LP64__)
DumpFreeSpace();
@ -233,6 +234,16 @@ 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));
@ -560,7 +571,7 @@ class MicrodumpWriter {
void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); }
const struct ucontext* const ucontext_;
const ucontext_t* const ucontext_;
#if !defined(__ARM_EABI__) && !defined(__mips__)
const google_breakpad::fpstate_t* const float_state_;
#endif

View File

@ -84,6 +84,173 @@ inline static bool IsMappedFileOpenUnsafe(
namespace google_breakpad {
#if defined(__CHROMEOS__)
namespace {
// 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);
}
} // namespace
#endif // __CHROMEOS__
// All interesting auvx entry types are below AT_SYSINFO_EHDR
#define AT_MAX AT_SYSINFO_EHDR
@ -113,6 +280,11 @@ bool LinuxDumper::LateInit() {
#if defined(__ANDROID__)
LatePostprocessMappings();
#endif
#if defined(__CHROMEOS__)
CrOSPostProcessMappings(mappings_);
#endif
return true;
}

View File

@ -1248,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 struct ucontext* const ucontext_; // also from the signal handler
const ucontext_t* const ucontext_; // also from the signal handler
#if !defined(__ARM_EABI__) && !defined(__mips__)
const google_breakpad::fpstate_t* const float_state_; // ditto
#endif

View File

@ -169,6 +169,7 @@ TEST(MinidumpWriterTest, MappingInfo) {
info.start_addr = kMemoryAddress;
info.size = memory_size;
info.offset = 0;
info.exec = false;
strcpy(info.name, kMemoryName);
MappingList mappings;
@ -323,6 +324,7 @@ 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

@ -764,9 +764,10 @@ bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {
// static
bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
MinidumpCallback callback,
void* callback_context) {
void* callback_context,
MINIDUMP_TYPE dump_type) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context,
HANDLER_NONE);
HANDLER_NONE, dump_type, (HANDLE)NULL, NULL);
return handler.WriteMinidump();
}
@ -775,7 +776,8 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child,
DWORD child_blamed_thread,
const wstring& dump_path,
MinidumpCallback callback,
void* callback_context) {
void* callback_context,
MINIDUMP_TYPE dump_type) {
EXCEPTION_RECORD ex;
CONTEXT ctx;
EXCEPTION_POINTERS exinfo = { NULL, NULL };
@ -806,7 +808,7 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child,
}
ExceptionHandler handler(dump_path, NULL, callback, callback_context,
HANDLER_NONE);
HANDLER_NONE, dump_type, (HANDLE)NULL, NULL);
bool success = handler.WriteMinidumpWithExceptionForProcess(
child_blamed_thread,
exinfo.ExceptionRecord ? &exinfo : NULL,

View File

@ -238,7 +238,8 @@ 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);
MinidumpCallback callback, void* callback_context,
MINIDUMP_TYPE dump_type = MiniDumpNormal);
// Write a minidump of |child| immediately. This can be used to
// capture the execution state of |child| independently of a crash.
@ -249,7 +250,8 @@ class ExceptionHandler {
DWORD child_blamed_thread,
const wstring& dump_path,
MinidumpCallback callback,
void* callback_context);
void* callback_context,
MINIDUMP_TYPE dump_type = MiniDumpNormal);
// 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

@ -34,12 +34,20 @@
// 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: Add missing user_regs_struct and user_fpsimd_struct structs.
// - aarch64:
// - NDK r10: Add missing user_regs_struct and user_fpsimd_struct structs.
// - NDK r11+: Add missing <stdint.h> include
// - 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__
@ -52,6 +60,7 @@ 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" {
@ -71,5 +80,6 @@ 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,7 +46,9 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
unsigned return_address_register,
uint8_t version,
const string &augmentation,
bool dwarf64) {
bool dwarf64,
uint8_t address_size,
uint8_t segment_size) {
assert(!entry_length_);
entry_length_ = new PendingLength();
in_fde_ = false;
@ -63,6 +65,10 @@ 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,7 +138,9 @@ class CFISection: public Section {
unsigned return_address_register,
uint8_t version = 3,
const string &augmentation = "",
bool dwarf64 = false);
bool dwarf64 = false,
uint8_t address_size = 8,
uint8_t segment_size = 0);
// 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

@ -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 3 (there was never a
// version 2 of CFI data). For .eh_frame, we handle versions 1 and 3 as well;
// 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;
// the difference between those versions seems to be the same as for
// .debug_frame.
if (cie->version < 1 || cie->version > 3) {
if (cie->version < 1 || cie->version > 4) {
reporter_->UnrecognizedVersion(cie->offset, cie->version);
return false;
}
@ -2287,16 +2287,36 @@ 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) {
@ -2407,7 +2427,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
return true;
}
bool CallFrameInfo::ReadFDEFields(FDE *fde) {
const uint8_t *cursor = fde->fields;
size_t size;
@ -2648,6 +2668,22 @@ 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,6 +1227,14 @@ 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,6 +126,8 @@ 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));
@ -605,6 +607,91 @@ 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

@ -926,8 +926,10 @@ 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));
module.reset(new Module(name, os, architecture, id, code_id));
return true;
}

View File

@ -40,6 +40,8 @@
#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"
@ -54,6 +56,7 @@ 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;
@ -61,7 +64,9 @@ 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) {
@ -78,7 +83,11 @@ class DumpSymbols : public Test {
uint8_t* elfdata;
};
TEST_F(DumpSymbols, Invalid) {
typedef Types<ElfClass32, ElfClass64> ElfClasses;
TYPED_TEST_CASE(DumpSymbols, ElfClasses);
TYPED_TEST(DumpSymbols, Invalid) {
Elf32_Ehdr header;
memset(&header, 0, sizeof(header));
Module* module;
@ -90,8 +99,8 @@ TEST_F(DumpSymbols, Invalid) {
&module));
}
TEST_F(DumpSymbols, SimplePublic32) {
ELF elf(EM_386, ELFCLASS32, kLittleEndian);
TYPED_TEST(DumpSymbols, SimplePublic) {
ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian);
// Zero out text section for simplicity.
Section text(kLittleEndian);
text.Append(4096, 0);
@ -99,8 +108,11 @@ TEST_F(DumpSymbols, SimplePublic32) {
// Add a public symbol.
StringTable table(kLittleEndian);
SymbolTable syms(kLittleEndian, 4, table);
syms.AddSymbol("superfunc", (uint32_t)0x1000, (uint32_t)0x10,
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),
SHN_UNDEF + 1);
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
@ -109,14 +121,14 @@ TEST_F(DumpSymbols, SimplePublic32) {
SHF_ALLOC, // flags
0, // addr
index, // link
sizeof(Elf32_Sym)); // entsize
sizeof(typename TypeParam::Sym)); // entsize
elf.Finish();
GetElfContents(elf);
this->GetElfContents(elf);
Module* module;
DumpOptions options(ALL_SYMBOL_DATA, true);
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
"foo",
vector<string>(),
options,
@ -124,24 +136,40 @@ TEST_F(DumpSymbols, SimplePublic32) {
stringstream s;
module->Write(s, ALL_SYMBOL_DATA);
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n",
s.str());
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());
delete module;
}
TEST_F(DumpSymbols, SimplePublic64) {
ELF elf(EM_X86_64, ELFCLASS64, kLittleEndian);
TYPED_TEST(DumpSymbols, SimpleBuildID) {
ELF elf(TypeParam::kMachine, TypeParam::kClass, 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, 8, table);
syms.AddSymbol("superfunc", (uint64_t)0x1000, (uint64_t)0x10,
ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
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),
SHN_UNDEF + 1);
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
elf.AddSection(".dynsym", syms,
@ -149,14 +177,14 @@ TEST_F(DumpSymbols, SimplePublic64) {
SHF_ALLOC, // flags
0, // addr
index, // link
sizeof(Elf64_Sym)); // entsize
sizeof(typename TypeParam::Sym)); // entsize
elf.Finish();
GetElfContents(elf);
this->GetElfContents(elf);
Module* module;
DumpOptions options(ALL_SYMBOL_DATA, true);
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
"foo",
vector<string>(),
options,
@ -164,9 +192,13 @@ TEST_F(DumpSymbols, SimplePublic64) {
stringstream s;
module->Write(s, ALL_SYMBOL_DATA);
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n",
s.str());
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;
}
} // namespace google_breakpad

View File

@ -49,9 +49,13 @@ 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 {
@ -62,9 +66,13 @@ 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

@ -164,8 +164,18 @@ bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) {
return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
}
// This function is not ever called in an unsafe context, so it's OK
// These three functions are 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) {
@ -181,13 +191,13 @@ string FileID::ConvertIdentifierToUUIDString(
uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
*data3 = htons(*data3);
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;
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());
}
} // namespace google_breakpad

View File

@ -73,6 +73,10 @@ class FileID {
static std::string ConvertIdentifierToUUIDString(
const wasteful_vector<uint8_t>& identifier);
// Convert the entire |identifier| data to a hex string.
static std::string ConvertIdentifierToString(
const wasteful_vector<uint8_t>& identifier);
private:
// Storage for the path specified
std::string path_;

View File

@ -319,3 +319,20 @@ 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,18 +87,7 @@ 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

@ -44,7 +44,6 @@
#ifdef __APPLE__
#define sys_mmap mmap
#define sys_mmap2 mmap
#define sys_munmap munmap
#define MAP_ANONYMOUS MAP_ANON
#else
@ -117,14 +116,8 @@ 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,11 +49,13 @@ using std::hex;
Module::Module(const string &name, const string &os,
const string &architecture, const string &id) :
const string &architecture, const string &id,
const string &code_id /* = "" */) :
name_(name),
os_(os),
architecture_(architecture),
id_(id),
code_id_(code_id),
load_address_(0) { }
Module::~Module() {
@ -235,6 +237,10 @@ 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 &id, const string &code_id = "");
~Module();
// Set the module's load address to LOAD_ADDRESS; addresses given
@ -281,6 +281,7 @@ 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
@ -293,7 +294,7 @@ class Module {
static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream);
// Module header entries.
string name_, os_, architecture_, id_;
string name_, os_, architecture_, id_, code_id_;
// The module's nominal load address. Addresses for functions and
// lines are absolute, assuming the module is loaded at this

View File

@ -64,6 +64,7 @@ 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;
@ -74,6 +75,16 @@ 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

@ -100,6 +100,9 @@ typedef enum {
/* 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
/* Per http://support.microsoft.com/kb/185294,
generated by Visual C++ compiler */

View File

@ -86,7 +86,14 @@ class CodeModule {
// ownership of. The new CodeModule may be of a different concrete class
// than the CodeModule being copied, but will behave identically to the
// copied CodeModule as far as the CodeModule interface is concerned.
virtual const CodeModule* Copy() const = 0;
virtual CodeModule* Copy() const = 0;
// Getter and setter for shrink_down_delta. This is used when the address
// range for a module is shrunk down due to address range conflicts with
// other modules. The base_address and size fields are not updated and they
// should always reflect the original values (reported in the minidump).
virtual uint64_t shrink_down_delta() const = 0;
virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) = 0;
};
} // namespace google_breakpad

View File

@ -35,7 +35,12 @@
#ifndef GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__
#define GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__
#include <stddef.h>
#include <vector>
#include "google_breakpad/common/breakpad_types.h"
#include "processor/linked_ptr.h"
namespace google_breakpad {
@ -91,6 +96,14 @@ class CodeModules {
// returns objects in may differ between a copy and the original CodeModules
// object.
virtual const CodeModules* Copy() const = 0;
// Returns a vector of all modules which address ranges needed to be shrunk
// down due to address range conflicts with other modules.
virtual std::vector<linked_ptr<const CodeModule> >
GetShrunkRangeModules() const = 0;
// Returns true, if module address range shrink is enabled.
virtual bool IsModuleShrinkEnabled() const = 0;
};
} // namespace google_breakpad

View File

@ -58,6 +58,9 @@ class MicrodumpModules : public BasicCodeModules {
public:
// Takes over ownership of |module|.
void Add(const CodeModule* module);
// Enables/disables module address range shrink.
void SetEnableModuleShrink(bool is_enabled);
};
// MicrodumpContext carries a CPU-specific context.

View File

@ -151,6 +151,8 @@ class MinidumpStream : public MinidumpObject {
// that implements MinidumpStream can compare expected_size to a
// known size as an integrity check.
virtual bool Read(uint32_t expected_size) = 0;
DISALLOW_COPY_AND_ASSIGN(MinidumpStream);
};
@ -191,6 +193,8 @@ class MinidumpContext : public DumpContext {
// for access to data about the minidump file itself, such as whether
// it should be byte-swapped.
Minidump* minidump_;
DISALLOW_COPY_AND_ASSIGN(MinidumpContext);
};
@ -358,6 +362,8 @@ class MinidumpThreadList : public MinidumpStream {
// The list of threads.
MinidumpThreads* threads_;
uint32_t thread_count_;
DISALLOW_COPY_AND_ASSIGN(MinidumpThreadList);
};
@ -392,7 +398,14 @@ class MinidumpModule : public MinidumpObject,
virtual string debug_file() const;
virtual string debug_identifier() const;
virtual string version() const;
virtual const CodeModule* Copy() const;
virtual CodeModule* Copy() const;
// Getter and setter for shrink_down_delta. This is used when the address
// range for a module is shrunk down due to address range conflicts with
// other modules. The base_address and size fields are not updated and they
// should always reflect the original values (reported in the minidump).
virtual uint64_t shrink_down_delta() const;
virtual void SetShrinkDownDelta(uint64_t shrink_down_delta);
// The CodeView record, which contains information to locate the module's
// debugging information (pdb). This is returned as uint8_t* because
@ -501,6 +514,13 @@ class MinidumpModuleList : public MinidumpStream,
virtual const MinidumpModule* GetModuleAtIndex(unsigned int index) const;
virtual const CodeModules* Copy() const;
// Returns a vector of all modules which address ranges needed to be shrunk
// down due to address range conflicts with other modules.
virtual vector<linked_ptr<const CodeModule> > GetShrunkRangeModules() const;
// Returns true, if module address range shrink is enabled.
virtual bool IsModuleShrinkEnabled() const;
// Print a human-readable representation of the object to stdout.
void Print();
@ -525,6 +545,8 @@ class MinidumpModuleList : public MinidumpStream,
MinidumpModules *modules_;
uint32_t module_count_;
DISALLOW_COPY_AND_ASSIGN(MinidumpModuleList);
};
@ -587,6 +609,8 @@ class MinidumpMemoryList : public MinidumpStream {
// The list of regions.
MemoryRegions *regions_;
uint32_t region_count_;
DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryList);
};
@ -626,6 +650,8 @@ class MinidumpException : public MinidumpStream {
MDRawExceptionStream exception_;
MinidumpContext* context_;
DISALLOW_COPY_AND_ASSIGN(MinidumpException);
};
// MinidumpAssertion wraps MDRawAssertionInfo, which contains information
@ -666,6 +692,8 @@ class MinidumpAssertion : public MinidumpStream {
string expression_;
string function_;
string file_;
DISALLOW_COPY_AND_ASSIGN(MinidumpAssertion);
};
@ -719,6 +747,8 @@ class MinidumpSystemInfo : public MinidumpStream {
// A string identifying the CPU vendor, if known.
const string* cpu_vendor_;
DISALLOW_COPY_AND_ASSIGN(MinidumpSystemInfo);
};
@ -752,6 +782,8 @@ class MinidumpMiscInfo : public MinidumpStream {
string daylight_name_;
string build_string_;
string dbg_bld_str_;
DISALLOW_COPY_AND_ASSIGN(MinidumpMiscInfo);
};
@ -784,6 +816,8 @@ class MinidumpBreakpadInfo : public MinidumpStream {
bool Read(uint32_t expected_size_);
MDRawBreakpadInfo breakpad_info_;
DISALLOW_COPY_AND_ASSIGN(MinidumpBreakpadInfo);
};
// MinidumpMemoryInfo wraps MDRawMemoryInfo, which provides information
@ -854,6 +888,8 @@ class MinidumpMemoryInfoList : public MinidumpStream {
MinidumpMemoryInfos* infos_;
uint32_t info_count_;
DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryInfoList);
};
// MinidumpLinuxMaps wraps information about a single mapped memory region
@ -1061,6 +1097,9 @@ class Minidump {
// Print a human-readable representation of the object to stdout.
void Print();
// Is the OS Android.
bool IsAndroid();
private:
// MinidumpStreamInfo is used in the MinidumpStreamMap. It lets
// the Minidump object locate interesting streams quickly, and
@ -1121,6 +1160,8 @@ class Minidump {
// construction or after a failed Read(); true following a successful
// Read().
bool valid_;
DISALLOW_COPY_AND_ASSIGN(Minidump);
};

View File

@ -39,8 +39,10 @@
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
#include "google_breakpad/processor/system_info.h"
#include "google_breakpad/processor/code_modules.h"
#include "google_breakpad/processor/minidump.h"
#include "google_breakpad/processor/system_info.h"
#include "processor/linked_ptr.h"
namespace google_breakpad {
@ -109,6 +111,9 @@ class ProcessState {
}
const SystemInfo* system_info() const { return &system_info_; }
const CodeModules* modules() const { return modules_; }
const vector<linked_ptr<const CodeModule> >* shrunk_range_modules() const {
return &shrunk_range_modules_;
}
const vector<const CodeModule*>* modules_without_symbols() const {
return &modules_without_symbols_;
}
@ -172,6 +177,10 @@ class ProcessState {
// ProcessState.
const CodeModules *modules_;
// The modules which virtual address ranges were shrunk down due to
// virtual address conflicts.
vector<linked_ptr<const CodeModule> > shrunk_range_modules_;
// The modules that didn't have symbols when the report was processed.
vector<const CodeModule*> modules_without_symbols_;

View File

@ -57,6 +57,7 @@ class BasicCodeModule : public CodeModule {
explicit BasicCodeModule(const CodeModule *that)
: base_address_(that->base_address()),
size_(that->size()),
shrink_down_delta_(that->shrink_down_delta()),
code_file_(that->code_file()),
code_identifier_(that->code_identifier()),
debug_file_(that->debug_file()),
@ -64,18 +65,19 @@ class BasicCodeModule : public CodeModule {
version_(that->version()) {}
BasicCodeModule(uint64_t base_address, uint64_t size,
const string &code_file,
const string &code_identifier,
const string &debug_file,
const string &debug_identifier,
const string &version)
: base_address_(base_address),
size_(size),
code_file_(code_file),
code_identifier_(code_identifier),
debug_file_(debug_file),
debug_identifier_(debug_identifier),
version_(version)
const string &code_file,
const string &code_identifier,
const string &debug_file,
const string &debug_identifier,
const string &version)
: base_address_(base_address),
size_(size),
shrink_down_delta_(0),
code_file_(code_file),
code_identifier_(code_identifier),
debug_file_(debug_file),
debug_identifier_(debug_identifier),
version_(version)
{}
virtual ~BasicCodeModule() {}
@ -83,16 +85,21 @@ class BasicCodeModule : public CodeModule {
// members.
virtual uint64_t base_address() const { return base_address_; }
virtual uint64_t size() const { return size_; }
virtual uint64_t shrink_down_delta() const { return shrink_down_delta_; }
virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {
shrink_down_delta_ = shrink_down_delta;
}
virtual string code_file() const { return code_file_; }
virtual string code_identifier() const { return code_identifier_; }
virtual string debug_file() const { return debug_file_; }
virtual string debug_identifier() const { return debug_identifier_; }
virtual string version() const { return version_; }
virtual const CodeModule* Copy() const { return new BasicCodeModule(this); }
virtual CodeModule* Copy() const { return new BasicCodeModule(this); }
private:
uint64_t base_address_;
uint64_t size_;
uint64_t shrink_down_delta_;
string code_file_;
string code_identifier_;
string debug_file_;

View File

@ -38,6 +38,8 @@
#include <assert.h>
#include <vector>
#include "google_breakpad/processor/code_module.h"
#include "processor/linked_ptr.h"
#include "processor/logging.h"
@ -45,31 +47,50 @@
namespace google_breakpad {
using std::vector;
BasicCodeModules::BasicCodeModules(const CodeModules *that)
: main_address_(0), map_() {
BPLOG_IF(ERROR, !that) << "BasicCodeModules::BasicCodeModules requires "
"|that|";
assert(that);
map_.SetEnableShrinkDown(that->IsModuleShrinkEnabled());
const CodeModule *main_module = that->GetMainModule();
if (main_module)
main_address_ = main_module->base_address();
unsigned int count = that->module_count();
for (unsigned int module_sequence = 0;
module_sequence < count;
++module_sequence) {
for (unsigned int i = 0; i < count; ++i) {
// Make a copy of the module and insert it into the map. Use
// GetModuleAtIndex because ordering is unimportant when slurping the
// entire list, and GetModuleAtIndex may be faster than
// GetModuleAtSequence.
linked_ptr<const CodeModule> module(
that->GetModuleAtIndex(module_sequence)->Copy());
linked_ptr<const CodeModule> module(that->GetModuleAtIndex(i)->Copy());
if (!map_.StoreRange(module->base_address(), module->size(), module)) {
BPLOG(ERROR) << "Module " << module->code_file() <<
" could not be stored";
BPLOG(ERROR) << "Module " << module->code_file()
<< " could not be stored";
}
}
// Report modules with shrunk ranges.
for (unsigned int i = 0; i < count; ++i) {
linked_ptr<const CodeModule> module(that->GetModuleAtIndex(i)->Copy());
uint64_t delta = 0;
if (map_.RetrieveRange(module->base_address() + module->size() - 1,
&module, NULL /* base */, &delta, NULL /* size */) &&
delta > 0) {
BPLOG(INFO) << "The range for module " << module->code_file()
<< " was shrunk down by " << HexString(delta) << " bytes.";
linked_ptr<CodeModule> shrunk_range_module(module->Copy());
shrunk_range_module->SetShrinkDownDelta(delta);
shrunk_range_modules_.push_back(shrunk_range_module);
}
}
// TODO(ivanpe): Report modules with conflicting ranges. The list of such
// modules should be copied from |that|.
}
BasicCodeModules::BasicCodeModules() : main_address_(0), map_() { }
@ -122,4 +143,13 @@ const CodeModules* BasicCodeModules::Copy() const {
return new BasicCodeModules(this);
}
vector<linked_ptr<const CodeModule> >
BasicCodeModules::GetShrunkRangeModules() const {
return shrunk_range_modules_;
}
bool BasicCodeModules::IsModuleShrinkEnabled() const {
return map_.IsShrinkDownEnabled();
}
} // namespace google_breakpad

View File

@ -43,6 +43,8 @@
#include <stddef.h>
#include <vector>
#include "google_breakpad/processor/code_modules.h"
#include "processor/linked_ptr.h"
#include "processor/range_map.h"
@ -67,6 +69,9 @@ class BasicCodeModules : public CodeModules {
virtual const CodeModule* GetModuleAtSequence(unsigned int sequence) const;
virtual const CodeModule* GetModuleAtIndex(unsigned int index) const;
virtual const CodeModules* Copy() const;
virtual std::vector<linked_ptr<const CodeModule> >
GetShrunkRangeModules() const;
virtual bool IsModuleShrinkEnabled() const;
protected:
BasicCodeModules();
@ -78,6 +83,10 @@ class BasicCodeModules : public CodeModules {
// address range.
RangeMap<uint64_t, linked_ptr<const CodeModule> > map_;
// A vector of all CodeModules that were shrunk downs due to
// address range conflicts.
std::vector<linked_ptr<const CodeModule> > shrunk_range_modules_;
private:
// Disallow copy constructor and assignment operator.
BasicCodeModules(const BasicCodeModules &that);

View File

@ -68,9 +68,11 @@ class TestCodeModule : public CodeModule {
virtual string debug_file() const { return ""; }
virtual string debug_identifier() const { return ""; }
virtual string version() const { return ""; }
virtual const CodeModule* Copy() const {
virtual CodeModule* Copy() const {
return new TestCodeModule(code_file_);
}
virtual uint64_t shrink_down_delta() const { return 0; }
virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {}
private:
string code_file_;

View File

@ -79,9 +79,11 @@ class TestCodeModule : public CodeModule {
virtual string debug_file() const { return ""; }
virtual string debug_identifier() const { return ""; }
virtual string version() const { return ""; }
virtual const CodeModule* Copy() const {
virtual CodeModule* Copy() const {
return new TestCodeModule(code_file_);
}
virtual uint64_t shrink_down_delta() const { return 0; }
virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {}
private:
string code_file_;

View File

@ -110,6 +110,9 @@ void MicrodumpModules::Add(const CodeModule* module) {
}
}
void MicrodumpModules::SetEnableModuleShrink(bool is_enabled) {
map_.SetEnableShrinkDown(is_enabled);
}
//
// MicrodumpContext
@ -262,6 +265,7 @@ Microdump::Microdump(const string& contents)
} else if (os_id == "A") {
system_info_->os = "Android";
system_info_->os_short = "android";
modules_->SetEnableModuleShrink(true);
}
// OS line also contains release and version for future use.

View File

@ -201,7 +201,7 @@ TEST_F(MicrodumpProcessorTest, TestProcessX86) {
AnalyzeDump("microdump-x86.dmp", false /* omit_symbols */,
4 /* expected_cpu_count */, &state);
ASSERT_EQ(105U, state.modules()->module_count());
ASSERT_EQ(124U, state.modules()->module_count());
ASSERT_EQ("x86", state.system_info()->cpu);
ASSERT_EQ("asus/WW_Z00A/Z00A:5.0/LRX21V/2.19.40.22_20150627_5104_user:user/"
"release-keys", state.system_info()->os_version);
@ -216,11 +216,11 @@ TEST_F(MicrodumpProcessorTest, TestProcessMultiple) {
ProcessState state;
AnalyzeDump("microdump-multiple.dmp", false /* omit_symbols */,
6 /* expected_cpu_count */, &state);
ASSERT_EQ(133U, state.modules()->module_count());
ASSERT_EQ(156U, state.modules()->module_count());
ASSERT_EQ("arm", state.system_info()->cpu);
ASSERT_EQ("lge/p1_tmo_us/p1:6.0/MRA58K/1603210524c8d:user/release-keys",
state.system_info()->os_version);
ASSERT_EQ(2U, state.threads()->at(0)->frames()->size());
ASSERT_EQ(5U, state.threads()->at(0)->frames()->size());
}
TEST_F(MicrodumpProcessorTest, TestProcessMips) {
@ -249,7 +249,7 @@ TEST_F(MicrodumpProcessorTest, TestProcessMips64) {
AnalyzeDump("microdump-mips64.dmp", false /* omit_symbols */,
1 /* expected_cpu_count */, &state);
ASSERT_EQ(7U, state.modules()->module_count());
ASSERT_EQ(8U, state.modules()->module_count());
ASSERT_EQ("mips64", state.system_info()->cpu);
ASSERT_EQ("3.10.0-gf185e20 #112 PREEMPT Mon Oct 5 11:12:49 PDT 2015",
state.system_info()->os_version);

View File

@ -2109,11 +2109,21 @@ string MinidumpModule::version() const {
}
const CodeModule* MinidumpModule::Copy() const {
CodeModule* MinidumpModule::Copy() const {
return new BasicCodeModule(this);
}
uint64_t MinidumpModule::shrink_down_delta() const {
return 0;
}
void MinidumpModule::SetShrinkDownDelta(uint64_t shrink_down_delta) {
// Not implemented
assert(false);
}
const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) {
if (!module_valid_) {
BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord";
@ -2497,6 +2507,7 @@ MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
range_map_(new RangeMap<uint64_t, unsigned int>()),
modules_(NULL),
module_count_(0) {
range_map_->SetEnableShrinkDown(minidump_->IsAndroid());
}
@ -2709,7 +2720,7 @@ const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
}
unsigned int module_index;
if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index,
if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index,
NULL /* base */, NULL /* delta */,
NULL /* size */)) {
BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence;
@ -2741,6 +2752,14 @@ const CodeModules* MinidumpModuleList::Copy() const {
return new BasicCodeModules(this);
}
vector<linked_ptr<const CodeModule> >
MinidumpModuleList::GetShrunkRangeModules() const {
return vector<linked_ptr<const CodeModule> >();
}
bool MinidumpModuleList::IsModuleShrinkEnabled() const {
return range_map_->IsShrinkDownEnabled();
}
void MinidumpModuleList::Print() {
if (!valid_) {
@ -4532,6 +4551,24 @@ MinidumpLinuxMapsList *Minidump::GetLinuxMapsList() {
return GetStream(&linux_maps_list);
}
bool Minidump::IsAndroid() {
// Save the current stream position
off_t saved_position = Tell();
if (saved_position == -1) {
return false;
}
const MDRawSystemInfo* system_info =
GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
// Restore position and return
if (!SeekSet(saved_position)) {
BPLOG(ERROR) << "Couldn't seek back to saved position";
return false;
}
return system_info && system_info->platform_id == MD_OS_ANDROID;
}
static const char* get_stream_name(uint32_t stream_type) {
switch (stream_type) {
case MD_UNUSED_STREAM:
@ -4645,7 +4682,7 @@ void Minidump::Print() {
iterator != stream_map_->end();
++iterator) {
uint32_t stream_type = iterator->first;
MinidumpStreamInfo info = iterator->second;
const MinidumpStreamInfo& info = iterator->second;
printf(" stream type 0x%x (%s) at index %d\n", stream_type,
get_stream_name(stream_type),
info.stream_index);
@ -4802,7 +4839,7 @@ bool Minidump::SeekToStreamType(uint32_t stream_type,
return false;
}
MinidumpStreamInfo info = iterator->second;
const MinidumpStreamInfo& info = iterator->second;
if (info.stream_index >= header_.stream_count) {
BPLOG(ERROR) << "SeekToStreamType: type " << stream_type <<
" out of range: " <<

View File

@ -126,8 +126,20 @@ ProcessResult MinidumpProcessor::Process(
// Put a copy of the module list into ProcessState object. This is not
// necessarily a MinidumpModuleList, but it adheres to the CodeModules
// interface, which is all that ProcessState needs to expose.
if (module_list)
if (module_list) {
process_state->modules_ = module_list->Copy();
process_state->shrunk_range_modules_ =
process_state->modules_->GetShrunkRangeModules();
for (unsigned int i = 0;
i < process_state->shrunk_range_modules_.size();
i++) {
linked_ptr<const CodeModule> module =
process_state->shrunk_range_modules_[i];
BPLOG(INFO) << "The range for module " << module->code_file()
<< " was shrunk down by " << HexString(
module->shrink_down_delta()) << " bytes. ";
}
}
MinidumpMemoryList *memory_list = dump->GetMemoryList();
if (memory_list) {
@ -1174,6 +1186,9 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION:
reason = "EXCEPTION_HEAP_CORRUPTION";
break;
case MD_EXCEPTION_OUT_OF_MEMORY:
reason = "Out of Memory";
break;
case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION:
reason = "Unhandled C++ Exception";
break;

View File

@ -52,6 +52,11 @@ void RangeMap<AddressType, EntryType>::SetEnableShrinkDown(
enable_shrink_down_ = enable_shrink_down;
}
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::IsShrinkDownEnabled() const {
return enable_shrink_down_;
}
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType &base,
const AddressType &size,

View File

@ -60,6 +60,7 @@ class RangeMap {
// will be shrunk down by moving its start position to a higher address so
// that it does not overlap anymore.
void SetEnableShrinkDown(bool enable_shrink_down);
bool IsShrinkDownEnabled() const;
// Inserts a range into the map. Returns false for a parameter error,
// or if the location of the range would conflict with a range already

View File

@ -48,6 +48,7 @@
#include "google_breakpad/processor/memory_region.h"
#include "google_breakpad/processor/symbol_supplier.h"
#include "google_breakpad/processor/system_info.h"
#include "processor/linked_ptr.h"
class MockMemoryRegion: public google_breakpad::MemoryRegion {
public:
@ -114,9 +115,11 @@ class MockCodeModule: public google_breakpad::CodeModule {
string debug_file() const { return code_file_; }
string debug_identifier() const { return code_file_; }
string version() const { return version_; }
const google_breakpad::CodeModule *Copy() const {
google_breakpad::CodeModule *Copy() const {
abort(); // Tests won't use this.
}
virtual uint64_t shrink_down_delta() const { return 0; }
virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {}
private:
uint64_t base_address_;
@ -126,11 +129,11 @@ class MockCodeModule: public google_breakpad::CodeModule {
};
class MockCodeModules: public google_breakpad::CodeModules {
public:
public:
typedef google_breakpad::CodeModule CodeModule;
typedef google_breakpad::CodeModules CodeModules;
void Add(const MockCodeModule *module) {
void Add(const MockCodeModule *module) {
modules_.push_back(module);
}
@ -157,9 +160,19 @@ class MockCodeModules: public google_breakpad::CodeModules {
return modules_.at(index);
}
const CodeModules *Copy() const { abort(); } // Tests won't use this.
CodeModules *Copy() const { abort(); } // Tests won't use this
private:
virtual std::vector<google_breakpad::linked_ptr<const CodeModule> >
GetShrunkRangeModules() const {
return std::vector<google_breakpad::linked_ptr<const CodeModule> >();
}
// Returns true, if module address range shrink is enabled.
bool IsModuleShrinkEnabled() const {
return false;
}
private:
typedef std::vector<const MockCodeModule *> ModuleVector;
ModuleVector modules_;
};

1
src/testing Submodule

@ -0,0 +1 @@
Subproject commit ec44c6c1675c25b9827aacd08c02433cccde7780

1
src/third_party/glog vendored Submodule

@ -0,0 +1 @@
Subproject commit d8cb47f77d1c31779f3ff890e1a5748483778d6a

1
src/third_party/lss vendored Submodule

@ -0,0 +1 @@
Subproject commit 3f6478ac95edf86cd3da300c2c0d34a438f5dbeb

1
src/third_party/protobuf/protobuf vendored Submodule

@ -0,0 +1 @@
Subproject commit cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac

1
src/tools/gyp Submodule

@ -0,0 +1 @@
Subproject commit a7055b3989c1074adca03b4b4829e7f0e57f6efd

View File

@ -38,6 +38,8 @@
// cpu: the CPU that the module was built for (x86 or ppc)
// symbol_file: the contents of the breakpad-format symbol file
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <Foundation/Foundation.h>
@ -165,6 +167,25 @@ SetupOptions(int argc, const char *argv[], Options *options) {
exit(1);
}
int fd = open(argv[optind], O_RDONLY);
if (fd < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
exit(1);
}
struct stat statbuf;
if (fstat(fd, &statbuf) < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
close(fd);
exit(1);
}
close(fd);
if (!S_ISREG(statbuf.st_mode)) {
fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]);
exit(1);
}
options->symbolsPath = [NSString stringWithUTF8String:argv[optind]];
options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]];
}

View File

@ -113,7 +113,7 @@
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<BufferSecurityCheck>true</BufferSecurityCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<DisableSpecificWarnings>4091;4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ExceptionHandling>false</ExceptionHandling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<MinimalRebuild>false</MinimalRebuild>
@ -162,7 +162,7 @@
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<BufferSecurityCheck>true</BufferSecurityCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<DisableSpecificWarnings>4091;4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ExceptionHandling>false</ExceptionHandling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<MinimalRebuild>false</MinimalRebuild>
@ -211,7 +211,7 @@
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<BufferSecurityCheck>false</BufferSecurityCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<DisableSpecificWarnings>4091;4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ExceptionHandling>false</ExceptionHandling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<MinimalRebuild>false</MinimalRebuild>
@ -261,7 +261,7 @@
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<BufferSecurityCheck>true</BufferSecurityCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<DisableSpecificWarnings>4091;4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ExceptionHandling>false</ExceptionHandling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<MinimalRebuild>false</MinimalRebuild>
@ -314,7 +314,7 @@
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<BufferSecurityCheck>true</BufferSecurityCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<DisableSpecificWarnings>4091;4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ExceptionHandling>false</ExceptionHandling>
<FunctionLevelLinking>true</FunctionLevelLinking>
<MinimalRebuild>false</MinimalRebuild>