Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
89a54adbec | ||
|
25d9bef21d | ||
|
ec9650bde3 | ||
|
43b476ba46 | ||
|
85998ab1f3 | ||
|
e406e6433c | ||
|
3c80b703d7 | ||
|
8c2c0d2b2a | ||
|
72aaf6d8fb | ||
|
acc23b8972 | ||
|
81456eb33d | ||
|
dd3cb8b446 | ||
|
291e9d94c6 | ||
|
1ef219527e | ||
|
bbebd8d5e7 | ||
|
13c634f6a1 | ||
|
600ec35c5b | ||
|
0fc6d0c8df | ||
|
f7be4815a2 | ||
|
f5638b8c2e | ||
|
0e4af9d8f9 | ||
|
5f638d5323 | ||
|
b5200a97b7 | ||
|
c99d374dde | ||
|
5adeef6117 | ||
|
0ebdc4a10a | ||
|
41b91d064e | ||
|
965424f183 | ||
|
dfd2da7979 | ||
|
e0f2c17988 | ||
|
af8840d910 | ||
|
1600b6054e | ||
|
f140a0339f | ||
|
5325fd5162 | ||
|
83a5552060 | ||
|
24f5931c5e | ||
|
67f738b7ad | ||
|
c44217f646 |
10
.gitignore
vendored
10
.gitignore
vendored
@ -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
15
.gitmodules
vendored
Normal 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/
|
10
.travis.yml
10
.travis.yml
@ -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
2
DEPS
@ -59,7 +59,7 @@ deps = {
|
||||
# Linux syscall support.
|
||||
"src/src/third_party/lss":
|
||||
"https://chromium.googlesource.com/linux-syscall-support/" +
|
||||
"@9292030109847793f7a6689adac1ddafb412fe14"
|
||||
"@3f6478ac95edf86cd3da300c2c0d34a438f5dbeb",
|
||||
}
|
||||
|
||||
hooks = [
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
10
README.md
10
README.md
@ -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 they’re 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 CC’d.
|
||||
|
@ -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/+/
|
||||
|
@ -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 "$@"
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
|
||||
get_depot_tools() {
|
||||
|
131
scripts/windows/install_google_breakpad.py
Normal file
131
scripts/windows/install_google_breakpad.py
Normal 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)
|
@ -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': {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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':"
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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: " <<
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
1
src/testing
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ec44c6c1675c25b9827aacd08c02433cccde7780
|
1
src/third_party/glog
vendored
Submodule
1
src/third_party/glog
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d8cb47f77d1c31779f3ff890e1a5748483778d6a
|
1
src/third_party/lss
vendored
Submodule
1
src/third_party/lss
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 3f6478ac95edf86cd3da300c2c0d34a438f5dbeb
|
1
src/third_party/protobuf/protobuf
vendored
Submodule
1
src/third_party/protobuf/protobuf
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac
|
1
src/tools/gyp
Submodule
1
src/tools/gyp
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit a7055b3989c1074adca03b4b4829e7f0e57f6efd
|
@ -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]];
|
||||
}
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user