No known key found for this signature in database
GPG Key ID: A5A7629F109C8FD1
4081 changed files with 1185566 additions and 45 deletions
-
2.ci/linux/build.sh
-
57.gitmodules
-
1externals/breakpad
-
9externals/breakpad/.clang-format
-
73externals/breakpad/.github/workflows/build-test-ci.yml
-
22externals/breakpad/.github/workflows/close-pull-request.yml
-
43externals/breakpad/.github/workflows/coverity.yml
-
90externals/breakpad/.gitignore
-
1externals/breakpad/AUTHORS
-
0externals/breakpad/ChangeLog
-
58externals/breakpad/DEPS
-
13externals/breakpad/DIR_METADATA
-
370externals/breakpad/INSTALL
-
1068externals/breakpad/LICENSE
-
1794externals/breakpad/Makefile.am
-
10322externals/breakpad/Makefile.in
-
0externals/breakpad/NEWS
-
13externals/breakpad/OWNERS
-
139externals/breakpad/README.ANDROID
-
82externals/breakpad/README.md
-
1273externals/breakpad/aclocal.m4
-
371externals/breakpad/android/common-functions.sh
-
104externals/breakpad/android/google_breakpad/Android.mk
-
554externals/breakpad/android/run-checks.sh
-
32externals/breakpad/android/sample_app/README
-
43externals/breakpad/android/sample_app/jni/Android.mk
-
31externals/breakpad/android/sample_app/jni/Application.mk
-
56externals/breakpad/android/sample_app/jni/test_breakpad.cpp
-
131externals/breakpad/android/test-driver
-
130externals/breakpad/android/test-shell.sh
-
42externals/breakpad/appveyor.yml
-
271externals/breakpad/autotools/ar-lib
-
348externals/breakpad/autotools/compile
-
1701externals/breakpad/autotools/config.guess
-
1876externals/breakpad/autotools/config.sub
-
791externals/breakpad/autotools/depcomp
-
541externals/breakpad/autotools/install-sh
-
8406externals/breakpad/autotools/ltmain.sh
-
215externals/breakpad/autotools/missing
-
3externals/breakpad/autotools/root-test-driver
-
153externals/breakpad/autotools/test-driver
-
10externals/breakpad/breakpad-client.pc.in
-
10externals/breakpad/breakpad.pc.in
-
3externals/breakpad/codereview.settings
-
12104externals/breakpad/configure
-
240externals/breakpad/configure.ac
-
38externals/breakpad/default.xml
-
1externals/breakpad/docs/OWNERS
-
BINexternals/breakpad/docs/breakpad.png
-
1023externals/breakpad/docs/breakpad.svg
-
223externals/breakpad/docs/client_design.md
-
35externals/breakpad/docs/contributing_to_breakpad.md
-
128externals/breakpad/docs/exception_handling.md
-
115externals/breakpad/docs/getting_started_with_breakpad.md
-
39externals/breakpad/docs/linux_core_handler.md
-
110externals/breakpad/docs/linux_starter_guide.md
-
47externals/breakpad/docs/linux_system_calls.md
-
184externals/breakpad/docs/mac_breakpad_starter_guide.md
-
82externals/breakpad/docs/mozilla_brown_bag_talk.md
-
231externals/breakpad/docs/processor_design.md
-
144externals/breakpad/docs/stack_walking.md
-
214externals/breakpad/docs/sym_upload_v2_protocol.md
-
581externals/breakpad/docs/symbol_files.md
-
70externals/breakpad/docs/windows_client_integration.md
-
67externals/breakpad/m4/ax_append_compile_flags.m4
-
71externals/breakpad/m4/ax_append_flag.m4
-
74externals/breakpad/m4/ax_check_compile_flag.m4
-
92externals/breakpad/m4/ax_check_define.m4
-
1009externals/breakpad/m4/ax_cxx_compile_stdcxx.m4
-
283externals/breakpad/m4/ax_pthread.m4
-
37externals/breakpad/m4/ax_require_defined.m4
-
7377externals/breakpad/m4/libtool.m4
-
368externals/breakpad/m4/ltoptions.m4
-
123externals/breakpad/m4/ltsugar.m4
-
23externals/breakpad/m4/ltversion.m4
-
92externals/breakpad/m4/lt~obsolete.m4
-
56externals/breakpad/src/breakpad_googletest_includes.h
-
72externals/breakpad/src/client/apple/Framework/BreakpadDefines.h
-
259externals/breakpad/src/client/ios/Breakpad.h
-
986externals/breakpad/src/client/ios/Breakpad.mm
-
604externals/breakpad/src/client/ios/Breakpad.xcodeproj/project.pbxproj
-
153externals/breakpad/src/client/ios/BreakpadController.h
-
373externals/breakpad/src/client/ios/BreakpadController.mm
-
7externals/breakpad/src/client/ios/Breakpad_Prefix.pch
-
265externals/breakpad/src/client/ios/exception_handler_no_mach.cc
-
178externals/breakpad/src/client/ios/exception_handler_no_mach.h
-
73externals/breakpad/src/client/ios/handler/ios_exception_minidump_generator.h
-
209externals/breakpad/src/client/ios/handler/ios_exception_minidump_generator.mm
-
52externals/breakpad/src/client/linux/crash_generation/client_info.h
-
108externals/breakpad/src/client/linux/crash_generation/crash_generation_client.cc
-
61externals/breakpad/src/client/linux/crash_generation/crash_generation_client.h
-
336externals/breakpad/src/client/linux/crash_generation/crash_generation_server.cc
-
134externals/breakpad/src/client/linux/crash_generation/crash_generation_server.h
-
3externals/breakpad/src/client/linux/data/linux-gate-amd.sym
-
3externals/breakpad/src/client/linux/data/linux-gate-intel.sym
-
73externals/breakpad/src/client/linux/dump_writer_common/mapping_info.h
-
60externals/breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h
-
395externals/breakpad/src/client/linux/dump_writer_common/thread_info.cc
-
90externals/breakpad/src/client/linux/dump_writer_common/thread_info.h
-
329externals/breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc
@ -0,0 +1,9 @@ |
|||
# Defines the Chromium style for automatic reformatting. |
|||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html |
|||
BasedOnStyle: Chromium |
|||
|
|||
# This defaults to 'Auto'. Explicitly set it for a while, so that |
|||
# 'vector<vector<int> >' in existing files gets formatted to |
|||
# 'vector<vector<int>>'. ('Auto' means that clang-format will only use |
|||
# 'int>>' if the file already contains at least one such instance.) |
|||
Standard: Cpp11 |
|||
@ -0,0 +1,73 @@ |
|||
# GitHub actions workflow. |
|||
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions |
|||
|
|||
name: Build+Test CI |
|||
|
|||
on: |
|||
push: |
|||
branches: [main] |
|||
|
|||
schedule: |
|||
# The GH mirroring from Google GoB does not trigger push actions. |
|||
# Fire it every other day to provide some coverage. This will run ~8 AM PT. |
|||
- cron: '39 3 */2 * *' |
|||
|
|||
# Allow for manual triggers from the web. |
|||
workflow_dispatch: |
|||
|
|||
jobs: |
|||
autotools: |
|||
strategy: |
|||
fail-fast: false |
|||
matrix: |
|||
include: |
|||
- os: ubuntu-latest |
|||
cc: gcc |
|||
cxx: g++ |
|||
- os: ubuntu-latest |
|||
cc: clang |
|||
cxx: clang++ |
|||
- os: macos-latest |
|||
cc: clang |
|||
cxx: clang++ |
|||
runs-on: ${{ matrix.os }} |
|||
env: |
|||
CC: ${{ matrix.cc }} |
|||
CXX: ${{ matrix.cxx }} |
|||
|
|||
steps: |
|||
- name: System settings |
|||
run: | |
|||
set -x |
|||
$CC --version |
|||
$CXX --version |
|||
getconf _NPROCESSORS_ONLN |
|||
getconf _NPROCESSORS_CONF |
|||
true |
|||
|
|||
- name: Checkout depot_tools |
|||
run: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git ../depot_tools |
|||
|
|||
- name: Checkout breakpad |
|||
run: | |
|||
set -xe |
|||
PATH+=:$PWD/../depot_tools |
|||
gclient config --unmanaged --name=src https://github.com/${{ github.repository }} |
|||
gclient sync --no-history --nohooks |
|||
|
|||
# First build & test in-tree. |
|||
- run: ./configure --disable-silent-rules |
|||
working-directory: src |
|||
- run: make -j$(getconf _NPROCESSORS_CONF) |
|||
working-directory: src |
|||
- run: make -j$(getconf _NPROCESSORS_CONF) check VERBOSE=1 |
|||
working-directory: src |
|||
- run: make -j$(getconf _NPROCESSORS_CONF) distclean |
|||
working-directory: src |
|||
|
|||
# Then build & test out-of-tree. |
|||
- run: mkdir -p src/build/native |
|||
- run: ../../configure --disable-silent-rules |
|||
working-directory: src/build/native |
|||
- run: make -j$(getconf _NPROCESSORS_CONF) distcheck VERBOSE=1 |
|||
working-directory: src/build/native |
|||
@ -0,0 +1,22 @@ |
|||
# GitHub actions workflow. |
|||
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions |
|||
|
|||
# https://github.com/superbrothers/close-pull-request |
|||
name: Close Pull Request |
|||
|
|||
on: |
|||
pull_request_target: |
|||
types: [opened] |
|||
|
|||
jobs: |
|||
run: |
|||
runs-on: ubuntu-latest |
|||
steps: |
|||
- uses: superbrothers/close-pull-request@v3 |
|||
with: |
|||
comment: > |
|||
Thanks for your contribution! |
|||
Unfortunately, we don't use GitHub pull requests to manage code |
|||
contributions to this repository. |
|||
Instead, please see [README.md](../blob/HEAD/README.md) which |
|||
provides full instructions on how to get involved. |
|||
@ -0,0 +1,43 @@ |
|||
# GitHub actions workflow. |
|||
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions |
|||
|
|||
# https://scan.coverity.com/projects/google-breakpad |
|||
name: Coverity Scan |
|||
|
|||
on: |
|||
push: |
|||
branches: [main] |
|||
|
|||
schedule: |
|||
# The GH mirroring from Google GoB does not trigger push actions. |
|||
# Fire it once a week to provide some coverage. |
|||
- cron: '39 2 * * WED' |
|||
|
|||
# Allow for manual triggers from the web. |
|||
workflow_dispatch: |
|||
|
|||
jobs: |
|||
coverity: |
|||
runs-on: ubuntu-latest |
|||
env: |
|||
CC: clang |
|||
CXX: clang++ |
|||
steps: |
|||
- name: Checkout depot_tools |
|||
run: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git ../depot_tools |
|||
|
|||
- name: Checkout breakpad |
|||
run: | |
|||
set -xe |
|||
PATH+=:$PWD/../depot_tools |
|||
gclient config --unmanaged --name=src https://github.com/${{ github.repository }} |
|||
gclient sync --no-history --nohooks |
|||
|
|||
- run: ./configure --disable-silent-rules |
|||
working-directory: src |
|||
|
|||
- uses: vapier/coverity-scan-action@v1 |
|||
with: |
|||
command: make -C src -O -j$(getconf _NPROCESSORS_CONF) |
|||
email: ${{ secrets.COVERITY_SCAN_EMAIL }} |
|||
token: ${{ secrets.COVERITY_SCAN_TOKEN }} |
|||
@ -0,0 +1,90 @@ |
|||
# Copyright 2014 Google LLC |
|||
# |
|||
# Redistribution and use in source and binary forms, with or without |
|||
# modification, are permitted provided that the following conditions are |
|||
# met: |
|||
# |
|||
# * Redistributions of source code must retain the above copyright |
|||
# notice, this list of conditions and the following disclaimer. |
|||
# * Redistributions in binary form must reproduce the above |
|||
# copyright notice, this list of conditions and the following disclaimer |
|||
# in the documentation and/or other materials provided with the |
|||
# distribution. |
|||
# * Neither the name of Google LLC nor the names of its |
|||
# contributors may be used to endorse or promote products derived from |
|||
# this software without specific prior written permission. |
|||
# |
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
# Ignore other VCSs. |
|||
.repo/ |
|||
.svn/ |
|||
|
|||
# Ignore common compiled artifacts. |
|||
*~ |
|||
*.dwo |
|||
*.o |
|||
lib*.a |
|||
/breakpad.pc |
|||
/breakpad-client.pc |
|||
/src/client/linux/linux_client_unittest_shlib |
|||
/src/client/linux/linux_dumper_unittest_helper |
|||
/src/common/linux/google_crashdump_uploader_test |
|||
/src/processor/microdump_stackwalk |
|||
/src/processor/minidump_dump |
|||
/src/processor/minidump_stackwalk |
|||
/src/tools/linux/core2md/core2md |
|||
/src/tools/linux/core_handler/core_handler |
|||
/src/tools/linux/dump_syms/dump_syms |
|||
/src/tools/linux/md2core/minidump-2-core |
|||
/src/tools/linux/pid2md/pid2md |
|||
/src/tools/linux/symupload/minidump_upload |
|||
/src/tools/linux/symupload/sym_upload |
|||
/src/tools/mac/dump_syms/dump_syms |
|||
/src/tools/mac/dump_syms/dump_syms_mac |
|||
|
|||
# Ignore unit test artifacts. |
|||
*_unittest |
|||
*.log |
|||
*.trs |
|||
|
|||
# Ignore autotools generated artifacts. |
|||
.deps |
|||
.dirstamp |
|||
autom4te.cache/ |
|||
/config.cache |
|||
config.h |
|||
/config.log |
|||
/config.status |
|||
/Makefile |
|||
stamp-h1 |
|||
|
|||
# Ignore generated Visual Studio artifacts. |
|||
*.filters |
|||
*.sdf |
|||
*.sln |
|||
*.suo |
|||
*.vcproj |
|||
*.vcxproj |
|||
|
|||
# Ignore generated Makefiles |
|||
src/Makefile |
|||
*.Makefile |
|||
*.target.mk |
|||
|
|||
# Ignore compiled Python files. |
|||
*.pyc |
|||
|
|||
# Ignore directories gclient syncs. |
|||
src/testing |
|||
src/third_party/protobuf |
|||
@ -0,0 +1 @@ |
|||
opensource@google.com |
|||
@ -0,0 +1,58 @@ |
|||
# Copyright 2010 Google LLC |
|||
# |
|||
# Redistribution and use in source and binary forms, with or without |
|||
# modification, are permitted provided that the following conditions are |
|||
# met: |
|||
# |
|||
# * Redistributions of source code must retain the above copyright |
|||
# notice, this list of conditions and the following disclaimer. |
|||
# * Redistributions in binary form must reproduce the above |
|||
# copyright notice, this list of conditions and the following disclaimer |
|||
# in the documentation and/or other materials provided with the |
|||
# distribution. |
|||
# * Neither the name of Google LLC nor the names of its |
|||
# contributors may be used to endorse or promote products derived from |
|||
# this software without specific prior written permission. |
|||
# |
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
# This is used to mimic the svn:externals mechanism for gclient (both Git and |
|||
# SVN) based checkouts of Breakpad. As such, its use is entirely optional. If |
|||
# using a manually managed SVN checkout as opposed to a gclient managed checkout |
|||
# you can still use the hooks mechanism for generating project files by calling |
|||
# 'gclient runhooks' rather than 'gclient sync'. |
|||
|
|||
deps = { |
|||
# Testing libraries and utilities. |
|||
"src/src/testing": |
|||
"https://github.com/google/googletest.git" + |
|||
"@release-1.11.0", |
|||
|
|||
# Protobuf. |
|||
"src/src/third_party/protobuf/protobuf": |
|||
"https://github.com/google/protobuf.git" + |
|||
"@cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac", |
|||
|
|||
# Linux syscall support. |
|||
"src/src/third_party/lss": |
|||
"https://chromium.googlesource.com/linux-syscall-support/" + |
|||
"@9719c1e1e676814c456b55f5f070eabad6709d31", |
|||
} |
|||
|
|||
hooks = [ |
|||
{ |
|||
# Keep the manifest up to date. |
|||
"action": ["src/src/tools/python/deps-to-manifest.py", |
|||
"src/DEPS", "src/default.xml"], |
|||
}, |
|||
] |
|||
@ -0,0 +1,13 @@ |
|||
# Metadata information for this directory. |
|||
# |
|||
# For more information on DIR_METADATA files, see: |
|||
# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md |
|||
# |
|||
# For the schema of this file, see Metadata message: |
|||
# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto |
|||
|
|||
monorail { |
|||
project: "google-breakpad" |
|||
} |
|||
|
|||
team_email: "google-breakpad-dev@googlegroups.com" |
|||
@ -0,0 +1,370 @@ |
|||
Installation Instructions |
|||
************************* |
|||
|
|||
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, |
|||
Inc. |
|||
|
|||
Copying and distribution of this file, with or without modification, |
|||
are permitted in any medium without royalty provided the copyright |
|||
notice and this notice are preserved. This file is offered as-is, |
|||
without warranty of any kind. |
|||
|
|||
Basic Installation |
|||
================== |
|||
|
|||
Briefly, the shell commands `./configure; make; make install' should |
|||
configure, build, and install this package. The following |
|||
more-detailed instructions are generic; see the `README' file for |
|||
instructions specific to this package. Some packages provide this |
|||
`INSTALL' file but do not implement all of the features documented |
|||
below. The lack of an optional feature in a given package is not |
|||
necessarily a bug. More recommendations for GNU packages can be found |
|||
in *note Makefile Conventions: (standards)Makefile Conventions. |
|||
|
|||
The `configure' shell script attempts to guess correct values for |
|||
various system-dependent variables used during compilation. It uses |
|||
those values to create a `Makefile' in each directory of the package. |
|||
It may also create one or more `.h' files containing system-dependent |
|||
definitions. Finally, it creates a shell script `config.status' that |
|||
you can run in the future to recreate the current configuration, and a |
|||
file `config.log' containing compiler output (useful mainly for |
|||
debugging `configure'). |
|||
|
|||
It can also use an optional file (typically called `config.cache' |
|||
and enabled with `--cache-file=config.cache' or simply `-C') that saves |
|||
the results of its tests to speed up reconfiguring. Caching is |
|||
disabled by default to prevent problems with accidental use of stale |
|||
cache files. |
|||
|
|||
If you need to do unusual things to compile the package, please try |
|||
to figure out how `configure' could check whether to do them, and mail |
|||
diffs or instructions to the address given in the `README' so they can |
|||
be considered for the next release. If you are using the cache, and at |
|||
some point `config.cache' contains results you don't want to keep, you |
|||
may remove or edit it. |
|||
|
|||
The file `configure.ac' (or `configure.in') is used to create |
|||
`configure' by a program called `autoconf'. You need `configure.ac' if |
|||
you want to change it or regenerate `configure' using a newer version |
|||
of `autoconf'. |
|||
|
|||
The simplest way to compile this package is: |
|||
|
|||
1. `cd' to the directory containing the package's source code and type |
|||
`./configure' to configure the package for your system. |
|||
|
|||
Running `configure' might take a while. While running, it prints |
|||
some messages telling which features it is checking for. |
|||
|
|||
2. Type `make' to compile the package. |
|||
|
|||
3. Optionally, type `make check' to run any self-tests that come with |
|||
the package, generally using the just-built uninstalled binaries. |
|||
|
|||
4. Type `make install' to install the programs and any data files and |
|||
documentation. When installing into a prefix owned by root, it is |
|||
recommended that the package be configured and built as a regular |
|||
user, and only the `make install' phase executed with root |
|||
privileges. |
|||
|
|||
5. Optionally, type `make installcheck' to repeat any self-tests, but |
|||
this time using the binaries in their final installed location. |
|||
This target does not install anything. Running this target as a |
|||
regular user, particularly if the prior `make install' required |
|||
root privileges, verifies that the installation completed |
|||
correctly. |
|||
|
|||
6. You can remove the program binaries and object files from the |
|||
source code directory by typing `make clean'. To also remove the |
|||
files that `configure' created (so you can compile the package for |
|||
a different kind of computer), type `make distclean'. There is |
|||
also a `make maintainer-clean' target, but that is intended mainly |
|||
for the package's developers. If you use it, you may have to get |
|||
all sorts of other programs in order to regenerate files that came |
|||
with the distribution. |
|||
|
|||
7. Often, you can also type `make uninstall' to remove the installed |
|||
files again. In practice, not all packages have tested that |
|||
uninstallation works correctly, even though it is required by the |
|||
GNU Coding Standards. |
|||
|
|||
8. Some packages, particularly those that use Automake, provide `make |
|||
distcheck', which can by used by developers to test that all other |
|||
targets like `make install' and `make uninstall' work correctly. |
|||
This target is generally not run by end users. |
|||
|
|||
Compilers and Options |
|||
===================== |
|||
|
|||
Some systems require unusual options for compilation or linking that |
|||
the `configure' script does not know about. Run `./configure --help' |
|||
for details on some of the pertinent environment variables. |
|||
|
|||
You can give `configure' initial values for configuration parameters |
|||
by setting variables in the command line or in the environment. Here |
|||
is an example: |
|||
|
|||
./configure CC=c99 CFLAGS=-g LIBS=-lposix |
|||
|
|||
*Note Defining Variables::, for more details. |
|||
|
|||
Compiling For Multiple Architectures |
|||
==================================== |
|||
|
|||
You can compile the package for more than one kind of computer at the |
|||
same time, by placing the object files for each architecture in their |
|||
own directory. To do this, you can use GNU `make'. `cd' to the |
|||
directory where you want the object files and executables to go and run |
|||
the `configure' script. `configure' automatically checks for the |
|||
source code in the directory that `configure' is in and in `..'. This |
|||
is known as a "VPATH" build. |
|||
|
|||
With a non-GNU `make', it is safer to compile the package for one |
|||
architecture at a time in the source code directory. After you have |
|||
installed the package for one architecture, use `make distclean' before |
|||
reconfiguring for another architecture. |
|||
|
|||
On MacOS X 10.5 and later systems, you can create libraries and |
|||
executables that work on multiple system types--known as "fat" or |
|||
"universal" binaries--by specifying multiple `-arch' options to the |
|||
compiler but only a single `-arch' option to the preprocessor. Like |
|||
this: |
|||
|
|||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ |
|||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ |
|||
CPP="gcc -E" CXXCPP="g++ -E" |
|||
|
|||
This is not guaranteed to produce working output in all cases, you |
|||
may have to build one architecture at a time and combine the results |
|||
using the `lipo' tool if you have problems. |
|||
|
|||
Installation Names |
|||
================== |
|||
|
|||
By default, `make install' installs the package's commands under |
|||
`/usr/local/bin', include files under `/usr/local/include', etc. You |
|||
can specify an installation prefix other than `/usr/local' by giving |
|||
`configure' the option `--prefix=PREFIX', where PREFIX must be an |
|||
absolute file name. |
|||
|
|||
You can specify separate installation prefixes for |
|||
architecture-specific files and architecture-independent files. If you |
|||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses |
|||
PREFIX as the prefix for installing programs and libraries. |
|||
Documentation and other data files still use the regular prefix. |
|||
|
|||
In addition, if you use an unusual directory layout you can give |
|||
options like `--bindir=DIR' to specify different values for particular |
|||
kinds of files. Run `configure --help' for a list of the directories |
|||
you can set and what kinds of files go in them. In general, the |
|||
default for these options is expressed in terms of `${prefix}', so that |
|||
specifying just `--prefix' will affect all of the other directory |
|||
specifications that were not explicitly provided. |
|||
|
|||
The most portable way to affect installation locations is to pass the |
|||
correct locations to `configure'; however, many packages provide one or |
|||
both of the following shortcuts of passing variable assignments to the |
|||
`make install' command line to change installation locations without |
|||
having to reconfigure or recompile. |
|||
|
|||
The first method involves providing an override variable for each |
|||
affected directory. For example, `make install |
|||
prefix=/alternate/directory' will choose an alternate location for all |
|||
directory configuration variables that were expressed in terms of |
|||
`${prefix}'. Any directories that were specified during `configure', |
|||
but not in terms of `${prefix}', must each be overridden at install |
|||
time for the entire installation to be relocated. The approach of |
|||
makefile variable overrides for each directory variable is required by |
|||
the GNU Coding Standards, and ideally causes no recompilation. |
|||
However, some platforms have known limitations with the semantics of |
|||
shared libraries that end up requiring recompilation when using this |
|||
method, particularly noticeable in packages that use GNU Libtool. |
|||
|
|||
The second method involves providing the `DESTDIR' variable. For |
|||
example, `make install DESTDIR=/alternate/directory' will prepend |
|||
`/alternate/directory' before all installation names. The approach of |
|||
`DESTDIR' overrides is not required by the GNU Coding Standards, and |
|||
does not work on platforms that have drive letters. On the other hand, |
|||
it does better at avoiding recompilation issues, and works well even |
|||
when some directory options were not specified in terms of `${prefix}' |
|||
at `configure' time. |
|||
|
|||
Optional Features |
|||
================= |
|||
|
|||
If the package supports it, you can cause programs to be installed |
|||
with an extra prefix or suffix on their names by giving `configure' the |
|||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. |
|||
|
|||
Some packages pay attention to `--enable-FEATURE' options to |
|||
`configure', where FEATURE indicates an optional part of the package. |
|||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE |
|||
is something like `gnu-as' or `x' (for the X Window System). The |
|||
`README' should mention any `--enable-' and `--with-' options that the |
|||
package recognizes. |
|||
|
|||
For packages that use the X Window System, `configure' can usually |
|||
find the X include and library files automatically, but if it doesn't, |
|||
you can use the `configure' options `--x-includes=DIR' and |
|||
`--x-libraries=DIR' to specify their locations. |
|||
|
|||
Some packages offer the ability to configure how verbose the |
|||
execution of `make' will be. For these packages, running `./configure |
|||
--enable-silent-rules' sets the default to minimal output, which can be |
|||
overridden with `make V=1'; while running `./configure |
|||
--disable-silent-rules' sets the default to verbose, which can be |
|||
overridden with `make V=0'. |
|||
|
|||
Particular systems |
|||
================== |
|||
|
|||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU |
|||
CC is not installed, it is recommended to use the following options in |
|||
order to use an ANSI C compiler: |
|||
|
|||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500" |
|||
|
|||
and if that doesn't work, install pre-built binaries of GCC for HP-UX. |
|||
|
|||
HP-UX `make' updates targets which have the same time stamps as |
|||
their prerequisites, which makes it generally unusable when shipped |
|||
generated files such as `configure' are involved. Use GNU `make' |
|||
instead. |
|||
|
|||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot |
|||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as |
|||
a workaround. If GNU CC is not installed, it is therefore recommended |
|||
to try |
|||
|
|||
./configure CC="cc" |
|||
|
|||
and if that doesn't work, try |
|||
|
|||
./configure CC="cc -nodtk" |
|||
|
|||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This |
|||
directory contains several dysfunctional programs; working variants of |
|||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb' |
|||
in your `PATH', put it _after_ `/usr/bin'. |
|||
|
|||
On Haiku, software installed for all users goes in `/boot/common', |
|||
not `/usr/local'. It is recommended to use the following options: |
|||
|
|||
./configure --prefix=/boot/common |
|||
|
|||
Specifying the System Type |
|||
========================== |
|||
|
|||
There may be some features `configure' cannot figure out |
|||
automatically, but needs to determine by the type of machine the package |
|||
will run on. Usually, assuming the package is built to be run on the |
|||
_same_ architectures, `configure' can figure that out, but if it prints |
|||
a message saying it cannot guess the machine type, give it the |
|||
`--build=TYPE' option. TYPE can either be a short name for the system |
|||
type, such as `sun4', or a canonical name which has the form: |
|||
|
|||
CPU-COMPANY-SYSTEM |
|||
|
|||
where SYSTEM can have one of these forms: |
|||
|
|||
OS |
|||
KERNEL-OS |
|||
|
|||
See the file `config.sub' for the possible values of each field. If |
|||
`config.sub' isn't included in this package, then this package doesn't |
|||
need to know the machine type. |
|||
|
|||
If you are _building_ compiler tools for cross-compiling, you should |
|||
use the option `--target=TYPE' to select the type of system they will |
|||
produce code for. |
|||
|
|||
If you want to _use_ a cross compiler, that generates code for a |
|||
platform different from the build platform, you should specify the |
|||
"host" platform (i.e., that on which the generated programs will |
|||
eventually be run) with `--host=TYPE'. |
|||
|
|||
Sharing Defaults |
|||
================ |
|||
|
|||
If you want to set default values for `configure' scripts to share, |
|||
you can create a site shell script called `config.site' that gives |
|||
default values for variables like `CC', `cache_file', and `prefix'. |
|||
`configure' looks for `PREFIX/share/config.site' if it exists, then |
|||
`PREFIX/etc/config.site' if it exists. Or, you can set the |
|||
`CONFIG_SITE' environment variable to the location of the site script. |
|||
A warning: not all `configure' scripts look for a site script. |
|||
|
|||
Defining Variables |
|||
================== |
|||
|
|||
Variables not defined in a site shell script can be set in the |
|||
environment passed to `configure'. However, some packages may run |
|||
configure again during the build, and the customized values of these |
|||
variables may be lost. In order to avoid this problem, you should set |
|||
them in the `configure' command line, using `VAR=value'. For example: |
|||
|
|||
./configure CC=/usr/local2/bin/gcc |
|||
|
|||
causes the specified `gcc' to be used as the C compiler (unless it is |
|||
overridden in the site shell script). |
|||
|
|||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to |
|||
an Autoconf limitation. Until the limitation is lifted, you can use |
|||
this workaround: |
|||
|
|||
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash |
|||
|
|||
`configure' Invocation |
|||
====================== |
|||
|
|||
`configure' recognizes the following options to control how it |
|||
operates. |
|||
|
|||
`--help' |
|||
`-h' |
|||
Print a summary of all of the options to `configure', and exit. |
|||
|
|||
`--help=short' |
|||
`--help=recursive' |
|||
Print a summary of the options unique to this package's |
|||
`configure', and exit. The `short' variant lists options used |
|||
only in the top level, while the `recursive' variant lists options |
|||
also present in any nested packages. |
|||
|
|||
`--version' |
|||
`-V' |
|||
Print the version of Autoconf used to generate the `configure' |
|||
script, and exit. |
|||
|
|||
`--cache-file=FILE' |
|||
Enable the cache: use and save the results of the tests in FILE, |
|||
traditionally `config.cache'. FILE defaults to `/dev/null' to |
|||
disable caching. |
|||
|
|||
`--config-cache' |
|||
`-C' |
|||
Alias for `--cache-file=config.cache'. |
|||
|
|||
`--quiet' |
|||
`--silent' |
|||
`-q' |
|||
Do not print messages saying which checks are being made. To |
|||
suppress all normal output, redirect it to `/dev/null' (any error |
|||
messages will still be shown). |
|||
|
|||
`--srcdir=DIR' |
|||
Look for the package's source code in directory DIR. Usually |
|||
`configure' can determine that directory automatically. |
|||
|
|||
`--prefix=DIR' |
|||
Use DIR as the installation prefix. *note Installation Names:: |
|||
for more details, including other options available for fine-tuning |
|||
the installation locations. |
|||
|
|||
`--no-create' |
|||
`-n' |
|||
Run the configure checks, but stop before creating any output |
|||
files. |
|||
|
|||
`configure' also accepts some other, not widely useful, options. Run |
|||
`configure --help' for more details. |
|||
1068
externals/breakpad/LICENSE
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1794
externals/breakpad/Makefile.am
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
10322
externals/breakpad/Makefile.in
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,13 @@ |
|||
# Sorted alphabetically. |
|||
# Please see README.md for contact info. |
|||
|
|||
ivanpe@chromium.org |
|||
jperaza@chromium.org |
|||
mark@chromium.org |
|||
nbilling@google.com |
|||
primiano@chromium.org |
|||
saugustine@google.com |
|||
rsesek@chromium.org |
|||
ted@mielczarek.org |
|||
thestig@chromium.org |
|||
vapier@chromium.org |
|||
@ -0,0 +1,139 @@ |
|||
Google Breakpad for Android |
|||
=========================== |
|||
|
|||
This document explains how to use the Google Breakpad client library |
|||
on Android, and later generate valid stack traces from the minidumps |
|||
it generates. |
|||
|
|||
This release supports ARM, x86 and MIPS based Android systems. |
|||
This release requires NDK release r11c or higher. |
|||
|
|||
I. Building the client library: |
|||
=============================== |
|||
|
|||
The Android client is built as a static library that you can |
|||
link into your own Android native code. There are two ways to |
|||
build it: |
|||
|
|||
I.1. Building with ndk-build: |
|||
----------------------------- |
|||
|
|||
If you're using the ndk-build build system, you can follow |
|||
these simple steps: |
|||
|
|||
1/ Include android/google_breakpad/Android.mk from your own |
|||
project's Android.mk |
|||
|
|||
This can be done either directly, or using ndk-build's |
|||
import-module feature. |
|||
|
|||
2/ Link the library to one of your modules by using: |
|||
|
|||
LOCAL_STATIC_LIBRARIES += breakpad_client |
|||
|
|||
NOTE: The client library requires a C++ STL implementation, |
|||
which you can select with APP_STL in your Application.mk |
|||
|
|||
It has been tested succesfully with both STLport and GNU libstdc++ |
|||
|
|||
|
|||
I.2. Building with a standalone Android toolchain: |
|||
-------------------------------------------------- |
|||
|
|||
All you need to do is configure your build with the right 'host' |
|||
value, and disable the processor and tools, as in: |
|||
|
|||
$GOOGLE_BREAKPAD_PATH/configure --host=arm-linux-androideabi \ |
|||
--disable-processor \ |
|||
--disable-tools |
|||
make -j4 |
|||
|
|||
The library will be under src/client/linux/libbreakpad_client.a |
|||
|
|||
You can also use 'make check' to run the test suite on a connected |
|||
Android device. This requires the Android 'adb' tool to be in your |
|||
path. |
|||
|
|||
II. Using the client library in Android: |
|||
======================================== |
|||
|
|||
The usage instructions are very similar to the Linux ones that are |
|||
found at https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/linux_starter_guide.md |
|||
|
|||
1/ You need to include "client/linux/handler/exception_handler.h" from a C++ |
|||
source file. |
|||
|
|||
2/ If you're not using ndk-build, you also need to: |
|||
|
|||
- add the following to your compiler include search paths: |
|||
$GOOGLE_BREAKPAD_PATH/src |
|||
$GOOGLE_BREAKPAD_PATH/src/common/android/include |
|||
|
|||
- add -llog to your linker flags |
|||
|
|||
Note that ndk-build does that for your automatically. |
|||
|
|||
3/ Keep in mind that there is no /tmp directory on Android. |
|||
|
|||
If you use the library from a regular Android applications, specify a |
|||
path under your app-specific storage directory. An alternative is to |
|||
store them on the SDCard, but this requires a specific permission. |
|||
|
|||
For a concrete example, see the sample test application under |
|||
android/sample_app. See its README for more information. |
|||
|
|||
|
|||
III. Getting a stack trace on the host: |
|||
======================================= |
|||
|
|||
This process is similar to other platforms, but here's a quick example: |
|||
|
|||
1/ Retrieve the minidumps on your development machine. |
|||
|
|||
2/ Dump the symbols for your native libraries with the 'dump_syms' tool. |
|||
This first requires building the host version of Google Breakpad, then |
|||
calling: |
|||
|
|||
dump_syms $PROJECT_PATH/obj/local/$ABI/libfoo.so > libfoo.so.sym |
|||
|
|||
3/ Create the symbol directory hierarchy. |
|||
|
|||
The first line of the generated libfoo.so.sym will have a "MODULE" |
|||
entry that carries a hexadecimal version number, e.g.: |
|||
|
|||
MODULE Linux arm D51B4A5504974FA6ECC1869CAEE3603B0 test_google_breakpad |
|||
|
|||
Note: The second field could be either 'Linux' or 'Android'. |
|||
|
|||
Extract the version number, and a 'symbol' directory, for example: |
|||
|
|||
$PROJECT_PATH/symbols/libfoo.so/$VERSION/ |
|||
|
|||
Copy/Move your libfoo.sym file there. |
|||
|
|||
4/ Invoke minidump_stackwalk to create the stack trace: |
|||
|
|||
minidump_stackwalk $MINIDUMP_FILE $PROJECT_PATH/symbols |
|||
|
|||
Note that various helper scripts can be found on the web to automate these |
|||
steps. |
|||
|
|||
IV. Verifying the Android build library: |
|||
======================================== |
|||
|
|||
If you modify Google Breakpad and want to check that it still works correctly |
|||
on Android, please run the android/run-checks.sh script which will do all |
|||
necessary verifications for you. This includes: |
|||
|
|||
- Rebuilding the full host binaries. |
|||
- Rebuilding the full Android binaries with configure/make. |
|||
- Rebuilding the client library unit tests, and running them on a device. |
|||
- Rebuilding the client library with ndk-build. |
|||
- Building, installing and running a test crasher program on a device. |
|||
- Extracting the corresponding minidump, dumping the test program symbols |
|||
and generating a stack trace. |
|||
- Checking the generated stack trace for valid source locations. |
|||
|
|||
For more details, please run: |
|||
|
|||
android/run-checks.sh --help-all |
|||
@ -0,0 +1,82 @@ |
|||
# Breakpad |
|||
|
|||
Breakpad is a set of client and server components which implement a |
|||
crash-reporting system. |
|||
|
|||
* [Homepage](https://chromium.googlesource.com/breakpad/breakpad/) |
|||
* [Documentation](./docs/) |
|||
* [Bugs](https://bugs.chromium.org/p/google-breakpad/) |
|||
* Discussion/Questions: [google-breakpad-discuss@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-discuss) |
|||
* Developer/Reviews: [google-breakpad-dev@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-dev) |
|||
* Tests: [](https://github.com/google/breakpad/actions/workflows/build-test-ci.yml) [](https://ci.appveyor.com/project/vapier/breakpad) |
|||
* Coverage [](https://scan.coverity.com/projects/google-breakpad) |
|||
|
|||
## Getting started (from main) |
|||
|
|||
1. First, [download depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools) |
|||
and ensure that they’re in your `PATH`. |
|||
|
|||
2. Create a new directory for checking out the source code (it must be named |
|||
breakpad). |
|||
|
|||
```sh |
|||
mkdir breakpad && cd breakpad |
|||
``` |
|||
|
|||
3. Run the `fetch` tool from depot_tools to download all the source repos. |
|||
|
|||
```sh |
|||
fetch breakpad |
|||
cd src |
|||
``` |
|||
|
|||
4. Build the source. |
|||
|
|||
```sh |
|||
./configure && make |
|||
``` |
|||
|
|||
You can also cd to another directory and run configure from there to build |
|||
outside the source tree. |
|||
|
|||
This will build the processor tools (`src/processor/minidump_stackwalk`, |
|||
`src/processor/minidump_dump`, etc), and when building on Linux it will |
|||
also build the client libraries and some tools |
|||
(`src/tools/linux/dump_syms/dump_syms`, |
|||
`src/tools/linux/md2core/minidump-2-core`, etc). |
|||
|
|||
5. Optionally, run tests. |
|||
|
|||
```sh |
|||
make check |
|||
``` |
|||
|
|||
6. Optionally, install the built libraries |
|||
|
|||
```sh |
|||
make install |
|||
``` |
|||
|
|||
If you need to reconfigure your build be sure to run `make distclean` first. |
|||
|
|||
To update an existing checkout to a newer revision, you can |
|||
`git pull` as usual, but then you should run `gclient sync` to ensure that the |
|||
dependent repos are up-to-date. |
|||
|
|||
## To request change review |
|||
|
|||
1. Follow the steps above to get the source and build it. |
|||
|
|||
2. Make changes. Build and test your changes. |
|||
For core code like processor use methods above. |
|||
For linux/mac/windows, there are test targets in each project file. |
|||
|
|||
3. Commit your changes to your local repo and upload them to the server. |
|||
http://dev.chromium.org/developers/contributing-code |
|||
e.g. `git commit ... && git cl upload ...` |
|||
You will be prompted for credential and a description. |
|||
|
|||
4. At https://chromium-review.googlesource.com/ you'll find your issue listed; |
|||
click on it, then “Add reviewer”, and enter in the code reviewer. Depending |
|||
on your settings, you may not see an email, but the reviewer has been |
|||
notified with google-breakpad-dev@googlegroups.com always CC’d. |
|||
1273
externals/breakpad/aclocal.m4
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,371 @@ |
|||
# Copyright 2012 Google LLC |
|||
# |
|||
# Redistribution and use in source and binary forms, with or without |
|||
# modification, are permitted provided that the following conditions are |
|||
# met: |
|||
# |
|||
# * Redistributions of source code must retain the above copyright |
|||
# notice, this list of conditions and the following disclaimer. |
|||
# * Redistributions in binary form must reproduce the above |
|||
# copyright notice, this list of conditions and the following disclaimer |
|||
# in the documentation and/or other materials provided with the |
|||
# distribution. |
|||
# * Neither the name of Google LLC nor the names of its |
|||
# contributors may be used to endorse or promote products derived from |
|||
# this software without specific prior written permission. |
|||
# |
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
# Collection of common shell functions for 'run-checks.sh' et 'test-shell.sh' |
|||
|
|||
# All internal variables and functions use an underscore as a prefix |
|||
# (e.g. _VERBOSE, _ALL_CLEANUPS, etc..). |
|||
|
|||
# Sanitize the environment |
|||
export LANG=C |
|||
export LC_ALL=C |
|||
|
|||
if [ "$BASH_VERSION" ]; then |
|||
set -o posix |
|||
fi |
|||
|
|||
# Utility functions |
|||
|
|||
_ALL_CLEANUPS= |
|||
|
|||
# Register a function to be called when the script exits, even in case of |
|||
# Ctrl-C, logout, etc. |
|||
# $1: function name. |
|||
atexit () { |
|||
if [ -z "$_ALL_CLEANUPS" ]; then |
|||
_ALL_CLEANUPS=$1 |
|||
# Ensure a clean exit when the script is: |
|||
# - Exiting normally (EXIT) |
|||
# - Interrupted by Ctrl-C (INT) |
|||
# - Interrupted by log out (HUP) |
|||
# - Being asked to quit nicely (TERM) |
|||
# - Being asked to quit and dump core (QUIT) |
|||
trap "_exit_cleanups \$?" EXIT INT HUP QUIT TERM |
|||
else |
|||
_ALL_CLEANUPS="$_ALL_CLEANUPS $1" |
|||
fi |
|||
} |
|||
|
|||
# Called on exit if at least one function was registered with atexit |
|||
# $1: final exit status code |
|||
_exit_cleanups () { |
|||
local CLEANUP CLEANUPS |
|||
# Ignore calls to atexit during cleanups |
|||
CLEANUPS=$_ALL_CLEANUPS |
|||
_ALL_CLEANUPS= |
|||
for CLEANUP in $CLEANUPS; do |
|||
($CLEANUP) |
|||
done |
|||
exit "$@" |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
# Dump a panic message then exit. |
|||
# $1+: message |
|||
panic () { |
|||
echo "ERROR: $@" >&2 |
|||
exit 1 |
|||
} |
|||
|
|||
# If the previous command failed, dump a panic message then exit. |
|||
# $1+: message. |
|||
fail_panic () { |
|||
if [ $? != 0 ]; then |
|||
panic "$@" |
|||
fi; |
|||
} |
|||
|
|||
_VERBOSE=0 |
|||
|
|||
# Increase verbosity for dump/log/run/run2 functions |
|||
increase_verbosity () { |
|||
_VERBOSE=$(( $_VERBOSE + 1 )) |
|||
} |
|||
|
|||
# Decrease verbosity |
|||
decrease_verbosity () { |
|||
_VERBOSE=$(( $_VERBOSE - 1 )) |
|||
} |
|||
|
|||
# Returns success iff verbosity level is higher than a specific value |
|||
# $1: verbosity level |
|||
verbosity_is_higher_than () { |
|||
[ "$_VERBOSE" -gt "$1" ] |
|||
} |
|||
|
|||
# Returns success iff verbosity level is lower than a specific value |
|||
# $1: verbosity level |
|||
verbosity_is_lower_than () { |
|||
[ "$_VERBOSE" -le "$1" ] |
|||
} |
|||
|
|||
# Dump message to stdout, unless verbosity is < 0, i.e. --quiet was called |
|||
# $1+: message |
|||
dump () { |
|||
if [ "$_VERBOSE" -ge 0 ]; then |
|||
printf "%s\n" "$*" |
|||
fi |
|||
} |
|||
|
|||
# If --verbose was used, dump a message to stdout. |
|||
# $1+: message |
|||
log () { |
|||
if [ "$_VERBOSE" -ge 1 ]; then |
|||
printf "%s\n" "$*" |
|||
fi |
|||
} |
|||
|
|||
_RUN_LOG= |
|||
|
|||
# Set a run log file that can be used to collect the output of commands that |
|||
# are not displayed. |
|||
set_run_log () { |
|||
_RUN_LOG=$1 |
|||
} |
|||
|
|||
# Run a command. Output depends on $_VERBOSE: |
|||
# $_VERBOSE <= 0: Run command, store output into the run log |
|||
# $_VERBOSE >= 1: Dump command, run it, output goest to stdout |
|||
# Note: Ideally, the command's output would go to the run log for $_VERBOSE >= 1 |
|||
# but the 'tee' tool doesn't preserve the status code of its input pipe |
|||
# in case of error. |
|||
run () { |
|||
local LOGILE |
|||
if [ "$_RUN_LOG" ]; then |
|||
LOGFILE=$_RUN_LOG |
|||
else |
|||
LOGFILE=/dev/null |
|||
fi |
|||
|
|||
if [ "$_VERBOSE" -ge 1 ]; then |
|||
echo "COMMAND: $@" |
|||
"$@" |
|||
else |
|||
"$@" >>$LOGFILE 2>&1 |
|||
fi |
|||
} |
|||
|
|||
# Same as run(), but only dump command output for $_VERBOSE >= 2 |
|||
run2 () { |
|||
local LOGILE |
|||
if [ "$_RUN_LOG" ]; then |
|||
LOGFILE=$_RUN_LOG |
|||
else |
|||
LOGFILE=/dev/null |
|||
fi |
|||
|
|||
if [ "$_VERBOSE" -ge 1 ]; then |
|||
echo "COMMAND: $@" |
|||
fi |
|||
if [ "$_VERBOSE" -ge 2 ]; then |
|||
"$@" |
|||
else |
|||
"$@" >>$LOGFILE 2>&1 |
|||
fi |
|||
} |
|||
|
|||
# Extract number of cores to speed up the builds |
|||
# Out: number of CPU cores |
|||
get_core_count () { |
|||
case $(uname -s) in |
|||
Linux) |
|||
grep -c -e '^processor' /proc/cpuinfo |
|||
;; |
|||
Darwin) |
|||
sysctl -n hw.ncpu |
|||
;; |
|||
CYGWIN*|*_NT-*) |
|||
echo $NUMBER_OF_PROCESSORS |
|||
;; |
|||
*) |
|||
echo 1 |
|||
;; |
|||
esac |
|||
} |
|||
|
|||
|
|||
# Check for the Android ADB program. |
|||
# |
|||
# On success, return nothing, but updates internal variables so later calls to |
|||
# adb_shell, adb_push, etc.. will work. You can get the path to the ADB program |
|||
# with adb_get_program if needed. |
|||
# |
|||
# On failure, returns 1, and updates the internal adb error message, which can |
|||
# be retrieved with adb_get_error. |
|||
# |
|||
# $1: optional ADB program path. |
|||
# Return: success or failure. |
|||
_ADB= |
|||
_ADB_STATUS= |
|||
_ADB_ERROR= |
|||
|
|||
adb_check () { |
|||
# First, try to find the executable in the path, or the SDK install dir. |
|||
_ADB=$1 |
|||
if [ -z "$_ADB" ]; then |
|||
_ADB=$(which adb 2>/dev/null) |
|||
if [ -z "$_ADB" -a "$ANDROID_SDK_ROOT" ]; then |
|||
_ADB=$ANDROID_SDK_ROOT/platform-tools/adb |
|||
if [ ! -f "$_ADB" ]; then |
|||
_ADB= |
|||
fi |
|||
fi |
|||
if [ -z "$_ADB" ]; then |
|||
_ADB_STATUS=1 |
|||
_ADB_ERROR="The Android 'adb' tool is not in your path." |
|||
return 1 |
|||
fi |
|||
fi |
|||
|
|||
log "Found ADB program: $_ADB" |
|||
|
|||
# Check that it works correctly |
|||
local ADB_VERSION |
|||
ADB_VERSION=$("$_ADB" version 2>/dev/null) |
|||
case $ADB_VERSION in |
|||
"Android Debug Bridge "*) # Pass |
|||
log "Found ADB version: $ADB_VERSION" |
|||
;; |
|||
*) # Fail |
|||
_ADB_ERROR="Your ADB binary reports a bad version ($ADB_VERSION): $_ADB" |
|||
_ADB_STATUS=1 |
|||
return 1 |
|||
esac |
|||
|
|||
_ADB_STATUS=0 |
|||
return 0 |
|||
} |
|||
|
|||
|
|||
# Return the path to the Android ADB program, if correctly detected. |
|||
# On failure, return the empty string. |
|||
# Out: ADB program path (or empty on failure) |
|||
# Return: success or failure. |
|||
adb_get_program () { |
|||
# Return cached value as soon as possible. |
|||
if [ -z "$_ADB_STATUS" ]; then |
|||
adb_check $1 |
|||
fi |
|||
echo "$_ADB" |
|||
return $_ADB_STATUS |
|||
} |
|||
|
|||
# Return the error corresponding to the last ADB function failure. |
|||
adb_get_error () { |
|||
echo "$_ADB_ERROR" |
|||
} |
|||
|
|||
# Check that there is one device connected through ADB. |
|||
# In case of failure, use adb_get_error to know why this failed. |
|||
# $1: Optional adb program path |
|||
# Return: success or failure. |
|||
_ADB_DEVICE= |
|||
_ADB_DEVICE_STATUS= |
|||
adb_check_device () { |
|||
if [ "$_ADB_DEVICE_STATUS" ]; then |
|||
return $_ADB_DEVICE_STATUS |
|||
fi |
|||
|
|||
# Check for ADB. |
|||
if ! adb_check $1; then |
|||
_ADB_DEVICE_STATUS=$_ADB_STATUS |
|||
return 1 |
|||
fi |
|||
|
|||
local ADB_DEVICES NUM_DEVICES FINGERPRINT |
|||
|
|||
# Count the number of connected devices. |
|||
ADB_DEVICES=$("$_ADB" devices 2>/dev/null | awk '$2 == "device" { print $1; }') |
|||
NUM_DEVICES=$(echo "$ADB_DEVICES" | wc -l) |
|||
case $NUM_DEVICES in |
|||
0) |
|||
_ADB_ERROR="No Android device connected. Please connect one to your machine." |
|||
_ADB_DEVICE_STATUS=1 |
|||
return 1 |
|||
;; |
|||
1) # Pass |
|||
# Ensure the same device will be called in later adb_shell calls. |
|||
export ANDROID_SERIAL=$ADB_DEVICES |
|||
;; |
|||
*) # 2 or more devices. |
|||
if [ "$ANDROID_SERIAL" ]; then |
|||
ADB_DEVICES=$ANDROID_SERIAL |
|||
NUM_DEVICES=1 |
|||
else |
|||
_ADB_ERROR="More than one Android device connected. \ |
|||
Please define ANDROID_SERIAL in your environment" |
|||
_ADB_DEVICE_STATUS=1 |
|||
return 1 |
|||
fi |
|||
;; |
|||
esac |
|||
|
|||
_ADB_DEVICE_STATUS=0 |
|||
_ADB_DEVICE=$ADB_DEVICES |
|||
|
|||
FINGERPRINT=$(adb_shell getprop ro.build.fingerprint) |
|||
log "Using ADB device: $ANDROID_SERIAL ($FINGERPRINT)" |
|||
return 0 |
|||
} |
|||
|
|||
# The 'adb shell' command is pretty hopeless, try to make sense of it by: |
|||
# 1/ Removing trailing \r from line endings. |
|||
# 2/ Ensuring the function returns the command's status code. |
|||
# |
|||
# $1+: Command |
|||
# Out: command output (stdout + stderr combined) |
|||
# Return: command exit status |
|||
adb_shell () { |
|||
local RET ADB_LOG |
|||
# Check for ADB device. |
|||
adb_check_device || return 1 |
|||
ADB_LOG=$(mktemp "${TMPDIR:-/tmp}/adb-XXXXXXXX") |
|||
"$_ADB" shell "$@" ";" echo \$? > "$ADB_LOG" 2>&1 |
|||
sed -i -e 's![[:cntrl:]]!!g' "$ADB_LOG" # Remove \r. |
|||
RET=$(sed -e '$!d' "$ADB_LOG") # Last line contains status code. |
|||
sed -e '$d' "$ADB_LOG" # Print everything except last line. |
|||
rm -f "$ADB_LOG" |
|||
return $RET |
|||
} |
|||
|
|||
# Push a file to a device. |
|||
# $1: source file path |
|||
# $2: device target file path |
|||
# Return: success or failure. |
|||
adb_push () { |
|||
adb_check_device || return 1 |
|||
run "$_ADB" push "$1" "$2" |
|||
} |
|||
|
|||
# Pull a file from a device |
|||
# $1: device file path |
|||
# $2: target host file path |
|||
# Return: success or failure. |
|||
adb_pull () { |
|||
adb_check_device || return 1 |
|||
run "$_ADB" pull "$1" "$2" |
|||
} |
|||
|
|||
# Same as adb_push, but will panic if the operations didn't succeed. |
|||
adb_install () { |
|||
adb_push "$@" |
|||
fail_panic "Failed to install $1 to the Android device at $2" |
|||
} |
|||
|
|||
@ -0,0 +1,104 @@ |
|||
# Copyright 2012 Google LLC
|
|||
#
|
|||
# Redistribution and use in source and binary forms, with or without
|
|||
# modification, are permitted provided that the following conditions are
|
|||
# met:
|
|||
#
|
|||
# * Redistributions of source code must retain the above copyright
|
|||
# notice, this list of conditions and the following disclaimer.
|
|||
# * Redistributions in binary form must reproduce the above
|
|||
# copyright notice, this list of conditions and the following disclaimer
|
|||
# in the documentation and/or other materials provided with the
|
|||
# distribution.
|
|||
# * Neither the name of Google LLC nor the names of its
|
|||
# contributors may be used to endorse or promote products derived from
|
|||
# this software without specific prior written permission.
|
|||
#
|
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
# ndk-build module definition for the Google Breakpad client library
|
|||
#
|
|||
# To use this file, do the following:
|
|||
#
|
|||
# 1/ Include this file from your own Android.mk, either directly
|
|||
# or with through the NDK's import-module function.
|
|||
#
|
|||
# 2/ Use the client static library in your project with:
|
|||
#
|
|||
# LOCAL_STATIC_LIBRARIES += breakpad_client
|
|||
#
|
|||
# 3/ In your source code, include "src/client/linux/exception_handler.h"
|
|||
# and use the Linux instructions to use it.
|
|||
#
|
|||
# This module works with either the STLport or GNU libstdc++, but you need
|
|||
# to select one in your Application.mk
|
|||
#
|
|||
|
|||
# The top Google Breakpad directory.
|
|||
# We assume this Android.mk to be under 'android/google_breakpad'
|
|||
|
|||
LOCAL_PATH := $(call my-dir)/../.. |
|||
|
|||
# Defube the client library module, as a simple static library that
|
|||
# exports the right include path / linker flags to its users.
|
|||
|
|||
include $(CLEAR_VARS) |
|||
|
|||
LOCAL_MODULE := breakpad_client |
|||
|
|||
LOCAL_CPP_EXTENSION := .cc |
|||
|
|||
# Breakpad uses inline ARM assembly that requires the library
|
|||
# to be built in ARM mode. Otherwise, the build will fail with
|
|||
# cryptic assembler messages like:
|
|||
# Compile++ thumb : google_breakpad_client <= crash_generation_client.cc
|
|||
# /tmp/cc8aMSoD.s: Assembler messages:
|
|||
# /tmp/cc8aMSoD.s:132: Error: invalid immediate: 288 is out of range
|
|||
# /tmp/cc8aMSoD.s:244: Error: invalid immediate: 296 is out of range
|
|||
LOCAL_ARM_MODE := arm |
|||
|
|||
# List of client source files, directly taken from Makefile.am
|
|||
LOCAL_SRC_FILES := \
|
|||
src/client/linux/crash_generation/crash_generation_client.cc \
|
|||
src/client/linux/dump_writer_common/thread_info.cc \
|
|||
src/client/linux/dump_writer_common/ucontext_reader.cc \
|
|||
src/client/linux/handler/exception_handler.cc \
|
|||
src/client/linux/handler/minidump_descriptor.cc \
|
|||
src/client/linux/log/log.cc \
|
|||
src/client/linux/microdump_writer/microdump_writer.cc \
|
|||
src/client/linux/minidump_writer/linux_dumper.cc \
|
|||
src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
|
|||
src/client/linux/minidump_writer/minidump_writer.cc \
|
|||
src/client/linux/minidump_writer/pe_file.cc \
|
|||
src/client/minidump_file_writer.cc \
|
|||
src/common/convert_UTF.cc \
|
|||
src/common/md5.cc \
|
|||
src/common/string_conversion.cc \
|
|||
src/common/linux/breakpad_getcontext.S \
|
|||
src/common/linux/elfutils.cc \
|
|||
src/common/linux/file_id.cc \
|
|||
src/common/linux/guid_creator.cc \
|
|||
src/common/linux/linux_libc_support.cc \
|
|||
src/common/linux/memory_mapped_file.cc \
|
|||
src/common/linux/safe_readlink.cc |
|||
|
|||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src/common/android/include \
|
|||
$(LOCAL_PATH)/src \
|
|||
$(LSS_PATH) |
|||
|
|||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) |
|||
LOCAL_EXPORT_LDLIBS := -llog |
|||
|
|||
include $(BUILD_STATIC_LIBRARY) |
|||
|
|||
# Done.
|
|||
@ -0,0 +1,554 @@ |
|||
#!/bin/sh |
|||
# Copyright 2012 Google LLC |
|||
# |
|||
# Redistribution and use in source and binary forms, with or without |
|||
# modification, are permitted provided that the following conditions are |
|||
# met: |
|||
# |
|||
# * Redistributions of source code must retain the above copyright |
|||
# notice, this list of conditions and the following disclaimer. |
|||
# * Redistributions in binary form must reproduce the above |
|||
# copyright notice, this list of conditions and the following disclaimer |
|||
# in the documentation and/or other materials provided with the |
|||
# distribution. |
|||
# * Neither the name of Google LLC nor the names of its |
|||
# contributors may be used to endorse or promote products derived from |
|||
# this software without specific prior written permission. |
|||
# |
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
# Sanitize the environment |
|||
export LANG=C |
|||
export LC_ALL=C |
|||
|
|||
if [ "$BASH_VERSION" ]; then |
|||
set -o posix |
|||
fi |
|||
|
|||
PROGDIR=$(dirname "$0") |
|||
PROGDIR=$(cd "$PROGDIR" && pwd) |
|||
PROGNAME=$(basename "$0") |
|||
|
|||
. $PROGDIR/common-functions.sh |
|||
|
|||
DEFAULT_ABI="armeabi" |
|||
VALID_ABIS="armeabi armeabi-v7a x86 mips" |
|||
|
|||
ABI= |
|||
ADB= |
|||
ALL_TESTS= |
|||
ENABLE_M32= |
|||
HELP= |
|||
HELP_ALL= |
|||
NDK_DIR= |
|||
NO_CLEANUP= |
|||
NO_DEVICE= |
|||
NUM_JOBS=$(get_core_count) |
|||
TMPDIR= |
|||
|
|||
for opt do |
|||
# The following extracts the value if the option is like --name=<value>. |
|||
optarg=$(expr -- $opt : '^--[^=]*=\(.*\)$') |
|||
case $opt in |
|||
--abi=*) ABI=$optarg;; |
|||
--adb=*) ADB=$optarg;; |
|||
--all-tests) ALL_TESTS=true;; |
|||
--enable-m32) ENABLE_M32=true;; |
|||
--help|-h|-?) HELP=TRUE;; |
|||
--help-all) HELP_ALL=true;; |
|||
--jobs=*) NUM_JOBS=$optarg;; |
|||
--ndk-dir=*) NDK_DIR=$optarg;; |
|||
--tmp-dir=*) TMPDIR=$optarg;; |
|||
--no-cleanup) NO_CLEANUP=true;; |
|||
--no-device) NO_DEVICE=true;; |
|||
--quiet) decrease_verbosity;; |
|||
--verbose) increase_verbosity;; |
|||
-*) panic "Invalid option '$opt', see --help for details.";; |
|||
*) panic "This script doesn't take any parameters. See --help for details." |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
if [ "$HELP" -o "$HELP_ALL" ]; then |
|||
echo "\ |
|||
Usage: $PROGNAME [options] |
|||
|
|||
This script is used to check that your Google Breakpad source tree can |
|||
be properly built for Android, and that the client library and host tools |
|||
work properly together. |
|||
" |
|||
if [ "$HELP_ALL" ]; then |
|||
echo "\ |
|||
In more details, this script will: |
|||
|
|||
- Rebuild the host version of Google Breakpad in a temporary |
|||
directory (with the Auto-tools based build system). |
|||
|
|||
- Rebuild the Android client library with the Google Breakpad build |
|||
system (using autotools/configure). This requires that you define |
|||
ANDROID_NDK_ROOT in your environment to point to a valid Android NDK |
|||
installation directory, or use the --ndk-dir=<path> option. |
|||
|
|||
- Rebuild the Android client library and a test crashing program with the |
|||
Android NDK build system (ndk-build). |
|||
|
|||
- Require an Android device connected to your machine, and the 'adb' |
|||
tool in your path. They are used to: |
|||
|
|||
- Install and run a test crashing program. |
|||
- Extract the corresponding minidump from the device. |
|||
- Dump the symbols from the test program on the host with 'dump_syms' |
|||
- Generate a stack trace with 'minidump_stackwalk' |
|||
- Check the stack trace content for valid source file locations. |
|||
|
|||
You can however skip this requirement and only test the builds by using |
|||
the --no-device flag. |
|||
|
|||
By default, all generated files will be created in a temporary directory |
|||
that is removed when the script completion. If you want to inspect the |
|||
files, use the --no-cleanup option. |
|||
|
|||
Finally, use --verbose to increase the verbosity level, this will help |
|||
you see which exact commands are being issues and their result. Use the |
|||
flag twice for even more output. Use --quiet to decrease verbosity |
|||
instead and run the script silently. |
|||
|
|||
If you have a device connected, the script will probe it to determine |
|||
its primary CPU ABI, and build the test program for it. You can however |
|||
use the --abi=<name> option to override this (this can be useful to check |
|||
the secondary ABI, e.g. using --abi=armeabi to check that such a program |
|||
works correctly on an ARMv7-A device). |
|||
|
|||
If you don't have a device connected, the test program will be built (but |
|||
not run) with the default '$DEFAULT_ABI' ABI. Again, you can use |
|||
--abi=<name> to override this. Valid ABI names are: |
|||
|
|||
$VALID_ABIS |
|||
|
|||
The script will only run the client library unit test on the device |
|||
by default. You can use --all-tests to also build and run the unit |
|||
tests for the Breakpad tools and processor, but be warned that this |
|||
adds several minutes of testing time. --all-tests will also run the |
|||
host unit tests suite. |
|||
" |
|||
|
|||
fi # HELP_ALL |
|||
|
|||
echo "\ |
|||
Valid options: |
|||
|
|||
--help|-h|-? Display this message. |
|||
--help-all Display extended help. |
|||
--enable-m32 Build 32-bit version of host tools. |
|||
--abi=<name> Specify target CPU ABI [auto-detected]. |
|||
--jobs=<count> Run <count> build tasks in parallel [$NUM_JOBS]. |
|||
--ndk-dir=<path> Specify NDK installation directory. |
|||
--tmp-dir=<path> Specify temporary directory (will be wiped-out). |
|||
--adb=<path> Specify adb program path. |
|||
--no-cleanup Don't remove temporary directory after completion. |
|||
--no-device Do not try to detect devices, nor run crash test. |
|||
--all-tests Run all unit tests (i.e. tools and processor ones too). |
|||
--verbose Increase verbosity. |
|||
--quiet Decrease verbosity." |
|||
|
|||
exit 0 |
|||
fi |
|||
|
|||
TESTAPP_DIR=$PROGDIR/sample_app |
|||
|
|||
# Select NDK install directory. |
|||
if [ -z "$NDK_DIR" ]; then |
|||
if [ -z "$ANDROID_NDK_ROOT" ]; then |
|||
panic "Please define ANDROID_NDK_ROOT in your environment, or use \ |
|||
--ndk-dir=<path>." |
|||
fi |
|||
NDK_DIR="$ANDROID_NDK_ROOT" |
|||
log "Found NDK directory: $NDK_DIR" |
|||
else |
|||
log "Using NDK directory: $NDK_DIR" |
|||
fi |
|||
# Small sanity check. |
|||
NDK_BUILD="$NDK_DIR/ndk-build" |
|||
if [ ! -f "$NDK_BUILD" ]; then |
|||
panic "Your NDK directory is not valid (missing ndk-build): $NDK_DIR" |
|||
fi |
|||
|
|||
# Ensure the temporary directory is deleted on exit, except if the --no-cleanup |
|||
# option is used. |
|||
|
|||
clean_tmpdir () { |
|||
if [ "$TMPDIR" ]; then |
|||
if [ -z "$NO_CLEANUP" ]; then |
|||
log "Cleaning up: $TMPDIR" |
|||
rm -rf "$TMPDIR" |
|||
else |
|||
dump "Temporary directory contents preserved: $TMPDIR" |
|||
fi |
|||
fi |
|||
exit "$@" |
|||
} |
|||
|
|||
atexit clean_tmpdir |
|||
|
|||
# If --tmp-dir=<path> is not used, create a temporary directory. |
|||
# Otherwise, start by cleaning up the user-provided path. |
|||
if [ -z "$TMPDIR" ]; then |
|||
TMPDIR=$(mktemp -d /tmp/$PROGNAME.XXXXXXXX) |
|||
fail_panic "Can't create temporary directory!" |
|||
log "Using temporary directory: $TMPDIR" |
|||
else |
|||
if [ ! -d "$TMPDIR" ]; then |
|||
mkdir -p "$TMPDIR" |
|||
fail_panic "Can't create temporary directory: $TMPDIR" |
|||
else |
|||
log "Cleaning up temporary directory: $TMPDIR" |
|||
rm -rf "$TMPDIR"/* |
|||
fail_panic "Cannot cleanup temporary directory!" |
|||
fi |
|||
fi |
|||
|
|||
if [ -z "$NO_DEVICE" ]; then |
|||
if ! adb_check_device $ADB; then |
|||
echo "$(adb_get_error)" |
|||
echo "Use --no-device to build the code without running any tests." |
|||
exit 1 |
|||
fi |
|||
fi |
|||
|
|||
BUILD_LOG="$TMPDIR/build.log" |
|||
RUN_LOG="$TMPDIR/run.log" |
|||
CRASH_LOG="$TMPDIR/crash.log" |
|||
|
|||
set_run_log "$RUN_LOG" |
|||
|
|||
TMPHOST="$TMPDIR/host-local" |
|||
|
|||
cd "$TMPDIR" |
|||
|
|||
# Build host version of the tools |
|||
dump "Building host binaries." |
|||
CONFIGURE_FLAGS= |
|||
if [ "$ENABLE_M32" ]; then |
|||
CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-m32" |
|||
fi |
|||
( |
|||
run mkdir "$TMPDIR/build-host" && |
|||
run cd "$TMPDIR/build-host" && |
|||
run2 "$PROGDIR/../configure" --prefix="$TMPHOST" $CONFIGURE_FLAGS && |
|||
run2 make -j$NUM_JOBS install |
|||
) |
|||
fail_panic "Can't build host binaries!" |
|||
|
|||
if [ "$ALL_TESTS" ]; then |
|||
dump "Running host unit tests." |
|||
( |
|||
run cd "$TMPDIR/build-host" && |
|||
run2 make -j$NUM_JOBS check |
|||
) |
|||
fail_panic "Host unit tests failed!!" |
|||
fi |
|||
|
|||
TMPBIN=$TMPHOST/bin |
|||
|
|||
# Generate a stand-alone NDK toolchain |
|||
|
|||
# Extract CPU ABI and architecture from device, if any. |
|||
if adb_check_device; then |
|||
DEVICE_ABI=$(adb_shell getprop ro.product.cpu.abi) |
|||
DEVICE_ABI2=$(adb_shell getprop ro.product.cpu.abi2) |
|||
if [ -z "$DEVICE_ABI" ]; then |
|||
panic "Can't extract ABI from connected device!" |
|||
fi |
|||
if [ "$DEVICE_ABI2" ]; then |
|||
dump "Found device ABIs: $DEVICE_ABI $DEVICE_ABI2" |
|||
else |
|||
dump "Found device ABI: $DEVICE_ABI" |
|||
DEVICE_ABI2=$DEVICE_ABI |
|||
fi |
|||
|
|||
# If --abi=<name> is used, check that the device supports it. |
|||
if [ "$ABI" -a "$DEVICE_ABI" != "$ABI" -a "$DEVICE_ABI2" != "$ABI" ]; then |
|||
dump "ERROR: Device ABI(s) do not match --abi command-line value ($ABI)!" |
|||
panic "Please use --no-device to skip device tests." |
|||
fi |
|||
|
|||
if [ -z "$ABI" ]; then |
|||
ABI=$DEVICE_ABI |
|||
dump "Using CPU ABI: $ABI (device)" |
|||
else |
|||
dump "Using CPU ABI: $ABI (command-line)" |
|||
fi |
|||
else |
|||
if [ -z "$ABI" ]; then |
|||
# No device connected, choose default ABI |
|||
ABI=$DEFAULT_ABI |
|||
dump "Using CPU ABI: $ABI (default)" |
|||
else |
|||
dump "Using CPU ABI: $ABI (command-line)" |
|||
fi |
|||
fi |
|||
|
|||
# Check the ABI value |
|||
VALID= |
|||
for VALID_ABI in $VALID_ABIS; do |
|||
if [ "$ABI" = "$VALID_ABI" ]; then |
|||
VALID=true |
|||
break |
|||
fi |
|||
done |
|||
|
|||
if [ -z "$VALID" ]; then |
|||
panic "Unknown CPU ABI '$ABI'. Valid values are: $VALID_ABIS" |
|||
fi |
|||
|
|||
# Extract architecture name from ABI |
|||
case $ABI in |
|||
armeabi*) ARCH=arm;; |
|||
*) ARCH=$ABI;; |
|||
esac |
|||
|
|||
# Extract GNU configuration name |
|||
case $ARCH in |
|||
arm) |
|||
GNU_CONFIG=arm-linux-androideabi |
|||
;; |
|||
x86) |
|||
GNU_CONFIG=i686-linux-android |
|||
;; |
|||
mips) |
|||
GNU_CONFIG=mipsel-linux-android |
|||
;; |
|||
*) |
|||
GNU_CONFIG="$ARCH-linux-android" |
|||
;; |
|||
esac |
|||
|
|||
# Generate standalone NDK toolchain installation |
|||
NDK_STANDALONE="$TMPDIR/ndk-$ARCH-toolchain" |
|||
echo "Generating NDK standalone toolchain installation" |
|||
mkdir -p "$NDK_STANDALONE" |
|||
# NOTE: The --platform=android-9 is required to provide <regex.h> for GTest. |
|||
run "$NDK_DIR/build/tools/make-standalone-toolchain.sh" \ |
|||
--arch="$ARCH" \ |
|||
--platform=android-9 \ |
|||
--install-dir="$NDK_STANDALONE" |
|||
fail_panic "Can't generate standalone NDK toolchain installation!" |
|||
|
|||
# Rebuild the client library, processor and tools with the auto-tools based |
|||
# build system. Even though it's not going to be used, this checks that this |
|||
# still works correctly. |
|||
echo "Building full Android binaries with configure/make" |
|||
TMPTARGET="$TMPDIR/target-local" |
|||
( |
|||
PATH="$NDK_STANDALONE/bin:$PATH" |
|||
run mkdir "$TMPTARGET" && |
|||
run mkdir "$TMPDIR"/build-target && |
|||
run cd "$TMPDIR"/build-target && |
|||
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \ |
|||
--host="$GNU_CONFIG" && |
|||
run2 make -j$NUM_JOBS install |
|||
) |
|||
fail_panic "Could not rebuild Android binaries!" |
|||
|
|||
# Build and/or run unit test suite. |
|||
# If --no-device is used, only rebuild it, otherwise, run in on the |
|||
# connected device. |
|||
if [ "$NO_DEVICE" ]; then |
|||
ACTION="Building" |
|||
# This is a trick to force the Makefile to ignore running the scripts. |
|||
TESTS_ENVIRONMENT="TESTS_ENVIRONMENT=true" |
|||
else |
|||
ACTION="Running" |
|||
TESTS_ENVIRONMENT= |
|||
fi |
|||
|
|||
( |
|||
PATH="$NDK_STANDALONE/bin:$PATH" |
|||
run cd "$TMPDIR"/build-target && |
|||
# Reconfigure to only run the client unit test suite. |
|||
# This one should _never_ fail. |
|||
dump "$ACTION Android client library unit tests." |
|||
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \ |
|||
--host="$GNU_CONFIG" \ |
|||
--disable-tools \ |
|||
--disable-processor && |
|||
run make -j$NUM_JOBS check $TESTS_ENVIRONMENT || exit $? |
|||
|
|||
if [ "$ALL_TESTS" ]; then |
|||
dump "$ACTION Tools and processor unit tests." |
|||
# Reconfigure to run the processor and tools tests. |
|||
# Most of these fail for now, so do not worry about it. |
|||
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \ |
|||
--host="$GNU_CONFIG" && |
|||
run make -j$NUM_JOBS check $TESTS_ENVIRONMENT |
|||
if [ $? != 0 ]; then |
|||
dump "Tools and processor unit tests failed as expected. \ |
|||
Use --verbose for results." |
|||
fi |
|||
fi |
|||
) |
|||
fail_panic "Client library unit test suite failed!" |
|||
|
|||
# Copy sources to temporary directory |
|||
PROJECT_DIR=$TMPDIR/project |
|||
dump "Copying test program sources to: $PROJECT_DIR" |
|||
run cp -r "$TESTAPP_DIR" "$PROJECT_DIR" && |
|||
run rm -rf "$PROJECT_DIR/obj" && |
|||
run rm -rf "$PROJECT_DIR/libs" |
|||
fail_panic "Could not copy test program sources to: $PROJECT_DIR" |
|||
|
|||
# Build the test program with ndk-build. |
|||
dump "Building test program with ndk-build" |
|||
export NDK_MODULE_PATH="$PROGDIR" |
|||
NDK_BUILD_FLAGS="-j$NUM_JOBS" |
|||
if verbosity_is_higher_than 1; then |
|||
NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS NDK_LOG=1 V=1" |
|||
fi |
|||
run "$NDK_DIR/ndk-build" -C "$PROJECT_DIR" $NDK_BUILD_FLAGS APP_ABI=$ABI |
|||
fail_panic "Can't build test program!" |
|||
|
|||
# Unless --no-device was used, stop right here if ADB isn't in the path, |
|||
# or there is no connected device. |
|||
if [ "$NO_DEVICE" ]; then |
|||
dump "Done. Please connect a device to run all tests!" |
|||
clean_exit 0 |
|||
fi |
|||
|
|||
# Push the program to the device. |
|||
TESTAPP=test_google_breakpad |
|||
TESTAPP_FILE="$PROJECT_DIR/libs/$ABI/test_google_breakpad" |
|||
if [ ! -f "$TESTAPP_FILE" ]; then |
|||
panic "Device requires '$ABI' binaries. None found!" |
|||
fi |
|||
|
|||
# Run the program there |
|||
dump "Installing test program on device" |
|||
DEVICE_TMP=/data/local/tmp |
|||
adb_push "$TESTAPP_FILE" "$DEVICE_TMP/" |
|||
fail_panic "Cannot push test program to device!" |
|||
|
|||
dump "Running test program on device" |
|||
adb_shell cd "$DEVICE_TMP" "&&" ./$TESTAPP > "$CRASH_LOG" 2>/dev/null |
|||
if [ $? = 0 ]; then |
|||
panic "Test program did *not* crash as expected!" |
|||
fi |
|||
if verbosity_is_higher_than 0; then |
|||
echo -n "Crash log: " |
|||
cat "$CRASH_LOG" |
|||
fi |
|||
|
|||
# Extract minidump from device |
|||
MINIDUMP_NAME=$(awk '$1 == "Dump" && $2 == "path:" { print $3; }' "$CRASH_LOG") |
|||
MINIDUMP_NAME=$(basename "$MINIDUMP_NAME") |
|||
if [ -z "$MINIDUMP_NAME" ]; then |
|||
panic "Test program didn't write minidump properly!" |
|||
fi |
|||
|
|||
dump "Extracting minidump: $MINIDUMP_NAME" |
|||
adb_pull "$DEVICE_TMP/$MINIDUMP_NAME" . |
|||
fail_panic "Can't extract minidump!" |
|||
|
|||
dump "Parsing test program symbols" |
|||
if verbosity_is_higher_than 1; then |
|||
log "COMMAND: $TMPBIN/dump_syms \ |
|||
$PROJECT_DIR/obj/local/$ABI/$TESTAPP >$TESTAPP.sym" |
|||
fi |
|||
"$TMPBIN/dump_syms" "$PROJECT_DIR/obj/local/$ABI/$TESTAPP" > $TESTAPP.sym |
|||
fail_panic "dump_syms doesn't work!" |
|||
|
|||
VERSION=$(awk '$1 == "MODULE" { print $4; }' $TESTAPP.sym) |
|||
dump "Found module version: $VERSION" |
|||
if [ -z "$VERSION" ]; then |
|||
echo "ERROR: Can't find proper module version from symbol dump!" |
|||
head -n5 $TESTAPP.sym |
|||
clean_exit 1 |
|||
fi |
|||
|
|||
run mkdir -p "$TMPDIR/symbols/$TESTAPP/$VERSION" |
|||
run mv $TESTAPP.sym "$TMPDIR/symbols/$TESTAPP/$VERSION/" |
|||
|
|||
dump "Generating stack trace" |
|||
# Don't use 'run' to be able to send stdout and stderr to two different files. |
|||
log "COMMAND: $TMPBIN/minidump_stackwalk $MINIDUMP_NAME symbols" |
|||
"$TMPBIN/minidump_stackwalk" $MINIDUMP_NAME \ |
|||
"$TMPDIR/symbols" \ |
|||
> "$BUILD_LOG" 2>>"$RUN_LOG" |
|||
fail_panic "minidump_stackwalk doesn't work!" |
|||
|
|||
dump "Checking stack trace content" |
|||
|
|||
if verbosity_is_higher_than 1; then |
|||
cat "$BUILD_LOG" |
|||
fi |
|||
|
|||
# The generated stack trace should look like the following: |
|||
# |
|||
# Thread 0 (crashed) |
|||
# 0 test_google_breakpad!crash [test_breakpad.cpp : 17 + 0x4] |
|||
# r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c |
|||
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000 |
|||
# sp = 0xbea2cb50 lr = 0x00009025 pc = 0x00008f84 |
|||
# Found by: given as instruction pointer in context |
|||
# 1 test_google_breakpad!main [test_breakpad.cpp : 25 + 0x3] |
|||
# r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c |
|||
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000 |
|||
# sp = 0xbea2cb50 pc = 0x00009025 |
|||
# Found by: call frame info |
|||
# 2 libc.so + 0x164e5 |
|||
# r4 = 0x00008f64 r5 = 0xbea2cc34 r6 = 0x00000001 r7 = 0xbea2cc3c |
|||
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000 |
|||
# sp = 0xbea2cc18 pc = 0x400c34e7 |
|||
# Found by: call frame info |
|||
# ... |
|||
# |
|||
# The most important part for us is ensuring that the source location could |
|||
# be extracted, so look at the 'test_breakpad.cpp' references here. |
|||
# |
|||
# First, extract all the lines with test_google_breakpad! in them, and |
|||
# dump the corresponding crash location. |
|||
# |
|||
# Note that if the source location can't be extracted, the second field |
|||
# will only be 'test_google_breakpad' without the exclamation mark. |
|||
# |
|||
LOCATIONS=$(awk '$2 ~ "^test_google_breakpad!.*" { print $3; }' "$BUILD_LOG") |
|||
|
|||
if [ -z "$LOCATIONS" ]; then |
|||
if verbosity_is_lower_than 1; then |
|||
cat "$BUILD_LOG" |
|||
fi |
|||
panic "No source location found in stack trace!" |
|||
fi |
|||
|
|||
# Now check that they all match "[<source file>" |
|||
BAD_LOCATIONS= |
|||
for LOCATION in $LOCATIONS; do |
|||
case $LOCATION in |
|||
# Escape the opening bracket, or some shells like Dash will not |
|||
# match them properly. |
|||
\[*.cpp|\[*.cc|\[*.h) # These are valid source locations in our executable |
|||
;; |
|||
*) # Everything else is not! |
|||
BAD_LOCATIONS="$BAD_LOCATIONS $LOCATION" |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
if [ "$BAD_LOCATIONS" ]; then |
|||
dump "ERROR: Generated stack trace doesn't contain valid source locations:" |
|||
cat "$BUILD_LOG" |
|||
echo "Bad locations are: $BAD_LOCATIONS" |
|||
exit 1 |
|||
fi |
|||
|
|||
echo "All clear! Congratulations." |
|||
|
|||
@ -0,0 +1,32 @@ |
|||
This is a sample Android executable that can be used to test the |
|||
Google Breakpad client library on Android. |
|||
|
|||
Its purpose is simply to crash and generate a minidump under /data/local/tmp. |
|||
|
|||
Build instructions: |
|||
|
|||
cd android/sample_app |
|||
$NDK/ndk-build |
|||
|
|||
Where $NDK points to a valid Android NDK installation. |
|||
|
|||
Usage instructions: |
|||
|
|||
After buildind the test program, send it to a device, then run it as |
|||
the shell UID: |
|||
|
|||
adb push libs/armeabi/test_google_breakpad /data/local/tmp |
|||
adb shell /data/local/tmp/test_google_breakpad |
|||
|
|||
This will simply crash after dumping the name of the generated minidump |
|||
file. |
|||
|
|||
See jni/test_breakpad.cpp for details. |
|||
|
|||
Use 'armeabi-v7a' instead of 'armeabi' above to test the ARMv7-A version |
|||
of the binary. |
|||
|
|||
Note: |
|||
If you plan to use the library in a regular Android application, store |
|||
the minidump files either to your app-specific directory, or to the SDCard |
|||
(the latter requiring a specific permission). |
|||
@ -0,0 +1,43 @@ |
|||
# Copyright 2012 Google LLC
|
|||
#
|
|||
# Redistribution and use in source and binary forms, with or without
|
|||
# modification, are permitted provided that the following conditions are
|
|||
# met:
|
|||
#
|
|||
# * Redistributions of source code must retain the above copyright
|
|||
# notice, this list of conditions and the following disclaimer.
|
|||
# * Redistributions in binary form must reproduce the above
|
|||
# copyright notice, this list of conditions and the following disclaimer
|
|||
# in the documentation and/or other materials provided with the
|
|||
# distribution.
|
|||
# * Neither the name of Google LLC nor the names of its
|
|||
# contributors may be used to endorse or promote products derived from
|
|||
# this software without specific prior written permission.
|
|||
#
|
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
LOCAL_PATH := $(call my-dir) |
|||
|
|||
include $(CLEAR_VARS) |
|||
LOCAL_MODULE := test_google_breakpad |
|||
LOCAL_SRC_FILES := test_breakpad.cpp |
|||
LOCAL_STATIC_LIBRARIES += breakpad_client |
|||
include $(BUILD_EXECUTABLE) |
|||
|
|||
# If NDK_MODULE_PATH is defined, import the module, otherwise do a direct
|
|||
# includes. This allows us to build in all scenarios easily.
|
|||
ifneq ($(NDK_MODULE_PATH),) |
|||
$(call import-module,google_breakpad) |
|||
else |
|||
include $(LOCAL_PATH)/../../google_breakpad/Android.mk |
|||
endif |
|||
@ -0,0 +1,31 @@ |
|||
# Copyright 2012 Google LLC
|
|||
#
|
|||
# Redistribution and use in source and binary forms, with or without
|
|||
# modification, are permitted provided that the following conditions are
|
|||
# met:
|
|||
#
|
|||
# * Redistributions of source code must retain the above copyright
|
|||
# notice, this list of conditions and the following disclaimer.
|
|||
# * Redistributions in binary form must reproduce the above
|
|||
# copyright notice, this list of conditions and the following disclaimer
|
|||
# in the documentation and/or other materials provided with the
|
|||
# distribution.
|
|||
# * Neither the name of Google LLC nor the names of its
|
|||
# contributors may be used to endorse or promote products derived from
|
|||
# this software without specific prior written permission.
|
|||
#
|
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
APP_STL := stlport_static |
|||
APP_ABI := all |
|||
APP_CXXFLAGS := -std=c++11 -D__STDC_LIMIT_MACROS |
|||
@ -0,0 +1,56 @@ |
|||
// Copyright 2012 Google LLC
|
|||
//
|
|||
// Redistribution and use in source and binary forms, with or without
|
|||
// modification, are permitted provided that the following conditions are
|
|||
// met:
|
|||
//
|
|||
// * Redistributions of source code must retain the above copyright
|
|||
// notice, this list of conditions and the following disclaimer.
|
|||
// * Redistributions in binary form must reproduce the above
|
|||
// copyright notice, this list of conditions and the following disclaimer
|
|||
// in the documentation and/or other materials provided with the
|
|||
// distribution.
|
|||
// * Neither the name of Google LLC nor the names of its
|
|||
// contributors may be used to endorse or promote products derived from
|
|||
// this software without specific prior written permission.
|
|||
//
|
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
#include <stdio.h>
|
|||
|
|||
#include "client/linux/handler/exception_handler.h"
|
|||
#include "client/linux/handler/minidump_descriptor.h"
|
|||
|
|||
namespace { |
|||
|
|||
bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, |
|||
void* context, |
|||
bool succeeded) { |
|||
printf("Dump path: %s\n", descriptor.path()); |
|||
return succeeded; |
|||
} |
|||
|
|||
void Crash() { |
|||
volatile int* a = reinterpret_cast<volatile int*>(NULL); |
|||
*a = 1; |
|||
} |
|||
|
|||
} // namespace
|
|||
|
|||
int main(int argc, char* argv[]) { |
|||
google_breakpad::MinidumpDescriptor descriptor("."); |
|||
google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, |
|||
NULL, true, -1); |
|||
Crash(); |
|||
return 0; |
|||
} |
|||
@ -0,0 +1,131 @@ |
|||
#! /bin/sh |
|||
# test-driver - basic testsuite driver script. |
|||
|
|||
# Slightly modified for Android, see ANDROID comment below. |
|||
|
|||
scriptversion=2012-06-27.10; # UTC |
|||
|
|||
# Copyright (C) 2011-2013 Free Software Foundation, Inc. |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2, or (at your option) |
|||
# any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
# As a special exception to the GNU General Public License, if you |
|||
# distribute this file as part of a program that contains a |
|||
# configuration script generated by Autoconf, you may include it under |
|||
# the same distribution terms that you use for the rest of that program. |
|||
|
|||
# This file is maintained in Automake, please report |
|||
# bugs to <bug-automake@gnu.org> or send patches to |
|||
# <automake-patches@gnu.org>. |
|||
|
|||
# Make unconditional expansion of undefined variables an error. This |
|||
# helps a lot in preventing typo-related bugs. |
|||
set -u |
|||
|
|||
usage_error () |
|||
{ |
|||
echo "$0: $*" >&2 |
|||
print_usage >&2 |
|||
exit 2 |
|||
} |
|||
|
|||
print_usage () |
|||
{ |
|||
cat <<END |
|||
Usage: |
|||
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH |
|||
[--expect-failure={yes|no}] [--color-tests={yes|no}] |
|||
[--enable-hard-errors={yes|no}] [--] TEST-SCRIPT |
|||
The '--test-name', '--log-file' and '--trs-file' options are mandatory. |
|||
END |
|||
} |
|||
|
|||
# TODO: better error handling in option parsing (in particular, ensure |
|||
# TODO: $log_file, $trs_file and $test_name are defined). |
|||
test_name= # Used for reporting. |
|||
log_file= # Where to save the output of the test script. |
|||
trs_file= # Where to save the metadata of the test run. |
|||
expect_failure=no |
|||
color_tests=no |
|||
enable_hard_errors=yes |
|||
while test $# -gt 0; do |
|||
case $1 in |
|||
--help) print_usage; exit $?;; |
|||
--version) echo "test-driver $scriptversion"; exit $?;; |
|||
--test-name) test_name=$2; shift;; |
|||
--log-file) log_file=$2; shift;; |
|||
--trs-file) trs_file=$2; shift;; |
|||
--color-tests) color_tests=$2; shift;; |
|||
--expect-failure) expect_failure=$2; shift;; |
|||
--enable-hard-errors) enable_hard_errors=$2; shift;; |
|||
--) shift; break;; |
|||
-*) usage_error "invalid option: '$1'";; |
|||
esac |
|||
shift |
|||
done |
|||
|
|||
if test $color_tests = yes; then |
|||
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'. |
|||
red='[0;31m' # Red. |
|||
grn='[0;32m' # Green. |
|||
lgn='[1;32m' # Light green. |
|||
blu='[1;34m' # Blue. |
|||
mgn='[0;35m' # Magenta. |
|||
std='[m' # No color. |
|||
else |
|||
red= grn= lgn= blu= mgn= std= |
|||
fi |
|||
|
|||
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st' |
|||
trap "st=129; $do_exit" 1 |
|||
trap "st=130; $do_exit" 2 |
|||
trap "st=141; $do_exit" 13 |
|||
trap "st=143; $do_exit" 15 |
|||
|
|||
# Test script is run here. |
|||
# ANDROID: old line was: "$@" > $log_file 2>&1 |
|||
progdir=$(dirname "$0") |
|||
"$progdir/test-shell.sh" "$@" > $log_file 2>&1 |
|||
estatus=$? |
|||
if test $enable_hard_errors = no && test $estatus -eq 99; then |
|||
estatus=1 |
|||
fi |
|||
|
|||
case $estatus:$expect_failure in |
|||
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; |
|||
0:*) col=$grn res=PASS recheck=no gcopy=no;; |
|||
77:*) col=$blu res=SKIP recheck=no gcopy=yes;; |
|||
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; |
|||
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; |
|||
*:*) col=$red res=FAIL recheck=yes gcopy=yes;; |
|||
esac |
|||
|
|||
# Report outcome to console. |
|||
echo "${col}${res}${std}: $test_name" |
|||
|
|||
# Register the test result, and other relevant metadata. |
|||
echo ":test-result: $res" > $trs_file |
|||
echo ":global-test-result: $res" >> $trs_file |
|||
echo ":recheck: $recheck" >> $trs_file |
|||
echo ":copy-in-global-log: $gcopy" >> $trs_file |
|||
|
|||
# Local Variables: |
|||
# mode: shell-script |
|||
# sh-indentation: 2 |
|||
# eval: (add-hook 'write-file-hooks 'time-stamp) |
|||
# time-stamp-start: "scriptversion=" |
|||
# time-stamp-format: "%:y-%02m-%02d.%02H" |
|||
# time-stamp-time-zone: "UTC" |
|||
# time-stamp-end: "; # UTC" |
|||
# End: |
|||
@ -0,0 +1,130 @@ |
|||
#!/bin/sh |
|||
# |
|||
# Copyright 2012 Google LLC |
|||
# |
|||
# Redistribution and use in source and binary forms, with or without |
|||
# modification, are permitted provided that the following conditions are |
|||
# met: |
|||
# |
|||
# * Redistributions of source code must retain the above copyright |
|||
# notice, this list of conditions and the following disclaimer. |
|||
# * Redistributions in binary form must reproduce the above |
|||
# copyright notice, this list of conditions and the following disclaimer |
|||
# in the documentation and/or other materials provided with the |
|||
# distribution. |
|||
# * Neither the name of Google LLC nor the names of its |
|||
# contributors may be used to endorse or promote products derived from |
|||
# this software without specific prior written permission. |
|||
# |
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
# A special shell wrapper that can be used to run the Google Breakpad unit |
|||
# tests on a connected Android device. |
|||
# |
|||
# This is designed to be called from the Makefile during 'make check' |
|||
# |
|||
|
|||
PROGDIR=$(dirname "$0") |
|||
PROGNAME=$(basename "$0") |
|||
. $PROGDIR/common-functions.sh |
|||
|
|||
# Extract test program name first. |
|||
TEST_PROGRAM=$1 |
|||
shift |
|||
|
|||
if [ -z "$TEST_PROGRAM" ]; then |
|||
panic "No test program/script name on the command-line!" |
|||
fi |
|||
|
|||
if [ ! -f "$TEST_PROGRAM" ]; then |
|||
panic "Can't find test program/script: $TEST_PROGRAM" |
|||
fi |
|||
|
|||
# Create test directory on the device |
|||
TEST_DIR=/data/local/tmp/test-google-breakpad-$$ |
|||
adb_shell mkdir "$TEST_DIR" || |
|||
panic "Can't create test directory on device: $TEST_DIR" |
|||
|
|||
# Ensure that it is always removed when the script exits. |
|||
clean_test_dir () { |
|||
# Don't care about success/failure, use '$ADB shell' directly. |
|||
adb_shell rm -r "$TEST_DIR" |
|||
} |
|||
|
|||
atexit clean_test_dir |
|||
|
|||
TEST_PROGRAM_NAME=$(basename "$TEST_PROGRAM") |
|||
TEST_PROGRAM_DIR=$(dirname "$TEST_PROGRAM") |
|||
|
|||
# Handle special case(s) here. |
|||
DATA_FILES= |
|||
case $TEST_PROGRAM_NAME in |
|||
linux_client_unittest) |
|||
# linux_client_unittest will call another executable at runtime, ensure |
|||
# it is installed too. |
|||
adb_install "$TEST_PROGRAM_DIR/linux_dumper_unittest_helper" "$TEST_DIR" |
|||
# linux_client_unittest loads a shared library at runtime, ensure it is |
|||
# installed too. |
|||
adb_install "$TEST_PROGRAM_DIR/linux_client_unittest_shlib" "$TEST_DIR" |
|||
;; |
|||
basic_source_line_resolver_unittest) |
|||
DATA_FILES="module1.out \ |
|||
module2.out \ |
|||
module3_bad.out \ |
|||
module4_bad.out" |
|||
;; |
|||
exploitability_unittest) |
|||
DATA_FILES="scii_read_av.dmp \ |
|||
ascii_read_av_block_write.dmp \ |
|||
ascii_read_av_clobber_write.dmp \ |
|||
ascii_read_av_conditional.dmp \ |
|||
ascii_read_av_non_null.dmp \ |
|||
ascii_read_av_then_jmp.dmp \ |
|||
ascii_read_av_xchg_write.dmp \ |
|||
ascii_write_av.dmp \ |
|||
ascii_write_av_arg_to_call.dmp \ |
|||
exec_av_on_stack.dmp \ |
|||
null_read_av.dmp \ |
|||
null_write_av.dmp \ |
|||
read_av.dmp \ |
|||
null_read_av.dmp \ |
|||
write_av_non_null.dmp" |
|||
;; |
|||
fast_source_line_resolver_unittest) |
|||
DATA_FILES="module0.out \ |
|||
module1.out \ |
|||
module2.out \ |
|||
module3_bad.out \ |
|||
module4_bad.out" |
|||
;; |
|||
minidump_processor_unittest|minidump_unittest) |
|||
DATA_FILES="src/processor/testdata/minidump2.dmp" |
|||
;; |
|||
esac |
|||
|
|||
# Install the data files, their path is relative to the environment |
|||
# variable 'srcdir' |
|||
for FILE in $DATA_FILES; do |
|||
FILEDIR=src/processor/testdata/$(dirname "$FILE") |
|||
adb_shell mkdir -p "$TEST_DIR/$FILEDIR" |
|||
adb_install "${srcdir:-.}/$FILE" "$TEST_DIR"/"$FILE" |
|||
done |
|||
|
|||
# Copy test program to device |
|||
adb_install "$TEST_PROGRAM" "$TEST_DIR" |
|||
|
|||
# Run it |
|||
adb_shell "cd $TEST_DIR && LD_LIBRARY_PATH=. ./$TEST_PROGRAM_NAME $@" |
|||
|
|||
# Note: exiting here will call cleanup_exit which will remove the temporary |
|||
# files from the device. |
|||
@ -0,0 +1,42 @@ |
|||
version: '{build}' |
|||
|
|||
environment: |
|||
GYP_MSVS_VERSION: 2013 |
|||
|
|||
platform: |
|||
- Win32 |
|||
|
|||
configuration: |
|||
- Debug |
|||
- Release |
|||
|
|||
# Use the source dir expected by gclient. |
|||
clone_folder: c:\projects\breakpad\src |
|||
|
|||
# Before checkout. |
|||
init: |
|||
- cd %APPVEYOR_BUILD_FOLDER%\..\.. |
|||
- appveyor DownloadFile https://storage.googleapis.com/chrome-infra/depot_tools.zip |
|||
- 7z -bd x depot_tools.zip -odepot_tools |
|||
- depot_tools\update_depot_tools |
|||
- cd %APPVEYOR_BUILD_FOLDER% |
|||
|
|||
# After checkout. |
|||
install: |
|||
- PATH C:\projects\depot_tools;%PATH% |
|||
- cd %APPVEYOR_BUILD_FOLDER%\.. |
|||
- gclient config https://%APPVEYOR_REPO_PROVIDER%.com/%APPVEYOR_REPO_NAME% --unmanaged --name=src |
|||
- gclient sync |
|||
|
|||
build_script: |
|||
- cd %APPVEYOR_BUILD_FOLDER% |
|||
- msbuild src\client\windows\breakpad_client.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /m /verbosity:normal |
|||
- msbuild src\tools\windows\tools_windows.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /m /verbosity:normal |
|||
|
|||
test_script: |
|||
- src\client\windows\%CONFIGURATION%\client_tests.exe |
|||
- src\tools\windows\%CONFIGURATION%\dump_syms_unittest.exe |
|||
|
|||
artifacts: |
|||
- path: '**\*.exe' |
|||
- path: '**\*.lib' |
|||
@ -0,0 +1,271 @@ |
|||
#! /bin/sh |
|||
# Wrapper for Microsoft lib.exe |
|||
|
|||
me=ar-lib |
|||
scriptversion=2019-07-04.01; # UTC |
|||
|
|||
# Copyright (C) 2010-2021 Free Software Foundation, Inc. |
|||
# Written by Peter Rosin <peda@lysator.liu.se>. |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2, or (at your option) |
|||
# any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
|
|||
# As a special exception to the GNU General Public License, if you |
|||
# distribute this file as part of a program that contains a |
|||
# configuration script generated by Autoconf, you may include it under |
|||
# the same distribution terms that you use for the rest of that program. |
|||
|
|||
# This file is maintained in Automake, please report |
|||
# bugs to <bug-automake@gnu.org> or send patches to |
|||
# <automake-patches@gnu.org>. |
|||
|
|||
|
|||
# func_error message |
|||
func_error () |
|||
{ |
|||
echo "$me: $1" 1>&2 |
|||
exit 1 |
|||
} |
|||
|
|||
file_conv= |
|||
|
|||
# func_file_conv build_file |
|||
# Convert a $build file to $host form and store it in $file |
|||
# Currently only supports Windows hosts. |
|||
func_file_conv () |
|||
{ |
|||
file=$1 |
|||
case $file in |
|||
/ | /[!/]*) # absolute file, and not a UNC file |
|||
if test -z "$file_conv"; then |
|||
# lazily determine how to convert abs files |
|||
case `uname -s` in |
|||
MINGW*) |
|||
file_conv=mingw |
|||
;; |
|||
CYGWIN* | MSYS*) |
|||
file_conv=cygwin |
|||
;; |
|||
*) |
|||
file_conv=wine |
|||
;; |
|||
esac |
|||
fi |
|||
case $file_conv in |
|||
mingw) |
|||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` |
|||
;; |
|||
cygwin | msys) |
|||
file=`cygpath -m "$file" || echo "$file"` |
|||
;; |
|||
wine) |
|||
file=`winepath -w "$file" || echo "$file"` |
|||
;; |
|||
esac |
|||
;; |
|||
esac |
|||
} |
|||
|
|||
# func_at_file at_file operation archive |
|||
# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE |
|||
# for each of them. |
|||
# When interpreting the content of the @FILE, do NOT use func_file_conv, |
|||
# since the user would need to supply preconverted file names to |
|||
# binutils ar, at least for MinGW. |
|||
func_at_file () |
|||
{ |
|||
operation=$2 |
|||
archive=$3 |
|||
at_file_contents=`cat "$1"` |
|||
eval set x "$at_file_contents" |
|||
shift |
|||
|
|||
for member |
|||
do |
|||
$AR -NOLOGO $operation:"$member" "$archive" || exit $? |
|||
done |
|||
} |
|||
|
|||
case $1 in |
|||
'') |
|||
func_error "no command. Try '$0 --help' for more information." |
|||
;; |
|||
-h | --h*) |
|||
cat <<EOF |
|||
Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...] |
|||
|
|||
Members may be specified in a file named with @FILE. |
|||
EOF |
|||
exit $? |
|||
;; |
|||
-v | --v*) |
|||
echo "$me, version $scriptversion" |
|||
exit $? |
|||
;; |
|||
esac |
|||
|
|||
if test $# -lt 3; then |
|||
func_error "you must specify a program, an action and an archive" |
|||
fi |
|||
|
|||
AR=$1 |
|||
shift |
|||
while : |
|||
do |
|||
if test $# -lt 2; then |
|||
func_error "you must specify a program, an action and an archive" |
|||
fi |
|||
case $1 in |
|||
-lib | -LIB \ |
|||
| -ltcg | -LTCG \ |
|||
| -machine* | -MACHINE* \ |
|||
| -subsystem* | -SUBSYSTEM* \ |
|||
| -verbose | -VERBOSE \ |
|||
| -wx* | -WX* ) |
|||
AR="$AR $1" |
|||
shift |
|||
;; |
|||
*) |
|||
action=$1 |
|||
shift |
|||
break |
|||
;; |
|||
esac |
|||
done |
|||
orig_archive=$1 |
|||
shift |
|||
func_file_conv "$orig_archive" |
|||
archive=$file |
|||
|
|||
# strip leading dash in $action |
|||
action=${action#-} |
|||
|
|||
delete= |
|||
extract= |
|||
list= |
|||
quick= |
|||
replace= |
|||
index= |
|||
create= |
|||
|
|||
while test -n "$action" |
|||
do |
|||
case $action in |
|||
d*) delete=yes ;; |
|||
x*) extract=yes ;; |
|||
t*) list=yes ;; |
|||
q*) quick=yes ;; |
|||
r*) replace=yes ;; |
|||
s*) index=yes ;; |
|||
S*) ;; # the index is always updated implicitly |
|||
c*) create=yes ;; |
|||
u*) ;; # TODO: don't ignore the update modifier |
|||
v*) ;; # TODO: don't ignore the verbose modifier |
|||
*) |
|||
func_error "unknown action specified" |
|||
;; |
|||
esac |
|||
action=${action#?} |
|||
done |
|||
|
|||
case $delete$extract$list$quick$replace,$index in |
|||
yes,* | ,yes) |
|||
;; |
|||
yesyes*) |
|||
func_error "more than one action specified" |
|||
;; |
|||
*) |
|||
func_error "no action specified" |
|||
;; |
|||
esac |
|||
|
|||
if test -n "$delete"; then |
|||
if test ! -f "$orig_archive"; then |
|||
func_error "archive not found" |
|||
fi |
|||
for member |
|||
do |
|||
case $1 in |
|||
@*) |
|||
func_at_file "${1#@}" -REMOVE "$archive" |
|||
;; |
|||
*) |
|||
func_file_conv "$1" |
|||
$AR -NOLOGO -REMOVE:"$file" "$archive" || exit $? |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
elif test -n "$extract"; then |
|||
if test ! -f "$orig_archive"; then |
|||
func_error "archive not found" |
|||
fi |
|||
if test $# -gt 0; then |
|||
for member |
|||
do |
|||
case $1 in |
|||
@*) |
|||
func_at_file "${1#@}" -EXTRACT "$archive" |
|||
;; |
|||
*) |
|||
func_file_conv "$1" |
|||
$AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $? |
|||
;; |
|||
esac |
|||
done |
|||
else |
|||
$AR -NOLOGO -LIST "$archive" | tr -d '\r' | sed -e 's/\\/\\\\/g' \ |
|||
| while read member |
|||
do |
|||
$AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $? |
|||
done |
|||
fi |
|||
|
|||
elif test -n "$quick$replace"; then |
|||
if test ! -f "$orig_archive"; then |
|||
if test -z "$create"; then |
|||
echo "$me: creating $orig_archive" |
|||
fi |
|||
orig_archive= |
|||
else |
|||
orig_archive=$archive |
|||
fi |
|||
|
|||
for member |
|||
do |
|||
case $1 in |
|||
@*) |
|||
func_file_conv "${1#@}" |
|||
set x "$@" "@$file" |
|||
;; |
|||
*) |
|||
func_file_conv "$1" |
|||
set x "$@" "$file" |
|||
;; |
|||
esac |
|||
shift |
|||
shift |
|||
done |
|||
|
|||
if test -n "$orig_archive"; then |
|||
$AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $? |
|||
else |
|||
$AR -NOLOGO -OUT:"$archive" "$@" || exit $? |
|||
fi |
|||
|
|||
elif test -n "$list"; then |
|||
if test ! -f "$orig_archive"; then |
|||
func_error "archive not found" |
|||
fi |
|||
$AR -NOLOGO -LIST "$archive" || exit $? |
|||
fi |
|||
@ -0,0 +1,348 @@ |
|||
#! /bin/sh |
|||
# Wrapper for compilers which do not understand '-c -o'. |
|||
|
|||
scriptversion=2018-03-07.03; # UTC |
|||
|
|||
# Copyright (C) 1999-2021 Free Software Foundation, Inc. |
|||
# Written by Tom Tromey <tromey@cygnus.com>. |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2, or (at your option) |
|||
# any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
|
|||
# As a special exception to the GNU General Public License, if you |
|||
# distribute this file as part of a program that contains a |
|||
# configuration script generated by Autoconf, you may include it under |
|||
# the same distribution terms that you use for the rest of that program. |
|||
|
|||
# This file is maintained in Automake, please report |
|||
# bugs to <bug-automake@gnu.org> or send patches to |
|||
# <automake-patches@gnu.org>. |
|||
|
|||
nl=' |
|||
' |
|||
|
|||
# We need space, tab and new line, in precisely that order. Quoting is |
|||
# there to prevent tools from complaining about whitespace usage. |
|||
IFS=" "" $nl" |
|||
|
|||
file_conv= |
|||
|
|||
# func_file_conv build_file lazy |
|||
# Convert a $build file to $host form and store it in $file |
|||
# Currently only supports Windows hosts. If the determined conversion |
|||
# type is listed in (the comma separated) LAZY, no conversion will |
|||
# take place. |
|||
func_file_conv () |
|||
{ |
|||
file=$1 |
|||
case $file in |
|||
/ | /[!/]*) # absolute file, and not a UNC file |
|||
if test -z "$file_conv"; then |
|||
# lazily determine how to convert abs files |
|||
case `uname -s` in |
|||
MINGW*) |
|||
file_conv=mingw |
|||
;; |
|||
CYGWIN* | MSYS*) |
|||
file_conv=cygwin |
|||
;; |
|||
*) |
|||
file_conv=wine |
|||
;; |
|||
esac |
|||
fi |
|||
case $file_conv/,$2, in |
|||
*,$file_conv,*) |
|||
;; |
|||
mingw/*) |
|||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` |
|||
;; |
|||
cygwin/* | msys/*) |
|||
file=`cygpath -m "$file" || echo "$file"` |
|||
;; |
|||
wine/*) |
|||
file=`winepath -w "$file" || echo "$file"` |
|||
;; |
|||
esac |
|||
;; |
|||
esac |
|||
} |
|||
|
|||
# func_cl_dashL linkdir |
|||
# Make cl look for libraries in LINKDIR |
|||
func_cl_dashL () |
|||
{ |
|||
func_file_conv "$1" |
|||
if test -z "$lib_path"; then |
|||
lib_path=$file |
|||
else |
|||
lib_path="$lib_path;$file" |
|||
fi |
|||
linker_opts="$linker_opts -LIBPATH:$file" |
|||
} |
|||
|
|||
# func_cl_dashl library |
|||
# Do a library search-path lookup for cl |
|||
func_cl_dashl () |
|||
{ |
|||
lib=$1 |
|||
found=no |
|||
save_IFS=$IFS |
|||
IFS=';' |
|||
for dir in $lib_path $LIB |
|||
do |
|||
IFS=$save_IFS |
|||
if $shared && test -f "$dir/$lib.dll.lib"; then |
|||
found=yes |
|||
lib=$dir/$lib.dll.lib |
|||
break |
|||
fi |
|||
if test -f "$dir/$lib.lib"; then |
|||
found=yes |
|||
lib=$dir/$lib.lib |
|||
break |
|||
fi |
|||
if test -f "$dir/lib$lib.a"; then |
|||
found=yes |
|||
lib=$dir/lib$lib.a |
|||
break |
|||
fi |
|||
done |
|||
IFS=$save_IFS |
|||
|
|||
if test "$found" != yes; then |
|||
lib=$lib.lib |
|||
fi |
|||
} |
|||
|
|||
# func_cl_wrapper cl arg... |
|||
# Adjust compile command to suit cl |
|||
func_cl_wrapper () |
|||
{ |
|||
# Assume a capable shell |
|||
lib_path= |
|||
shared=: |
|||
linker_opts= |
|||
for arg |
|||
do |
|||
if test -n "$eat"; then |
|||
eat= |
|||
else |
|||
case $1 in |
|||
-o) |
|||
# configure might choose to run compile as 'compile cc -o foo foo.c'. |
|||
eat=1 |
|||
case $2 in |
|||
*.o | *.[oO][bB][jJ]) |
|||
func_file_conv "$2" |
|||
set x "$@" -Fo"$file" |
|||
shift |
|||
;; |
|||
*) |
|||
func_file_conv "$2" |
|||
set x "$@" -Fe"$file" |
|||
shift |
|||
;; |
|||
esac |
|||
;; |
|||
-I) |
|||
eat=1 |
|||
func_file_conv "$2" mingw |
|||
set x "$@" -I"$file" |
|||
shift |
|||
;; |
|||
-I*) |
|||
func_file_conv "${1#-I}" mingw |
|||
set x "$@" -I"$file" |
|||
shift |
|||
;; |
|||
-l) |
|||
eat=1 |
|||
func_cl_dashl "$2" |
|||
set x "$@" "$lib" |
|||
shift |
|||
;; |
|||
-l*) |
|||
func_cl_dashl "${1#-l}" |
|||
set x "$@" "$lib" |
|||
shift |
|||
;; |
|||
-L) |
|||
eat=1 |
|||
func_cl_dashL "$2" |
|||
;; |
|||
-L*) |
|||
func_cl_dashL "${1#-L}" |
|||
;; |
|||
-static) |
|||
shared=false |
|||
;; |
|||
-Wl,*) |
|||
arg=${1#-Wl,} |
|||
save_ifs="$IFS"; IFS=',' |
|||
for flag in $arg; do |
|||
IFS="$save_ifs" |
|||
linker_opts="$linker_opts $flag" |
|||
done |
|||
IFS="$save_ifs" |
|||
;; |
|||
-Xlinker) |
|||
eat=1 |
|||
linker_opts="$linker_opts $2" |
|||
;; |
|||
-*) |
|||
set x "$@" "$1" |
|||
shift |
|||
;; |
|||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++) |
|||
func_file_conv "$1" |
|||
set x "$@" -Tp"$file" |
|||
shift |
|||
;; |
|||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) |
|||
func_file_conv "$1" mingw |
|||
set x "$@" "$file" |
|||
shift |
|||
;; |
|||
*) |
|||
set x "$@" "$1" |
|||
shift |
|||
;; |
|||
esac |
|||
fi |
|||
shift |
|||
done |
|||
if test -n "$linker_opts"; then |
|||
linker_opts="-link$linker_opts" |
|||
fi |
|||
exec "$@" $linker_opts |
|||
exit 1 |
|||
} |
|||
|
|||
eat= |
|||
|
|||
case $1 in |
|||
'') |
|||
echo "$0: No command. Try '$0 --help' for more information." 1>&2 |
|||
exit 1; |
|||
;; |
|||
-h | --h*) |
|||
cat <<\EOF |
|||
Usage: compile [--help] [--version] PROGRAM [ARGS] |
|||
|
|||
Wrapper for compilers which do not understand '-c -o'. |
|||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining |
|||
arguments, and rename the output as expected. |
|||
|
|||
If you are trying to build a whole package this is not the |
|||
right script to run: please start by reading the file 'INSTALL'. |
|||
|
|||
Report bugs to <bug-automake@gnu.org>. |
|||
EOF |
|||
exit $? |
|||
;; |
|||
-v | --v*) |
|||
echo "compile $scriptversion" |
|||
exit $? |
|||
;; |
|||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ |
|||
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) |
|||
func_cl_wrapper "$@" # Doesn't return... |
|||
;; |
|||
esac |
|||
|
|||
ofile= |
|||
cfile= |
|||
|
|||
for arg |
|||
do |
|||
if test -n "$eat"; then |
|||
eat= |
|||
else |
|||
case $1 in |
|||
-o) |
|||
# configure might choose to run compile as 'compile cc -o foo foo.c'. |
|||
# So we strip '-o arg' only if arg is an object. |
|||
eat=1 |
|||
case $2 in |
|||
*.o | *.obj) |
|||
ofile=$2 |
|||
;; |
|||
*) |
|||
set x "$@" -o "$2" |
|||
shift |
|||
;; |
|||
esac |
|||
;; |
|||
*.c) |
|||
cfile=$1 |
|||
set x "$@" "$1" |
|||
shift |
|||
;; |
|||
*) |
|||
set x "$@" "$1" |
|||
shift |
|||
;; |
|||
esac |
|||
fi |
|||
shift |
|||
done |
|||
|
|||
if test -z "$ofile" || test -z "$cfile"; then |
|||
# If no '-o' option was seen then we might have been invoked from a |
|||
# pattern rule where we don't need one. That is ok -- this is a |
|||
# normal compilation that the losing compiler can handle. If no |
|||
# '.c' file was seen then we are probably linking. That is also |
|||
# ok. |
|||
exec "$@" |
|||
fi |
|||
|
|||
# Name of file we expect compiler to create. |
|||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` |
|||
|
|||
# Create the lock directory. |
|||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name |
|||
# that we are using for the .o file. Also, base the name on the expected |
|||
# object file name, since that is what matters with a parallel build. |
|||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d |
|||
while true; do |
|||
if mkdir "$lockdir" >/dev/null 2>&1; then |
|||
break |
|||
fi |
|||
sleep 1 |
|||
done |
|||
# FIXME: race condition here if user kills between mkdir and trap. |
|||
trap "rmdir '$lockdir'; exit 1" 1 2 15 |
|||
|
|||
# Run the compile. |
|||
"$@" |
|||
ret=$? |
|||
|
|||
if test -f "$cofile"; then |
|||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile" |
|||
elif test -f "${cofile}bj"; then |
|||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" |
|||
fi |
|||
|
|||
rmdir "$lockdir" |
|||
exit $ret |
|||
|
|||
# Local Variables: |
|||
# mode: shell-script |
|||
# sh-indentation: 2 |
|||
# eval: (add-hook 'before-save-hook 'time-stamp) |
|||
# time-stamp-start: "scriptversion=" |
|||
# time-stamp-format: "%:y-%02m-%02d.%02H" |
|||
# time-stamp-time-zone: "UTC0" |
|||
# time-stamp-end: "; # UTC" |
|||
# End: |
|||
1701
externals/breakpad/autotools/config.guess
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1876
externals/breakpad/autotools/config.sub
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,791 @@ |
|||
#! /bin/sh |
|||
# depcomp - compile a program generating dependencies as side-effects |
|||
|
|||
scriptversion=2018-03-07.03; # UTC |
|||
|
|||
# Copyright (C) 1999-2021 Free Software Foundation, Inc. |
|||
|
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2, or (at your option) |
|||
# any later version. |
|||
|
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
|
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
|
|||
# As a special exception to the GNU General Public License, if you |
|||
# distribute this file as part of a program that contains a |
|||
# configuration script generated by Autoconf, you may include it under |
|||
# the same distribution terms that you use for the rest of that program. |
|||
|
|||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>. |
|||
|
|||
case $1 in |
|||
'') |
|||
echo "$0: No command. Try '$0 --help' for more information." 1>&2 |
|||
exit 1; |
|||
;; |
|||
-h | --h*) |
|||
cat <<\EOF |
|||
Usage: depcomp [--help] [--version] PROGRAM [ARGS] |
|||
|
|||
Run PROGRAMS ARGS to compile a file, generating dependencies |
|||
as side-effects. |
|||
|
|||
Environment variables: |
|||
depmode Dependency tracking mode. |
|||
source Source file read by 'PROGRAMS ARGS'. |
|||
object Object file output by 'PROGRAMS ARGS'. |
|||
DEPDIR directory where to store dependencies. |
|||
depfile Dependency file to output. |
|||
tmpdepfile Temporary file to use when outputting dependencies. |
|||
libtool Whether libtool is used (yes/no). |
|||
|
|||
Report bugs to <bug-automake@gnu.org>. |
|||
EOF |
|||
exit $? |
|||
;; |
|||
-v | --v*) |
|||
echo "depcomp $scriptversion" |
|||
exit $? |
|||
;; |
|||
esac |
|||
|
|||
# Get the directory component of the given path, and save it in the |
|||
# global variables '$dir'. Note that this directory component will |
|||
# be either empty or ending with a '/' character. This is deliberate. |
|||
set_dir_from () |
|||
{ |
|||
case $1 in |
|||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; |
|||
*) dir=;; |
|||
esac |
|||
} |
|||
|
|||
# Get the suffix-stripped basename of the given path, and save it the |
|||
# global variable '$base'. |
|||
set_base_from () |
|||
{ |
|||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` |
|||
} |
|||
|
|||
# If no dependency file was actually created by the compiler invocation, |
|||
# we still have to create a dummy depfile, to avoid errors with the |
|||
# Makefile "include basename.Plo" scheme. |
|||
make_dummy_depfile () |
|||
{ |
|||
echo "#dummy" > "$depfile" |
|||
} |
|||
|
|||
# Factor out some common post-processing of the generated depfile. |
|||
# Requires the auxiliary global variable '$tmpdepfile' to be set. |
|||
aix_post_process_depfile () |
|||
{ |
|||
# If the compiler actually managed to produce a dependency file, |
|||
# post-process it. |
|||
if test -f "$tmpdepfile"; then |
|||
# Each line is of the form 'foo.o: dependency.h'. |
|||
# Do two passes, one to just change these to |
|||
# $object: dependency.h |
|||
# and one to simply output |
|||
# dependency.h: |
|||
# which is needed to avoid the deleted-header problem. |
|||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" |
|||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" |
|||
} > "$depfile" |
|||
rm -f "$tmpdepfile" |
|||
else |
|||
make_dummy_depfile |
|||
fi |
|||
} |
|||
|
|||
# A tabulation character. |
|||
tab=' ' |
|||
# A newline character. |
|||
nl=' |
|||
' |
|||
# Character ranges might be problematic outside the C locale. |
|||
# These definitions help. |
|||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ |
|||
lower=abcdefghijklmnopqrstuvwxyz |
|||
digits=0123456789 |
|||
alpha=${upper}${lower} |
|||
|
|||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then |
|||
echo "depcomp: Variables source, object and depmode must be set" 1>&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. |
|||
depfile=${depfile-`echo "$object" | |
|||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} |
|||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} |
|||
|
|||
rm -f "$tmpdepfile" |
|||
|
|||
# Avoid interferences from the environment. |
|||
gccflag= dashmflag= |
|||
|
|||
# Some modes work just like other modes, but use different flags. We |
|||
# parameterize here, but still list the modes in the big case below, |
|||
# to make depend.m4 easier to write. Note that we *cannot* use a case |
|||
# here, because this file can only contain one case statement. |
|||
if test "$depmode" = hp; then |
|||
# HP compiler uses -M and no extra arg. |
|||
gccflag=-M |
|||
depmode=gcc |
|||
fi |
|||
|
|||
if test "$depmode" = dashXmstdout; then |
|||
# This is just like dashmstdout with a different argument. |
|||
dashmflag=-xM |
|||
depmode=dashmstdout |
|||
fi |
|||
|
|||
cygpath_u="cygpath -u -f -" |
|||
if test "$depmode" = msvcmsys; then |
|||
# This is just like msvisualcpp but w/o cygpath translation. |
|||
# Just convert the backslash-escaped backslashes to single forward |
|||
# slashes to satisfy depend.m4 |
|||
cygpath_u='sed s,\\\\,/,g' |
|||
depmode=msvisualcpp |
|||
fi |
|||
|
|||
if test "$depmode" = msvc7msys; then |
|||
# This is just like msvc7 but w/o cygpath translation. |
|||
# Just convert the backslash-escaped backslashes to single forward |
|||
# slashes to satisfy depend.m4 |
|||
cygpath_u='sed s,\\\\,/,g' |
|||
depmode=msvc7 |
|||
fi |
|||
|
|||
if test "$depmode" = xlc; then |
|||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. |
|||
gccflag=-qmakedep=gcc,-MF |
|||
depmode=gcc |
|||
fi |
|||
|
|||
case "$depmode" in |
|||
gcc3) |
|||
## gcc 3 implements dependency tracking that does exactly what |
|||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like |
|||
## it if -MD -MP comes after the -MF stuff. Hmm. |
|||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon |
|||
## the command line argument order; so add the flags where they |
|||
## appear in depend2.am. Note that the slowdown incurred here |
|||
## affects only configure: in makefiles, %FASTDEP% shortcuts this. |
|||
for arg |
|||
do |
|||
case $arg in |
|||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; |
|||
*) set fnord "$@" "$arg" ;; |
|||
esac |
|||
shift # fnord |
|||
shift # $arg |
|||
done |
|||
"$@" |
|||
stat=$? |
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile" |
|||
exit $stat |
|||
fi |
|||
mv "$tmpdepfile" "$depfile" |
|||
;; |
|||
|
|||
gcc) |
|||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. |
|||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. |
|||
## (see the conditional assignment to $gccflag above). |
|||
## There are various ways to get dependency output from gcc. Here's |
|||
## why we pick this rather obscure method: |
|||
## - Don't want to use -MD because we'd like the dependencies to end |
|||
## up in a subdir. Having to rename by hand is ugly. |
|||
## (We might end up doing this anyway to support other compilers.) |
|||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like |
|||
## -MM, not -M (despite what the docs say). Also, it might not be |
|||
## supported by the other compilers which use the 'gcc' depmode. |
|||
## - Using -M directly means running the compiler twice (even worse |
|||
## than renaming). |
|||
if test -z "$gccflag"; then |
|||
gccflag=-MD, |
|||
fi |
|||
"$@" -Wp,"$gccflag$tmpdepfile" |
|||
stat=$? |
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile" |
|||
exit $stat |
|||
fi |
|||
rm -f "$depfile" |
|||
echo "$object : \\" > "$depfile" |
|||
# The second -e expression handles DOS-style file names with drive |
|||
# letters. |
|||
sed -e 's/^[^:]*: / /' \ |
|||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" |
|||
## This next piece of magic avoids the "deleted header file" problem. |
|||
## The problem is that when a header file which appears in a .P file |
|||
## is deleted, the dependency causes make to die (because there is |
|||
## typically no way to rebuild the header). We avoid this by adding |
|||
## dummy dependencies for each header file. Too bad gcc doesn't do |
|||
## this for us directly. |
|||
## Some versions of gcc put a space before the ':'. On the theory |
|||
## that the space means something, we add a space to the output as |
|||
## well. hp depmode also adds that space, but also prefixes the VPATH |
|||
## to the object. Take care to not repeat it in the output. |
|||
## Some versions of the HPUX 10.20 sed can't process this invocation |
|||
## correctly. Breaking it into two sed invocations is a workaround. |
|||
tr ' ' "$nl" < "$tmpdepfile" \ |
|||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ |
|||
| sed -e 's/$/ :/' >> "$depfile" |
|||
rm -f "$tmpdepfile" |
|||
;; |
|||
|
|||
hp) |
|||
# This case exists only to let depend.m4 do its work. It works by |
|||
# looking at the text of this script. This case will never be run, |
|||
# since it is checked for above. |
|||
exit 1 |
|||
;; |
|||
|
|||
sgi) |
|||
if test "$libtool" = yes; then |
|||
"$@" "-Wp,-MDupdate,$tmpdepfile" |
|||
else |
|||
"$@" -MDupdate "$tmpdepfile" |
|||
fi |
|||
stat=$? |
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile" |
|||
exit $stat |
|||
fi |
|||
rm -f "$depfile" |
|||
|
|||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files |
|||
echo "$object : \\" > "$depfile" |
|||
# Clip off the initial element (the dependent). Don't try to be |
|||
# clever and replace this with sed code, as IRIX sed won't handle |
|||
# lines with more than a fixed number of characters (4096 in |
|||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; |
|||
# the IRIX cc adds comments like '#:fec' to the end of the |
|||
# dependency line. |
|||
tr ' ' "$nl" < "$tmpdepfile" \ |
|||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ |
|||
| tr "$nl" ' ' >> "$depfile" |
|||
echo >> "$depfile" |
|||
# The second pass generates a dummy entry for each header file. |
|||
tr ' ' "$nl" < "$tmpdepfile" \ |
|||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ |
|||
>> "$depfile" |
|||
else |
|||
make_dummy_depfile |
|||
fi |
|||
rm -f "$tmpdepfile" |
|||
;; |
|||
|
|||
xlc) |
|||
# This case exists only to let depend.m4 do its work. It works by |
|||
# looking at the text of this script. This case will never be run, |
|||
# since it is checked for above. |
|||
exit 1 |
|||
;; |
|||
|
|||
aix) |
|||
# The C for AIX Compiler uses -M and outputs the dependencies |
|||
# in a .u file. In older versions, this file always lives in the |
|||
# current directory. Also, the AIX compiler puts '$object:' at the |
|||
# start of each line; $object doesn't have directory information. |
|||
# Version 6 uses the directory in both cases. |
|||
set_dir_from "$object" |
|||
set_base_from "$object" |
|||
if test "$libtool" = yes; then |
|||
tmpdepfile1=$dir$base.u |
|||
tmpdepfile2=$base.u |
|||
tmpdepfile3=$dir.libs/$base.u |
|||
"$@" -Wc,-M |
|||
else |
|||
tmpdepfile1=$dir$base.u |
|||
tmpdepfile2=$dir$base.u |
|||
tmpdepfile3=$dir$base.u |
|||
"$@" -M |
|||
fi |
|||
stat=$? |
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" |
|||
exit $stat |
|||
fi |
|||
|
|||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" |
|||
do |
|||
test -f "$tmpdepfile" && break |
|||
done |
|||
aix_post_process_depfile |
|||
;; |
|||
|
|||
tcc) |
|||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 |
|||
# FIXME: That version still under development at the moment of writing. |
|||
# Make that this statement remains true also for stable, released |
|||
# versions. |
|||
# It will wrap lines (doesn't matter whether long or short) with a |
|||
# trailing '\', as in: |
|||
# |
|||
# foo.o : \ |
|||
# foo.c \ |
|||
# foo.h \ |
|||
# |
|||
# It will put a trailing '\' even on the last line, and will use leading |
|||
# spaces rather than leading tabs (at least since its commit 0394caf7 |
|||
# "Emit spaces for -MD"). |
|||
"$@" -MD -MF "$tmpdepfile" |
|||
stat=$? |
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile" |
|||
exit $stat |
|||
fi |
|||
rm -f "$depfile" |
|||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. |
|||
# We have to change lines of the first kind to '$object: \'. |
|||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" |
|||
# And for each line of the second kind, we have to emit a 'dep.h:' |
|||
# dummy dependency, to avoid the deleted-header problem. |
|||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" |
|||
rm -f "$tmpdepfile" |
|||
;; |
|||
|
|||
## The order of this option in the case statement is important, since the |
|||
## shell code in configure will try each of these formats in the order |
|||
## listed in this file. A plain '-MD' option would be understood by many |
|||
## compilers, so we must ensure this comes after the gcc and icc options. |
|||
pgcc) |
|||
# Portland's C compiler understands '-MD'. |
|||
# Will always output deps to 'file.d' where file is the root name of the |
|||
# source file under compilation, even if file resides in a subdirectory. |
|||
# The object file name does not affect the name of the '.d' file. |
|||
# pgcc 10.2 will output |
|||
# foo.o: sub/foo.c sub/foo.h |
|||
# and will wrap long lines using '\' : |
|||
# foo.o: sub/foo.c ... \ |
|||
# sub/foo.h ... \ |
|||
# ... |
|||
set_dir_from "$object" |
|||
# Use the source, not the object, to determine the base name, since |
|||
# that's sadly what pgcc will do too. |
|||
set_base_from "$source" |
|||
tmpdepfile=$base.d |
|||
|
|||
# For projects that build the same source file twice into different object |
|||
# files, the pgcc approach of using the *source* file root name can cause |
|||
# problems in parallel builds. Use a locking strategy to avoid stomping on |
|||
# the same $tmpdepfile. |
|||
lockdir=$base.d-lock |
|||
trap " |
|||
echo '$0: caught signal, cleaning up...' >&2 |
|||
rmdir '$lockdir' |
|||
exit 1 |
|||
" 1 2 13 15 |
|||
numtries=100 |
|||
i=$numtries |
|||
while test $i -gt 0; do |
|||
# mkdir is a portable test-and-set. |
|||
if mkdir "$lockdir" 2>/dev/null; then |
|||
# This process acquired the lock. |
|||
"$@" -MD |
|||
stat=$? |
|||
# Release the lock. |
|||
rmdir "$lockdir" |
|||
break |
|||
else |
|||
# If the lock is being held by a different process, wait |
|||
# until the winning process is done or we timeout. |
|||
while test -d "$lockdir" && test $i -gt 0; do |
|||
sleep 1 |
|||
i=`expr $i - 1` |
|||
done |
|||
fi |
|||
i=`expr $i - 1` |
|||
done |
|||
trap - 1 2 13 15 |
|||
if test $i -le 0; then |
|||
echo "$0: failed to acquire lock after $numtries attempts" >&2 |
|||
echo "$0: check lockdir '$lockdir'" >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile" |
|||
exit $stat |
|||
fi |
|||
rm -f "$depfile" |
|||
# Each line is of the form `foo.o: dependent.h', |
|||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. |
|||
# Do two passes, one to just change these to |
|||
# `$object: dependent.h' and one to simply `dependent.h:'. |
|||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" |
|||
# Some versions of the HPUX 10.20 sed can't process this invocation |
|||
# correctly. Breaking it into two sed invocations is a workaround. |
|||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ |
|||
| sed -e 's/$/ :/' >> "$depfile" |
|||
rm -f "$tmpdepfile" |
|||
;; |
|||
|
|||
hp2) |
|||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64 |
|||
# compilers, which have integrated preprocessors. The correct option |
|||
# to use with these is +Maked; it writes dependencies to a file named |
|||
# 'foo.d', which lands next to the object file, wherever that |
|||
# happens to be. |
|||
# Much of this is similar to the tru64 case; see comments there. |
|||
set_dir_from "$object" |
|||
set_base_from "$object" |
|||
if test "$libtool" = yes; then |
|||
tmpdepfile1=$dir$base.d |
|||
tmpdepfile2=$dir.libs/$base.d |
|||
"$@" -Wc,+Maked |
|||
else |
|||
tmpdepfile1=$dir$base.d |
|||
tmpdepfile2=$dir$base.d |
|||
"$@" +Maked |
|||
fi |
|||
stat=$? |
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile1" "$tmpdepfile2" |
|||
exit $stat |
|||
fi |
|||
|
|||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" |
|||
do |
|||
test -f "$tmpdepfile" && break |
|||
done |
|||
if test -f "$tmpdepfile"; then |
|||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" |
|||
# Add 'dependent.h:' lines. |
|||
sed -ne '2,${ |
|||
s/^ *// |
|||
s/ \\*$// |
|||
s/$/:/ |
|||
p |
|||
}' "$tmpdepfile" >> "$depfile" |
|||
else |
|||
make_dummy_depfile |
|||
fi |
|||
rm -f "$tmpdepfile" "$tmpdepfile2" |
|||
;; |
|||
|
|||
tru64) |
|||
# The Tru64 compiler uses -MD to generate dependencies as a side |
|||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. |
|||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put |
|||
# dependencies in 'foo.d' instead, so we check for that too. |
|||
# Subdirectories are respected. |
|||
set_dir_from "$object" |
|||
set_base_from "$object" |
|||
|
|||
if test "$libtool" = yes; then |
|||
# Libtool generates 2 separate objects for the 2 libraries. These |
|||
# two compilations output dependencies in $dir.libs/$base.o.d and |
|||
# in $dir$base.o.d. We have to check for both files, because |
|||
# one of the two compilations can be disabled. We should prefer |
|||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is |
|||
# automatically cleaned when .libs/ is deleted, while ignoring |
|||
# the former would cause a distcleancheck panic. |
|||
tmpdepfile1=$dir$base.o.d # libtool 1.5 |
|||
tmpdepfile2=$dir.libs/$base.o.d # Likewise. |
|||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 |
|||
"$@" -Wc,-MD |
|||
else |
|||
tmpdepfile1=$dir$base.d |
|||
tmpdepfile2=$dir$base.d |
|||
tmpdepfile3=$dir$base.d |
|||
"$@" -MD |
|||
fi |
|||
|
|||
stat=$? |
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" |
|||
exit $stat |
|||
fi |
|||
|
|||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" |
|||
do |
|||
test -f "$tmpdepfile" && break |
|||
done |
|||
# Same post-processing that is required for AIX mode. |
|||
aix_post_process_depfile |
|||
;; |
|||
|
|||
msvc7) |
|||
if test "$libtool" = yes; then |
|||
showIncludes=-Wc,-showIncludes |
|||
else |
|||
showIncludes=-showIncludes |
|||
fi |
|||
"$@" $showIncludes > "$tmpdepfile" |
|||
stat=$? |
|||
grep -v '^Note: including file: ' "$tmpdepfile" |
|||
if test $stat -ne 0; then |
|||
rm -f "$tmpdepfile" |
|||
exit $stat |
|||
fi |
|||
rm -f "$depfile" |
|||
echo "$object : \\" > "$depfile" |
|||
# The first sed program below extracts the file names and escapes |
|||
# backslashes for cygpath. The second sed program outputs the file |
|||
# name when reading, but also accumulates all include files in the |
|||
# hold buffer in order to output them again at the end. This only |
|||
# works with sed implementations that can handle large buffers. |
|||
sed < "$tmpdepfile" -n ' |
|||
/^Note: including file: *\(.*\)/ { |
|||
s//\1/ |
|||
s/\\/\\\\/g |
|||
p |
|||
}' | $cygpath_u | sort -u | sed -n ' |
|||
s/ /\\ /g |
|||
s/\(.*\)/'"$tab"'\1 \\/p |
|||
s/.\(.*\) \\/\1:/ |
|||
H |
|||
$ { |
|||
s/.*/'"$tab"'/ |
|||
G |
|||
p |
|||
}' >> "$depfile" |
|||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash |
|||
rm -f "$tmpdepfile" |
|||
;; |
|||
|
|||
msvc7msys) |
|||
# This case exists only to let depend.m4 do its work. It works by |
|||
# looking at the text of this script. This case will never be run, |
|||
# since it is checked for above. |
|||
exit 1 |
|||
;; |
|||
|
|||
#nosideeffect) |
|||
# This comment above is used by automake to tell side-effect |
|||
# dependency tracking mechanisms from slower ones. |
|||
|
|||
dashmstdout) |
|||
# Important note: in order to support this mode, a compiler *must* |
|||
# always write the preprocessed file to stdout, regardless of -o. |
|||
"$@" || exit $? |
|||
|
|||
# Remove the call to Libtool. |
|||
if test "$libtool" = yes; then |
|||
while test "X$1" != 'X--mode=compile'; do |
|||
shift |
|||
done |
|||
shift |
|||
fi |
|||
|
|||
# Remove '-o $object'. |
|||
IFS=" " |
|||
for arg |
|||
do |
|||
case $arg in |
|||
-o) |
|||
shift |
|||
;; |
|||
$object) |
|||
shift |
|||
;; |
|||
*) |
|||
set fnord "$@" "$arg" |
|||
shift # fnord |
|||
shift # $arg |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
test -z "$dashmflag" && dashmflag=-M |
|||
# Require at least two characters before searching for ':' |
|||
# in the target name. This is to cope with DOS-style filenames: |
|||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. |
|||
"$@" $dashmflag | |
|||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" |
|||
rm -f "$depfile" |
|||
cat < "$tmpdepfile" > "$depfile" |
|||
# Some versions of the HPUX 10.20 sed can't process this sed invocation |
|||
# correctly. Breaking it into two sed invocations is a workaround. |
|||
tr ' ' "$nl" < "$tmpdepfile" \ |
|||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ |
|||
| sed -e 's/$/ :/' >> "$depfile" |
|||
rm -f "$tmpdepfile" |
|||
;; |
|||
|
|||
dashXmstdout) |
|||
# This case only exists to satisfy depend.m4. It is never actually |
|||
# run, as this mode is specially recognized in the preamble. |
|||
exit 1 |
|||
;; |
|||
|
|||
makedepend) |
|||
"$@" || exit $? |
|||
# Remove any Libtool call |
|||
if test "$libtool" = yes; then |
|||
while test "X$1" != 'X--mode=compile'; do |
|||
shift |
|||
done |
|||
shift |
|||
fi |
|||
# X makedepend |
|||
shift |
|||
cleared=no eat=no |
|||
for arg |
|||
do |
|||
case $cleared in |
|||
no) |
|||
set ""; shift |
|||
cleared=yes ;; |
|||
esac |
|||
if test $eat = yes; then |
|||
eat=no |
|||
continue |
|||
fi |
|||
case "$arg" in |
|||
-D*|-I*) |
|||
set fnord "$@" "$arg"; shift ;; |
|||
# Strip any option that makedepend may not understand. Remove |
|||
# the object too, otherwise makedepend will parse it as a source file. |
|||
-arch) |
|||
eat=yes ;; |
|||
-*|$object) |
|||
;; |
|||
*) |
|||
set fnord "$@" "$arg"; shift ;; |
|||
esac |
|||
done |
|||
obj_suffix=`echo "$object" | sed 's/^.*\././'` |
|||
touch "$tmpdepfile" |
|||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" |
|||
rm -f "$depfile" |
|||
# makedepend may prepend the VPATH from the source file name to the object. |
|||
# No need to regex-escape $object, excess matching of '.' is harmless. |
|||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" |
|||
# Some versions of the HPUX 10.20 sed can't process the last invocation |
|||
# correctly. Breaking it into two sed invocations is a workaround. |
|||
sed '1,2d' "$tmpdepfile" \ |
|||
| tr ' ' "$nl" \ |
|||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ |
|||
| sed -e 's/$/ :/' >> "$depfile" |
|||
rm -f "$tmpdepfile" "$tmpdepfile".bak |
|||
;; |
|||
|
|||
cpp) |
|||
# Important note: in order to support this mode, a compiler *must* |
|||
# always write the preprocessed file to stdout. |
|||
"$@" || exit $? |
|||
|
|||
# Remove the call to Libtool. |
|||
if test "$libtool" = yes; then |
|||
while test "X$1" != 'X--mode=compile'; do |
|||
shift |
|||
done |
|||
shift |
|||
fi |
|||
|
|||
# Remove '-o $object'. |
|||
IFS=" " |
|||
for arg |
|||
do |
|||
case $arg in |
|||
-o) |
|||
shift |
|||
;; |
|||
$object) |
|||
shift |
|||
;; |
|||
*) |
|||
set fnord "$@" "$arg" |
|||
shift # fnord |
|||
shift # $arg |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
"$@" -E \ |
|||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ |
|||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ |
|||
| sed '$ s: \\$::' > "$tmpdepfile" |
|||
rm -f "$depfile" |
|||
echo "$object : \\" > "$depfile" |
|||
cat < "$tmpdepfile" >> "$depfile" |
|||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" |
|||
rm -f "$tmpdepfile" |
|||
;; |
|||
|
|||
msvisualcpp) |
|||
# Important note: in order to support this mode, a compiler *must* |
|||
# always write the preprocessed file to stdout. |
|||
"$@" || exit $? |
|||
|
|||
# Remove the call to Libtool. |
|||
if test "$libtool" = yes; then |
|||
while test "X$1" != 'X--mode=compile'; do |
|||
shift |
|||
done |
|||
shift |
|||
fi |
|||
|
|||
IFS=" " |
|||
for arg |
|||
do |
|||
case "$arg" in |
|||
-o) |
|||
shift |
|||
;; |
|||
$object) |
|||
shift |
|||
;; |
|||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") |
|||
set fnord "$@" |
|||
shift |
|||
shift |
|||
;; |
|||
*) |
|||
set fnord "$@" "$arg" |
|||
shift |
|||
shift |
|||
;; |
|||
esac |
|||
done |
|||
"$@" -E 2>/dev/null | |
|||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" |
|||
rm -f "$depfile" |
|||
echo "$object : \\" > "$depfile" |
|||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" |
|||
echo "$tab" >> "$depfile" |
|||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" |
|||
rm -f "$tmpdepfile" |
|||
;; |
|||
|
|||
msvcmsys) |
|||
# This case exists only to let depend.m4 do its work. It works by |
|||
# looking at the text of this script. This case will never be run, |
|||
# since it is checked for above. |
|||
exit 1 |
|||
;; |
|||
|
|||
none) |
|||
exec "$@" |
|||
;; |
|||
|
|||
*) |
|||
echo "Unknown depmode $depmode" 1>&2 |
|||
exit 1 |
|||
;; |
|||
esac |
|||
|
|||
exit 0 |
|||
|
|||
# Local Variables: |
|||
# mode: shell-script |
|||
# sh-indentation: 2 |
|||
# eval: (add-hook 'before-save-hook 'time-stamp) |
|||
# time-stamp-start: "scriptversion=" |
|||
# time-stamp-format: "%:y-%02m-%02d.%02H" |
|||
# time-stamp-time-zone: "UTC0" |
|||
# time-stamp-end: "; # UTC" |
|||
# End: |
|||
@ -0,0 +1,541 @@ |
|||
#!/bin/sh |
|||
# install - install a program, script, or datafile |
|||
|
|||
scriptversion=2020-11-14.01; # UTC |
|||
|
|||
# This originates from X11R5 (mit/util/scripts/install.sh), which was |
|||
# later released in X11R6 (xc/config/util/install.sh) with the |
|||
# following copyright and license. |
|||
# |
|||
# Copyright (C) 1994 X Consortium |
|||
# |
|||
# Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
# of this software and associated documentation files (the "Software"), to |
|||
# deal in the Software without restriction, including without limitation the |
|||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
|||
# sell copies of the Software, and to permit persons to whom the Software is |
|||
# furnished to do so, subject to the following conditions: |
|||
# |
|||
# The above copyright notice and this permission notice shall be included in |
|||
# all copies or substantial portions of the Software. |
|||
# |
|||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
|||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- |
|||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|||
# |
|||
# Except as contained in this notice, the name of the X Consortium shall not |
|||
# be used in advertising or otherwise to promote the sale, use or other deal- |
|||
# ings in this Software without prior written authorization from the X Consor- |
|||
# tium. |
|||
# |
|||
# |
|||
# FSF changes to this file are in the public domain. |
|||
# |
|||
# Calling this script install-sh is preferred over install.sh, to prevent |
|||
# 'make' implicit rules from creating a file called install from it |
|||
# when there is no Makefile. |
|||
# |
|||
# This script is compatible with the BSD install script, but was written |
|||
# from scratch. |
|||
|
|||
tab=' ' |
|||
nl=' |
|||
' |
|||
IFS=" $tab$nl" |
|||
|
|||
# Set DOITPROG to "echo" to test this script. |
|||
|
|||
doit=${DOITPROG-} |
|||
doit_exec=${doit:-exec} |
|||
|
|||
# Put in absolute file names if you don't have them in your path; |
|||
# or use environment vars. |
|||
|
|||
chgrpprog=${CHGRPPROG-chgrp} |
|||
chmodprog=${CHMODPROG-chmod} |
|||
chownprog=${CHOWNPROG-chown} |
|||
cmpprog=${CMPPROG-cmp} |
|||
cpprog=${CPPROG-cp} |
|||
mkdirprog=${MKDIRPROG-mkdir} |
|||
mvprog=${MVPROG-mv} |
|||
rmprog=${RMPROG-rm} |
|||
stripprog=${STRIPPROG-strip} |
|||
|
|||
posix_mkdir= |
|||
|
|||
# Desired mode of installed file. |
|||
mode=0755 |
|||
|
|||
# Create dirs (including intermediate dirs) using mode 755. |
|||
# This is like GNU 'install' as of coreutils 8.32 (2020). |
|||
mkdir_umask=22 |
|||
|
|||
backupsuffix= |
|||
chgrpcmd= |
|||
chmodcmd=$chmodprog |
|||
chowncmd= |
|||
mvcmd=$mvprog |
|||
rmcmd="$rmprog -f" |
|||
stripcmd= |
|||
|
|||
src= |
|||
dst= |
|||
dir_arg= |
|||
dst_arg= |
|||
|
|||
copy_on_change=false |
|||
is_target_a_directory=possibly |
|||
|
|||
usage="\ |
|||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE |
|||
or: $0 [OPTION]... SRCFILES... DIRECTORY |
|||
or: $0 [OPTION]... -t DIRECTORY SRCFILES... |
|||
or: $0 [OPTION]... -d DIRECTORIES... |
|||
|
|||
In the 1st form, copy SRCFILE to DSTFILE. |
|||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. |
|||
In the 4th, create DIRECTORIES. |
|||
|
|||
Options: |
|||
--help display this help and exit. |
|||
--version display version info and exit. |
|||
|
|||
-c (ignored) |
|||
-C install only if different (preserve data modification time) |
|||
-d create directories instead of installing files. |
|||
-g GROUP $chgrpprog installed files to GROUP. |
|||
-m MODE $chmodprog installed files to MODE. |
|||
-o USER $chownprog installed files to USER. |
|||
-p pass -p to $cpprog. |
|||
-s $stripprog installed files. |
|||
-S SUFFIX attempt to back up existing files, with suffix SUFFIX. |
|||
-t DIRECTORY install into DIRECTORY. |
|||
-T report an error if DSTFILE is a directory. |
|||
|
|||
Environment variables override the default commands: |
|||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG |
|||
RMPROG STRIPPROG |
|||
|
|||
By default, rm is invoked with -f; when overridden with RMPROG, |
|||
it's up to you to specify -f if you want it. |
|||
|
|||
If -S is not specified, no backups are attempted. |
|||
|
|||
Email bug reports to bug-automake@gnu.org. |
|||
Automake home page: https://www.gnu.org/software/automake/ |
|||
" |
|||
|
|||
while test $# -ne 0; do |
|||
case $1 in |
|||
-c) ;; |
|||
|
|||
-C) copy_on_change=true;; |
|||
|
|||
-d) dir_arg=true;; |
|||
|
|||
-g) chgrpcmd="$chgrpprog $2" |
|||
shift;; |
|||
|
|||
--help) echo "$usage"; exit $?;; |
|||
|
|||
-m) mode=$2 |
|||
case $mode in |
|||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) |
|||
echo "$0: invalid mode: $mode" >&2 |
|||
exit 1;; |
|||
esac |
|||
shift;; |
|||
|
|||
-o) chowncmd="$chownprog $2" |
|||
shift;; |
|||
|
|||
-p) cpprog="$cpprog -p";; |
|||
|
|||
-s) stripcmd=$stripprog;; |
|||
|
|||
-S) backupsuffix="$2" |
|||
shift;; |
|||
|
|||
-t) |
|||
is_target_a_directory=always |
|||
dst_arg=$2 |
|||
# Protect names problematic for 'test' and other utilities. |
|||
case $dst_arg in |
|||
-* | [=\(\)!]) dst_arg=./$dst_arg;; |
|||
esac |
|||
shift;; |
|||
|
|||
-T) is_target_a_directory=never;; |
|||
|
|||
--version) echo "$0 $scriptversion"; exit $?;; |
|||
|
|||
--) shift |
|||
break;; |
|||
|
|||
-*) echo "$0: invalid option: $1" >&2 |
|||
exit 1;; |
|||
|
|||
*) break;; |
|||
esac |
|||
shift |
|||
done |
|||
|
|||
# We allow the use of options -d and -T together, by making -d |
|||
# take the precedence; this is for compatibility with GNU install. |
|||
|
|||
if test -n "$dir_arg"; then |
|||
if test -n "$dst_arg"; then |
|||
echo "$0: target directory not allowed when installing a directory." >&2 |
|||
exit 1 |
|||
fi |
|||
fi |
|||
|
|||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then |
|||
# When -d is used, all remaining arguments are directories to create. |
|||
# When -t is used, the destination is already specified. |
|||
# Otherwise, the last argument is the destination. Remove it from $@. |
|||
for arg |
|||
do |
|||
if test -n "$dst_arg"; then |
|||
# $@ is not empty: it contains at least $arg. |
|||
set fnord "$@" "$dst_arg" |
|||
shift # fnord |
|||
fi |
|||
shift # arg |
|||
dst_arg=$arg |
|||
# Protect names problematic for 'test' and other utilities. |
|||
case $dst_arg in |
|||
-* | [=\(\)!]) dst_arg=./$dst_arg;; |
|||
esac |
|||
done |
|||
fi |
|||
|
|||
if test $# -eq 0; then |
|||
if test -z "$dir_arg"; then |
|||
echo "$0: no input file specified." >&2 |
|||
exit 1 |
|||
fi |
|||
# It's OK to call 'install-sh -d' without argument. |
|||
# This can happen when creating conditional directories. |
|||
exit 0 |
|||
fi |
|||
|
|||
if test -z "$dir_arg"; then |
|||
if test $# -gt 1 || test "$is_target_a_directory" = always; then |
|||
if test ! -d "$dst_arg"; then |
|||
echo "$0: $dst_arg: Is not a directory." >&2 |
|||
exit 1 |
|||
fi |
|||
fi |
|||
fi |
|||
|
|||
if test -z "$dir_arg"; then |
|||
do_exit='(exit $ret); exit $ret' |
|||
trap "ret=129; $do_exit" 1 |
|||
trap "ret=130; $do_exit" 2 |
|||
trap "ret=141; $do_exit" 13 |
|||
trap "ret=143; $do_exit" 15 |
|||
|
|||
# Set umask so as not to create temps with too-generous modes. |
|||
# However, 'strip' requires both read and write access to temps. |
|||
case $mode in |
|||
# Optimize common cases. |
|||
*644) cp_umask=133;; |
|||
*755) cp_umask=22;; |
|||
|
|||
*[0-7]) |
|||
if test -z "$stripcmd"; then |
|||
u_plus_rw= |
|||
else |
|||
u_plus_rw='% 200' |
|||
fi |
|||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; |
|||
*) |
|||
if test -z "$stripcmd"; then |
|||
u_plus_rw= |
|||
else |
|||
u_plus_rw=,u+rw |
|||
fi |
|||
cp_umask=$mode$u_plus_rw;; |
|||
esac |
|||
fi |
|||
|
|||
for src |
|||
do |
|||
# Protect names problematic for 'test' and other utilities. |
|||
case $src in |
|||
-* | [=\(\)!]) src=./$src;; |
|||
esac |
|||
|
|||
if test -n "$dir_arg"; then |
|||
dst=$src |
|||
dstdir=$dst |
|||
test -d "$dstdir" |
|||
dstdir_status=$? |
|||
# Don't chown directories that already exist. |
|||
if test $dstdir_status = 0; then |
|||
chowncmd="" |
|||
fi |
|||
else |
|||
|
|||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command |
|||
# might cause directories to be created, which would be especially bad |
|||
# if $src (and thus $dsttmp) contains '*'. |
|||
if test ! -f "$src" && test ! -d "$src"; then |
|||
echo "$0: $src does not exist." >&2 |
|||
exit 1 |
|||
fi |
|||
|
|||
if test -z "$dst_arg"; then |
|||
echo "$0: no destination specified." >&2 |
|||
exit 1 |
|||
fi |
|||
dst=$dst_arg |
|||
|
|||
# If destination is a directory, append the input filename. |
|||
if test -d "$dst"; then |
|||
if test "$is_target_a_directory" = never; then |
|||
echo "$0: $dst_arg: Is a directory" >&2 |
|||
exit 1 |
|||
fi |
|||
dstdir=$dst |
|||
dstbase=`basename "$src"` |
|||
case $dst in |
|||
*/) dst=$dst$dstbase;; |
|||
*) dst=$dst/$dstbase;; |
|||
esac |
|||
dstdir_status=0 |
|||
else |
|||
dstdir=`dirname "$dst"` |
|||
test -d "$dstdir" |
|||
dstdir_status=$? |
|||
fi |
|||
fi |
|||
|
|||
case $dstdir in |
|||
*/) dstdirslash=$dstdir;; |
|||
*) dstdirslash=$dstdir/;; |
|||
esac |
|||
|
|||
obsolete_mkdir_used=false |
|||
|
|||
if test $dstdir_status != 0; then |
|||
case $posix_mkdir in |
|||
'') |
|||
# With -d, create the new directory with the user-specified mode. |
|||
# Otherwise, rely on $mkdir_umask. |
|||
if test -n "$dir_arg"; then |
|||
mkdir_mode=-m$mode |
|||
else |
|||
mkdir_mode= |
|||
fi |
|||
|
|||
posix_mkdir=false |
|||
# The $RANDOM variable is not portable (e.g., dash). Use it |
|||
# here however when possible just to lower collision chance. |
|||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ |
|||
|
|||
trap ' |
|||
ret=$? |
|||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null |
|||
exit $ret |
|||
' 0 |
|||
|
|||
# Because "mkdir -p" follows existing symlinks and we likely work |
|||
# directly in world-writeable /tmp, make sure that the '$tmpdir' |
|||
# directory is successfully created first before we actually test |
|||
# 'mkdir -p'. |
|||
if (umask $mkdir_umask && |
|||
$mkdirprog $mkdir_mode "$tmpdir" && |
|||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 |
|||
then |
|||
if test -z "$dir_arg" || { |
|||
# Check for POSIX incompatibilities with -m. |
|||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or |
|||
# other-writable bit of parent directory when it shouldn't. |
|||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory. |
|||
test_tmpdir="$tmpdir/a" |
|||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"` |
|||
case $ls_ld_tmpdir in |
|||
d????-?r-*) different_mode=700;; |
|||
d????-?--*) different_mode=755;; |
|||
*) false;; |
|||
esac && |
|||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && { |
|||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` |
|||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" |
|||
} |
|||
} |
|||
then posix_mkdir=: |
|||
fi |
|||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" |
|||
else |
|||
# Remove any dirs left behind by ancient mkdir implementations. |
|||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null |
|||
fi |
|||
trap '' 0;; |
|||
esac |
|||
|
|||
if |
|||
$posix_mkdir && ( |
|||
umask $mkdir_umask && |
|||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" |
|||
) |
|||
then : |
|||
else |
|||
|
|||
# mkdir does not conform to POSIX, |
|||
# or it failed possibly due to a race condition. Create the |
|||
# directory the slow way, step by step, checking for races as we go. |
|||
|
|||
case $dstdir in |
|||
/*) prefix='/';; |
|||
[-=\(\)!]*) prefix='./';; |
|||
*) prefix='';; |
|||
esac |
|||
|
|||
oIFS=$IFS |
|||
IFS=/ |
|||
set -f |
|||
set fnord $dstdir |
|||
shift |
|||
set +f |
|||
IFS=$oIFS |
|||
|
|||
prefixes= |
|||
|
|||
for d |
|||
do |
|||
test X"$d" = X && continue |
|||
|
|||
prefix=$prefix$d |
|||
if test -d "$prefix"; then |
|||
prefixes= |
|||
else |
|||
if $posix_mkdir; then |
|||
(umask $mkdir_umask && |
|||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break |
|||
# Don't fail if two instances are running concurrently. |
|||
test -d "$prefix" || exit 1 |
|||
else |
|||
case $prefix in |
|||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; |
|||
*) qprefix=$prefix;; |
|||
esac |
|||
prefixes="$prefixes '$qprefix'" |
|||
fi |
|||
fi |
|||
prefix=$prefix/ |
|||
done |
|||
|
|||
if test -n "$prefixes"; then |
|||
# Don't fail if two instances are running concurrently. |
|||
(umask $mkdir_umask && |
|||
eval "\$doit_exec \$mkdirprog $prefixes") || |
|||
test -d "$dstdir" || exit 1 |
|||
obsolete_mkdir_used=true |
|||
fi |
|||
fi |
|||
fi |
|||
|
|||
if test -n "$dir_arg"; then |
|||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } && |
|||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && |
|||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || |
|||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 |
|||
else |
|||
|
|||
# Make a couple of temp file names in the proper directory. |
|||
dsttmp=${dstdirslash}_inst.$$_ |
|||
rmtmp=${dstdirslash}_rm.$$_ |
|||
|
|||
# Trap to clean up those temp files at exit. |
|||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 |
|||
|
|||
# Copy the file name to the temp name. |
|||
(umask $cp_umask && |
|||
{ test -z "$stripcmd" || { |
|||
# Create $dsttmp read-write so that cp doesn't create it read-only, |
|||
# which would cause strip to fail. |
|||
if test -z "$doit"; then |
|||
: >"$dsttmp" # No need to fork-exec 'touch'. |
|||
else |
|||
$doit touch "$dsttmp" |
|||
fi |
|||
} |
|||
} && |
|||
$doit_exec $cpprog "$src" "$dsttmp") && |
|||
|
|||
# and set any options; do chmod last to preserve setuid bits. |
|||
# |
|||
# If any of these fail, we abort the whole thing. If we want to |
|||
# ignore errors from any of these, just make sure not to ignore |
|||
# errors from the above "$doit $cpprog $src $dsttmp" command. |
|||
# |
|||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && |
|||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && |
|||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && |
|||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && |
|||
|
|||
# If -C, don't bother to copy if it wouldn't change the file. |
|||
if $copy_on_change && |
|||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && |
|||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && |
|||
set -f && |
|||
set X $old && old=:$2:$4:$5:$6 && |
|||
set X $new && new=:$2:$4:$5:$6 && |
|||
set +f && |
|||
test "$old" = "$new" && |
|||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 |
|||
then |
|||
rm -f "$dsttmp" |
|||
else |
|||
# If $backupsuffix is set, and the file being installed |
|||
# already exists, attempt a backup. Don't worry if it fails, |
|||
# e.g., if mv doesn't support -f. |
|||
if test -n "$backupsuffix" && test -f "$dst"; then |
|||
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null |
|||
fi |
|||
|
|||
# Rename the file to the real destination. |
|||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || |
|||
|
|||
# The rename failed, perhaps because mv can't rename something else |
|||
# to itself, or perhaps because mv is so ancient that it does not |
|||
# support -f. |
|||
{ |
|||
# Now remove or move aside any old file at destination location. |
|||
# We try this two ways since rm can't unlink itself on some |
|||
# systems and the destination file might be busy for other |
|||
# reasons. In this case, the final cleanup might fail but the new |
|||
# file should still install successfully. |
|||
{ |
|||
test ! -f "$dst" || |
|||
$doit $rmcmd "$dst" 2>/dev/null || |
|||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && |
|||
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; } |
|||
} || |
|||
{ echo "$0: cannot unlink or rename $dst" >&2 |
|||
(exit 1); exit 1 |
|||
} |
|||
} && |
|||
|
|||
# Now rename the file to the real destination. |
|||
$doit $mvcmd "$dsttmp" "$dst" |
|||
} |
|||
fi || exit 1 |
|||
|
|||
trap '' 0 |
|||
fi |
|||
done |
|||
|
|||
# Local variables: |
|||
# eval: (add-hook 'before-save-hook 'time-stamp) |
|||
# time-stamp-start: "scriptversion=" |
|||
# time-stamp-format: "%:y-%02m-%02d.%02H" |
|||
# time-stamp-time-zone: "UTC0" |
|||
# time-stamp-end: "; # UTC" |
|||
# End: |
|||
8406
externals/breakpad/autotools/ltmain.sh
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,215 @@ |
|||
#! /bin/sh |
|||
# Common wrapper for a few potentially missing GNU programs. |
|||
|
|||
scriptversion=2018-03-07.03; # UTC |
|||
|
|||
# Copyright (C) 1996-2021 Free Software Foundation, Inc. |
|||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. |
|||
|
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2, or (at your option) |
|||
# any later version. |
|||
|
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
|
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
|
|||
# As a special exception to the GNU General Public License, if you |
|||
# distribute this file as part of a program that contains a |
|||
# configuration script generated by Autoconf, you may include it under |
|||
# the same distribution terms that you use for the rest of that program. |
|||
|
|||
if test $# -eq 0; then |
|||
echo 1>&2 "Try '$0 --help' for more information" |
|||
exit 1 |
|||
fi |
|||
|
|||
case $1 in |
|||
|
|||
--is-lightweight) |
|||
# Used by our autoconf macros to check whether the available missing |
|||
# script is modern enough. |
|||
exit 0 |
|||
;; |
|||
|
|||
--run) |
|||
# Back-compat with the calling convention used by older automake. |
|||
shift |
|||
;; |
|||
|
|||
-h|--h|--he|--hel|--help) |
|||
echo "\ |
|||
$0 [OPTION]... PROGRAM [ARGUMENT]... |
|||
|
|||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due |
|||
to PROGRAM being missing or too old. |
|||
|
|||
Options: |
|||
-h, --help display this help and exit |
|||
-v, --version output version information and exit |
|||
|
|||
Supported PROGRAM values: |
|||
aclocal autoconf autoheader autom4te automake makeinfo |
|||
bison yacc flex lex help2man |
|||
|
|||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and |
|||
'g' are ignored when checking the name. |
|||
|
|||
Send bug reports to <bug-automake@gnu.org>." |
|||
exit $? |
|||
;; |
|||
|
|||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version) |
|||
echo "missing $scriptversion (GNU Automake)" |
|||
exit $? |
|||
;; |
|||
|
|||
-*) |
|||
echo 1>&2 "$0: unknown '$1' option" |
|||
echo 1>&2 "Try '$0 --help' for more information" |
|||
exit 1 |
|||
;; |
|||
|
|||
esac |
|||
|
|||
# Run the given program, remember its exit status. |
|||
"$@"; st=$? |
|||
|
|||
# If it succeeded, we are done. |
|||
test $st -eq 0 && exit 0 |
|||
|
|||
# Also exit now if we it failed (or wasn't found), and '--version' was |
|||
# passed; such an option is passed most likely to detect whether the |
|||
# program is present and works. |
|||
case $2 in --version|--help) exit $st;; esac |
|||
|
|||
# Exit code 63 means version mismatch. This often happens when the user |
|||
# tries to use an ancient version of a tool on a file that requires a |
|||
# minimum version. |
|||
if test $st -eq 63; then |
|||
msg="probably too old" |
|||
elif test $st -eq 127; then |
|||
# Program was missing. |
|||
msg="missing on your system" |
|||
else |
|||
# Program was found and executed, but failed. Give up. |
|||
exit $st |
|||
fi |
|||
|
|||
perl_URL=https://www.perl.org/ |
|||
flex_URL=https://github.com/westes/flex |
|||
gnu_software_URL=https://www.gnu.org/software |
|||
|
|||
program_details () |
|||
{ |
|||
case $1 in |
|||
aclocal|automake) |
|||
echo "The '$1' program is part of the GNU Automake package:" |
|||
echo "<$gnu_software_URL/automake>" |
|||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" |
|||
echo "<$gnu_software_URL/autoconf>" |
|||
echo "<$gnu_software_URL/m4/>" |
|||
echo "<$perl_URL>" |
|||
;; |
|||
autoconf|autom4te|autoheader) |
|||
echo "The '$1' program is part of the GNU Autoconf package:" |
|||
echo "<$gnu_software_URL/autoconf/>" |
|||
echo "It also requires GNU m4 and Perl in order to run:" |
|||
echo "<$gnu_software_URL/m4/>" |
|||
echo "<$perl_URL>" |
|||
;; |
|||
esac |
|||
} |
|||
|
|||
give_advice () |
|||
{ |
|||
# Normalize program name to check for. |
|||
normalized_program=`echo "$1" | sed ' |
|||
s/^gnu-//; t |
|||
s/^gnu//; t |
|||
s/^g//; t'` |
|||
|
|||
printf '%s\n' "'$1' is $msg." |
|||
|
|||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'" |
|||
case $normalized_program in |
|||
autoconf*) |
|||
echo "You should only need it if you modified 'configure.ac'," |
|||
echo "or m4 files included by it." |
|||
program_details 'autoconf' |
|||
;; |
|||
autoheader*) |
|||
echo "You should only need it if you modified 'acconfig.h' or" |
|||
echo "$configure_deps." |
|||
program_details 'autoheader' |
|||
;; |
|||
automake*) |
|||
echo "You should only need it if you modified 'Makefile.am' or" |
|||
echo "$configure_deps." |
|||
program_details 'automake' |
|||
;; |
|||
aclocal*) |
|||
echo "You should only need it if you modified 'acinclude.m4' or" |
|||
echo "$configure_deps." |
|||
program_details 'aclocal' |
|||
;; |
|||
autom4te*) |
|||
echo "You might have modified some maintainer files that require" |
|||
echo "the 'autom4te' program to be rebuilt." |
|||
program_details 'autom4te' |
|||
;; |
|||
bison*|yacc*) |
|||
echo "You should only need it if you modified a '.y' file." |
|||
echo "You may want to install the GNU Bison package:" |
|||
echo "<$gnu_software_URL/bison/>" |
|||
;; |
|||
lex*|flex*) |
|||
echo "You should only need it if you modified a '.l' file." |
|||
echo "You may want to install the Fast Lexical Analyzer package:" |
|||
echo "<$flex_URL>" |
|||
;; |
|||
help2man*) |
|||
echo "You should only need it if you modified a dependency" \ |
|||
"of a man page." |
|||
echo "You may want to install the GNU Help2man package:" |
|||
echo "<$gnu_software_URL/help2man/>" |
|||
;; |
|||
makeinfo*) |
|||
echo "You should only need it if you modified a '.texi' file, or" |
|||
echo "any other file indirectly affecting the aspect of the manual." |
|||
echo "You might want to install the Texinfo package:" |
|||
echo "<$gnu_software_URL/texinfo/>" |
|||
echo "The spurious makeinfo call might also be the consequence of" |
|||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" |
|||
echo "want to install GNU make:" |
|||
echo "<$gnu_software_URL/make/>" |
|||
;; |
|||
*) |
|||
echo "You might have modified some files without having the proper" |
|||
echo "tools for further handling them. Check the 'README' file, it" |
|||
echo "often tells you about the needed prerequisites for installing" |
|||
echo "this package. You may also peek at any GNU archive site, in" |
|||
echo "case some other package contains this missing '$1' program." |
|||
;; |
|||
esac |
|||
} |
|||
|
|||
give_advice "$1" | sed -e '1s/^/WARNING: /' \ |
|||
-e '2,$s/^/ /' >&2 |
|||
|
|||
# Propagate the correct exit status (expected to be 127 for a program |
|||
# not found, 63 for a program that failed due to version mismatch). |
|||
exit $st |
|||
|
|||
# Local variables: |
|||
# eval: (add-hook 'before-save-hook 'time-stamp) |
|||
# time-stamp-start: "scriptversion=" |
|||
# time-stamp-format: "%:y-%02m-%02d.%02H" |
|||
# time-stamp-time-zone: "UTC0" |
|||
# time-stamp-end: "; # UTC" |
|||
# End: |
|||
@ -0,0 +1,3 @@ |
|||
#!/bin/sh |
|||
# -E to keep the environment variables needed to run the tests. |
|||
exec sudo -E "$@" |
|||
@ -0,0 +1,153 @@ |
|||
#! /bin/sh |
|||
# test-driver - basic testsuite driver script. |
|||
|
|||
scriptversion=2018-03-07.03; # UTC |
|||
|
|||
# Copyright (C) 2011-2021 Free Software Foundation, Inc. |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify |
|||
# it under the terms of the GNU General Public License as published by |
|||
# the Free Software Foundation; either version 2, or (at your option) |
|||
# any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License |
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
|
|||
# As a special exception to the GNU General Public License, if you |
|||
# distribute this file as part of a program that contains a |
|||
# configuration script generated by Autoconf, you may include it under |
|||
# the same distribution terms that you use for the rest of that program. |
|||
|
|||
# This file is maintained in Automake, please report |
|||
# bugs to <bug-automake@gnu.org> or send patches to |
|||
# <automake-patches@gnu.org>. |
|||
|
|||
# Make unconditional expansion of undefined variables an error. This |
|||
# helps a lot in preventing typo-related bugs. |
|||
set -u |
|||
|
|||
usage_error () |
|||
{ |
|||
echo "$0: $*" >&2 |
|||
print_usage >&2 |
|||
exit 2 |
|||
} |
|||
|
|||
print_usage () |
|||
{ |
|||
cat <<END |
|||
Usage: |
|||
test-driver --test-name NAME --log-file PATH --trs-file PATH |
|||
[--expect-failure {yes|no}] [--color-tests {yes|no}] |
|||
[--enable-hard-errors {yes|no}] [--] |
|||
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS] |
|||
|
|||
The '--test-name', '--log-file' and '--trs-file' options are mandatory. |
|||
See the GNU Automake documentation for information. |
|||
END |
|||
} |
|||
|
|||
test_name= # Used for reporting. |
|||
log_file= # Where to save the output of the test script. |
|||
trs_file= # Where to save the metadata of the test run. |
|||
expect_failure=no |
|||
color_tests=no |
|||
enable_hard_errors=yes |
|||
while test $# -gt 0; do |
|||
case $1 in |
|||
--help) print_usage; exit $?;; |
|||
--version) echo "test-driver $scriptversion"; exit $?;; |
|||
--test-name) test_name=$2; shift;; |
|||
--log-file) log_file=$2; shift;; |
|||
--trs-file) trs_file=$2; shift;; |
|||
--color-tests) color_tests=$2; shift;; |
|||
--expect-failure) expect_failure=$2; shift;; |
|||
--enable-hard-errors) enable_hard_errors=$2; shift;; |
|||
--) shift; break;; |
|||
-*) usage_error "invalid option: '$1'";; |
|||
*) break;; |
|||
esac |
|||
shift |
|||
done |
|||
|
|||
missing_opts= |
|||
test x"$test_name" = x && missing_opts="$missing_opts --test-name" |
|||
test x"$log_file" = x && missing_opts="$missing_opts --log-file" |
|||
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file" |
|||
if test x"$missing_opts" != x; then |
|||
usage_error "the following mandatory options are missing:$missing_opts" |
|||
fi |
|||
|
|||
if test $# -eq 0; then |
|||
usage_error "missing argument" |
|||
fi |
|||
|
|||
if test $color_tests = yes; then |
|||
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'. |
|||
red='[0;31m' # Red. |
|||
grn='[0;32m' # Green. |
|||
lgn='[1;32m' # Light green. |
|||
blu='[1;34m' # Blue. |
|||
mgn='[0;35m' # Magenta. |
|||
std='[m' # No color. |
|||
else |
|||
red= grn= lgn= blu= mgn= std= |
|||
fi |
|||
|
|||
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st' |
|||
trap "st=129; $do_exit" 1 |
|||
trap "st=130; $do_exit" 2 |
|||
trap "st=141; $do_exit" 13 |
|||
trap "st=143; $do_exit" 15 |
|||
|
|||
# Test script is run here. We create the file first, then append to it, |
|||
# to ameliorate tests themselves also writing to the log file. Our tests |
|||
# don't, but others can (automake bug#35762). |
|||
: >"$log_file" |
|||
"$@" >>"$log_file" 2>&1 |
|||
estatus=$? |
|||
|
|||
if test $enable_hard_errors = no && test $estatus -eq 99; then |
|||
tweaked_estatus=1 |
|||
else |
|||
tweaked_estatus=$estatus |
|||
fi |
|||
|
|||
case $tweaked_estatus:$expect_failure in |
|||
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; |
|||
0:*) col=$grn res=PASS recheck=no gcopy=no;; |
|||
77:*) col=$blu res=SKIP recheck=no gcopy=yes;; |
|||
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; |
|||
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; |
|||
*:*) col=$red res=FAIL recheck=yes gcopy=yes;; |
|||
esac |
|||
|
|||
# Report the test outcome and exit status in the logs, so that one can |
|||
# know whether the test passed or failed simply by looking at the '.log' |
|||
# file, without the need of also peaking into the corresponding '.trs' |
|||
# file (automake bug#11814). |
|||
echo "$res $test_name (exit status: $estatus)" >>"$log_file" |
|||
|
|||
# Report outcome to console. |
|||
echo "${col}${res}${std}: $test_name" |
|||
|
|||
# Register the test result, and other relevant metadata. |
|||
echo ":test-result: $res" > $trs_file |
|||
echo ":global-test-result: $res" >> $trs_file |
|||
echo ":recheck: $recheck" >> $trs_file |
|||
echo ":copy-in-global-log: $gcopy" >> $trs_file |
|||
|
|||
# Local Variables: |
|||
# mode: shell-script |
|||
# sh-indentation: 2 |
|||
# eval: (add-hook 'before-save-hook 'time-stamp) |
|||
# time-stamp-start: "scriptversion=" |
|||
# time-stamp-format: "%:y-%02m-%02d.%02H" |
|||
# time-stamp-time-zone: "UTC0" |
|||
# time-stamp-end: "; # UTC" |
|||
# End: |
|||
@ -0,0 +1,10 @@ |
|||
prefix=@prefix@ |
|||
exec_prefix=@exec_prefix@ |
|||
libdir=@libdir@ |
|||
includedir=@includedir@/@PACKAGE_NAME@ |
|||
|
|||
Name: google-breakpad-client |
|||
Description: An open-source multi-platform crash reporting system |
|||
Version: @PACKAGE_VERSION@ |
|||
Libs: -L${libdir} -lbreakpad_client @PTHREAD_LIBS@ |
|||
Cflags: -I${includedir} @PTHREAD_CFLAGS@ |
|||
@ -0,0 +1,10 @@ |
|||
prefix=@prefix@ |
|||
exec_prefix=@exec_prefix@ |
|||
libdir=@libdir@ |
|||
includedir=@includedir@/@PACKAGE_NAME@ |
|||
|
|||
Name: google-breakpad |
|||
Description: An open-source multi-platform crash reporting system |
|||
Version: @PACKAGE_VERSION@ |
|||
Libs: -L${libdir} -lbreakpad @PTHREAD_LIBS@ |
|||
Cflags: -I${includedir} @PTHREAD_CFLAGS@ |
|||
@ -0,0 +1,3 @@ |
|||
GERRIT_HOST: True |
|||
CODE_REVIEW_SERVER: chromium-review.googlesource.com |
|||
VIEW_VC: https://chromium.googlesource.com/breakpad/breakpad/+/ |
|||
12104
externals/breakpad/configure
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,240 @@ |
|||
# Copyright 2006 Google LLC |
|||
# |
|||
# Redistribution and use in source and binary forms, with or without |
|||
# modification, are permitted provided that the following conditions are |
|||
# met: |
|||
# |
|||
# * Redistributions of source code must retain the above copyright |
|||
# notice, this list of conditions and the following disclaimer. |
|||
# * Redistributions in binary form must reproduce the above |
|||
# copyright notice, this list of conditions and the following disclaimer |
|||
# in the documentation and/or other materials provided with the |
|||
# distribution. |
|||
# * Neither the name of Google LLC nor the names of its |
|||
# contributors may be used to endorse or promote products derived from |
|||
# this software without specific prior written permission. |
|||
# |
|||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
|
|||
AC_PREREQ([2.71]) |
|||
|
|||
AC_INIT([breakpad],[0.1],[google-breakpad-dev@googlegroups.com]) |
|||
dnl Sanity check: the argument is just a file that should exist. |
|||
AC_CONFIG_SRCDIR(README.md) |
|||
AC_CONFIG_AUX_DIR(autotools) |
|||
AC_CONFIG_MACRO_DIR([m4]) |
|||
AC_CANONICAL_HOST |
|||
|
|||
AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.13) |
|||
AC_CONFIG_HEADERS(src/config.h) |
|||
AM_MAINTAINER_MODE |
|||
|
|||
AM_PROG_AR |
|||
AM_PROG_AS |
|||
AC_PROG_CC |
|||
AM_PROG_CC_C_O |
|||
AC_PROG_CPP |
|||
AC_PROG_CXX |
|||
AC_PROG_RANLIB |
|||
|
|||
dnl This must come before all the feature tests below. |
|||
AC_ARG_ENABLE(m32, |
|||
AS_HELP_STRING([--enable-m32], |
|||
[Compile/build with -m32] |
|||
[(default is no)]),, |
|||
[enable_m32=no]) |
|||
if test "x$enable_m32" = xyes; then |
|||
CFLAGS="${CFLAGS} -m32" |
|||
CXXFLAGS="${CXXFLAGS} -m32" |
|||
fi |
|||
|
|||
AC_SYS_LARGEFILE |
|||
AX_PTHREAD |
|||
AC_CHECK_HEADERS([a.out.h sys/mman.h sys/random.h]) |
|||
AC_CHECK_FUNCS([arc4random getcontext getrandom memfd_create]) |
|||
AM_CONDITIONAL([HAVE_GETCONTEXT], [test "x$ac_cv_func_getcontext" = xyes]) |
|||
AM_CONDITIONAL([HAVE_MEMFD_CREATE], [test "x$ac_cv_func_memfd_create" = xyes]) |
|||
|
|||
AX_CXX_COMPILE_STDCXX(17, , mandatory) |
|||
|
|||
dnl Test supported warning flags. |
|||
WARN_CXXFLAGS= |
|||
dnl This warning flag is used by clang. Its default behavior is to warn when |
|||
dnl given an unknown flag rather than error out. |
|||
AC_LANG_PUSH([C++]) |
|||
AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[ |
|||
ax_compiler_flags_test="-Werror=unknown-warning-option" |
|||
],[ |
|||
ax_compiler_flags_test="" |
|||
]) |
|||
AX_APPEND_COMPILE_FLAGS(m4_flatten([ |
|||
-Wmissing-braces |
|||
-Wnon-virtual-dtor |
|||
-Woverloaded-virtual |
|||
-Wreorder |
|||
-Wsign-compare |
|||
-Wunused-local-typedefs |
|||
-Wunused-variable |
|||
-Wvla |
|||
]), [WARN_CXXFLAGS], [${ax_compiler_flags_test}]) |
|||
AS_VAR_APPEND([WARN_CXXFLAGS], " -Werror") |
|||
AC_LANG_POP([C++]) |
|||
AC_SUBST([WARN_CXXFLAGS]) |
|||
|
|||
dnl Test support for O_CLOEXEC |
|||
AX_CHECK_DEFINE([fcntl.h], [O_CLOEXEC], [], |
|||
[AC_DEFINE([O_CLOEXEC], [0], [Fallback definition for old systems])]) |
|||
|
|||
# Only build Linux client libs when compiling for Linux |
|||
case $host in |
|||
*-*-linux* | *-android* ) |
|||
LINUX_HOST=true |
|||
;; |
|||
esac |
|||
AM_CONDITIONAL(LINUX_HOST, test x$LINUX_HOST = xtrue) |
|||
|
|||
# Only use Android support headers when compiling for Android |
|||
case $host in |
|||
*-android*) |
|||
ANDROID_HOST=true |
|||
;; |
|||
esac |
|||
AM_CONDITIONAL(ANDROID_HOST, test x$ANDROID_HOST = xtrue) |
|||
|
|||
# Some tools (like mac ones) only support x86 currently. |
|||
case $host_cpu in |
|||
i?86|x86_64) |
|||
X86_HOST=true |
|||
;; |
|||
esac |
|||
AM_CONDITIONAL(X86_HOST, test x$X86_HOST = xtrue) |
|||
|
|||
AC_ARG_ENABLE(processor, |
|||
AS_HELP_STRING([--disable-processor], |
|||
[Don't build processor library] |
|||
[(default is no)]),, |
|||
[enable_processor=yes]) |
|||
AM_CONDITIONAL(DISABLE_PROCESSOR, test "x$enable_processor" != xyes) |
|||
|
|||
AC_ARG_ENABLE(tools, |
|||
AS_HELP_STRING([--disable-tools], |
|||
[Don't build tool binaries] |
|||
[(default is no)]),, |
|||
[enable_tools=yes]) |
|||
AM_CONDITIONAL(DISABLE_TOOLS, test "x$enable_tools" != xyes) |
|||
|
|||
if test x$LINUX_HOST = xfalse -a "x$enable_processor" != xyes -a "x$enable_tools" != xyes; then |
|||
AC_MSG_ERROR([--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!]) |
|||
fi |
|||
|
|||
AC_ARG_ENABLE(system-test-libs, |
|||
AS_HELP_STRING([--enable-system-test-libs], |
|||
[Use gtest/gmock/etc... from the system instead ] |
|||
[of the local copies (default is local)]),, |
|||
[enable_system_test_libs=no]) |
|||
AM_CONDITIONAL(SYSTEM_TEST_LIBS, test "x$enable_system_test_libs" = xyes) |
|||
|
|||
AC_ARG_VAR([GMOCK_CFLAGS], [Compiler flags for gmock]) |
|||
AC_ARG_VAR([GMOCK_LIBS], [Linker flags for gmock]) |
|||
AC_ARG_VAR([GTEST_CFLAGS], [Compiler flags for gtest]) |
|||
AC_ARG_VAR([GTEST_LIBS], [Linker flags for gtest]) |
|||
if test "x$enable_system_test_libs" = xyes; then |
|||
: "${GMOCK_CFLAGS:=-pthread}" |
|||
: "${GMOCK_LIBS:=-lgmock -lgtest -pthread -lpthread}" |
|||
: "${GTEST_CFLAGS:=-pthread}" |
|||
: "${GTEST_LIBS:=-lgtest -pthread -lpthread}" |
|||
fi |
|||
|
|||
AC_ARG_ENABLE(selftest, |
|||
AS_HELP_STRING([--enable-selftest], |
|||
[Run extra tests with "make check" ] |
|||
[(may conflict with optimizations) ] |
|||
[(default is no)]),, |
|||
[enable_selftest=no]) |
|||
AM_CONDITIONAL(SELFTEST, test "x$enable_selftest" = xyes) |
|||
|
|||
AC_ARG_WITH(rustc-demangle, |
|||
AS_HELP_STRING([--with-rustc-demangle=/path/to/rustc-demangle], |
|||
[Link against the rustc-demangle library] |
|||
[to demangle Rust language symbols during] |
|||
[symbol dumping (default is no)] |
|||
[Pass the path to the crate root.]),, |
|||
[with_rustc_demangle=no]) |
|||
|
|||
RUSTC_DEMANGLE_BASE_CFLAGS="-DHAVE_RUSTC_DEMANGLE" |
|||
RUSTC_DEMANGLE_BASE_LIBS="-lrustc_demangle -lpthread -ldl" |
|||
|
|||
if test "x${with_rustc_demangle}" != xno; then |
|||
if ! test -f "${with_rustc_demangle}/Cargo.toml"; then |
|||
AC_MSG_ERROR(You must pass the path to the rustc-demangle crate for --with-rustc-demangle) |
|||
fi |
|||
RUSTC_DEMANGLE_CFLAGS="-I${with_rustc_demangle}/crates/capi/include ${RUSTC_DEMANGLE_BASE_CFLAGS}" |
|||
RUSTC_DEMANGLE_LIBS="-L${with_rustc_demangle}/target/release ${RUSTC_DEMANGLE_BASE_LIBS}" |
|||
fi |
|||
|
|||
AC_ARG_ENABLE(system-rustc-demangle, |
|||
AS_HELP_STRING([--enable-system-rustc-demangle], |
|||
[Link against the rustc-demangle library] |
|||
[to demangle Rust language symbols during] |
|||
[symbol dumping (default is no). This assumes] |
|||
[that rustc-demangle is installed in your sysroot,] |
|||
[and all headers from it are available in your] |
|||
[standard include path] |
|||
),, |
|||
[enable_system_rustc_demangle=no]) |
|||
|
|||
if test "x${enable_system_rustc_demangle}" != xno; then |
|||
if test "x${with_rustc_demangle}" != xno; then |
|||
AC_MSG_ERROR([--enable-system-rustc-demangle and --with-rustc-demangle are mutually exclusive.]) |
|||
fi |
|||
|
|||
RUSTC_DEMANGLE_CFLAGS="${RUSTC_DEMANGLE_BASE_CFLAGS}" |
|||
RUSTC_DEMANGLE_LIBS="${RUSTC_DEMANGLE_BASE_LIBS}" |
|||
|
|||
AC_CHECK_LIB([rustc_demangle], [rustc_demangle], [], |
|||
[AC_MSG_ERROR(librustc_demangle.a must be present when --enable-system-rustc-demangle is specified)], |
|||
[$RUSTC_DEMANGLE_LIBS]) |
|||
AC_CHECK_HEADERS(rustc_demangle.h, [], |
|||
[AC_MSG_ERROR(rustc_demangle.h must be present when --enable-system-rustc-demangle is specified)]) |
|||
fi |
|||
|
|||
AC_ARG_VAR([RUSTC_DEMANGLE_CFLAGS], [Compiler flags for rustc-demangle]) |
|||
AC_ARG_VAR([RUSTC_DEMANGLE_LIBS], [Linker flags for rustc-demangle]) |
|||
|
|||
AC_ARG_ENABLE(zstd, |
|||
AS_HELP_STRING([--enable-zstd], |
|||
[Enable decompression of ELF sections with zstd]),, |
|||
[enable_zstd=no]) |
|||
if test "x${enable_zstd}" != xno; then |
|||
AC_CHECK_LIB(zstd, ZSTD_decompress, [], |
|||
[AC_MSG_ERROR([zstd library not found.])]) |
|||
AC_CHECK_HEADER(zstd.h, [], |
|||
[AC_MSG_ERROR([zstd header not found.])]) |
|||
fi |
|||
|
|||
AC_ARG_WITH(tests-as-root, |
|||
AS_HELP_STRING([--with-tests-as-root], |
|||
[Run the tests as root. Use this on platforms] |
|||
[like travis-ci.org that require root privileges] |
|||
[to use ptrace (default is no)]),, |
|||
[with_tests_as_root=no]) |
|||
AM_CONDITIONAL(TESTS_AS_ROOT, test "x$with_tests_as_root" = xyes) |
|||
|
|||
AC_CONFIG_FILES(m4_flatten([ |
|||
breakpad.pc |
|||
breakpad-client.pc |
|||
Makefile |
|||
])) |
|||
|
|||
AC_OUTPUT |
|||
@ -0,0 +1,38 @@ |
|||
<?xml version='1.0' encoding='UTF-8'?> |
|||
<!-- AUTOGENERATED BY deps-to-manifest.py; DO NOT EDIT --> |
|||
<manifest> |
|||
|
|||
<default revision='refs/heads/main' |
|||
remote='chromium' |
|||
sync-c='true' |
|||
sync-j='8' /> |
|||
|
|||
<remote name='github' |
|||
fetch='https://github.com/' |
|||
review='' /> |
|||
|
|||
<remote name='chromium' |
|||
fetch='https://chromium.googlesource.com/' |
|||
review='https://chromium-review.googlesource.com' /> |
|||
|
|||
<project path='src' |
|||
name='breakpad/breakpad' |
|||
revision='refs/heads/main' |
|||
remote='chromium' /> |
|||
|
|||
<project path='src/src/testing' |
|||
name='google/googletest.git' |
|||
revision='refs/tags/release-1.11.0' |
|||
remote='github' /> |
|||
|
|||
<project path='src/src/third_party/lss' |
|||
name='linux-syscall-support/' |
|||
revision='9719c1e1e676814c456b55f5f070eabad6709d31' |
|||
remote='chromium' /> |
|||
|
|||
<project path='src/src/third_party/protobuf/protobuf' |
|||
name='google/protobuf.git' |
|||
revision='cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac' |
|||
remote='github' /> |
|||
|
|||
</manifest> |
|||
@ -0,0 +1 @@ |
|||
* |
|||
|
After Width: 708 | Height: 774 | Size: 82 KiB |
1023
externals/breakpad/docs/breakpad.svg
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,223 @@ |
|||
# Breakpad Client Libraries |
|||
|
|||
## Objective |
|||
|
|||
The Breakpad client libraries are responsible for monitoring an application for |
|||
crashes (exceptions), handling them when they occur by generating a dump, and |
|||
providing a means to upload dumps to a crash reporting server. These tasks are |
|||
divided between the “handler” (short for “exception handler”) library linked in |
|||
to an application being monitored for crashes, and the “sender” library, |
|||
intended to be linked in to a separate external program. |
|||
|
|||
## Background |
|||
|
|||
As one of the chief tasks of the client handler is to generate a dump, an |
|||
understanding of [dump files](processor_design.md) will aid in understanding the |
|||
handler. |
|||
|
|||
## Overview |
|||
|
|||
Breakpad provides client libraries for each of its target platforms. Currently, |
|||
these exist for Windows on x86 and Mac OS X on both x86 and PowerPC. A Linux |
|||
implementation has been written and is currently under review. |
|||
|
|||
Because the mechanisms for catching exceptions and the methods for obtaining the |
|||
information that a dump contains vary between operating systems, each target |
|||
operating system requires a completely different handler implementation. Where |
|||
multiple CPUs are supported for a single operating system, the handler |
|||
implementation will likely also require separate code for each processor type to |
|||
extract CPU-specific information. One of the goals of the Breakpad handler is to |
|||
provide a prepackaged cross-platform system that masks many of these |
|||
system-level differences and quirks from the application developer. Although the |
|||
underlying implementations differ, the handler library for each system follows |
|||
the same set of principles and exposes a similar interface. |
|||
|
|||
Code that wishes to take advantage of Breakpad should be linked against the |
|||
handler library, and should, at an appropriate time, install a Breakpad handler. |
|||
For applications, it is generally desirable to install the handler as early in |
|||
the start-up process as possible. Developers of library code using Breakpad to |
|||
monitor itself may wish to install a Breakpad handler when the library is |
|||
loaded, or may only want to install a handler when calls are made in to the |
|||
library. |
|||
|
|||
The handler can be triggered to generate a dump either by catching an exception |
|||
or at the request of the application itself. The latter case may be useful in |
|||
debugging assertions or other conditions where developers want to know how a |
|||
program got in to a specific non-crash state. After generating a dump, the |
|||
handler calls a user-specified callback function. The callback function may |
|||
collect additional data about the program’s state, quit the program, launch a |
|||
crash reporter application, or perform other tasks. Allowing for this |
|||
functionality to be dictated by a callback function preserves flexibility. |
|||
|
|||
The sender library is also has a separate implementation for each supported |
|||
platform, because of the varying interfaces for accessing network resources on |
|||
different operating systems. The sender transmits a dump along with other |
|||
application-defined information to a crash report server via HTTP. Because dumps |
|||
may contain sensitive data, the sender allows for the use of HTTPS. |
|||
|
|||
The canonical example of the entire client system would be for a monitored |
|||
application to link against the handler library, install a Breakpad handler from |
|||
its main function, and provide a callback to launch a small crash reporter |
|||
program. The crash reporter program would be linked against the sender library, |
|||
and would send the crash dump when launched. A separate process is recommended |
|||
for this function because of the unreliability inherent in doing any significant |
|||
amount of work from a crashed process. |
|||
|
|||
## Detailed Design |
|||
|
|||
### Exception Handler Installation |
|||
|
|||
The mechanisms for installing an exception handler vary between operating |
|||
systems. On Windows, it’s a relatively simple matter of making one call to |
|||
register a [top-level exception |
|||
filter](http://msdn.microsoft.com/library/en-us/debug/base/setunhandledexceptionfilter.asp) |
|||
callback function. On most Unix-like systems such as Linux, processes are |
|||
informed of exceptions by the delivery of a signal, so an exception handler |
|||
takes the form of a signal handler. The native mechanism to catch exceptions on |
|||
Mac OS X requires a large amount of code to set up a Mach port, identify it as |
|||
the exception port, and assign a thread to listen for an exception on that port. |
|||
Just as the preparation of exception handlers differ, the manner in which they |
|||
are called differs as well. On Windows and most Unix-like systems, the handler |
|||
is called on the thread that caused the exception. On Mac OS X, the thread |
|||
listening to the exception port is notified that an exception has occurred. The |
|||
different implementations of the Breakpad handler libraries perform these tasks |
|||
in the appropriate ways on each platform, while exposing a similar interface on |
|||
each. |
|||
|
|||
A Breakpad handler is embodied in an `ExceptionHandler` object. Because it’s a |
|||
C++ object, `ExceptionHandler`s may be created as local variables, allowing them |
|||
to be installed and removed as functions are called and return. This provides |
|||
one possible way for a developer to monitor only a portion of an application for |
|||
crashes. |
|||
|
|||
### Exception Basics |
|||
|
|||
Once an application encounters an exception, it is in an indeterminate and |
|||
possibly hazardous state. Consequently, any code that runs after an exception |
|||
occurs must take extreme care to avoid performing operations that might fail, |
|||
hang, or cause additional exceptions. This task is not at all straightforward, |
|||
and the Breakpad handler library seeks to do it properly, accounting for all of |
|||
the minute details while allowing other application developers, even those with |
|||
little systems programming experience, to reap the benefits. All of the Breakpad |
|||
handler code that executes after an exception occurs has been written according |
|||
to the following guidelines for safety at exception time: |
|||
|
|||
* Use of the application heap is forbidden. The heap may be corrupt or |
|||
otherwise unusable, and allocators may not function. |
|||
* Resource allocation must be severely limited. The handler may create a new |
|||
file to contain the dump, and it may attempt to launch a process to continue |
|||
handling the crash. |
|||
* Execution on the thread that caused the exception is significantly limited. |
|||
The only code permitted to execute on this thread is the code necessary to |
|||
transition handling to a dedicated preallocated handler thread, and the code |
|||
to return from the exception handler. |
|||
* Handlers shouldn’t handle crashes by attempting to walk stacks themselves, |
|||
as stacks may be in inconsistent states. Dump generation should be performed |
|||
by interfacing with the operating system’s memory manager and code module |
|||
manager. |
|||
* Library code, including runtime library code, must be avoided unless it |
|||
provably meets the above guidelines. For example, this means that the STL |
|||
string class may not be used, because it performs operations that attempt to |
|||
allocate and use heap memory. It also means that many C runtime functions |
|||
must be avoided, particularly on Windows, because of heap operations that |
|||
they may perform. |
|||
|
|||
A dedicated handler thread is used to preserve the state of the exception thread |
|||
when an exception occurs: during dump generation, it is difficult if not |
|||
impossible for a thread to accurately capture its own state. Performing all |
|||
exception-handling functions on a separate thread is also critical when handling |
|||
stack-limit-exceeded exceptions. It would be hazardous to run out of stack space |
|||
while attempting to handle an exception. Because of the rule against allocating |
|||
resources at exception time, the Breakpad handler library creates its handler |
|||
thread when it installs its exception handler. On Mac OS X, this handler thread |
|||
is created during the normal setup of the exception handler, and the handler |
|||
thread will be signaled directly in the event of an exception. On Windows and |
|||
Linux, the handler thread is signaled by a small amount of code that executes on |
|||
the exception thread. Because the code that executes on the exception thread in |
|||
this case is small and safe, this does not pose a problem. Even when an |
|||
exception is caused by exceeding stack size limits, this code is sufficiently |
|||
compact to execute entirely within the stack’s guard page without causing an |
|||
exception. |
|||
|
|||
The handler thread may also be triggered directly by a user call, even when no |
|||
exception occurs, to allow dumps to be generated at any point deemed |
|||
interesting. |
|||
|
|||
### Filter Callback |
|||
|
|||
When the handler thread begins handling an exception, it calls an optional |
|||
user-defined filter callback function, which is responsible for judging whether |
|||
Breakpad’s handler should continue handling the exception or not. This mechanism |
|||
is provided for the benefit of library or plug-in code, whose developers may not |
|||
be interested in reports of crashes that occur outside of their modules but |
|||
within processes hosting their code. If the filter callback indicates that it is |
|||
not interested in the exception, the Breakpad handler arranges for it to be |
|||
delivered to any previously-installed handler. |
|||
|
|||
### Dump Generation |
|||
|
|||
Assuming that the filter callback approves (or does not exist), the handler |
|||
writes a dump in a directory specified by the application developer when the |
|||
handler was installed, using a previously generated unique identifier to avoid |
|||
name collisions. The mechanics of dump generation also vary between platforms, |
|||
but in general, the process involves enumerating each thread of execution, and |
|||
capturing its state, including processor context and the active portion of its |
|||
stack area. The dump also includes a list of the code modules loaded in to the |
|||
application, and an indicator of which thread generated the exception or |
|||
requested the dump. In order to avoid allocating memory during this process, the |
|||
dump is written in place on disk. |
|||
|
|||
### Post-Dump Behavior |
|||
|
|||
Upon completion of writing the dump, a second callback function is called. This |
|||
callback may be used to launch a separate crash reporting program or to collect |
|||
additional data from the application. The callback may also be used to influence |
|||
whether Breakpad will treat the exception as handled or unhandled. Even after a |
|||
dump is successfully generated, Breakpad can be made to behave as though it |
|||
didn’t actually handle an exception. This function may be useful for developers |
|||
who want to test their applications with Breakpad enabled but still retain the |
|||
ability to use traditional debugging techniques. It also allows a |
|||
Breakpad-enabled application to coexist with a platform’s native crash reporting |
|||
system, such as Mac OS X’ [CrashReporter](http://developer.apple.com/technotes/tn2004/tn2123.html) |
|||
and [Windows Error Reporting](http://msdn.microsoft.com/isv/resources/wer/). |
|||
|
|||
Typically, when Breakpad handles an exception fully and no debuggers are |
|||
involved, the crashed process will terminate. |
|||
|
|||
Authors of both callback functions that execute within a Breakpad handler are |
|||
cautioned that their code will be run at exception time, and that as a result, |
|||
they should observe the same programming practices that the Breakpad handler |
|||
itself adheres to. Notably, if a callback is to be used to collect additional |
|||
data from an application, it should take care to read only “safe” data. This |
|||
might involve accessing only static memory locations that are updated |
|||
periodically during the course of normal program execution. |
|||
|
|||
### Sender Library |
|||
|
|||
The Breakpad sender library provides a single function to send a crash report to |
|||
a crash server. It accepts a crash server’s URL, a map of key-value parameters |
|||
that will accompany the dump, and the path to a dump file itself. Each of the |
|||
key-value parameters and the dump file are sent as distinct parts of a multipart |
|||
HTTP POST request to the specified URL using the platform’s native HTTP |
|||
facilities. On Linux, [libcurl](http://curl.haxx.se/) is used for this function, |
|||
as it is the closest thing to a standard HTTP library available on that |
|||
platform. |
|||
|
|||
## Future Plans |
|||
|
|||
Although we’ve had great success with in-process dump generation by following |
|||
our guidelines for safe code at exception time, we are exploring options for |
|||
allowing dumps to be generated in a separate process, to further enhance the |
|||
handler library’s robustness. |
|||
|
|||
On Windows, we intend to offer tools to make it easier for Breakpad’s settings |
|||
to be managed by the native group policy management system. |
|||
|
|||
We also plan to offer tools that many developers would find desirable in the |
|||
context of handling crashes, such as a mechanism to determine at launch if the |
|||
program last terminated in a crash, and a way to calculate “crashiness” in terms |
|||
of crashes over time or the number of application launches between crashes. |
|||
|
|||
We are also investigating methods to capture crashes that occur early in an |
|||
application’s launch sequence, including crashes that occur before a program’s |
|||
main function begins executing. |
|||
@ -0,0 +1,35 @@ |
|||
# Introduction |
|||
|
|||
Thanks for thinking of contributing to Breakpad! Unfortunately there are some |
|||
pesky legal issues to get out of the way, but they're quick and painless. |
|||
|
|||
## Legal |
|||
|
|||
If you're doing work individually, not as part of any employment, you'll need to |
|||
sign the <a |
|||
href='http://code.google.com/legal/individual-cla-v1.0.html'>Individual |
|||
Contributor License Agreement</a>. This agreement can be completed |
|||
electronically. |
|||
|
|||
If you're contributing to Breakpad as part of your employment with another |
|||
organization, you'll need to sign a <a |
|||
href='http://code.google.com/legal/corporate-cla-v1.0.html'> Corporate |
|||
Contributor License Agreement</a>. Once completed this document will need to be |
|||
faxed. |
|||
|
|||
**_IMPORTANT_**: The authors(you!) of the contributions will maintain all |
|||
copyrights; the agreements you sign will grant rights to Google to use your |
|||
work. |
|||
|
|||
Thanks, and if you have any questions let me know and I'll loop in the legal guy |
|||
here to get you an answer. |
|||
|
|||
## Technical |
|||
|
|||
Once you have signed the agreement you can be added to our contributors list and |
|||
have write access to code. For full details on getting started see our trunk |
|||
`README`. |
|||
|
|||
## List of people who have signed contributor agreements |
|||
|
|||
None so far. |
|||
@ -0,0 +1,128 @@ |
|||
The goal of this document is to give an overview of the exception handling |
|||
options in breakpad. |
|||
|
|||
# Basics |
|||
|
|||
Exception handling is a mechanism designed to handle the occurrence of |
|||
exceptions, special conditions that change the normal flow of program execution. |
|||
|
|||
`SetUnhandledExceptionFilter` replaces all unhandled exceptions when Breakpad is |
|||
enabled. TODO: More on first and second change and vectored v. try/catch. |
|||
|
|||
There are two main types of exceptions across all platforms: in-process and |
|||
out-of-process. |
|||
|
|||
# In-Process |
|||
|
|||
In process exception handling is relatively simple since the crashing process |
|||
handles crash reporting. It is generally considered unsafe to write a minidump |
|||
from a crashed process. For example, key data structures could be corrupted or |
|||
the stack on which the exception handler runs could have been overwritten. For |
|||
this reason all platforms also support some level of out-of-process exception |
|||
handling. |
|||
|
|||
## Windows |
|||
|
|||
In-process exception handling Breakpad creates a 'handler head' that waits |
|||
infinitely on a semaphore at start up. When this thread is woken it writes the |
|||
minidump and signals to the excepting thread that it may continue. A filter will |
|||
tell the OS to kill the process if the minidump is written successfully. |
|||
Otherwise it continues. |
|||
|
|||
# Out-of-Process |
|||
|
|||
Out-of-process exception handling is more complicated than in-process exception |
|||
handling because of the need to set up a separate process that can read the |
|||
state of the crashing process. |
|||
|
|||
## Windows |
|||
|
|||
Breakpad uses two abstractions around the exception handler to make things work: |
|||
`CrashGenerationServer` and `CrashGenerationClient`. The constructor for these |
|||
takes a named pipe name. |
|||
|
|||
During server start up a named pipe and registers callbacks for client |
|||
connections are created. The named pipe is used for registration and all IO on |
|||
the pipe is done asynchronously. `OnPipeConnected` is called when a client |
|||
attempts to connect (call `CreateFile` on the pipe). `OnPipeConnected` does the |
|||
state machine transition from `Initial` to `Connecting` and on through |
|||
`Reading`, `Reading_Done`, `Writing`, `Writing_Done`, `Reading_ACK`, and |
|||
`Disconnecting`. |
|||
|
|||
When registering callbacks, the client passes in two pointers to pointers: 1. A |
|||
pointer to the `EXCEPTION_INFO` pointer 1. A pointer to the `MDRawAssertionInfo` |
|||
which handles various non-exception failures like assertions |
|||
|
|||
The essence of registration is adding a "`ClientInfo`" object that contains |
|||
handles used for synchronization with the crashing process to an array |
|||
maintained by the server. This is how we can keep track of all the clients on |
|||
the system that have registered for minidumps. These handles are: * |
|||
`server_died(mutex)` * `dump_requested(Event)` * `dump_generated(Event)` |
|||
|
|||
The server registers asynchronous waits on these events with the `ClientInfo` |
|||
object as the callback context. When the `dump_requested` event is set by the |
|||
client, the `OnDumpRequested()` callback is called. The server uses the handles |
|||
inside `ClientInfo` to communicate with the child process. Once the child sets |
|||
the event, it waits for two objects: 1. the `dump_generated` event 1. the |
|||
`server_died` mutex |
|||
|
|||
In the end handles are "duped" into the client process, and the clients use |
|||
`SetEvent` to request events, wait on the other event, or the `server_died` |
|||
mutex. |
|||
|
|||
## Linux |
|||
|
|||
### Current Status |
|||
|
|||
As of July 2011, Linux had a minidump generator that is not entirely |
|||
out-of-process. The minidump was generated from a separate process, but one that |
|||
shared an address space, file descriptors, signal handles and much else with the |
|||
crashing process. It worked by using the `clone()` system call to duplicate the |
|||
crashing process, and then uses `ptrace()` and the `/proc` file system to |
|||
retrieve the information required to write the minidump. Since then Breakpad has |
|||
updated Linux exception handling to provide more benefits of out-of-process |
|||
report generation. |
|||
|
|||
### Proposed Design |
|||
|
|||
#### Overview |
|||
|
|||
Breakpad would use a per-user daemon to write out a minidump that does not have, |
|||
interact with or depend on the crashing process. We don't want to start a new |
|||
separate process every time a user launches a Breakpad-enabled process. Doing |
|||
one daemon per machine is unacceptable for security concerns around one user |
|||
being able to initiate a minidump generation for another user's process. |
|||
|
|||
#### Client/Server Communication |
|||
|
|||
On Breakpad initialization in a process, the initializer would check if the |
|||
daemon is running and, if not, start it. The race condition between the check |
|||
and the initialization is not a problem because multiple daemons can check if |
|||
the IPC endpoint already exists and if a server is listening. Even if multiple |
|||
copies of the daemon try to `bind()` the filesystem to name the socket, all but |
|||
one will fail and can terminate. |
|||
|
|||
This point is relevant for error handling conditions. Linux does not clean the |
|||
file system representation of a UNIX domain socket even if both endpoints |
|||
terminate, so checking for existence is not strong enough. However checking the |
|||
process list or sending a ping on the socket can handle this. |
|||
|
|||
Breakpad uses UNIX domain sockets since they support full duplex communication |
|||
(unlike Windows, named pipes on Linux are half) and the kernal automatically |
|||
creates a private channel between the client and server once the client calls |
|||
`connect()`. |
|||
|
|||
#### Minidump Generation |
|||
|
|||
Breakpad could use the current system with `ptrace()` and `/proc` within the |
|||
daemon executable. |
|||
|
|||
Overall the operations look like: 1. Signal from OS indicating crash 1. Signal |
|||
Handler suspends all threads except itself 1. Signal Handler sends |
|||
`CRASH_DUMP_REQUEST` message to server and waits for response 1. Server inspects |
|||
1. Minidump is asynchronously written to disk by the server 1. Server responds |
|||
indicating inspection is done |
|||
|
|||
## Mac OSX |
|||
|
|||
Out-of-process exception handling is fully supported on Mac. |
|||
@ -0,0 +1,115 @@ |
|||
# Introduction |
|||
|
|||
Breakpad is a library and tool suite that allows you to distribute an |
|||
application to users with compiler-provided debugging information removed, |
|||
record crashes in compact "minidump" files, send them back to your server, and |
|||
produce C and C++ stack traces from these minidumps. Breakpad can also write |
|||
minidumps on request for programs that have not crashed. |
|||
|
|||
Breakpad is currently used by Google Chrome, Firefox, Google Picasa, Camino, |
|||
Google Earth, and other projects. |
|||
|
|||
 |
|||
|
|||
Breakpad has three main components: |
|||
|
|||
* The **client** is a library that you include in your application. It can |
|||
write minidump files capturing the current threads' state and the identities |
|||
of the currently loaded executable and shared libraries. You can configure |
|||
the client to write a minidump when a crash occurs, or when explicitly |
|||
requested. |
|||
|
|||
* The **symbol dumper** is a program that reads the debugging information |
|||
produced by the compiler and produces a **symbol file**, in [Breakpad's own |
|||
format](symbol_files.md). |
|||
|
|||
* The **processor** is a program that reads a minidump file, finds the |
|||
appropriate symbol files for the versions of the executables and shared |
|||
libraries the minidump mentions, and produces a human-readable C/C++ stack |
|||
trace. |
|||
|
|||
# The minidump file format |
|||
|
|||
The minidump file format is similar to core files but was developed by Microsoft |
|||
for its crash-uploading facility. A minidump file contains: |
|||
|
|||
* A list of the executable and shared libraries that were loaded in the |
|||
process at the time the dump was created. This list includes both file names |
|||
and identifiers for the particular versions of those files that were loaded. |
|||
|
|||
* A list of threads present in the process. For each thread, the minidump |
|||
includes the state of the processor registers, and the contents of the |
|||
threads' stack memory. These data are uninterpreted byte streams, as the |
|||
Breakpad client generally has no debugging information available to produce |
|||
function names or line numbers, or even identify stack frame boundaries. |
|||
|
|||
* Other information about the system on which the dump was collected: |
|||
processor and operating system versions, the reason for the dump, and so on. |
|||
|
|||
Breakpad uses Windows minidump files on all platforms, instead of the |
|||
traditional core files, for several reasons: |
|||
|
|||
* Core files can be very large, making them impractical to send across a |
|||
network to the collector for processing. Minidumps are smaller, as they were |
|||
designed to be used this way. |
|||
|
|||
* The core file format is poorly documented. For example, the Linux Standards |
|||
Base does not describe how registers are stored in `PT_NOTE` segments. |
|||
|
|||
* It is harder to persuade a Windows machine to produce a core dump file than |
|||
it is to persuade other machines to write a minidump file. |
|||
|
|||
* It simplifies the Breakpad processor to support only one file format. |
|||
|
|||
# Overview/Life of a minidump |
|||
|
|||
A minidump is generated via calls into the Breakpad library. By default, |
|||
initializing Breakpad installs an exception/signal handler that writes a |
|||
minidump to disk at exception time. On Windows, this is done via |
|||
`SetUnhandledExceptionFilter()`; on OS X, this is done by creating a thread that |
|||
waits on the Mach exception port; and on Linux, this is done by installing a |
|||
signal handler for various exceptions like `SIGILL, SIGSEGV` etc. |
|||
|
|||
Once the minidump is generated, each platform has a slightly different way of |
|||
uploading the crash dump. On Windows & Linux, a separate library of functions is |
|||
provided that can be called into to do the upload. On OS X, a separate process |
|||
is spawned that prompts the user for permission, if configured to do so, and |
|||
sends the file. |
|||
|
|||
# Terminology |
|||
|
|||
**In-process vs. out-of-process exception handling** - it's generally considered |
|||
that writing the minidump from within the crashed process is unsafe - key |
|||
process data structures could be corrupted, or the stack on which the exception |
|||
handler runs could have been overwritten, etc. All 3 platforms support what's |
|||
known as "out-of-process" exception handling. |
|||
|
|||
# Integration overview |
|||
|
|||
## Breakpad Code Overview |
|||
|
|||
All the client-side code is found by visiting the Google Project at |
|||
https://chromium.googlesource.com/breakpad/breakpad. The following directory structure is |
|||
present in the `src` directory: |
|||
|
|||
* `processor` Contains minidump-processing code that is used on the server |
|||
side and isn't of use on the client side |
|||
* `client` Contains client minidump-generation libraries for all platforms |
|||
* `tools` Contains source code & projects for building various tools on each |
|||
platform. |
|||
|
|||
(Among other directories) |
|||
|
|||
* [Windows Integration Guide](windows_client_integration.md) |
|||
* [Mac Integration Guide](mac_breakpad_starter_guide.md) |
|||
* [Linux Integration Guide](linux_starter_guide.md) |
|||
|
|||
## Build process specifics(symbol generation) |
|||
|
|||
This applies to all platforms. Inside `src/tools/{platform}/dump_syms` is a tool |
|||
that can read debugging information for each platform (e.g. for OS X/Linux, |
|||
DWARF and STABS, and for Windows, PDB files) and generate a Breakpad symbol |
|||
file. This tool should be run on your binary before it's stripped(in the case of |
|||
OS X/Linux) and the symbol files need to be stored somewhere that the minidump |
|||
processor can find. There is another tool, `symupload`, that can be used to |
|||
upload symbol files if you have written a server that can accept them. |
|||
@ -0,0 +1,39 @@ |
|||
# How To Use Breakpad As a Coredump Handler on Linux |
|||
|
|||
This document presents a way to use Breakpad in order to generate |
|||
minidumps system wide on Linux. |
|||
|
|||
Please refer to [Linux starter guide](./linux_starter_guide.md) if |
|||
instead you want to integrate breakpad into your application. |
|||
|
|||
## Motivation |
|||
|
|||
When working on an embedded system, disk and memory space is often |
|||
limited and when a process crashes it must be restarted as soon as |
|||
possible. Sometime saving a full coredump takes to much time or |
|||
consumes too much space. |
|||
|
|||
## Breakpad Core Handler |
|||
|
|||
In such case the program `core_handler` can be use to generate |
|||
minidumps instead of coredumps. `core_handler` reads the firsts |
|||
sections of the coredump (where the various threads are described) |
|||
generated by Linux from the standard input and then directly reads |
|||
`/proc/<pid>/mem` to reconstruct the stacktraces. |
|||
|
|||
One can test it with: |
|||
|
|||
``` |
|||
# echo "|/usr/libexec/core_handler %P /var/lib/minidump/%e-%i.md" > |
|||
/proc/sys/kernel/core_pattern |
|||
# echo 1 > /proc/sys/kernel/core_pipe_limit |
|||
``` |
|||
|
|||
Be aware that a real world integration would likely require further |
|||
customization and so `core_handler` can be wrapped into a script (for |
|||
example to change the permission of the minidump file or to signal the |
|||
presence of the minidump to another service). |
|||
|
|||
Please refer to |
|||
[core(5)](https://man7.org/linux/man-pages/man5/core.5.html) for more |
|||
details. |
|||
@ -0,0 +1,110 @@ |
|||
# How To Add Breakpad To Your Linux Application |
|||
|
|||
This document is an overview of using the Breakpad client libraries on Linux. |
|||
|
|||
## Building the Breakpad libraries |
|||
|
|||
Breakpad provides an Autotools build system that will build both the Linux |
|||
client libraries and the processor libraries. Running `./configure && make` in |
|||
the Breakpad source directory will produce |
|||
**src/client/linux/libbreakpad\_client.a**, which contains all the code |
|||
necessary to produce minidumps from an application. |
|||
|
|||
## Integrating Breakpad into your Application |
|||
|
|||
First, configure your build process to link **libbreakpad\_client.a** into your |
|||
binary, and set your include paths to include the **src** directory in the |
|||
**google-breakpad** source tree. Next, include the exception handler header: |
|||
|
|||
```cpp |
|||
#include "client/linux/handler/exception_handler.h" |
|||
``` |
|||
|
|||
Now you can instantiate an `ExceptionHandler` object. Exception handling is active for the lifetime of the `ExceptionHandler` object, so you should instantiate it as early as possible in your application's startup process, and keep it alive for as close to shutdown as possible. To do anything useful, the `ExceptionHandler` constructor requires a path where it can write minidumps, as well as a callback function to receive information about minidumps that were written: |
|||
|
|||
```cpp |
|||
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, |
|||
void* context, bool succeeded) { |
|||
printf("Dump path: %s\n", descriptor.path()); |
|||
return succeeded; |
|||
} |
|||
|
|||
void crash() { volatile int* a = (int*)(NULL); *a = 1; } |
|||
|
|||
int main(int argc, char* argv[]) { |
|||
google_breakpad::MinidumpDescriptor descriptor("/tmp"); |
|||
google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1); |
|||
crash(); |
|||
return 0; |
|||
} |
|||
``` |
|||
|
|||
Compiling and running this example should produce a minidump file in /tmp, and |
|||
it should print the minidump filename before exiting. You can read more about |
|||
the other parameters to the `ExceptionHandler` constructor [in the exception_handler.h source file][1]. |
|||
|
|||
[1]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/client/linux/handler/exception_handler.h |
|||
|
|||
**Note**: You should do as little work as possible in the callback function. |
|||
Your application is in an unsafe state. It may not be safe to allocate memory or |
|||
call functions from other shared libraries. The safest thing to do is `fork` and |
|||
`exec` a new process to do any work you need to do. If you must do some work in |
|||
the callback, the Breakpad source contains [some simple reimplementations of libc functions][2], to avoid calling directly into |
|||
libc, as well as [a header file for making Linux system calls][3] (in **src/third\_party/lss**) to avoid calling into other shared libraries. |
|||
|
|||
[2]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/common/linux/linux_libc_support.h |
|||
[3]: https://chromium.googlesource.com/linux-syscall-support/+/master |
|||
|
|||
## Sending the minidump file |
|||
|
|||
In a real application, you would want to handle the minidump in some way, likely |
|||
by sending it to a server for analysis. The Breakpad source tree contains [some |
|||
HTTP upload source][4] that you might find useful, as well as [a minidump upload tool][5]. |
|||
|
|||
[4]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/common/linux/http_upload.h |
|||
[5]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/tools/linux/symupload/minidump_upload.cc |
|||
|
|||
## Producing symbols for your application |
|||
|
|||
To produce useful stack traces, Breakpad requires you to convert the debugging |
|||
symbols in your binaries to [text-format symbol files][6]. First, ensure that you've compiled your binaries with `-g` to |
|||
include debugging symbols. Next, compile the `dump_syms` tool by running |
|||
`configure && make` in the Breakpad source directory. Next, run `dump_syms` on |
|||
your binaries to produce the text-format symbols. For example, if your main |
|||
binary was named `test`: |
|||
|
|||
[6]: https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md |
|||
|
|||
``` |
|||
$ google-breakpad/src/tools/linux/dump_syms/dump_syms ./test > test.sym |
|||
``` |
|||
|
|||
In order to use these symbols with the `minidump_stackwalk` tool, you will need |
|||
to place them in a specific directory structure. The first line of the symbol |
|||
file contains the information you need to produce this directory structure, for |
|||
example (your output will vary): |
|||
|
|||
``` |
|||
$ head -n1 test.sym MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test |
|||
$ mkdir -p ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830 |
|||
$ mv test.sym ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830 |
|||
``` |
|||
|
|||
You may also find the [symbolstore.py][7] script in the Mozilla repository useful, as it encapsulates these steps. |
|||
|
|||
[7]: https://dxr.mozilla.org/mozilla-central/source/toolkit/crashreporter/tools/symbolstore.py |
|||
|
|||
## Processing the minidump to produce a stack trace |
|||
|
|||
Breakpad includes a tool called `minidump_stackwalk` which can take a minidump |
|||
plus its corresponding text-format symbols and produce a symbolized stacktrace. |
|||
It should be in the **google-breakpad/src/processor** directory if you compiled |
|||
the Breakpad source using the directions above. Simply pass it the minidump and |
|||
the symbol path as commandline parameters: |
|||
|
|||
``` |
|||
$ google-breakpad/src/processor/minidump_stackwalk minidump.dmp ./symbols |
|||
``` |
|||
|
|||
It produces verbose output on stderr, and the stacktrace on stdout, so you may |
|||
want to redirect stderr. |
|||
@ -0,0 +1,47 @@ |
|||
# Introduction |
|||
|
|||
Linux implements its userland-to-kernel transition using a special library |
|||
called linux-gate.so that is mapped by the kernel into every process. For more |
|||
information, see |
|||
|
|||
http://www.trilithium.com/johan/2005/08/linux-gate/ |
|||
|
|||
In a nutshell, the problem is that the system call gate function, |
|||
kernel\_vsyscall does not use EBP to point to the frame pointer. |
|||
|
|||
However, the Breakpad processor supports special frames like this via STACK |
|||
lines in the symbol file. If you look in src/client/linux/data you will see |
|||
symbol files for linux-gate.so for both Intel & AMD(the implementation of |
|||
kernel\_vsyscall changes depending on the CPU manufacturer). When processing |
|||
minidumps from Linux 2.6, having these symbol files is necessary for walking the |
|||
stack for crashes that happen while a thread is in a system call. |
|||
|
|||
If you're just interested in processing minidumps, those two symbol files should |
|||
be all you need! |
|||
|
|||
# Details |
|||
|
|||
The particular details of understanding the linux-gate.so symbol files can be |
|||
found by reading about STACK lines inside |
|||
src/common/windows/pdb\_source\_line\_writer.cc, and the above link. To |
|||
summarize briefly, we just have to inform the processor how to get to the |
|||
previous frame when the EIP is inside kernel\_vsyscall, and we do that by |
|||
telling the processor how many bytes kernel\_vsyscall has pushed onto the stack |
|||
in it's prologue. For example, one of the symbol files looks somewhat like the |
|||
following: |
|||
|
|||
MODULE Linux x86 random\_debug\_id linux-gate.so PUBLIC 400 0 kernel\_vsyscall |
|||
STACK WIN 4 100 1 1 0 0 0 0 0 1 |
|||
|
|||
The PUBLIC line indicates that kernel\_vsyscall is at offset 400 (in bytes) from |
|||
the beginning of linux-gate.so. The STACK line indicates the size of the |
|||
function(100), how many bytes it pushes(1), and how many bytes it pops(1). The |
|||
last 1 indicates that EBP is pushed onto the stack before being used by the |
|||
function. |
|||
|
|||
# Warnings |
|||
|
|||
These functions might change significantly depending on kernel version. In my |
|||
opinion, the actual function stack information is unlikely to change frequently, |
|||
but the Linux kernel might change the address of kernel\_vsyscall w.r.t the |
|||
beginning of linux-gate.so, which would cause these symbol files to be invalid. |
|||
@ -0,0 +1,184 @@ |
|||
# How To Add Breakpad To Your Mac Client Application |
|||
|
|||
This document is a step-by-step recipe to get your Mac client app to build with |
|||
Breakpad. |
|||
|
|||
## Preparing a binary build of Breakpad for use in your tree |
|||
|
|||
You can either check in a binary build of the Breakpad framework & tools or |
|||
build it as a dependency of your project. The former is recommended, and |
|||
detailed here, since building dependencies through other projects is |
|||
problematic(matching up configuration names), and the Breakpad code doesn't |
|||
change nearly often enough as your application's will. |
|||
|
|||
## Building the requisite targets |
|||
|
|||
All directories are relative to the `src` directory of the Breakpad checkout. |
|||
|
|||
* Build the 'All' target of `client/mac/Breakpad.xcodeproj` in Release mode. |
|||
* Execute `cp -R client/mac/build/Release/Breakpad.framework <location in your |
|||
source tree>` |
|||
* Inside `tools/mac/dump_syms` directory, build dump\_syms.xcodeproj, and copy |
|||
tools/mac/dump\_syms/build/Release/dump\_syms to a safe location where it |
|||
can be run during the build process. |
|||
|
|||
## Adding Breakpad.framework |
|||
|
|||
Inside your application's framework, add the Breakpad.Framework to your |
|||
project's framework settings. When you select it from the file chooser, it will |
|||
let you pick a target to add it to; go ahead and check the one that's relevant |
|||
to your application. |
|||
|
|||
## Copy Breakpad into your Application Package |
|||
|
|||
Copy Breakpad into your Application Package, so it will be around at run time. |
|||
|
|||
Go to the Targets section of your Xcode Project window. Hit the disclosure |
|||
triangle to reveal the build phases of your application. Add a new Copy Files |
|||
phase using the Contextual menu (Control Click). On the General panel of the new |
|||
'Get Info' of this new phase, set the destination to 'Frameworks' Close the |
|||
'Info' panel. Use the Contextual Menu to Rename your new phase 'Copy Frameworks' |
|||
Now drag Breakpad again into this Copy Frameworks phase. Drag it from whereever |
|||
it appears in the project file tree. |
|||
|
|||
## Add a New Run Script build phase |
|||
|
|||
Near the end of the build phases, add a new Run Script build phase. This will be |
|||
run before Xcode calls /usr/bin/strip on your project. This is where you'll be |
|||
calling dump\_sym to output the symbols for each architecture of your build. In |
|||
my case, the relevant lines read: |
|||
|
|||
``` |
|||
#!/bin/sh |
|||
$TOOL_DIR=<location of dump_syms from step 3 above> |
|||
|
|||
"$TOOL_DIR/dump_syms" -a ppc "$PROD" > "$TARGET_NAME ppc.breakpad" |
|||
|
|||
"$TOOL_DIR/dump_syms" -a i386 "$PROD" > "$TARGET_NAME i386.breakpad" |
|||
``` |
|||
|
|||
## Adjust the Project Settings |
|||
|
|||
* Turn on Separate Strip, |
|||
* Set the Strip Style to Non-Global Symbols. |
|||
|
|||
## Write Code! |
|||
|
|||
You'll need to have an object that acts as the delegate for NSApplication. |
|||
Inside this object's header, you'll need to add |
|||
|
|||
1. add an ivar for Breakpad and |
|||
2. a declaration for the applicationShouldTerminate:(NSApplication`*` sender) |
|||
message. |
|||
|
|||
``` |
|||
#import <Breakpad/Breakpad.h> |
|||
|
|||
@interface BreakpadTest : NSObject { |
|||
. |
|||
. |
|||
. |
|||
BreakpadRef breakpad; |
|||
. |
|||
. |
|||
. |
|||
} |
|||
. |
|||
. |
|||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; |
|||
. |
|||
. |
|||
@end |
|||
``` |
|||
|
|||
Inside your object's implementation file, |
|||
|
|||
1. add the following method InitBreakpad |
|||
2. modify your awakeFromNib method to look like the one below, |
|||
3. modify/add your application's delegate method to look like the one below |
|||
|
|||
``` |
|||
static BreakpadRef InitBreakpad(void) { |
|||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|||
BreakpadRef breakpad = 0; |
|||
NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; |
|||
if (plist) { |
|||
// Note: version 1.0.0.4 of the framework changed the type of the argument |
|||
// from CFDictionaryRef to NSDictionary * on the next line: |
|||
breakpad = BreakpadCreate(plist); |
|||
} |
|||
[pool release]; |
|||
return breakpad; |
|||
} |
|||
|
|||
- (void)awakeFromNib { |
|||
breakpad = InitBreakpad(); |
|||
} |
|||
|
|||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { |
|||
BreakpadRelease(breakpad); |
|||
return NSTerminateNow; |
|||
} |
|||
``` |
|||
|
|||
## Configure Breakpad |
|||
|
|||
Configure Breakpad for your application. |
|||
|
|||
1. Take a look inside the Breakpad.framework at the Breakpad.h file for the |
|||
keys, default values, and descriptions to be passed to BreakpadCreate(). |
|||
2. Add/Edit the Breakpad specific entries in the dictionary passed to |
|||
BreakpadCreate() -- typically your application's info plist. |
|||
|
|||
Example from the Notifier Info.plist: |
|||
`<key>BreakpadProduct</key><string>Google_Notifier_Mac</string> |
|||
<key>BreakpadProductDisplay</key><string>${PRODUCT_NAME}</string> |
|||
` |
|||
|
|||
## Build Your Application |
|||
|
|||
Almost done! |
|||
|
|||
## Verify |
|||
|
|||
Double-check: |
|||
|
|||
Your app should have in its package contents: |
|||
myApp.app/Contents/Frameworks/Breakpad.framework. |
|||
|
|||
The symbol files have reasonable contents (you can look at them with a text |
|||
editor.) |
|||
|
|||
Look again at the Copy Frameworks phase of your project. Are you leaking .h |
|||
files? Select them and delete them. (If you drag a bunch of files into your |
|||
project, Xcode often wants to copy your .h files into the build, revealing |
|||
Google secrets. Be vigilant!) |
|||
|
|||
## Upload the symbol file |
|||
|
|||
You'll need to configure your build process to store symbols in a location that |
|||
is accessible by the minidump processor. There is a tool in tools/mac/symupload |
|||
that can be used to send the symbol file via HTTP post. |
|||
|
|||
1. Test |
|||
|
|||
Configure breakpad to send reports to a URL by adding to your app's Info.plist: |
|||
|
|||
``` |
|||
<key>BreakpadURL</key> |
|||
<string>upload URL</string> |
|||
<key>BreakpadReportInterval</key> |
|||
<string>30</string> |
|||
``` |
|||
|
|||
## Final Notes |
|||
|
|||
Breakpad checks whether it is being run under a debugger, and if so, normally |
|||
does nothing. But, you can force Breakpad to function under a debugger by |
|||
setting the Unix shell variable BREAKPAD\_IGNORE\_DEBUGGER to a non-zero value. |
|||
You can bracket the source code in the above Write The Code step with #if DEBUG |
|||
to completely eliminate it from Debug builds. See |
|||
//depot/googlemac/GoogleNotifier/main.m for an example. FYI, when your process |
|||
forks(), exception handlers are reset to the default for child processes. So |
|||
they must reinitialize Breakpad, otherwise exceptions will be handled by Apple's |
|||
Crash Reporter. |
|||
@ -0,0 +1,82 @@ |
|||
# Breakpad Crash Reporting for Mozilla |
|||
|
|||
* January 24, 2007 |
|||
* Links updated February 14, 2007 |
|||
* Mozilla HQ |
|||
* Mark Mentovai |
|||
* Brian Ryner |
|||
|
|||
## What is a crash reporter? |
|||
|
|||
* Enables developers to analyze crashes that occur in the wild |
|||
* Produces stack backtraces that help identify how a program failed |
|||
* Offers higher-level data aggregation (topcrashes, MTBF statistics) |
|||
|
|||
## Motivation |
|||
|
|||
* Talkback is proprietary and unmaintained |
|||
* Smaller open-source projects have few options |
|||
* Larger projects need flexibility and scalability |
|||
|
|||
## Design Options |
|||
|
|||
* Stackwalking done on client |
|||
* Apple CrashReporter |
|||
* GNOME BugBuddy |
|||
* Client sends memory dump |
|||
* Talkback |
|||
* Windows Error Reporting |
|||
* Breakpad |
|||
|
|||
## Goals |
|||
|
|||
* Provide libraries around which systems can be based |
|||
* Open-source |
|||
* Cross-platform |
|||
* Mac OS X x86, PowerPC |
|||
* Linux x86 |
|||
* Windows x86 |
|||
* No requirement to distribute symbols |
|||
|
|||
## Client Libraries |
|||
|
|||
* Exception handler installed at application startup |
|||
* Spawns a separate thread |
|||
* Minidump file written at crash time |
|||
* Format used by Windows debuggers |
|||
* Separate application invoked to send |
|||
* HTTP[S](S.md) POST, can include additional parameters |
|||
|
|||
## Symbols |
|||
|
|||
* Cross-platform symbol file format |
|||
* Contents |
|||
* Function names |
|||
* Source file names and line numbers |
|||
* Windows: Frame pointer omission data |
|||
* Future: parameters and local variables |
|||
* Symbol conversion methods |
|||
|
|||
## Processor |
|||
|
|||
* Examines minidump file and invokes stackwalker |
|||
* Symbol files requested from a SymbolSupplier |
|||
* Produces stack trace |
|||
* Output may be placed where convenient |
|||
|
|||
## Intergation |
|||
|
|||
* Breakpad client present in Gran Paradiso Alpha 1 for Windows |
|||
* Disabled by default |
|||
* Enable with `MOZ_AIRBAG` |
|||
* Proof-of-concept collector |
|||
* http://mavra.perilith.com/~luser/airbag-collector/list.pl |
|||
* Other platforms coming soon |
|||
|
|||
## More Information |
|||
|
|||
* Project home: https://chromium.googlesource.com/breakpad/breakpad |
|||
* Mailing lists |
|||
* [google-breakpad-dev@googlegroups.com](http://groups.google.com/group/google-breakpad-dev/) |
|||
* [google-breakpad-discuss@googlegroups.com](http://groups.google.com/group/google-breakpad-discuss/) |
|||
* Ask me (irc.mozilla.org: mento) |
|||
@ -0,0 +1,231 @@ |
|||
# Breakpad Processor Library |
|||
|
|||
## Objective |
|||
|
|||
The Breakpad processor library is an open-source framework to access the the |
|||
information contained within crash dumps for multiple platforms, and to use that |
|||
information to produce stack traces showing the call chain of each thread in a |
|||
process. After processing, this data is made available to users of the library. |
|||
|
|||
## Background |
|||
|
|||
The Breakpad processor is intended to sit at the core of a comprehensive |
|||
crash-reporting system that does not require debugging information to be |
|||
provided to those running applications being monitored. Some existing |
|||
crash-reporting systems, such as [GNOME](http://www.gnome.org/)’s Bug-Buddy and |
|||
[Apple](http://www.apple.com/)’s |
|||
[CrashReporter](http://developer.apple.com/technotes/tn2004/tn2123.html), |
|||
require symbolic |
|||
information to be present on the end user’s computer; in the case of |
|||
CrashReporter, the reports are transmitted only to Apple, not to third-party |
|||
developers. Other systems, such as [Microsoft](http://www.microsoft.com/)’s |
|||
[Windows Error Reporting](http://msdn.microsoft.com/isv/resources/wer/) and |
|||
SupportSoft’s Talkback, transmit only a snapshot of a crashed process’ state, |
|||
which can later be combined with symbolic debugging information without the need |
|||
for it to be present on end users’ computers. Because symbolic debugging |
|||
information consumes a large amount of space and is otherwise not needed during |
|||
the normal operation of software, and because some developers are reluctant to |
|||
release debugging symbols to their customers, Breakpad follows the latter |
|||
approach. |
|||
|
|||
We know of no currently-maintained crash-reporting systems that meet our |
|||
requirements, which are to: * allow for symbols to be separate from the |
|||
application, * handle crash reports from multiple platforms, * allow developers |
|||
to operate their own crash-reporting platform, and to * be open-source. Windows |
|||
Error Reporting only functions for Microsoft products, and requires the |
|||
involvement of Microsoft’s servers. Talkback, while cross-platform, has not been |
|||
maintained and at this point does not support Mac OS X on x86, which we consider |
|||
to be a significant platform. Talkback is also closed-source commercial |
|||
software, and has very specific requirements for its server platform. |
|||
|
|||
We are aware of Windows-only crash-reporting systems that leverage Microsoft’s |
|||
debugging interfaces. Such systems, even if extended to support dumps from other |
|||
platforms, are tied to using Windows for at least a portion of the processor |
|||
platform. |
|||
|
|||
## Overview |
|||
|
|||
The Breakpad processor itself is written in standard C++ and will work on a |
|||
variety of platforms. The dumps it accepts may also have been created on a |
|||
variety of systems. The library is able to combine dumps with symbolic debugging |
|||
information to create stack traces that include function signatures. The |
|||
processor library includes simple command-line tools to examine dumps and |
|||
process them, producing stack traces. It also exposes several layers of APIs |
|||
enabling crash-reporting systems to be built around the Breakpad processor. |
|||
|
|||
## Detailed Design |
|||
|
|||
### Dump Files |
|||
|
|||
In the processor, the dump data is of primary significance. Dumps typically |
|||
contain: |
|||
|
|||
* CPU context (register data) as it was at the time the crash occurred, and an |
|||
indication of which thread caused the crash. General-purpose registers are |
|||
included, as are special-purpose registers such as the instruction pointer |
|||
(program counter). |
|||
* Information about each thread of execution within a crashed process, |
|||
including: |
|||
* The memory region used for each thread’s stack. |
|||
* CPU context for each thread, which for various reasons is not the same |
|||
as the crash context in the case of the crashed thread. |
|||
* A list of loaded code segments (or modules), including: |
|||
* The name of the file (`.so`, `.exe`, `.dll`, etc.) which provides the |
|||
code. |
|||
* The boundaries of the memory region in which the code segment is visible |
|||
to the process. |
|||
* A reference to the debugging information for the code module, when such |
|||
information is available. |
|||
|
|||
Ordinarily, dumps are produced as a result of a crash, but other triggers may be |
|||
set to produce dumps at any time a developer deems appropriate. The Breakpad |
|||
processor can handle dumps in the minidump format, either generated by an |
|||
[Breakpad client “handler”](client_design.md) implementation, or by another |
|||
implementation that produces dumps in this format. The |
|||
[DbgHelp.dll!MiniDumpWriteDump](http://msdn2.microsoft.com/en-us/library/ms680360.aspx) |
|||
function on Windows |
|||
produces dumps in this format, and is the basis for the Breakpad handler |
|||
implementation on that platform. |
|||
|
|||
The [minidump format](http://msdn.microsoft.com/en-us/library/ms679293%28VS.85%29.aspx) is |
|||
essentially a simple container format, organized as a series of streams. Each |
|||
stream contains some type of data relevant to the crash. A typical “normal” |
|||
minidump contains streams for the thread list, the module list, the CPU context |
|||
at the time of the crash, and various bits of additional system information. |
|||
Other types of minidump can be generated, such as a full-memory minidump, which |
|||
in addition to stack memory contains snapshots of all of a process’ mapped |
|||
memory regions. |
|||
|
|||
The minidump format was chosen as Breakpad’s dump format because it has an |
|||
established track record on Windows, and it can be adapted to meet the needs of |
|||
the other platforms that Breakpad supports. Most other operating systems use |
|||
“core” files as their native dump formats, but the capabilities of core files |
|||
vary across platforms, and because core files are usually presented in a |
|||
platform’s native executable format, there are complications involved in |
|||
accessing the data contained therein without the benefit of the header files |
|||
that define an executable format’s entire structure. Because minidumps are |
|||
leaner than a typical executable format, a redefinition of the format in a |
|||
cross-platform header file, `minidump_format.h`, was a straightforward task. |
|||
Similarly, the capabilities of the minidump format are understood, and because |
|||
it provides an extensible container, any of Breakpad’s needs that could not be |
|||
met directly by the standard minidump format could likely be met by extending it |
|||
as needed. Finally, using this format means that the dump file is compatible |
|||
with native debugging tools at least on Windows. A possible future avenue for |
|||
exploration is the conversion of minidumps to core files, to enable this same |
|||
benefit on other platforms. |
|||
|
|||
We have already provided an extension to the minidump format that allows it to |
|||
carry dumps generated on systems with PowerPC processors. The format already |
|||
allows for variable CPUs, so our work in this area was limited to defining a |
|||
context structure sufficient to represent the execution state of a PowerPC. We |
|||
have also defined an extension that allows minidumps to indicate which thread of |
|||
execution requested a dump be produced for non-crash dumps. |
|||
|
|||
Often, the information contained within a dump alone is sufficient to produce a |
|||
full stack backtrace for each thread. Certain optimizations that compilers |
|||
employ in producing code frustrate this process. Specifically, the “frame |
|||
pointer omission” optimization of x86 compilers can make it impossible to |
|||
produce useful stack traces given only a stack snapshot and CPU context. In |
|||
these cases, however, compiler-emitted debugging information can aid in |
|||
producing useful stack traces. The Breakpad processor is able to take advantage |
|||
of this debugging information as supplied by Microsoft’s C/C++ compiler, the |
|||
only compiler to apply such optimizations by default. As a result, the Breakpad |
|||
processor can produce useful stack traces even from code with frame pointer |
|||
omission optimizations as produced by this compiler. |
|||
|
|||
### Symbol Files |
|||
|
|||
The [symbol files](symbol_files.md) that the Breakpad processor accepts allow |
|||
for frame pointer omission data, but this is only one of their capabilities. |
|||
Each symbol file also includes information about the functions, source files, |
|||
and source code line numbers for a single module of code. A module is an |
|||
individually-loadble chunk of code: these can be executables containing a main |
|||
program (`exe` files on Windows) or shared libraries (`.so` files on Linux, |
|||
`.dylib` files, frameworks, and bundles on Mac OS X, and `.dll` files on |
|||
Windows). Dumps contain information about which of these modules were loaded at |
|||
the time the dump was produced, and given this information, the Breakpad |
|||
processor attempts to locate debugging symbols for the module through a |
|||
user-supplied function embodied in a “symbol supplier.” Breakpad includes a |
|||
sample symbol supplier, called `SimpleSymbolSupplier`, that is used by its |
|||
command-line tools; this supplier locates symbol files by pathname. |
|||
`SimpleSymbolSupplier` is also available to other users of the Breakpad |
|||
processor library. This allows for the use of a simple reference implementation, |
|||
but preserves flexibility for users who may have more demanding symbol file |
|||
storage needs. |
|||
|
|||
Breakpad’s symbol file format is text-based, and was defined to be fairly |
|||
human-readable and to encompass the needs of multiple platforms. The Breakpad |
|||
processor itself does not operate directly with native symbol formats |
|||
([DWARF](http://dwarf.freestandards.org/) and |
|||
[STABS](http://sourceware.org/gdb/current/onlinedocs/stabs.html) |
|||
on most Unix-like systems, |
|||
[.pdb files](http://msdn2.microsoft.com/en-us/library/yd4f8bd1(VS.80).aspx) |
|||
on Windows), |
|||
because of the complications in accessing potentially complex symbol formats |
|||
with slight variations between platforms, stored within different types of |
|||
binary formats. In the case of `.pdb` files, the debugging format is not even |
|||
documented. Instead, Breakpad’s symbol files are produced on each platform, |
|||
using specific debugging APIs where available, to convert native symbols to |
|||
Breakpad’s cross-platform format. |
|||
|
|||
### Processing |
|||
|
|||
Most commonly, a developer will enable an application to use Breakpad by |
|||
building it with a platform-specific [client “handler”](client_design.md) |
|||
library. After building the application, the developer will create symbol files |
|||
for Breakpad’s use using the included `dump_syms` or `symupload` tools, or |
|||
another suitable tool, and place the symbol files where the processor’s symbol |
|||
supplier will be able to locate them. |
|||
|
|||
When a dump file is given to the processor’s `MinidumpProcessor` class, it will |
|||
read it using its included minidump reader, contained in the `Minidump` family |
|||
of classes. It will collect information about the operating system and CPU that |
|||
produced the dump, and determine whether the dump was produced as a result of a |
|||
crash or at the direct request of the application itself. It then loops over all |
|||
of the threads in a process, attempting to walk the stack associated with each |
|||
thread. This process is achieved by the processor’s `Stackwalker` components, of |
|||
which there are a slightly different implementations for each CPU type that the |
|||
processor is able to handle dumps from. Beginning with a thread’s context, and |
|||
possibly using debugging data, the stackwalker produces a list of stack frames, |
|||
containing each instruction executed in the chain. These instructions are |
|||
matched up with the modules that contributed them to a process, and the |
|||
`SymbolSupplier` is invoked to locate a symbol file. The symbol file is given to |
|||
a `SourceLineResolver`, which matches the instruction up with a specific |
|||
function name, source file, and line number, resulting in a representation of a |
|||
stack frame that can easily be used to identify which code was executing. |
|||
|
|||
The results of processing are made available in a `ProcessState` object, which |
|||
contains a vector of threads, each containing a vector of stack frames. |
|||
|
|||
For small-scale use of the Breakpad processor, and for testing and debugging, |
|||
the `minidump_stackwalk` tool is provided. It invokes the processor and displays |
|||
the full results of processing, optionally allowing symbols to be provided to |
|||
the processor by a pathname-based symbol supplier, `SimpleSymbolSupplier`. |
|||
|
|||
For lower-level testing and debugging, the processor library also includes a |
|||
`minidump_dump` tool, which walks through an entire minidump file and displays |
|||
its contents in somewhat readable form. |
|||
|
|||
### Platform Support |
|||
|
|||
The Breakpad processor library is able to process dumps produced on Mac OS X |
|||
systems running on x86, x86-64, and PowerPC processors, on Windows and Linux |
|||
systems running on x86 or x86-64 processors, and on Android systems running ARM |
|||
or x86 processors. The processor library itself is written in standard C++, and |
|||
should function properly in most Unix-like environments. It has been tested on |
|||
Linux and Mac OS X. |
|||
|
|||
## Future Plans |
|||
|
|||
There are currently no firm plans or timetables to implement any of these |
|||
features, although they are possible avenues for future exploration. |
|||
|
|||
The symbol file format can be extended to carry information about the locations |
|||
of parameters and local variables as stored in stack frames and registers, and |
|||
the processor can use this information to provide enhanced stack traces showing |
|||
function arguments and variable values. |
|||
|
|||
On Mac OS X and Linux, we can provide tools to convert files from the minidump |
|||
format into the native core format. This will enable developers to open dump |
|||
files in a native debugger, just as they are presently able to do with minidumps |
|||
on Windows. |
|||
@ -0,0 +1,144 @@ |
|||
# Introduction |
|||
|
|||
This page aims to provide a detailed description of how Breakpad produces stack |
|||
traces from the information contained within a minidump file. |
|||
|
|||
# Details |
|||
|
|||
## Starting the Process |
|||
|
|||
Typically the stack walking process is initiated by instantiating the |
|||
[MinidumpProcessor](../src/processor/minidump_processor.cc) |
|||
class and calling the [MinidumpProcessor::Process](../src/processor/minidump_processor.cc#61) |
|||
method, providing it a minidump file to process. To produce a useful stack |
|||
trace, the MinidumpProcessor requires two other objects which are passed in its |
|||
constructor: a [SymbolSupplier](../src/google_breakpad/processor/symbol_supplier.h) |
|||
and a [SourceLineResolverInterface](../src/google_breakpad/processor/source_line_resolver_interface.h). |
|||
The SymbolSupplier object is responsible for locating and providing SymbolFiles |
|||
that match modules from the minidump. The SourceLineResolverInterface is |
|||
responsible for loading the symbol files and using the information contained |
|||
within to provide function and source information for stack frames, as well as |
|||
information on how to unwind from a stack frame to its caller. More detail will |
|||
be provided on these interactions later. |
|||
|
|||
A number of data streams are extracted from the minidump to begin stack walking: |
|||
the list of threads from the process |
|||
([MinidumpThreadList](../src/google_breakpad/processor/minidump.h#335)), |
|||
the list of modules loaded in the process |
|||
([MinidumpModuleList](../src/google_breakpad/processor/minidump.h#501)), |
|||
and information about the exception that caused the process to crash |
|||
([MinidumpException](../src/google_breakpad/processor/minidump.h#615)). |
|||
|
|||
## Enumerating Threads |
|||
|
|||
For each thread in the thread list |
|||
([MinidumpThread](../src/google_breakpad/processor/minidump.h#299)), |
|||
the thread memory containing the stack for the thread |
|||
([MinidumpMemoryRegion](../src/google_breakpad/processor/minidump.h#236)) |
|||
and the CPU context representing the CPU state of the thread at the time the |
|||
dump was written ([MinidumpContext](../src/google_breakpad/processor/minidump.h#171)) |
|||
are extracted from the minidump. If the thread being processed is the thread |
|||
that produced the exception then a CPU context is obtained from the |
|||
MinidumpException object instead, which represents the CPU state of the thread |
|||
at the point of the exception. A stack walker is then instantiated by calling |
|||
the [Stackwalker::StackwalkerForCPU](../src/google_breakpad/processor/stackwalker.h#77) |
|||
method and passing it the CPU context, the thread memory, the module list, as |
|||
well as the SymbolSupplier and SourceLineResolverInterface. This method selects |
|||
the specific !Stackwalker subclass based on the CPU architecture of the provided |
|||
CPU context and returns an instance of that subclass. |
|||
|
|||
## Walking a thread's stack |
|||
|
|||
Once a !Stackwalker instance has been obtained, the processor calls the |
|||
[Stackwalker::Walk](../src/google_breakpad/processor/source_line_resolver_interface.h) |
|||
method to obtain a list of frames representing the stack of this thread. The |
|||
!Stackwalker starts by calling the GetContextFrame method which returns a |
|||
StackFrame representing the top of the stack, with CPU state provided by the |
|||
initial CPU context. From there, the stack walker repeats the following steps |
|||
for each frame in turn: |
|||
|
|||
### Finding the Module |
|||
|
|||
The address of the instruction pointer of the current frame is used to determine |
|||
which module contains the current frame by calling the module list's |
|||
[GetModuleForAddress](../src/google_breakpad/processor/code_modules.h#56) method. |
|||
|
|||
### Locating Symbols |
|||
|
|||
If a module is located, the SymbolSupplier is asked to locate symbols |
|||
corresponding to the module by calling its |
|||
[GetCStringSymbolData](../src/google_breakpad/processor/symbol_supplier.h#87) |
|||
method. Typically this is implemented by using the module's debug filename (the |
|||
PDB filename for Windows dumps) and debug identifier (a GUID plus one extra |
|||
digit) as a lookup key. The [SimpleSymbolSupplier](../src/processor/simple_symbol_supplier.cc) |
|||
class simply uses these as parts of a file path to locate a flat file on disk. |
|||
|
|||
### Loading Symbols |
|||
|
|||
If a symbol file is located, the SourceLineResolverInterface is then asked to |
|||
load the symbol file by calling its |
|||
[LoadModuleUsingMemoryBuffer](../src/google_breakpad/processor/source_line_resolver_interface.h#71) |
|||
method. The [BasicSourceLineResolver](../src/processor/basic_source_line_resolver.cc) |
|||
implementation parses the text-format [symbol file](symbol_files.md) into |
|||
in-memory data structures to make lookups by address of function names, source |
|||
line information, and unwind information easy. |
|||
|
|||
### Getting source line information |
|||
|
|||
If a symbol file has been successfully loaded, the SourceLineResolverInterface's |
|||
[FillSourceLineInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#89) |
|||
method is called to provide a function name and source line information for the |
|||
current frame. This is done by subtracting the base address of the module |
|||
containing the current frame from the instruction pointer of the current frame |
|||
to obtain a relative virtual address (RVA), which is a code offset relative to |
|||
the start of the module. This RVA is then used as a lookup into a table of |
|||
functions ([FUNC lines](SymbolFiles#FUNC_records.md) from the symbol file), each |
|||
of which has an associated address range (function start address, function |
|||
size). If a function is found whose address range contains the RVA, then its |
|||
name is used. The RVA is then used as a lookup into a table of source lines |
|||
([line records](SymbolFiles#Line_records.md) from the symbol file), each of |
|||
which also has an associated address range. If a match is found it will provide |
|||
the file name and source line associated with the current frame. If no match was |
|||
found in the function table, another table of publicly exported symbols may be |
|||
consulted ([PUBLIC lines](SymbolFiles#PUBLIC_records.md) from the symbol file). |
|||
Public symbols contain only a start address, so the lookup simply looks for the |
|||
nearest symbol that is less than the provided RVA. |
|||
|
|||
### Finding the caller frame |
|||
|
|||
To find the next frame in the stack, the !Stackwalker calls its |
|||
[GetCallerFrame](../src/google_breakpad/processor/stackwalker.h#186) |
|||
method, passing in the current frame. Each !Stackwalker subclass implements |
|||
GetCallerFrame differently, but there are common patterns. |
|||
|
|||
Typically the first step is to query the SourceLineResolverInterface for the |
|||
presence of detailed unwind information. This is done using its |
|||
[FindWindowsFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#96) |
|||
and [FindCFIFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#102) |
|||
methods. These methods look for Windows unwind info extracted from a PDB file |
|||
([STACK WIN](SymbolFiles#STACK_WIN_records.md) lines from the symbol file), or |
|||
DWARF CFI extracted from a binary ([STACK CFI](SymbolFiles#STACK_CFI_records.md) |
|||
lines from the symbol file) respectively. The information covers address ranges, |
|||
so the RVA of the current frame is used for lookup as with function and source |
|||
line information. |
|||
|
|||
If unwind info is found it provides a set of rules to recover the register state |
|||
of the caller frame given the current register state as well as the thread's |
|||
stack memory. The rules are evaluated to produce the caller frame. |
|||
|
|||
If unwind info is not found then the !Stackwalker may resort to other methods. |
|||
Typically on architectures which specify a frame pointer unwinding by |
|||
dereferencing the frame pointer is tried next. If that is successful it is used |
|||
to produce the caller frame. |
|||
|
|||
If no caller frame was found by any other method most !Stackwalker |
|||
implementations resort to stack scanning by looking at each word on the stack |
|||
down to a fixed depth (implemented in the |
|||
[Stackwalker::ScanForReturnAddress](../src/google_breakpad/processor/stackwalker.h#131) |
|||
method) and using a heuristic to attempt to find a reasonable return address |
|||
(implemented in the |
|||
[Stackwalker::InstructionAddressSeemsValid](../src/google_breakpad/processor/stackwalker.h#111) method). |
|||
|
|||
If no caller frame is found or the caller frame seems invalid, stack walking |
|||
stops. If a caller frame was found then these steps repeat using the new frame |
|||
as the current frame. |
|||
@ -0,0 +1,214 @@ |
|||
# Introduction |
|||
|
|||
The `sym_upload` tool is able to operate in `sym-upload-v2` protocol mode, in |
|||
addition to the legacy protocol (which will be referred to as `sym-upload-v1` |
|||
for the rest of this document). For now `sym-upload-v2` is HTTP/REST-based but |
|||
it could be extended to operate over gRPC instead, in the future. |
|||
|
|||
# Table of Contents |
|||
* [Why](#why) |
|||
* [How](#how) |
|||
* [Uploading](#uploading) |
|||
* [Uploading with `sym_upload`](#uploading-with-sym_upload) |
|||
* [Uploading with curl](#uploading-with-curl) |
|||
* [Serving the `sym-upload-v2` protocol](#serving-the-sym-upload-v2-protocol) |
|||
* [Authenticate using `key`](#authenticate-using-key) |
|||
* [Symbol `checkStatus`](#symbol-checkstatus) |
|||
* [Upload `create`](#upload-create) |
|||
* [Uploading the symbol file](#uploading-the-symbol-file) |
|||
* [Upload complete](#upload-complete) |
|||
|
|||
|
|||
# Why |
|||
|
|||
Using `sym_upload` in `sym-upload-v2` protocol mode has the following features |
|||
beyond `sym-upload-v1`: |
|||
* Authentication via `key` (arbitrary secret). |
|||
* Symbol identifier (product of `debug_file` and `debug_id`, as recorded in |
|||
output from `dump_syms`) can be checked against existing symbol information on |
|||
server. If it's present, then the upload is skipped entirely. |
|||
|
|||
# How |
|||
|
|||
## Uploading |
|||
|
|||
### Uploading with `sym_upload` |
|||
|
|||
Uploading in `sym-upload-v2` protocol mode is easy. Invoke `sym_upload` like |
|||
``` |
|||
$ ./sym_upload -p sym-upload-v2 [-k <API-key>] <symbol-file> <API-URL> |
|||
``` |
|||
|
|||
Where `symbol-file` is a symbol file created by `dump_syms`, `API-URL` is the |
|||
URL of your `sym-upload-v2` API service (see next section for details), and |
|||
`API-key` is a secret known to your uploader and server. |
|||
|
|||
For more options see `sym_upload --help`. |
|||
|
|||
### Uploading with curl |
|||
|
|||
As an example, if: |
|||
* Your API's URL was "https://sym-upload-api". |
|||
* Your service has assigned you `key` "myfancysecret123". |
|||
* You wanted to upload the symbol file at "path/to/file_name", with |
|||
`debug_file` being "file_name" and `debug_id` being |
|||
"123123123123123123123123123". Normally you would read these values from |
|||
"path/to/file_name", which in turn was generated by `dump_syms`. |
|||
|
|||
Then you might run: |
|||
``` |
|||
$ curl https://sym-upload-api/symbols/file_name/123123123123123123123123123:checkStatus?key=myfancysecret123 |
|||
``` |
|||
|
|||
And, upon seeing that this `debug_file`/`debug_id` combo is missing from symbol |
|||
storage then you could run: |
|||
``` |
|||
$ curl --request POST https://sym-upload-api/uploads:create?key=myfancysecret123 |
|||
``` |
|||
|
|||
Which returns `upload_url` "https://upload-server/42?creds=shhhhh" and |
|||
`upload_key` "42". Next you upload the file directly like: |
|||
``` |
|||
$ curl -T path/to/file_name "https://upload-server/42?creds=shhhhh" |
|||
``` |
|||
|
|||
Once the HTTP PUT is complete, run: |
|||
``` |
|||
$ curl --header "Content-Type: application/json" \ |
|||
--request POST \ |
|||
--data '{symbol_id:{"debugFile":"file_name",'\ |
|||
'"debugId":"123123123123123123123123123"}}' \ |
|||
https://sym-upload-api/uploads/42:complete?key=myfancysecret123 |
|||
``` |
|||
|
|||
### Serving the `sym-upload-v2` Protocol |
|||
|
|||
The protocol is currently defined only in HTTP/REST. There are three necessary |
|||
REST operations to implement in your service: |
|||
* `/symbols/<debug_file>/<debug_id>:checkStatus?key=<key>` |
|||
* `/uploads:create?key=<key>` |
|||
* `/uploads/<upload_key>:complete?key=<key>` |
|||
|
|||
#### Authenticate Using `key` |
|||
|
|||
The query string arg `key` contains some secret that both the uploader and |
|||
server understand. It is up to the service implementer to decide on what |
|||
constitutes a valid `key`, how the uploader acquires one, and how to handle |
|||
requests made with invalid ones. |
|||
|
|||
#### Symbol `checkStatus` |
|||
|
|||
``` |
|||
/symbols/<debug_file>/<debug_id>:checkStatus?key=<key> |
|||
``` |
|||
|
|||
This operation expects an empty (or no) JSON payload in the request. |
|||
|
|||
This operation should return the status of the symbol file uniquely identified |
|||
by the given `debug_file` and `debug_id`. JSON schema: |
|||
``` |
|||
{ |
|||
"type": object", |
|||
"properties": { |
|||
"status": { |
|||
"type": "string", |
|||
"enum": ["STATUS_UNSPECIFIED", "MISING", "FOUND"], |
|||
"required": true |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Where `MISSING` denotes that the symbol file does not exist on the server and |
|||
`FOUND` denotes that the symbol file exists on the server. |
|||
|
|||
#### Upload `create` |
|||
|
|||
``` |
|||
/uploads:create?key=<key> |
|||
``` |
|||
|
|||
This operation expects an empty (or no) JSON payload in the request. |
|||
|
|||
This operation should return a URL that uploader can HTTP PUT their symbol file |
|||
to, along with an "upload key" that can be used to notify the service once the |
|||
file upload is completed. JSON schema: |
|||
``` |
|||
{ |
|||
"type": "object", |
|||
"properties": { |
|||
"upload_url": { |
|||
"type: "string", |
|||
"required": true |
|||
}, |
|||
"upload_key": { |
|||
"type": "string", |
|||
"required": true |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Since this REST API operation can be authenticated via the `key` query string |
|||
arg, the service can return a URL that encodes permission delegation to the |
|||
upload endpoint resource and thereby constrain the ability to upload to those |
|||
with valid `key`s. |
|||
|
|||
#### Uploading the Symbol File |
|||
|
|||
Note that the actual symbol upload step is _not_ part of the REST API. The |
|||
upload URL obtained in the above operation is meant to be used as the endpoint |
|||
for a normal HTTP PUT request for the contents of the symbol file. Once that |
|||
HTTP PUT request is completed use the upload `complete` operation. |
|||
|
|||
#### Upload `complete` |
|||
|
|||
``` |
|||
/uploads/<upload_key>:complete?key=<key> |
|||
``` |
|||
|
|||
This operation expects a JSON payload in the HTTP request body with the |
|||
following schema: |
|||
``` |
|||
{ |
|||
"type": "object", |
|||
"properties": { |
|||
"symbol_id": { |
|||
"type": "object", |
|||
"properties": { |
|||
"debug_file": { |
|||
"type": "string", |
|||
"required": true |
|||
}, |
|||
"debug_id": { |
|||
"type": "string", |
|||
"required": true |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
This operation should cause the symbol storage back-end (however implemented) |
|||
to consume the symbol file identified by `upload_key`. It is up to the service |
|||
implementation to decide how uploads are assigned `upload_key`s and how to |
|||
retrieve a completed upload by its `upload_key`. If the symbol file cannot be |
|||
found, is malformed, or the operation cannot be completed for any other reason |
|||
then an HTTP error will be returned. JSON schema of non-error responses: |
|||
``` |
|||
{ |
|||
"type": "object", |
|||
"properties": { |
|||
"result": { |
|||
"type": string, |
|||
"enum": ["RESULT_UNSPECIFIED", "OK", "DUPLICATE_DATA"], |
|||
"required": true |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Where `OK` denotes that the symbol storage was updated with the new symbol file |
|||
and `DUPLICATE_DATA` denotes that the symbol file data was identical to data |
|||
already in symbol storage and therefore nothing changed. |
|||
@ -0,0 +1,581 @@ |
|||
# Introduction |
|||
|
|||
Given a minidump file, the Breakpad processor produces stack traces that include |
|||
function names and source locations. However, minidump files contain only the |
|||
byte-by-byte contents of threads' registers and stacks, without function names |
|||
or machine-code-to-source mapping data. The processor consults Breakpad symbol |
|||
files for the information it needs to produce human-readable stack traces from |
|||
the binary-only minidump file. |
|||
|
|||
The platform-specific symbol dumping tools parse the debugging information the |
|||
compiler provides (whether as DWARF or STABS sections in an ELF file or as |
|||
stand-alone PDB files), and write that information back out in the Breakpad |
|||
symbol file format. This format is much simpler and less detailed than compiler |
|||
debugging information, and values legibility over compactness. |
|||
|
|||
# Overview |
|||
|
|||
Breakpad symbol files are ASCII text files, with lines delimited as appropriate |
|||
for the host platform. Each line is a _record_, divided into fields by single |
|||
spaces; in some cases, the last field of the record can contain spaces. The |
|||
first field is a string indicating what sort of record the line represents |
|||
(except for line records; these are very common, making them the default saves |
|||
space). Some fields hold decimal or hexadecimal numbers; hexadecimal numbers |
|||
have no "0x" prefix, and use lower-case letters. |
|||
|
|||
Breakpad symbol files contain the following record types. With some |
|||
restrictions, these may appear in any order. |
|||
|
|||
* A `MODULE` record describes the executable file or shared library from which |
|||
this data was derived, for use by symbol suppliers. A `MODULE' record should |
|||
be the first record in the file. |
|||
|
|||
* A `FILE` record gives a source file name, and assigns it a number by which |
|||
other records can refer to it. |
|||
|
|||
* An `INLINE_ORIGIN` record holds an inline function name for `INLINE` records |
|||
to refer to. |
|||
|
|||
* A `FUNC` record describes a function present in the source code. |
|||
|
|||
* An `INLINE` record describes the inline function's nest level, call site |
|||
line and call site source file to which the given ranges of machine code |
|||
should be attributed. |
|||
|
|||
* A line record indicates to which source file and line a given range of |
|||
machine code should be attributed. The line is attributed to the function |
|||
defined by the most recent `FUNC` record. |
|||
|
|||
* A `PUBLIC` record gives the address of a linker symbol. |
|||
|
|||
* A `STACK` record provides information necessary to produce stack traces. |
|||
|
|||
# `MODULE` records |
|||
|
|||
A `MODULE` record provides meta-information about the module the symbol file |
|||
describes. It has the form: |
|||
|
|||
> `MODULE` _operatingsystem_ _architecture_ _id_ _name_ |
|||
|
|||
For example: `MODULE Linux x86 D3096ED481217FD4C16B29CD9BC208BA0 firefox-bin |
|||
` These records provide meta-information about the executable or shared library |
|||
from which this symbol file was generated. A symbol supplier might use this |
|||
information to find the correct symbol files to use to interpret a given |
|||
minidump, or to perform other sorts of validation. If present, a `MODULE` record |
|||
should be the first line in the file. |
|||
|
|||
The fields are separated by spaces, and cannot contain spaces themselves, except |
|||
for _name_. |
|||
|
|||
* The _operatingsystem_ field names the operating system on which the |
|||
executable or shared library was intended to run. This field should have one |
|||
of the following values: |
|||
|
|||
| **Value** | **Meaning** | |
|||
|:----------|:--------------------| |
|||
| Linux | Linux | |
|||
| mac | Macintosh OSX | |
|||
| windows | Microsoft Windows | |
|||
|
|||
* The _architecture_ field indicates what processor architecture the |
|||
executable or shared library contains machine code for. This field should |
|||
have one of the following values: |
|||
|
|||
| **Value** | **Instruction Set Architecture** | |
|||
|:----------|:---------------------------------| |
|||
| x86 | Intel IA-32 | |
|||
| x86\_64 | AMD64/Intel 64 | |
|||
| ppc | 32-bit PowerPC | |
|||
| ppc64 | 64-bit PowerPC | |
|||
| unknown | unknown | |
|||
|
|||
* The _id_ field is a sequence of hexadecimal digits that identifies the exact |
|||
executable or library whose contents the symbol file describes. The way in |
|||
which it is computed varies from platform to platform. |
|||
|
|||
* The _name_ field contains the base name (the final component of the |
|||
directory path) of the executable or library. It may contain spaces, and |
|||
extends to the end of the line. |
|||
|
|||
# `FILE` records |
|||
|
|||
A `FILE` record holds a source file name for other records to refer to. It has |
|||
the form: |
|||
|
|||
> `FILE` _number_ _name_ |
|||
|
|||
For example: `FILE 2 /home/jimb/mc/in/browser/app/nsBrowserApp.cpp |
|||
` |
|||
|
|||
A `FILE` record provides the name of a source file, and assigns it a number |
|||
which other records (line records, in particular) can use to refer to that file |
|||
name. The _number_ field is a decimal number. The _name_ field is the name of |
|||
the file; it may contain spaces. |
|||
|
|||
# `INLINE_ORIGIN` records |
|||
|
|||
An `INLINE_ORIGIN` record holds an inline function name for `INLINE` records to |
|||
refer to. It has the form: |
|||
|
|||
> `INLINE_ORIGIN` _number_ _name_ |
|||
|
|||
For example: `INLINE_ORIGIN 2 nsQueryInterfaceWithError::operator()(nsID const&, |
|||
void**) const |
|||
` |
|||
|
|||
An `INLINE_ORIGIN` record provides the name of an inline function, and assigns |
|||
it a number which other records (`INLINE` records, in particular) can use to |
|||
refer to that function name. The _number_ field is a decimal number. The _name_ |
|||
field is the name of the inline function; it may contain spaces. |
|||
|
|||
# `FUNC` records |
|||
|
|||
A `FUNC` record describes a source-language function. It has the form: |
|||
|
|||
> `FUNC` _[m]_ _address_ _size_ _parameter\_size_ _name_ |
|||
|
|||
For example: `FUNC m c184 30 0 nsQueryInterfaceWithError::operator()(nsID const&, |
|||
void**) const |
|||
` |
|||
|
|||
The _m_ field is optional. If present it indicates that multiple symbols |
|||
reference this function's instructions. (In which case, only one symbol name is |
|||
mentioned within the breakpad file.) Multiple symbols referencing the same |
|||
instructions may occur due to identical code folding by the linker. |
|||
|
|||
The _address_ and _size_ fields are hexadecimal numbers indicating the start |
|||
address and length in bytes of the machine code instructions the function |
|||
occupies. (Breakpad symbol files cannot accurately describe functions whose code |
|||
is not contiguous.) The start address is relative to the module's load address. |
|||
|
|||
The _parameter\_size_ field is a hexadecimal number indicating the size, in |
|||
bytes, of the arguments pushed on the stack for this function. Some calling |
|||
conventions, like the Microsoft Windows `stdcall` convention, require the called |
|||
function to pop parameters passed to it on the stack from its caller before |
|||
returning. The stack walker uses this value, along with data from `STACK` |
|||
records, to step from the called function's frame to the caller's frame. |
|||
|
|||
The _name_ field is the name of the function. In languages that use linker |
|||
symbol name mangling like C++, this should be the source language name (the |
|||
"unmangled" form). This field may contain spaces. |
|||
|
|||
# `INLINE` records |
|||
|
|||
An `INLINE` record describes the inline function's nest level, call site line |
|||
and call site source file to which the given ranges of machine code should be |
|||
attributed. It has the form: |
|||
|
|||
> `INLINE` _inline_nest_level_ _call_site_line_ _call_site_file_num_ |
|||
> _origin_num_ [_address_ _size_]+ |
|||
|
|||
For example: `INLINE 0 10 3 4 d30 2a fa1 b |
|||
` |
|||
|
|||
The _inline_nest_level_ field is a decimal number that means it's inlined at the |
|||
function described by a previous `INLINE` record which has _inline_nest_level_ |
|||
one less than its. In the example below, first and third `INLINE` records have |
|||
_inline_nest_level_ 0, which means they are inlined inside the function |
|||
described by the `FUNC` record. The second `INLINE` record has |
|||
_inline_nest_level_ 1 means that it's inlined at the inline function described |
|||
by first `INLINE` record. |
|||
``` |
|||
FUNC ... |
|||
INLINE 0 ... |
|||
INLINE 1 ... |
|||
INLINE 0 ... |
|||
``` |
|||
|
|||
The _call_site_line_ and _call_site_file_num_ fields are decimal numbers |
|||
indicating where this inline function being called at. |
|||
|
|||
The _origin_num_ field refers to an `INLINE_ORIGIN` record that has the name |
|||
of the inline function. |
|||
|
|||
The _address_ and _size_ fields are hexadecimal numbers indicating the start |
|||
address and length in bytes of the machine code. The address is relative to the |
|||
module's load address. There could be more than one [_address_ _size_] range |
|||
pair, since inline functions could have discontinuous address ranges. The ranges |
|||
of an `INLINE` record are always inside the ranges described by its parent |
|||
record (a `FUNC` record or an `INLINE` record). |
|||
|
|||
The `INLINE` record is assumed to belong to the function described by the last |
|||
preceding `FUNC` record. `INLINE` records may not appear before the first `FUNC` |
|||
record. |
|||
|
|||
# Line records |
|||
|
|||
A line record describes the source file and line number to which a given range |
|||
of machine code should be attributed. It has the form: |
|||
|
|||
> _address_ _size_ _line_ _filenum_ |
|||
|
|||
For example: `c184 7 59 4 |
|||
` |
|||
|
|||
Because they are so common, line records do not begin with a string indicating |
|||
the record type. All other record types' names use upper-case letters; |
|||
hexadecimal numbers, like a line record's _address_, use lower-case letters. |
|||
|
|||
The _address_ and _size_ fields are hexadecimal numbers indicating the start |
|||
address and length in bytes of the machine code. The address is relative to the |
|||
module's load address. |
|||
|
|||
The _line_ field is the line number to which the machine code should be |
|||
attributed, in decimal; the first line of the source file is line number 1. The |
|||
_filenum_ field is a decimal number appearing in a prior `FILE` record; the name |
|||
given in that record is the source file name for the machine code. |
|||
|
|||
The line is assumed to belong to the function described by the last preceding |
|||
`FUNC` record. Line records may not appear before the first `FUNC' record. |
|||
|
|||
No two line records in a symbol file cover the same range of addresses. However, |
|||
there may be many line records with identical line and file numbers, as a given |
|||
source line may contribute many non-contiguous blocks of machine code. |
|||
|
|||
# `PUBLIC` records |
|||
|
|||
A `PUBLIC` record describes a publicly visible linker symbol, such as that used |
|||
to identify an assembly language entry point or region of memory. It has the |
|||
form: |
|||
|
|||
> PUBLIC _[m]_ _address_ _parameter\_size_ _name_ |
|||
|
|||
For example: `PUBLIC m 2160 0 Public2_1 |
|||
` |
|||
|
|||
The Breakpad processor essentially treats a `PUBLIC` record as defining a |
|||
function with no line number data and an indeterminate size: the code extends to |
|||
the next address mentioned. If a given address is covered by both a `PUBLIC` |
|||
record and a `FUNC` record, the processor uses the `FUNC` data. |
|||
|
|||
The _m_ field is optional. If present it indicates that multiple symbols |
|||
reference this function's instructions. (In which case, only one symbol name is |
|||
mentioned within the breakpad file.) Multiple symbols referencing the same |
|||
instructions may occur due to identical code folding by the linker. |
|||
|
|||
The _address_ field is a hexadecimal number indicating the symbol's address, |
|||
relative to the module's load address. |
|||
|
|||
The _parameter\_size_ field is a hexadecimal number indicating the size of the |
|||
parameters passed to the code whose entry point the symbol marks, if known. This |
|||
field has the same meaning as the _parameter\_size_ field of a `FUNC` record; |
|||
see that description for more details. |
|||
|
|||
The _name_ field is the name of the symbol. In languages that use linker symbol |
|||
name mangling like C++, this should be the source language name (the "unmangled" |
|||
form). This field may contain spaces. |
|||
|
|||
# `STACK WIN` records |
|||
|
|||
Given a stack frame, a `STACK WIN` record indicates how to find the frame that |
|||
called it. It has the form: |
|||
|
|||
> STACK WIN _type_ _rva_ _code\_size_ _prologue\_size_ _epilogue\_size_ |
|||
> _parameter\_size_ _saved\_register\_size_ _local\_size_ _max\_stack\_size_ |
|||
> _has\_program\_string_ _program\_string\_OR\_allocates\_base\_pointer_ |
|||
|
|||
For example: `STACK WIN 4 2170 14 1 0 0 0 0 0 1 $eip 4 + ^ = $esp $ebp 8 + = |
|||
$ebp $ebp ^ = |
|||
` |
|||
|
|||
All fields of a `STACK WIN` record, except for the last, are hexadecimal |
|||
numbers. |
|||
|
|||
The _type_ field indicates what sort of stack frame data this record holds. Its |
|||
value should be one of the values of the |
|||
[StackFrameTypeEnum](http://msdn.microsoft.com/en-us/library/bc5207xw%28VS.100%29.aspx) |
|||
type in Microsoft's |
|||
[Debug Interface Access (DIA)](http://msdn.microsoft.com/en-us/library/x93ctkx8%28VS.100%29.aspx) API. |
|||
Breakpad uses only records of type 4 (`FrameTypeFrameData`) and 0 |
|||
(`FrameTypeFPO`); it ignores others. These types differ only in whether the last |
|||
field is an _allocates\_base\_pointer_ flag (`FrameTypeFPO`) or a program string |
|||
(`FrameTypeFrameData`). If more than one record covers a given address, Breakpad |
|||
prefers `FrameTypeFrameData` records over `FrameTypeFPO` records. |
|||
|
|||
The _rva_ and _code\_size_ fields give the starting address and length in bytes |
|||
of the machine code covered by this record. The starting address is relative to |
|||
the module's load address. |
|||
|
|||
The _prologue\_size_ and _epilogue\_size_ fields give the length, in bytes, of |
|||
the prologue and epilogue machine code within the record's range. Breakpad does |
|||
not use these values. |
|||
|
|||
The _parameter\_size_ field gives the number of argument bytes this function |
|||
expects to have been passed. This field has the same meaning as the |
|||
_parameter\_size_ field of a `FUNC` record; see that description for more |
|||
details. |
|||
|
|||
The _saved\_register\_size_ field gives the number of bytes in the stack frame |
|||
dedicated to preserving the values of any callee-saves registers used by this |
|||
function. |
|||
|
|||
The _local\_size_ field gives the number of bytes in the stack frame dedicated |
|||
to holding the function's local variables and temporary values. |
|||
|
|||
The _max\_stack\_size_ field gives the maximum number of bytes pushed on the |
|||
stack in the frame. Breakpad does not use this value. |
|||
|
|||
If the _has\_program\_string_ field is zero, then the `STACK WIN` record's final |
|||
field is an _allocates\_base\_pointer_ flag, as a hexadecimal number; this is |
|||
expected for records whose _type_ is 0. Otherwise, the final field is a program |
|||
string. |
|||
|
|||
## Interpreting a `STACK WIN` record |
|||
|
|||
Given the register values for a frame F, we can find the calling frame as |
|||
follows: |
|||
|
|||
* If the _has\_program\_string_ field of a `STACK WIN` record is zero, then |
|||
the final field is _allocates\_base\_pointer_, a flag indicating whether the |
|||
frame uses the frame pointer register, `%ebp`, as a general-purpose |
|||
register. |
|||
* If _allocates\_base\_pointer_ is true, then `%ebp` does not point to the |
|||
frame's base address. Instead, |
|||
* Let _next\_parameter\_size_ be the parameter size of the function |
|||
frame F called (**not** this record's _parameter\_size_ field), or |
|||
zero if F is the youngest frame on the stack. You must find this |
|||
value in F's callee's `FUNC`, `STACK WIN`, or `PUBLIC` records. |
|||
* Let _frame\_size_ be the sum of the _local\_size_ field, the |
|||
_saved\_register\_size_ field, and _next\_parameter\_size_. > > With |
|||
those definitions in place, we can recover the calling frame as |
|||
follows: |
|||
* F's return address is at `%esp +`_frame\_size_, |
|||
* the caller's value of `%ebp` is saved at `%esp |
|||
+`_next\_parameter\_size_`+`_saved\_register\_size_`- 8`, and |
|||
* the caller's value of `%esp` just before the call instruction was |
|||
`%esp +`_frame\_size_`+ 4`. > > (Why do we include |
|||
_next\_parameter\_size_ in the sum when computing _frame\_size_ and |
|||
the address of the saved `%ebp`? When a function A has called a |
|||
function B, the arguments that A pushed for B are considered part of |
|||
A's stack frame: A's value for `%esp` points at the last argument |
|||
pushed for B. Thus, we must include the size of those arguments |
|||
(given by the debugging info for B) along with the size of A's |
|||
register save area and local variable area (given by the debugging |
|||
info for A) when computing the overall size of A's frame.) |
|||
* If _allocates\_base\_pointer_ is false, then F's function doesn't use |
|||
`%ebp` at all. You may recover the calling frame as above, except that |
|||
the caller's value of `%ebp` is the same as F's value for `%ebp`, so no |
|||
steps are necessary to recover it. |
|||
* If the _has\_program\_string_ field of a `STACK WIN` record is not zero, |
|||
then the record's final field is a string containing a program to be |
|||
interpreted to recover the caller's frame. The comments in the |
|||
[postfix\_evaluator.h](../src/processor/postfix_evaluator.h#40) |
|||
header file explain the language in which the program is written. You should |
|||
place the following variables in the dictionary before interpreting the |
|||
program: |
|||
* `$ebp` and `$esp` should be the values of the `%ebp` and `%esp` |
|||
registers in F. |
|||
* `.cbParams`, `.cbSavedRegs`, and `.cbLocals`, should be the values of |
|||
the `STACK WIN` record's _parameter\_size_, _saved\_register\_size_, and |
|||
_local\_size_ fields. |
|||
* `.raSearchStart` should be set to the address on the stack to begin |
|||
scanning for a return address, if necessary. The Breakpad processor sets |
|||
this to the value of `%esp` in F, plus the _frame\_size_ value mentioned |
|||
above. |
|||
|
|||
> If the program stores values for `$eip`, `$esp`, `$ebp`, `$ebx`, `$esi`, or |
|||
> `$edi`, then those are the values of the given registers in the caller. If the |
|||
> value of `$eip` is zero, that indicates that the end of the stack has been |
|||
> reached. |
|||
|
|||
The Breakpad processor checks that the value yielded by the above for the |
|||
calling frame's instruction address refers to known code; if the address seems |
|||
to be bogus, then it uses a heuristic search to find F's return address and |
|||
stack base. |
|||
|
|||
# `STACK CFI` records |
|||
|
|||
`STACK CFI` ("Call Frame Information") records describe how to walk the stack |
|||
when execution is at a given machine instruction. These records take one of two |
|||
forms: |
|||
|
|||
> `STACK CFI INIT` _address_ _size_ _register<sub>1</sub>_: |
|||
> _expression<sub>1</sub>_ _register<sub>2</sub>_: _expression<sub>2</sub>_ ... |
|||
> |
|||
> `STACK CFI` _address_ _register<sub>1</sub>_: _expression<sub>1</sub>_ |
|||
> _register<sub>2</sub>_: _expression<sub>2</sub>_ ... |
|||
|
|||
For example: |
|||
|
|||
``` |
|||
STACK CFI INIT 804c4b0 40 .cfa: $esp 4 + $eip: .cfa 4 - ^ |
|||
STACK CFI 804c4b1 .cfa: $esp 8 + $ebp: .cfa 8 - ^ |
|||
``` |
|||
|
|||
The _address_ and _size_ fields are hexadecimal numbers. Each |
|||
_register_<sub>i</sub> is the name of a register or pseudoregister. Each |
|||
_expression_ is a Breakpad postfix expression, which may contain spaces, but |
|||
never ends with a colon. (The appropriate register names for a given |
|||
architecture are determined when `STACK CFI` records are first enabled for that |
|||
architecture, and should be documented in the appropriate |
|||
`stackwalker_`_architecture_`.cc` source file.) |
|||
|
|||
STACK CFI records describe, at each machine instruction in a given function, how |
|||
to recover the values the machine registers had in the function's caller. |
|||
Naturally, some registers' values are simply lost, but there are three cases in |
|||
which they can be recovered: |
|||
|
|||
* You can always recover the program counter, because that's the function's |
|||
return address. If the function is ever going to return, the PC must be |
|||
saved somewhere. |
|||
|
|||
* You can always recover the stack pointer. The function is responsible for |
|||
popping its stack frame before it returns to the caller, so it must be able |
|||
to restore this, as well. |
|||
|
|||
* You should be able to recover the values of callee-saves registers. These |
|||
are registers whose values the callee must preserve, either by saving them |
|||
in its own stack frame before using them and re-loading them before |
|||
returning, or by not using them at all. |
|||
|
|||
(As an exception, note that functions which never return may not save any of |
|||
this data. It may not be possible to walk the stack past such functions' stack |
|||
frames.) |
|||
|
|||
Given rules for recovering the values of a function's caller's registers, we can |
|||
walk up the stack. Starting with the current set of registers --- the PC of the |
|||
instruction we're currently executing, the current stack pointer, etc. --- we |
|||
use CFI to recover the values those registers had in the caller of the current |
|||
frame. This gives us a PC in the caller whose CFI we can look up; we apply the |
|||
process again to find that function's caller; and so on. |
|||
|
|||
Concretely, CFI records represent a table with a row for each machine |
|||
instruction address and a column for each register. The table entry for a given |
|||
address and register contains a rule describing how, when the PC is at that |
|||
address, to restore the value that register had in the caller. |
|||
|
|||
There are some special columns: |
|||
|
|||
* A column named `.cfa`, for "Canonical Frame Address", tells how to compute |
|||
the base address of the frame; other entries can refer to the CFA in their |
|||
rules. |
|||
|
|||
* A column named `.ra` represents the return address. |
|||
|
|||
For example, suppose we have a machine with 32-bit registers, one-byte |
|||
instructions, a stack that grows downwards, and an assembly language that |
|||
resembles C. Suppose further that we have a function whose machine code looks |
|||
like this: |
|||
|
|||
``` |
|||
func: ; entry point; return address at sp |
|||
func+0: sp -= 16 ; allocate space for stack frame |
|||
func+1: sp[12] = r0 ; save 4-byte r0 at sp+12 |
|||
... ; stuff that doesn't affect stack |
|||
func+10: sp -= 4; *sp = x ; push some 4-byte x on the stack |
|||
... ; stuff that doesn't affect stack |
|||
func+20: r0 = sp[16] ; restore saved r0 |
|||
func+21: sp += 20 ; pop whole stack frame |
|||
func+22: pc = *sp; sp += 4 ; pop return address and jump to it |
|||
``` |
|||
|
|||
The following table would describe the function above: |
|||
|
|||
| **code address** | **.cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **.ra** | |
|||
|:-----------------|:---------|:------------------------|:------------------------|:----|:---------| |
|||
| func+0 | sp | | | | `cfa[0]` | |
|||
| func+1 | sp+16 | | | | `cfa[0]` | |
|||
| func+2 | sp+16 | `cfa[-4]` | | | `cfa[0]` | |
|||
| func+11 | sp+20 | `cfa[-4]` | | | `cfa[0]` | |
|||
| func+21 | sp+20 | | | | `cfa[0]` | |
|||
| func+22 | sp | | | | `cfa[0]` | |
|||
|
|||
Some things to note here: |
|||
|
|||
* Each row describes the state of affairs **before** executing the instruction |
|||
at the given address. Thus, the row for func+0 describes the state before we |
|||
execute the first instruction, which allocates the stack frame. In the next |
|||
row, the formula for computing the CFA has changed, reflecting the |
|||
allocation. |
|||
|
|||
* The other entries are written in terms of the CFA; this allows them to |
|||
remain unchanged as the stack pointer gets bumped around. For example, to |
|||
find the caller's value for r0 (on Google Code) at func+2, we would first |
|||
compute the CFA by adding 16 to the sp, and then subtract four from that to |
|||
find the address at which r0 (on Google Code) was saved. |
|||
|
|||
* Although the example doesn't show this, most calling conventions designate |
|||
"callee-saves" and "caller-saves" registers. The callee must restore the |
|||
values of "callee-saves" registers before returning (if it uses them at |
|||
all), whereas the callee is free to use "caller-saves" registers without |
|||
restoring their values. A function that uses caller-saves registers |
|||
typically does not save their original values at all; in this case, the CFI |
|||
marks such registers' values as "unrecoverable". |
|||
|
|||
* Exactly where the CFA points in the frame --- at the return address? below |
|||
it? At some fixed point within the frame? --- is a question of definition |
|||
that depends on the architecture and ABI in use. But by definition, the CFA |
|||
remains constant throughout the lifetime of the frame. It's up to |
|||
architecture- specific code to know what significance to assign the CFA, if |
|||
any. |
|||
|
|||
To save space, the most common type of CFI record only mentions the table |
|||
entries at which changes take place. So for the above, the CFI data would only |
|||
actually mention the non-blank entries here: |
|||
|
|||
| **insn** | **cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **ra** | |
|||
|:---------|:--------|:------------------------|:------------------------|:----|:---------| |
|||
| func+0 | sp | | | | `cfa[0]` | |
|||
| func+1 | sp+16 | | | | | |
|||
| func+2 | | `cfa[-4]` | | | | |
|||
| func+11 | sp+20 | | | | | |
|||
| func+21 | | r0 (on Google Code) | | | | |
|||
| func+22 | sp | | | | | |
|||
|
|||
A `STACK CFI INIT` record indicates that, at the machine instruction at |
|||
_address_, belonging to some function, the value that _register<sub>n</sub>_ had |
|||
in that function's caller can be recovered by evaluating |
|||
_expression<sub>n</sub>_. The values of any callee-saves registers not mentioned |
|||
are assumed to be unchanged. (`STACK CFI` records never mention caller-saves |
|||
registers.) These rules apply starting at _address_ and continue up to, but not |
|||
including, the address given in the next `STACK CFI` record. The _size_ field is |
|||
the total number of bytes of machine code covered by this record and any |
|||
subsequent `STACK CFI` records (until the next `STACK CFI INIT` record). The |
|||
_address_ field is relative to the module's load address. |
|||
|
|||
A `STACK CFI` record (no `INIT`) is the same, except that it mentions only those |
|||
registers whose recovery rules have changed from the previous CFI record. There |
|||
must be a prior `STACK CFI INIT` or `STACK CFI` record in the symbol file. The |
|||
_address_ field of this record must be greater than that of the previous record, |
|||
and it must not be at or beyond the end of the range given by the most recent |
|||
`STACK CFI INIT` record. The address is relative to the module's load address. |
|||
|
|||
Each expression is a breakpad-style postfix expression. Expressions may contain |
|||
spaces, but their tokens may not end with colons. When an expression mentions a |
|||
register, it refers to the value of that register in the callee, even if a prior |
|||
name/expression pair gives that register's value in the caller. The exception is |
|||
`.cfa`, which refers to the canonical frame address computed by the .cfa rule in |
|||
force at the current instruction. |
|||
|
|||
The special expression `.undef` indicates that the given register's value cannot |
|||
be recovered. |
|||
|
|||
The register names preceding the expressions are always followed by colons. The |
|||
expressions themselves never contain tokens ending with colons. |
|||
|
|||
There are two special register names: |
|||
|
|||
* `.cfa` ("Canonical Frame Address") is the base address of the stack frame. |
|||
Other registers' rules may refer to this. If no rule is provided for the |
|||
stack pointer, the value of `.cfa` is the caller's stack pointer. |
|||
|
|||
* `.ra` is the return address. This is the value of the restored program |
|||
counter. We use `.ra` instead of the architecture-specific name for the |
|||
program counter. |
|||
|
|||
The Breakpad stack walker requires that there be rules in force for `.cfa` and |
|||
`.ra` at every code address from which it unwinds. If those rules are not |
|||
present, the stack walker will ignore the `STACK CFI` data, and try to use a |
|||
different strategy. |
|||
|
|||
So the CFI for the example function above would be as follows, if `func` were at |
|||
address 0x1000 (relative to the module's load address): |
|||
|
|||
``` |
|||
STACK CFI INIT 1000 .cfa: $sp .ra: .cfa ^ |
|||
STACK CFI 1001 .cfa: $sp 16 + |
|||
STACK CFI 1002 $r0: .cfa 4 - ^ |
|||
STACK CFI 100b .cfa: $sp 20 + |
|||
STACK CFI 1015 $r0: $r0 |
|||
STACK CFI 1016 .cfa: $sp |
|||
``` |
|||
@ -0,0 +1,70 @@ |
|||
# Windows Integration overview |
|||
|
|||
## Windows Client Code |
|||
|
|||
The Windows client code is in the `src/client/windows` directory of the tree. |
|||
Since the header files are fairly well commented some specifics are purposely |
|||
omitted from this document. |
|||
|
|||
## Integration of minidump-generation |
|||
|
|||
Once you build the solution inside `src/client/windows`, an output file of |
|||
`exception_handler.lib` will be generated. You can either check this into your |
|||
project's directory or build directly from the source, as the project itself |
|||
does. |
|||
|
|||
Enabling Breakpad in your application requires you to `#include |
|||
"exception_handler.h"` and instantiate the `ExceptionHandler` object like so: |
|||
|
|||
``` |
|||
handler = new ExceptionHandler(const wstring& dump_path, |
|||
FilterCallback filter, |
|||
MinidumpCallback callback, |
|||
void* callback_context, |
|||
int handler_types, |
|||
MINIDUMP_TYPE dump_type, |
|||
const wchar_t* pipe_name, |
|||
const CustomClientInfo* custom_info); |
|||
``` |
|||
|
|||
The parameters, in order, are: |
|||
|
|||
* pathname for minidumps to be written to - this is ignored if OOP dump |
|||
generation is used |
|||
* A callback that is called when the exception is first handled - you can |
|||
return true/false here to continue/stop exception processing |
|||
* A callback that is called after minidumps have been written |
|||
* Context for the callbacks |
|||
* Which exceptions to handle - see `HandlerType` enumeration in |
|||
exception\_handler.h |
|||
* The type of minidump to generate, using the `MINIDUMP_TYPE` definitions in |
|||
`DbgHelp.h` |
|||
* A pipe name that can be used to communicate with a crash generation server |
|||
* A pointer to a CustomClientInfo class that can be used to send custom data |
|||
along with the minidump when using OOP generation |
|||
|
|||
You can also see `src/client/windows/tests/crash_generation_app/*` for a sample |
|||
app that uses OOP generation. |
|||
|
|||
## OOP Minidump Generation |
|||
|
|||
For out of process minidump generation, more work is needed. If you look inside |
|||
`src/client/windows/crash_generation`, you will see a file called |
|||
`crash_generation_server.h`. This file is the interface for a crash generation |
|||
server, which must be instantiated with the same pipe name that is passed to the |
|||
client above. The logistics of running a separate process that instantiates the |
|||
crash generation server is left up to you, however. |
|||
|
|||
## Build process specifics(symbol generation, upload) |
|||
|
|||
The symbol creation step is talked about in the general overview doc, since it |
|||
doesn't vary much by platform. You'll need to make sure that the symbols are |
|||
available wherever minidumps are uploaded to for processing. |
|||
|
|||
## Out in the field - uploading the minidump |
|||
|
|||
Inside `src/client/windows/sender` is a class implementation called |
|||
`CrashReportSender`. This class can be compiled into a separate standalone CLI |
|||
or in the crash generation server and used to upload the report; it can know |
|||
when to do so via one of the callbacks provided by the `CrashGenerationServer` |
|||
or the `ExceptionHandler` object for in-process generation. |
|||
@ -0,0 +1,67 @@ |
|||
# =========================================================================== |
|||
# http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html |
|||
# =========================================================================== |
|||
# |
|||
# SYNOPSIS |
|||
# |
|||
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) |
|||
# |
|||
# DESCRIPTION |
|||
# |
|||
# For every FLAG1, FLAG2 it is checked whether the compiler works with the |
|||
# flag. If it does, the flag is added FLAGS-VARIABLE |
|||
# |
|||
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. |
|||
# CFLAGS) is used. During the check the flag is always added to the |
|||
# current language's flags. |
|||
# |
|||
# If EXTRA-FLAGS is defined, it is added to the current language's default |
|||
# flags (e.g. CFLAGS) when the check is done. The check is thus made with |
|||
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to |
|||
# force the compiler to issue an error when a bad flag is given. |
|||
# |
|||
# INPUT gives an alternative input source to AC_COMPILE_IFELSE. |
|||
# |
|||
# NOTE: This macro depends on the AX_APPEND_FLAG and |
|||
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with |
|||
# AX_APPEND_LINK_FLAGS. |
|||
# |
|||
# LICENSE |
|||
# |
|||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com> |
|||
# |
|||
# This program is free software: you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by the |
|||
# Free Software Foundation, either version 3 of the License, or (at your |
|||
# option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|||
# Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
# As a special exception, the respective Autoconf Macro's copyright owner |
|||
# gives unlimited permission to copy, distribute and modify the configure |
|||
# scripts that are the output of Autoconf when processing the Macro. You |
|||
# need not follow the terms of the GNU General Public License when using |
|||
# or distributing such scripts, even though portions of the text of the |
|||
# Macro appear in them. The GNU General Public License (GPL) does govern |
|||
# all other use of the material that constitutes the Autoconf Macro. |
|||
# |
|||
# This special exception to the GPL applies to versions of the Autoconf |
|||
# Macro released by the Autoconf Archive. When you make and distribute a |
|||
# modified version of the Autoconf Macro, you may extend this special |
|||
# exception to the GPL to apply to your modified version as well. |
|||
|
|||
#serial 5 |
|||
|
|||
AC_DEFUN([AX_APPEND_COMPILE_FLAGS], |
|||
[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) |
|||
AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) |
|||
for flag in $1; do |
|||
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4]) |
|||
done |
|||
])dnl AX_APPEND_COMPILE_FLAGS |
|||
@ -0,0 +1,71 @@ |
|||
# =========================================================================== |
|||
# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html |
|||
# =========================================================================== |
|||
# |
|||
# SYNOPSIS |
|||
# |
|||
# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) |
|||
# |
|||
# DESCRIPTION |
|||
# |
|||
# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space |
|||
# added in between. |
|||
# |
|||
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. |
|||
# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains |
|||
# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly |
|||
# FLAG. |
|||
# |
|||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. |
|||
# |
|||
# LICENSE |
|||
# |
|||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> |
|||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com> |
|||
# |
|||
# This program is free software: you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by the |
|||
# Free Software Foundation, either version 3 of the License, or (at your |
|||
# option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|||
# Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
# As a special exception, the respective Autoconf Macro's copyright owner |
|||
# gives unlimited permission to copy, distribute and modify the configure |
|||
# scripts that are the output of Autoconf when processing the Macro. You |
|||
# need not follow the terms of the GNU General Public License when using |
|||
# or distributing such scripts, even though portions of the text of the |
|||
# Macro appear in them. The GNU General Public License (GPL) does govern |
|||
# all other use of the material that constitutes the Autoconf Macro. |
|||
# |
|||
# This special exception to the GPL applies to versions of the Autoconf |
|||
# Macro released by the Autoconf Archive. When you make and distribute a |
|||
# modified version of the Autoconf Macro, you may extend this special |
|||
# exception to the GPL to apply to your modified version as well. |
|||
|
|||
#serial 6 |
|||
|
|||
AC_DEFUN([AX_APPEND_FLAG], |
|||
[dnl |
|||
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF |
|||
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) |
|||
AS_VAR_SET_IF(FLAGS,[ |
|||
AS_CASE([" AS_VAR_GET(FLAGS) "], |
|||
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], |
|||
[ |
|||
AS_VAR_APPEND(FLAGS,[" $1"]) |
|||
AC_RUN_LOG([: FLAGS="$FLAGS"]) |
|||
]) |
|||
], |
|||
[ |
|||
AS_VAR_SET(FLAGS,[$1]) |
|||
AC_RUN_LOG([: FLAGS="$FLAGS"]) |
|||
]) |
|||
AS_VAR_POPDEF([FLAGS])dnl |
|||
])dnl AX_APPEND_FLAG |
|||
@ -0,0 +1,74 @@ |
|||
# =========================================================================== |
|||
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html |
|||
# =========================================================================== |
|||
# |
|||
# SYNOPSIS |
|||
# |
|||
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) |
|||
# |
|||
# DESCRIPTION |
|||
# |
|||
# Check whether the given FLAG works with the current language's compiler |
|||
# or gives an error. (Warnings, however, are ignored) |
|||
# |
|||
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on |
|||
# success/failure. |
|||
# |
|||
# If EXTRA-FLAGS is defined, it is added to the current language's default |
|||
# flags (e.g. CFLAGS) when the check is done. The check is thus made with |
|||
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to |
|||
# force the compiler to issue an error when a bad flag is given. |
|||
# |
|||
# INPUT gives an alternative input source to AC_COMPILE_IFELSE. |
|||
# |
|||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this |
|||
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. |
|||
# |
|||
# LICENSE |
|||
# |
|||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> |
|||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com> |
|||
# |
|||
# This program is free software: you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by the |
|||
# Free Software Foundation, either version 3 of the License, or (at your |
|||
# option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|||
# Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
# As a special exception, the respective Autoconf Macro's copyright owner |
|||
# gives unlimited permission to copy, distribute and modify the configure |
|||
# scripts that are the output of Autoconf when processing the Macro. You |
|||
# need not follow the terms of the GNU General Public License when using |
|||
# or distributing such scripts, even though portions of the text of the |
|||
# Macro appear in them. The GNU General Public License (GPL) does govern |
|||
# all other use of the material that constitutes the Autoconf Macro. |
|||
# |
|||
# This special exception to the GPL applies to versions of the Autoconf |
|||
# Macro released by the Autoconf Archive. When you make and distribute a |
|||
# modified version of the Autoconf Macro, you may extend this special |
|||
# exception to the GPL to apply to your modified version as well. |
|||
|
|||
#serial 4 |
|||
|
|||
AC_DEFUN([AX_CHECK_COMPILE_FLAG], |
|||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF |
|||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl |
|||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ |
|||
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS |
|||
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" |
|||
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], |
|||
[AS_VAR_SET(CACHEVAR,[yes])], |
|||
[AS_VAR_SET(CACHEVAR,[no])]) |
|||
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) |
|||
AS_VAR_IF(CACHEVAR,yes, |
|||
[m4_default([$2], :)], |
|||
[m4_default([$3], :)]) |
|||
AS_VAR_POPDEF([CACHEVAR])dnl |
|||
])dnl AX_CHECK_COMPILE_FLAGS |
|||
@ -0,0 +1,92 @@ |
|||
# =========================================================================== |
|||
# https://www.gnu.org/software/autoconf-archive/ax_check_define.html |
|||
# =========================================================================== |
|||
# |
|||
# SYNOPSIS |
|||
# |
|||
# AC_CHECK_DEFINE([symbol], [ACTION-IF-FOUND], [ACTION-IF-NOT]) |
|||
# AX_CHECK_DEFINE([includes],[symbol], [ACTION-IF-FOUND], [ACTION-IF-NOT]) |
|||
# |
|||
# DESCRIPTION |
|||
# |
|||
# Complements AC_CHECK_FUNC but it does not check for a function but for a |
|||
# define to exist. Consider a usage like: |
|||
# |
|||
# AC_CHECK_DEFINE(__STRICT_ANSI__, CFLAGS="$CFLAGS -D_XOPEN_SOURCE=500") |
|||
# |
|||
# LICENSE |
|||
# |
|||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> |
|||
# |
|||
# This program is free software; you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by the |
|||
# Free Software Foundation; either version 3 of the License, or (at your |
|||
# option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|||
# Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
# |
|||
# As a special exception, the respective Autoconf Macro's copyright owner |
|||
# gives unlimited permission to copy, distribute and modify the configure |
|||
# scripts that are the output of Autoconf when processing the Macro. You |
|||
# need not follow the terms of the GNU General Public License when using |
|||
# or distributing such scripts, even though portions of the text of the |
|||
# Macro appear in them. The GNU General Public License (GPL) does govern |
|||
# all other use of the material that constitutes the Autoconf Macro. |
|||
# |
|||
# This special exception to the GPL applies to versions of the Autoconf |
|||
# Macro released by the Autoconf Archive. When you make and distribute a |
|||
# modified version of the Autoconf Macro, you may extend this special |
|||
# exception to the GPL to apply to your modified version as well. |
|||
|
|||
#serial 9 |
|||
|
|||
AU_ALIAS([AC_CHECK_DEFINED], [AC_CHECK_DEFINE]) |
|||
AC_DEFUN([AC_CHECK_DEFINE],[ |
|||
AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl |
|||
AC_CACHE_CHECK([for $1 defined], ac_var, |
|||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ |
|||
#ifdef $1 |
|||
int ok; |
|||
#else |
|||
choke me |
|||
#endif |
|||
]])],[AS_VAR_SET(ac_var, yes)],[AS_VAR_SET(ac_var, no)])) |
|||
AS_IF([test AS_VAR_GET(ac_var) != "no"], [$2], [$3])dnl |
|||
AS_VAR_POPDEF([ac_var])dnl |
|||
]) |
|||
|
|||
AU_ALIAS([AX_CHECK_DEFINED], [AX_CHECK_DEFINE]) |
|||
AC_DEFUN([AX_CHECK_DEFINE],[ |
|||
AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$2_$1])dnl |
|||
AC_CACHE_CHECK([for $2 defined in $1], ac_var, |
|||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <$1>]], [[ |
|||
#ifdef $2 |
|||
int ok; |
|||
#else |
|||
choke me |
|||
#endif |
|||
]])],[AS_VAR_SET(ac_var, yes)],[AS_VAR_SET(ac_var, no)])) |
|||
AS_IF([test AS_VAR_GET(ac_var) != "no"], [$3], [$4])dnl |
|||
AS_VAR_POPDEF([ac_var])dnl |
|||
]) |
|||
|
|||
AC_DEFUN([AX_CHECK_FUNC], |
|||
[AS_VAR_PUSHDEF([ac_var], [ac_cv_func_$2])dnl |
|||
AC_CACHE_CHECK([for $2], ac_var, |
|||
dnl AC_LANG_FUNC_LINK_TRY |
|||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([$1 |
|||
#undef $2 |
|||
char $2 ();],[ |
|||
char (*f) () = $2; |
|||
return f != $2; ])], |
|||
[AS_VAR_SET(ac_var, yes)], |
|||
[AS_VAR_SET(ac_var, no)])]) |
|||
AS_IF([test AS_VAR_GET(ac_var) = yes], [$3], [$4])dnl |
|||
AS_VAR_POPDEF([ac_var])dnl |
|||
])# AC_CHECK_FUNC |
|||
1009
externals/breakpad/m4/ax_cxx_compile_stdcxx.m4
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,283 @@ |
|||
# =========================================================================== |
|||
# http://www.nongnu.org/autoconf-archive/ax_pthread.html |
|||
# =========================================================================== |
|||
# |
|||
# SYNOPSIS |
|||
# |
|||
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) |
|||
# |
|||
# DESCRIPTION |
|||
# |
|||
# This macro figures out how to build C programs using POSIX threads. It |
|||
# sets the PTHREAD_LIBS output variable to the threads library and linker |
|||
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler |
|||
# flags that are needed. (The user can also force certain compiler |
|||
# flags/libs to be tested by setting these environment variables.) |
|||
# |
|||
# Also sets PTHREAD_CC to any special C compiler that is needed for |
|||
# multi-threaded programs (defaults to the value of CC otherwise). (This |
|||
# is necessary on AIX to use the special cc_r compiler alias.) |
|||
# |
|||
# NOTE: You are assumed to not only compile your program with these flags, |
|||
# but also link it with them as well. e.g. you should link with |
|||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS |
|||
# |
|||
# If you are only building threads programs, you may wish to use these |
|||
# variables in your default LIBS, CFLAGS, and CC: |
|||
# |
|||
# LIBS="$PTHREAD_LIBS $LIBS" |
|||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" |
|||
# CC="$PTHREAD_CC" |
|||
# |
|||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant |
|||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name |
|||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). |
|||
# |
|||
# ACTION-IF-FOUND is a list of shell commands to run if a threads library |
|||
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it |
|||
# is not found. If ACTION-IF-FOUND is not specified, the default action |
|||
# will define HAVE_PTHREAD. |
|||
# |
|||
# Please let the authors know if this macro fails on any platform, or if |
|||
# you have any other suggestions or comments. This macro was based on work |
|||
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help |
|||
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by |
|||
# Alejandro Forero Cuervo to the autoconf macro repository. We are also |
|||
# grateful for the helpful feedback of numerous users. |
|||
# |
|||
# LICENSE |
|||
# |
|||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu> |
|||
# |
|||
# This program is free software: you can redistribute it and/or modify it |
|||
# under the terms of the GNU General Public License as published by the |
|||
# Free Software Foundation, either version 3 of the License, or (at your |
|||
# option) any later version. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, but |
|||
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|||
# Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU General Public License along |
|||
# with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
# As a special exception, the respective Autoconf Macro's copyright owner |
|||
# gives unlimited permission to copy, distribute and modify the configure |
|||
# scripts that are the output of Autoconf when processing the Macro. You |
|||
# need not follow the terms of the GNU General Public License when using |
|||
# or distributing such scripts, even though portions of the text of the |
|||
# Macro appear in them. The GNU General Public License (GPL) does govern |
|||
# all other use of the material that constitutes the Autoconf Macro. |
|||
# |
|||
# This special exception to the GPL applies to versions of the Autoconf |
|||
# Macro released by the Autoconf Archive. When you make and distribute a |
|||
# modified version of the Autoconf Macro, you may extend this special |
|||
# exception to the GPL to apply to your modified version as well. |
|||
|
|||
#serial 6 |
|||
|
|||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) |
|||
AC_DEFUN([AX_PTHREAD], [ |
|||
AC_REQUIRE([AC_CANONICAL_HOST]) |
|||
AC_LANG_SAVE |
|||
AC_LANG_C |
|||
ax_pthread_ok=no |
|||
|
|||
# We used to check for pthread.h first, but this fails if pthread.h |
|||
# requires special compiler flags (e.g. on True64 or Sequent). |
|||
# It gets checked for in the link test anyway. |
|||
|
|||
# First of all, check if the user has set any of the PTHREAD_LIBS, |
|||
# etcetera environment variables, and if threads linking works using |
|||
# them: |
|||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then |
|||
save_CFLAGS="$CFLAGS" |
|||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS" |
|||
save_LIBS="$LIBS" |
|||
LIBS="$PTHREAD_LIBS $LIBS" |
|||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) |
|||
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) |
|||
AC_MSG_RESULT($ax_pthread_ok) |
|||
if test x"$ax_pthread_ok" = xno; then |
|||
PTHREAD_LIBS="" |
|||
PTHREAD_CFLAGS="" |
|||
fi |
|||
LIBS="$save_LIBS" |
|||
CFLAGS="$save_CFLAGS" |
|||
fi |
|||
|
|||
# We must check for the threads library under a number of different |
|||
# names; the ordering is very important because some systems |
|||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the |
|||
# libraries is broken (non-POSIX). |
|||
|
|||
# Create a list of thread flags to try. Items starting with a "-" are |
|||
# C compiler flags, and other items are library names, except for "none" |
|||
# which indicates that we try without any flags at all, and "pthread-config" |
|||
# which is a program returning the flags for the Pth emulation library. |
|||
|
|||
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" |
|||
|
|||
# The ordering *is* (sometimes) important. Some notes on the |
|||
# individual items follow: |
|||
|
|||
# pthreads: AIX (must check this before -lpthread) |
|||
# none: in case threads are in libc; should be tried before -Kthread and |
|||
# other compiler flags to prevent continual compiler warnings |
|||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) |
|||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) |
|||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) |
|||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) |
|||
# -pthreads: Solaris/gcc |
|||
# -mthreads: Mingw32/gcc, Lynx/gcc |
|||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it |
|||
# doesn't hurt to check since this sometimes defines pthreads too; |
|||
# also defines -D_REENTRANT) |
|||
# ... -mt is also the pthreads flag for HP/aCC |
|||
# pthread: Linux, etcetera |
|||
# --thread-safe: KAI C++ |
|||
# pthread-config: use pthread-config program (for GNU Pth library) |
|||
|
|||
case "${host_cpu}-${host_os}" in |
|||
*solaris*) |
|||
|
|||
# On Solaris (at least, for some versions), libc contains stubbed |
|||
# (non-functional) versions of the pthreads routines, so link-based |
|||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/ |
|||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather |
|||
# a function called by this macro, so we could check for that, but |
|||
# who knows whether they'll stub that too in a future libc.) So, |
|||
# we'll just look for -pthreads and -lpthread first: |
|||
|
|||
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" |
|||
;; |
|||
|
|||
*-darwin*) |
|||
acx_pthread_flags="-pthread $acx_pthread_flags" |
|||
;; |
|||
esac |
|||
|
|||
if test x"$ax_pthread_ok" = xno; then |
|||
for flag in $ax_pthread_flags; do |
|||
|
|||
case $flag in |
|||
none) |
|||
AC_MSG_CHECKING([whether pthreads work without any flags]) |
|||
;; |
|||
|
|||
-*) |
|||
AC_MSG_CHECKING([whether pthreads work with $flag]) |
|||
PTHREAD_CFLAGS="$flag" |
|||
;; |
|||
|
|||
pthread-config) |
|||
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) |
|||
if test x"$ax_pthread_config" = xno; then continue; fi |
|||
PTHREAD_CFLAGS="`pthread-config --cflags`" |
|||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" |
|||
;; |
|||
|
|||
*) |
|||
AC_MSG_CHECKING([for the pthreads library -l$flag]) |
|||
PTHREAD_LIBS="-l$flag" |
|||
;; |
|||
esac |
|||
|
|||
save_LIBS="$LIBS" |
|||
save_CFLAGS="$CFLAGS" |
|||
LIBS="$PTHREAD_LIBS $LIBS" |
|||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS" |
|||
|
|||
# Check for various functions. We must include pthread.h, |
|||
# since some functions may be macros. (On the Sequent, we |
|||
# need a special flag -Kthread to make this header compile.) |
|||
# We check for pthread_join because it is in -lpthread on IRIX |
|||
# while pthread_create is in libc. We check for pthread_attr_init |
|||
# due to DEC craziness with -lpthreads. We check for |
|||
# pthread_cleanup_push because it is one of the few pthread |
|||
# functions on Solaris that doesn't have a non-functional libc stub. |
|||
# We try pthread_create on general principles. |
|||
AC_TRY_LINK([#include <pthread.h> |
|||
static void routine(void* a) {a=0;} |
|||
static void* start_routine(void* a) {return a;}], |
|||
[pthread_t th; pthread_attr_t attr; |
|||
pthread_join(th, 0); |
|||
pthread_attr_init(&attr); |
|||
pthread_cleanup_push(routine, 0); |
|||
pthread_create(&th,0,start_routine,0); |
|||
pthread_cleanup_pop(0); ], |
|||
[ax_pthread_ok=yes]) |
|||
|
|||
LIBS="$save_LIBS" |
|||
CFLAGS="$save_CFLAGS" |
|||
|
|||
AC_MSG_RESULT($ax_pthread_ok) |
|||
if test "x$ax_pthread_ok" = xyes; then |
|||
break; |
|||
fi |
|||
|
|||
PTHREAD_LIBS="" |
|||
PTHREAD_CFLAGS="" |
|||
done |
|||
fi |
|||
|
|||
# Various other checks: |
|||
if test "x$ax_pthread_ok" = xyes; then |
|||
save_LIBS="$LIBS" |
|||
LIBS="$PTHREAD_LIBS $LIBS" |
|||
save_CFLAGS="$CFLAGS" |
|||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS" |
|||
|
|||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED. |
|||
AC_MSG_CHECKING([for joinable pthread attribute]) |
|||
attr_name=unknown |
|||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do |
|||
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;], |
|||
[attr_name=$attr; break]) |
|||
done |
|||
AC_MSG_RESULT($attr_name) |
|||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then |
|||
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, |
|||
[Define to necessary symbol if this constant |
|||
uses a non-standard name on your system.]) |
|||
fi |
|||
|
|||
AC_MSG_CHECKING([if more special flags are required for pthreads]) |
|||
flag=no |
|||
case "${host_cpu}-${host_os}" in |
|||
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; |
|||
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; |
|||
esac |
|||
AC_MSG_RESULT(${flag}) |
|||
if test "x$flag" != xno; then |
|||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" |
|||
fi |
|||
|
|||
LIBS="$save_LIBS" |
|||
CFLAGS="$save_CFLAGS" |
|||
|
|||
# More AIX lossage: must compile with xlc_r or cc_r |
|||
if test x"$GCC" != xyes; then |
|||
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) |
|||
else |
|||
PTHREAD_CC=$CC |
|||
fi |
|||
else |
|||
PTHREAD_CC="$CC" |
|||
fi |
|||
|
|||
AC_SUBST(PTHREAD_LIBS) |
|||
AC_SUBST(PTHREAD_CFLAGS) |
|||
AC_SUBST(PTHREAD_CC) |
|||
|
|||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: |
|||
if test x"$ax_pthread_ok" = xyes; then |
|||
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) |
|||
: |
|||
else |
|||
ax_pthread_ok=no |
|||
$2 |
|||
fi |
|||
AC_LANG_RESTORE |
|||
])dnl AX_PTHREAD |
|||
@ -0,0 +1,37 @@ |
|||
# =========================================================================== |
|||
# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html |
|||
# =========================================================================== |
|||
# |
|||
# SYNOPSIS |
|||
# |
|||
# AX_REQUIRE_DEFINED(MACRO) |
|||
# |
|||
# DESCRIPTION |
|||
# |
|||
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have |
|||
# been defined and thus are available for use. This avoids random issues |
|||
# where a macro isn't expanded. Instead the configure script emits a |
|||
# non-fatal: |
|||
# |
|||
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found |
|||
# |
|||
# It's like AC_REQUIRE except it doesn't expand the required macro. |
|||
# |
|||
# Here's an example: |
|||
# |
|||
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) |
|||
# |
|||
# LICENSE |
|||
# |
|||
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org> |
|||
# |
|||
# Copying and distribution of this file, with or without modification, are |
|||
# permitted in any medium without royalty provided the copyright notice |
|||
# and this notice are preserved. This file is offered as-is, without any |
|||
# warranty. |
|||
|
|||
#serial 1 |
|||
|
|||
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl |
|||
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) |
|||
])dnl AX_REQUIRE_DEFINED |
|||
7377
externals/breakpad/m4/libtool.m4
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,368 @@ |
|||
# Helper functions for option handling. -*- Autoconf -*- |
|||
# |
|||
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. |
|||
# Written by Gary V. Vaughan, 2004 |
|||
# |
|||
# This file is free software; the Free Software Foundation gives |
|||
# unlimited permission to copy and/or distribute it, with or without |
|||
# modifications, as long as this notice is preserved. |
|||
|
|||
# serial 6 ltoptions.m4 |
|||
|
|||
# This is to help aclocal find these macros, as it can't see m4_define. |
|||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) |
|||
|
|||
|
|||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) |
|||
# ------------------------------------------ |
|||
m4_define([_LT_MANGLE_OPTION], |
|||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) |
|||
|
|||
|
|||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) |
|||
# --------------------------------------- |
|||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a |
|||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are |
|||
# saved as a flag. |
|||
m4_define([_LT_SET_OPTION], |
|||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl |
|||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), |
|||
_LT_MANGLE_DEFUN([$1], [$2]), |
|||
[m4_warning([Unknown $1 option `$2'])])[]dnl |
|||
]) |
|||
|
|||
|
|||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) |
|||
# ------------------------------------------------------------ |
|||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. |
|||
m4_define([_LT_IF_OPTION], |
|||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) |
|||
|
|||
|
|||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) |
|||
# ------------------------------------------------------- |
|||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME |
|||
# are set. |
|||
m4_define([_LT_UNLESS_OPTIONS], |
|||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), |
|||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), |
|||
[m4_define([$0_found])])])[]dnl |
|||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 |
|||
])[]dnl |
|||
]) |
|||
|
|||
|
|||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) |
|||
# ---------------------------------------- |
|||
# OPTION-LIST is a space-separated list of Libtool options associated |
|||
# with MACRO-NAME. If any OPTION has a matching handler declared with |
|||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about |
|||
# the unknown option and exit. |
|||
m4_defun([_LT_SET_OPTIONS], |
|||
[# Set options |
|||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), |
|||
[_LT_SET_OPTION([$1], _LT_Option)]) |
|||
|
|||
m4_if([$1],[LT_INIT],[ |
|||
dnl |
|||
dnl Simply set some default values (i.e off) if boolean options were not |
|||
dnl specified: |
|||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no |
|||
]) |
|||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no |
|||
]) |
|||
dnl |
|||
dnl If no reference was made to various pairs of opposing options, then |
|||
dnl we run the default mode handler for the pair. For example, if neither |
|||
dnl `shared' nor `disable-shared' was passed, we enable building of shared |
|||
dnl archives by default: |
|||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) |
|||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) |
|||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) |
|||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], |
|||
[_LT_ENABLE_FAST_INSTALL]) |
|||
]) |
|||
])# _LT_SET_OPTIONS |
|||
|
|||
|
|||
## --------------------------------- ## |
|||
## Macros to handle LT_INIT options. ## |
|||
## --------------------------------- ## |
|||
|
|||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) |
|||
# ----------------------------------------- |
|||
m4_define([_LT_MANGLE_DEFUN], |
|||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) |
|||
|
|||
|
|||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) |
|||
# ----------------------------------------------- |
|||
m4_define([LT_OPTION_DEFINE], |
|||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl |
|||
])# LT_OPTION_DEFINE |
|||
|
|||
|
|||
# dlopen |
|||
# ------ |
|||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes |
|||
]) |
|||
|
|||
AU_DEFUN([AC_LIBTOOL_DLOPEN], |
|||
[_LT_SET_OPTION([LT_INIT], [dlopen]) |
|||
AC_DIAGNOSE([obsolete], |
|||
[$0: Remove this warning and the call to _LT_SET_OPTION when you |
|||
put the `dlopen' option into LT_INIT's first parameter.]) |
|||
]) |
|||
|
|||
dnl aclocal-1.4 backwards compatibility: |
|||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) |
|||
|
|||
|
|||
# win32-dll |
|||
# --------- |
|||
# Declare package support for building win32 dll's. |
|||
LT_OPTION_DEFINE([LT_INIT], [win32-dll], |
|||
[enable_win32_dll=yes |
|||
|
|||
case $host in |
|||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) |
|||
AC_CHECK_TOOL(AS, as, false) |
|||
AC_CHECK_TOOL(DLLTOOL, dlltool, false) |
|||
AC_CHECK_TOOL(OBJDUMP, objdump, false) |
|||
;; |
|||
esac |
|||
|
|||
test -z "$AS" && AS=as |
|||
_LT_DECL([], [AS], [0], [Assembler program])dnl |
|||
|
|||
test -z "$DLLTOOL" && DLLTOOL=dlltool |
|||
_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl |
|||
|
|||
test -z "$OBJDUMP" && OBJDUMP=objdump |
|||
_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl |
|||
])# win32-dll |
|||
|
|||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL], |
|||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl |
|||
_LT_SET_OPTION([LT_INIT], [win32-dll]) |
|||
AC_DIAGNOSE([obsolete], |
|||
[$0: Remove this warning and the call to _LT_SET_OPTION when you |
|||
put the `win32-dll' option into LT_INIT's first parameter.]) |
|||
]) |
|||
|
|||
dnl aclocal-1.4 backwards compatibility: |
|||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) |
|||
|
|||
|
|||
# _LT_ENABLE_SHARED([DEFAULT]) |
|||
# ---------------------------- |
|||
# implement the --enable-shared flag, and supports the `shared' and |
|||
# `disable-shared' LT_INIT options. |
|||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. |
|||
m4_define([_LT_ENABLE_SHARED], |
|||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl |
|||
AC_ARG_ENABLE([shared], |
|||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], |
|||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], |
|||
[p=${PACKAGE-default} |
|||
case $enableval in |
|||
yes) enable_shared=yes ;; |
|||
no) enable_shared=no ;; |
|||
*) |
|||
enable_shared=no |
|||
# Look at the argument we got. We use all the common list separators. |
|||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," |
|||
for pkg in $enableval; do |
|||
IFS="$lt_save_ifs" |
|||
if test "X$pkg" = "X$p"; then |
|||
enable_shared=yes |
|||
fi |
|||
done |
|||
IFS="$lt_save_ifs" |
|||
;; |
|||
esac], |
|||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT) |
|||
|
|||
_LT_DECL([build_libtool_libs], [enable_shared], [0], |
|||
[Whether or not to build shared libraries]) |
|||
])# _LT_ENABLE_SHARED |
|||
|
|||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) |
|||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) |
|||
|
|||
# Old names: |
|||
AC_DEFUN([AC_ENABLE_SHARED], |
|||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) |
|||
]) |
|||
|
|||
AC_DEFUN([AC_DISABLE_SHARED], |
|||
[_LT_SET_OPTION([LT_INIT], [disable-shared]) |
|||
]) |
|||
|
|||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) |
|||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) |
|||
|
|||
dnl aclocal-1.4 backwards compatibility: |
|||
dnl AC_DEFUN([AM_ENABLE_SHARED], []) |
|||
dnl AC_DEFUN([AM_DISABLE_SHARED], []) |
|||
|
|||
|
|||
|
|||
# _LT_ENABLE_STATIC([DEFAULT]) |
|||
# ---------------------------- |
|||
# implement the --enable-static flag, and support the `static' and |
|||
# `disable-static' LT_INIT options. |
|||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. |
|||
m4_define([_LT_ENABLE_STATIC], |
|||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl |
|||
AC_ARG_ENABLE([static], |
|||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], |
|||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], |
|||
[p=${PACKAGE-default} |
|||
case $enableval in |
|||
yes) enable_static=yes ;; |
|||
no) enable_static=no ;; |
|||
*) |
|||
enable_static=no |
|||
# Look at the argument we got. We use all the common list separators. |
|||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," |
|||
for pkg in $enableval; do |
|||
IFS="$lt_save_ifs" |
|||
if test "X$pkg" = "X$p"; then |
|||
enable_static=yes |
|||
fi |
|||
done |
|||
IFS="$lt_save_ifs" |
|||
;; |
|||
esac], |
|||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT) |
|||
|
|||
_LT_DECL([build_old_libs], [enable_static], [0], |
|||
[Whether or not to build static libraries]) |
|||
])# _LT_ENABLE_STATIC |
|||
|
|||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) |
|||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) |
|||
|
|||
# Old names: |
|||
AC_DEFUN([AC_ENABLE_STATIC], |
|||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) |
|||
]) |
|||
|
|||
AC_DEFUN([AC_DISABLE_STATIC], |
|||
[_LT_SET_OPTION([LT_INIT], [disable-static]) |
|||
]) |
|||
|
|||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) |
|||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) |
|||
|
|||
dnl aclocal-1.4 backwards compatibility: |
|||
dnl AC_DEFUN([AM_ENABLE_STATIC], []) |
|||
dnl AC_DEFUN([AM_DISABLE_STATIC], []) |
|||
|
|||
|
|||
|
|||
# _LT_ENABLE_FAST_INSTALL([DEFAULT]) |
|||
# ---------------------------------- |
|||
# implement the --enable-fast-install flag, and support the `fast-install' |
|||
# and `disable-fast-install' LT_INIT options. |
|||
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. |
|||
m4_define([_LT_ENABLE_FAST_INSTALL], |
|||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl |
|||
AC_ARG_ENABLE([fast-install], |
|||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], |
|||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], |
|||
[p=${PACKAGE-default} |
|||
case $enableval in |
|||
yes) enable_fast_install=yes ;; |
|||
no) enable_fast_install=no ;; |
|||
*) |
|||
enable_fast_install=no |
|||
# Look at the argument we got. We use all the common list separators. |
|||
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," |
|||
for pkg in $enableval; do |
|||
IFS="$lt_save_ifs" |
|||
if test "X$pkg" = "X$p"; then |
|||
enable_fast_install=yes |
|||
fi |
|||
done |
|||
IFS="$lt_save_ifs" |
|||
;; |
|||
esac], |
|||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) |
|||
|
|||
_LT_DECL([fast_install], [enable_fast_install], [0], |
|||
[Whether or not to optimize for fast installation])dnl |
|||
])# _LT_ENABLE_FAST_INSTALL |
|||
|
|||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) |
|||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) |
|||
|
|||
# Old names: |
|||
AU_DEFUN([AC_ENABLE_FAST_INSTALL], |
|||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) |
|||
AC_DIAGNOSE([obsolete], |
|||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put |
|||
the `fast-install' option into LT_INIT's first parameter.]) |
|||
]) |
|||
|
|||
AU_DEFUN([AC_DISABLE_FAST_INSTALL], |
|||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) |
|||
AC_DIAGNOSE([obsolete], |
|||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put |
|||
the `disable-fast-install' option into LT_INIT's first parameter.]) |
|||
]) |
|||
|
|||
dnl aclocal-1.4 backwards compatibility: |
|||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) |
|||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) |
|||
|
|||
|
|||
# _LT_WITH_PIC([MODE]) |
|||
# -------------------- |
|||
# implement the --with-pic flag, and support the `pic-only' and `no-pic' |
|||
# LT_INIT options. |
|||
# MODE is either `yes' or `no'. If omitted, it defaults to `both'. |
|||
m4_define([_LT_WITH_PIC], |
|||
[AC_ARG_WITH([pic], |
|||
[AS_HELP_STRING([--with-pic], |
|||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])], |
|||
[pic_mode="$withval"], |
|||
[pic_mode=default]) |
|||
|
|||
test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) |
|||
|
|||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl |
|||
])# _LT_WITH_PIC |
|||
|
|||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) |
|||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) |
|||
|
|||
# Old name: |
|||
AU_DEFUN([AC_LIBTOOL_PICMODE], |
|||
[_LT_SET_OPTION([LT_INIT], [pic-only]) |
|||
AC_DIAGNOSE([obsolete], |
|||
[$0: Remove this warning and the call to _LT_SET_OPTION when you |
|||
put the `pic-only' option into LT_INIT's first parameter.]) |
|||
]) |
|||
|
|||
dnl aclocal-1.4 backwards compatibility: |
|||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) |
|||
|
|||
## ----------------- ## |
|||
## LTDL_INIT Options ## |
|||
## ----------------- ## |
|||
|
|||
m4_define([_LTDL_MODE], []) |
|||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], |
|||
[m4_define([_LTDL_MODE], [nonrecursive])]) |
|||
LT_OPTION_DEFINE([LTDL_INIT], [recursive], |
|||
[m4_define([_LTDL_MODE], [recursive])]) |
|||
LT_OPTION_DEFINE([LTDL_INIT], [subproject], |
|||
[m4_define([_LTDL_MODE], [subproject])]) |
|||
|
|||
m4_define([_LTDL_TYPE], []) |
|||
LT_OPTION_DEFINE([LTDL_INIT], [installable], |
|||
[m4_define([_LTDL_TYPE], [installable])]) |
|||
LT_OPTION_DEFINE([LTDL_INIT], [convenience], |
|||
[m4_define([_LTDL_TYPE], [convenience])]) |
|||
@ -0,0 +1,123 @@ |
|||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- |
|||
# |
|||
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. |
|||
# Written by Gary V. Vaughan, 2004 |
|||
# |
|||
# This file is free software; the Free Software Foundation gives |
|||
# unlimited permission to copy and/or distribute it, with or without |
|||
# modifications, as long as this notice is preserved. |
|||
|
|||
# serial 6 ltsugar.m4 |
|||
|
|||
# This is to help aclocal find these macros, as it can't see m4_define. |
|||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) |
|||
|
|||
|
|||
# lt_join(SEP, ARG1, [ARG2...]) |
|||
# ----------------------------- |
|||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their |
|||
# associated separator. |
|||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier |
|||
# versions in m4sugar had bugs. |
|||
m4_define([lt_join], |
|||
[m4_if([$#], [1], [], |
|||
[$#], [2], [[$2]], |
|||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) |
|||
m4_define([_lt_join], |
|||
[m4_if([$#$2], [2], [], |
|||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) |
|||
|
|||
|
|||
# lt_car(LIST) |
|||
# lt_cdr(LIST) |
|||
# ------------ |
|||
# Manipulate m4 lists. |
|||
# These macros are necessary as long as will still need to support |
|||
# Autoconf-2.59 which quotes differently. |
|||
m4_define([lt_car], [[$1]]) |
|||
m4_define([lt_cdr], |
|||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], |
|||
[$#], 1, [], |
|||
[m4_dquote(m4_shift($@))])]) |
|||
m4_define([lt_unquote], $1) |
|||
|
|||
|
|||
# lt_append(MACRO-NAME, STRING, [SEPARATOR]) |
|||
# ------------------------------------------ |
|||
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. |
|||
# Note that neither SEPARATOR nor STRING are expanded; they are appended |
|||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). |
|||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different |
|||
# than defined and empty). |
|||
# |
|||
# This macro is needed until we can rely on Autoconf 2.62, since earlier |
|||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. |
|||
m4_define([lt_append], |
|||
[m4_define([$1], |
|||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) |
|||
|
|||
|
|||
|
|||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) |
|||
# ---------------------------------------------------------- |
|||
# Produce a SEP delimited list of all paired combinations of elements of |
|||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list |
|||
# has the form PREFIXmINFIXSUFFIXn. |
|||
# Needed until we can rely on m4_combine added in Autoconf 2.62. |
|||
m4_define([lt_combine], |
|||
[m4_if(m4_eval([$# > 3]), [1], |
|||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl |
|||
[[m4_foreach([_Lt_prefix], [$2], |
|||
[m4_foreach([_Lt_suffix], |
|||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, |
|||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) |
|||
|
|||
|
|||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) |
|||
# ----------------------------------------------------------------------- |
|||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited |
|||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. |
|||
m4_define([lt_if_append_uniq], |
|||
[m4_ifdef([$1], |
|||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], |
|||
[lt_append([$1], [$2], [$3])$4], |
|||
[$5])], |
|||
[lt_append([$1], [$2], [$3])$4])]) |
|||
|
|||
|
|||
# lt_dict_add(DICT, KEY, VALUE) |
|||
# ----------------------------- |
|||
m4_define([lt_dict_add], |
|||
[m4_define([$1($2)], [$3])]) |
|||
|
|||
|
|||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) |
|||
# -------------------------------------------- |
|||
m4_define([lt_dict_add_subkey], |
|||
[m4_define([$1($2:$3)], [$4])]) |
|||
|
|||
|
|||
# lt_dict_fetch(DICT, KEY, [SUBKEY]) |
|||
# ---------------------------------- |
|||
m4_define([lt_dict_fetch], |
|||
[m4_ifval([$3], |
|||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), |
|||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) |
|||
|
|||
|
|||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) |
|||
# ----------------------------------------------------------------- |
|||
m4_define([lt_if_dict_fetch], |
|||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], |
|||
[$5], |
|||
[$6])]) |
|||
|
|||
|
|||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) |
|||
# -------------------------------------------------------------- |
|||
m4_define([lt_dict_filter], |
|||
[m4_if([$5], [], [], |
|||
[lt_join(m4_quote(m4_default([$4], [[, ]])), |
|||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), |
|||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl |
|||
]) |
|||
@ -0,0 +1,23 @@ |
|||
# ltversion.m4 -- version numbers -*- Autoconf -*- |
|||
# |
|||
# Copyright (C) 2004 Free Software Foundation, Inc. |
|||
# Written by Scott James Remnant, 2004 |
|||
# |
|||
# This file is free software; the Free Software Foundation gives |
|||
# unlimited permission to copy and/or distribute it, with or without |
|||
# modifications, as long as this notice is preserved. |
|||
|
|||
# Generated from ltversion.in. |
|||
|
|||
# serial 3017 ltversion.m4 |
|||
# This file is part of GNU Libtool |
|||
|
|||
m4_define([LT_PACKAGE_VERSION], [2.2.6b]) |
|||
m4_define([LT_PACKAGE_REVISION], [1.3017]) |
|||
|
|||
AC_DEFUN([LTVERSION_VERSION], |
|||
[macro_version='2.2.6b' |
|||
macro_revision='1.3017' |
|||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) |
|||
_LT_DECL(, macro_revision, 0) |
|||
]) |
|||
@ -0,0 +1,92 @@ |
|||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- |
|||
# |
|||
# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. |
|||
# Written by Scott James Remnant, 2004. |
|||
# |
|||
# This file is free software; the Free Software Foundation gives |
|||
# unlimited permission to copy and/or distribute it, with or without |
|||
# modifications, as long as this notice is preserved. |
|||
|
|||
# serial 4 lt~obsolete.m4 |
|||
|
|||
# These exist entirely to fool aclocal when bootstrapping libtool. |
|||
# |
|||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) |
|||
# which have later been changed to m4_define as they aren't part of the |
|||
# exported API, or moved to Autoconf or Automake where they belong. |
|||
# |
|||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN |
|||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us |
|||
# using a macro with the same name in our local m4/libtool.m4 it'll |
|||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define |
|||
# and doesn't know about Autoconf macros at all.) |
|||
# |
|||
# So we provide this file, which has a silly filename so it's always |
|||
# included after everything else. This provides aclocal with the |
|||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything |
|||
# because those macros already exist, or will be overwritten later. |
|||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. |
|||
# |
|||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. |
|||
# Yes, that means every name once taken will need to remain here until |
|||
# we give up compatibility with versions before 1.7, at which point |
|||
# we need to keep only those names which we still refer to. |
|||
|
|||
# This is to help aclocal find these macros, as it can't see m4_define. |
|||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) |
|||
|
|||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) |
|||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) |
|||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) |
|||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) |
|||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) |
|||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) |
|||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) |
|||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) |
|||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) |
|||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) |
|||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) |
|||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) |
|||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) |
|||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) |
|||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) |
|||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) |
|||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) |
|||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) |
|||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) |
|||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) |
|||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) |
|||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) |
|||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) |
|||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) |
|||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) |
|||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) |
|||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) |
|||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) |
|||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) |
|||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) |
|||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) |
|||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) |
|||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) |
|||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) |
|||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) |
|||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) |
|||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) |
|||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) |
|||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) |
|||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) |
|||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) |
|||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) |
|||
m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) |
|||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) |
|||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) |
|||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) |
|||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) |
|||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) |
|||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) |
|||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) |
|||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) |
|||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) |
|||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) |
|||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) |
|||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) |
|||
@ -0,0 +1,56 @@ |
|||
// Copyright 2009 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef BREAKPAD_GOOGLETEST_INCLUDES_H__ |
|||
#define BREAKPAD_GOOGLETEST_INCLUDES_H__ |
|||
|
|||
#include "gtest/gtest.h" |
|||
#include "gmock/gmock.h" |
|||
|
|||
// If AddressSanitizer is used, NULL pointer dereferences generate SIGILL |
|||
// (illegal instruction) instead of SIGSEGV (segmentation fault). Also, |
|||
// the number of memory regions differs, so there is no point in running |
|||
// this test if AddressSanitizer is used. |
|||
// |
|||
// Ideally we'd use this attribute to disable ASAN on a per-func basis, |
|||
// but this doesn't seem to actually work, and it's changed names over |
|||
// time. So just stick with disabling the actual tests. |
|||
// http://crbug.com/304575 |
|||
//#define NO_ASAN __attribute__((no_sanitize_address)) |
|||
#if defined(__clang__) && defined(__has_feature) |
|||
// Have to keep this check sep from above as newer gcc will barf on it. |
|||
# if __has_feature(address_sanitizer) |
|||
# define ADDRESS_SANITIZER |
|||
# endif |
|||
#elif defined(__GNUC__) && defined(__SANITIZE_ADDRESS__) |
|||
# define ADDRESS_SANITIZER |
|||
#else |
|||
# undef ADDRESS_SANITIZER |
|||
#endif |
|||
|
|||
#endif // BREAKPAD_GOOGLETEST_INCLUDES_H__ |
|||
@ -0,0 +1,72 @@ |
|||
// Copyright 2011 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
// Keys for configuration file |
|||
#define kReporterMinidumpDirectoryKey "MinidumpDir" |
|||
#define kReporterMinidumpIDKey "MinidumpID" |
|||
|
|||
// Filename for recording uploaded IDs |
|||
#define kReporterLogFilename "uploads.log" |
|||
|
|||
// The default subdirectory of the Library to put crash dumps in |
|||
// The subdirectory is |
|||
// ~/Library/<kDefaultLibrarySubdirectory>/<GoogleBreakpadProduct> |
|||
#define kDefaultLibrarySubdirectory "Breakpad" |
|||
|
|||
// Specify some special keys to be used in the configuration file that is |
|||
// generated by Breakpad and consumed by the crash_sender. |
|||
#define BREAKPAD_PRODUCT "BreakpadProduct" |
|||
#define BREAKPAD_PRODUCT_DISPLAY "BreakpadProductDisplay" |
|||
#define BREAKPAD_VERSION "BreakpadVersion" |
|||
#define BREAKPAD_VENDOR "BreakpadVendor" |
|||
#define BREAKPAD_URL "BreakpadURL" |
|||
#define BREAKPAD_REPORT_INTERVAL "BreakpadReportInterval" |
|||
#define BREAKPAD_SKIP_CONFIRM "BreakpadSkipConfirm" |
|||
#define BREAKPAD_CONFIRM_TIMEOUT "BreakpadConfirmTimeout" |
|||
#define BREAKPAD_SEND_AND_EXIT "BreakpadSendAndExit" |
|||
#define BREAKPAD_DUMP_DIRECTORY "BreakpadMinidumpLocation" |
|||
#define BREAKPAD_INSPECTOR_LOCATION "BreakpadInspectorLocation" |
|||
#define BREAKPAD_REPORTER_EXE_LOCATION \ |
|||
"BreakpadReporterExeLocation" |
|||
#define BREAKPAD_LOGFILES "BreakpadLogFiles" |
|||
#define BREAKPAD_LOGFILE_UPLOAD_SIZE "BreakpadLogFileTailSize" |
|||
#define BREAKPAD_REQUEST_COMMENTS "BreakpadRequestComments" |
|||
#define BREAKPAD_COMMENTS "BreakpadComments" |
|||
#define BREAKPAD_REQUEST_EMAIL "BreakpadRequestEmail" |
|||
#define BREAKPAD_EMAIL "BreakpadEmail" |
|||
#define BREAKPAD_SERVER_TYPE "BreakpadServerType" |
|||
#define BREAKPAD_SERVER_PARAMETER_DICT "BreakpadServerParameters" |
|||
#define BREAKPAD_IN_PROCESS "BreakpadInProcess" |
|||
|
|||
// The keys below are NOT user supplied, and are used internally. |
|||
#define BREAKPAD_PROCESS_START_TIME "BreakpadProcStartTime" |
|||
#define BREAKPAD_PROCESS_UP_TIME "BreakpadProcessUpTime" |
|||
#define BREAKPAD_PROCESS_CRASH_TIME "BreakpadProcessCrashTime" |
|||
#define BREAKPAD_LOGFILE_KEY_PREFIX "BreakpadAppLogFile" |
|||
#define BREAKPAD_SERVER_PARAMETER_PREFIX "BreakpadServerParameterPrefix_" |
|||
#define BREAKPAD_ON_DEMAND "BreakpadOnDemand" |
|||
@ -0,0 +1,259 @@ |
|||
// Copyright 2011 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
// Framework to provide a simple C API to crash reporting for |
|||
// applications. By default, if any machine-level exception (e.g., |
|||
// EXC_BAD_ACCESS) occurs, it will be handled by the BreakpadRef |
|||
// object as follows: |
|||
// |
|||
// 1. Create a minidump file (see Breakpad for details) |
|||
// 2. Create a config file. |
|||
// |
|||
// These files can then be uploaded to a server. |
|||
|
|||
typedef void* BreakpadRef; |
|||
|
|||
#ifdef __cplusplus |
|||
extern "C" { |
|||
#endif |
|||
|
|||
#include <Foundation/Foundation.h> |
|||
|
|||
#include <client/apple/Framework/BreakpadDefines.h> |
|||
|
|||
// The keys in the dictionary returned by |BreakpadGenerateReport|. |
|||
#define BREAKPAD_OUTPUT_DUMP_FILE "BreakpadDumpFile" |
|||
#define BREAKPAD_OUTPUT_CONFIG_FILE "BreakpadConfigFile" |
|||
|
|||
// Optional user-defined function to decide if we should handle this crash or |
|||
// forward it along. |
|||
// Return true if you want Breakpad to handle it. |
|||
// Return false if you want Breakpad to skip it |
|||
// The exception handler always returns false, as if SEND_AND_EXIT were false |
|||
// (which means the next exception handler will take the exception) |
|||
typedef bool (*BreakpadFilterCallback)(int exception_type, |
|||
int exception_code, |
|||
mach_port_t crashing_thread, |
|||
void* context); |
|||
|
|||
// Optional user-defined function that will be called after a network upload |
|||
// of a crash report. |
|||
// |report_id| will be the id returned by the server, or "ERR" if an error |
|||
// occurred. |
|||
// |error| will contain the error, or nil if no error occured. |
|||
typedef void (*BreakpadUploadCompletionCallback)(NSString* report_id, |
|||
NSError* error); |
|||
|
|||
// Create a new BreakpadRef object and install it as an exception |
|||
// handler. The |parameters| will typically be the contents of your |
|||
// bundle's Info.plist. |
|||
// |
|||
// You can also specify these additional keys for customizable behavior: |
|||
// Key: Value: |
|||
// BREAKPAD_PRODUCT Product name (e.g., "MyAwesomeProduct") |
|||
// This one is used as the key to identify |
|||
// the product when uploading. Falls back to |
|||
// CFBundleName if not specified. |
|||
// REQUIRED |
|||
// |
|||
// BREAKPAD_PRODUCT_DISPLAY This is the display name, e.g. a pretty |
|||
// name for the product when the crash_sender |
|||
// pops up UI for the user. Falls back first to |
|||
// CFBundleDisplayName and then to |
|||
// BREAKPAD_PRODUCT if not specified. |
|||
// |
|||
// BREAKPAD_VERSION Product version (e.g., 1.2.3), used |
|||
// as metadata for crash report. Falls back to |
|||
// CFBundleVersion if not specified. |
|||
// REQUIRED |
|||
// |
|||
// BREAKPAD_VENDOR Vendor name, used in UI (e.g. "A report has |
|||
// been created that you can send to <vendor>") |
|||
// |
|||
// BREAKPAD_URL URL destination for reporting |
|||
// REQUIRED |
|||
// |
|||
// BREAKPAD_DUMP_DIRECTORY The directory to store crash-dumps |
|||
// in. By default, we use |
|||
// ~/Library/Cache/Breakpad/<BREAKPAD_PRODUCT> |
|||
// The path you specify here is tilde-expanded. |
|||
// |
|||
// BREAKPAD_SERVER_TYPE A parameter that tells Breakpad how to |
|||
// rewrite the upload parameters for a specific |
|||
// server type. The currently valid values are |
|||
// 'socorro' or 'google'. If you want to add |
|||
// other types, see the function in |
|||
// crash_report_sender.m that maps parameters to |
|||
// URL parameters. Defaults to 'google'. |
|||
// |
|||
// BREAKPAD_SERVER_PARAMETER_DICT A plist dictionary of static |
|||
// parameters that are uploaded to the |
|||
// server. The parameters are sent as |
|||
// is to the crash server. Their |
|||
// content isn't added to the minidump |
|||
// but pass as URL parameters when |
|||
// uploading theminidump to the crash |
|||
// server. |
|||
//============================================================================= |
|||
// The BREAKPAD_PRODUCT, BREAKPAD_VERSION and BREAKPAD_URL are |
|||
// required to have non-NULL values. By default, the BREAKPAD_PRODUCT |
|||
// will be the CFBundleName and the BREAKPAD_VERSION will be the |
|||
// CFBundleVersion when these keys are present in the bundle's |
|||
// Info.plist, which is usually passed in to BreakpadCreate() as an |
|||
// NSDictionary (you could also pass in another dictionary that had |
|||
// the same keys configured). If the BREAKPAD_PRODUCT or |
|||
// BREAKPAD_VERSION are ultimately undefined, BreakpadCreate() will |
|||
// fail. You have been warned. |
|||
// |
|||
// If you are running in a debugger, Breakpad will not install, unless the |
|||
// BREAKPAD_IGNORE_DEBUGGER envionment variable is set and/or non-zero. |
|||
// |
|||
//============================================================================= |
|||
// The following are NOT user-supplied but are documented here for |
|||
// completeness. They are calculated by Breakpad during initialization & |
|||
// crash-dump generation, or entered in by the user. |
|||
// |
|||
// BREAKPAD_PROCESS_START_TIME The time, in seconds since the Epoch, the |
|||
// process started |
|||
// |
|||
// BREAKPAD_PROCESS_CRASH_TIME The time, in seconds since the Epoch, the |
|||
// process crashed. |
|||
// |
|||
// BREAKPAD_PROCESS_UP_TIME The total time in milliseconds the process |
|||
// has been running. This parameter is not |
|||
// set until the crash-dump-generation phase. |
|||
// |
|||
// BREAKPAD_SERVER_PARAMETER_PREFIX This prefix is used by Breakpad |
|||
// internally, because Breakpad uses |
|||
// the same dictionary internally to |
|||
// track both its internal |
|||
// configuration parameters and |
|||
// parameters meant to be uploaded |
|||
// to the server. This string is |
|||
// used internally by Breakpad to |
|||
// prefix user-supplied parameter |
|||
// names so those can be sent to the |
|||
// server without leaking Breakpad's |
|||
// internal values. |
|||
|
|||
// Returns a new BreakpadRef object on success, NULL otherwise. |
|||
BreakpadRef BreakpadCreate(NSDictionary* parameters); |
|||
|
|||
// Uninstall and release the data associated with |ref|. |
|||
void BreakpadRelease(BreakpadRef ref); |
|||
|
|||
// User defined key and value string storage. Generally this is used |
|||
// to configure Breakpad's internal operation, such as whether the |
|||
// crash_sender should prompt the user, or the filesystem location for |
|||
// the minidump file. See Breakpad.h for some parameters that can be |
|||
// set. Anything longer than 255 bytes will be truncated. Note that |
|||
// the string is converted to UTF8 before truncation, so any multibyte |
|||
// character that straddles the 255(256 - 1 for terminator) byte limit |
|||
// will be mangled. |
|||
// |
|||
// A maximum number of 64 key/value pairs are supported. An assert() |
|||
// will fire if more than this number are set. Unfortunately, right |
|||
// now, the same dictionary is used for both Breakpad's parameters AND |
|||
// the Upload parameters. |
|||
// |
|||
// TODO (nealsid): Investigate how necessary this is if we don't |
|||
// automatically upload parameters to the server anymore. |
|||
// TODO (nealsid): separate server parameter dictionary from the |
|||
// dictionary used to configure Breakpad, and document limits for each |
|||
// independently. |
|||
void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value); |
|||
NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key); |
|||
void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key); |
|||
|
|||
// You can use this method to specify parameters that will be uploaded |
|||
// to the crash server. They will be automatically encoded as |
|||
// necessary. Note that as mentioned above there are limits on both |
|||
// the number of keys and their length. |
|||
void BreakpadAddUploadParameter(BreakpadRef ref, NSString* key, |
|||
NSString* value); |
|||
|
|||
// This method will remove a previously-added parameter from the |
|||
// upload parameter set. |
|||
void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString* key); |
|||
|
|||
// Method to handle uploading data to the server |
|||
|
|||
// Returns the number of crash reports waiting to send to the server. |
|||
int BreakpadGetCrashReportCount(BreakpadRef ref); |
|||
|
|||
// Returns the next upload configuration. The report file is deleted. |
|||
NSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref); |
|||
|
|||
// Returns the date of the most recent crash report. |
|||
NSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref); |
|||
|
|||
// Upload next report to the server. |
|||
void BreakpadUploadNextReport(BreakpadRef ref); |
|||
|
|||
// Upload next report to the server. |
|||
// |server_parameters| is additional server parameters to send. |
|||
void BreakpadUploadNextReportWithParameters( |
|||
BreakpadRef ref, |
|||
NSDictionary* server_parameters, |
|||
BreakpadUploadCompletionCallback callback); |
|||
|
|||
// Upload a report to the server. |
|||
// |server_parameters| is additional server parameters to send. |
|||
// |configuration| is the configuration of the breakpad report to send. |
|||
void BreakpadUploadReportWithParametersAndConfiguration( |
|||
BreakpadRef ref, |
|||
NSDictionary* server_parameters, |
|||
NSDictionary* configuration, |
|||
BreakpadUploadCompletionCallback callback); |
|||
|
|||
// Handles the network response of a breakpad upload. This function is needed if |
|||
// the actual upload is done by the Breakpad client. |
|||
// |configuration| is the configuration of the upload. It must contain the same |
|||
// fields as the configuration passed to |
|||
// BreakpadUploadReportWithParametersAndConfiguration. |
|||
// |data| and |error| contain the network response. |
|||
void BreakpadHandleNetworkResponse(BreakpadRef ref, |
|||
NSDictionary* configuration, |
|||
NSData* data, |
|||
NSError* error); |
|||
|
|||
// Upload a file to the server. |data| is the content of the file to sent. |
|||
// |server_parameters| is additional server parameters to send. |
|||
void BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name, |
|||
NSDictionary* server_parameters); |
|||
|
|||
// Generate a breakpad minidump and configuration file in the dump directory. |
|||
// The report will be available for uploading. The paths of the created files |
|||
// are returned in the dictionary. |server_parameters| is additional server |
|||
// parameters to add in the config file. |
|||
NSDictionary* BreakpadGenerateReport(BreakpadRef ref, |
|||
NSDictionary* server_parameters); |
|||
|
|||
#ifdef __cplusplus |
|||
} |
|||
#endif |
|||
@ -0,0 +1,986 @@ |
|||
// Copyright 2011 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#define IGNORE_DEBUGGER "BREAKPAD_IGNORE_DEBUGGER" |
|||
|
|||
#import "client/ios/Breakpad.h" |
|||
|
|||
#include <assert.h> |
|||
#import <Foundation/Foundation.h> |
|||
#include <pthread.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/sysctl.h> |
|||
#include <TargetConditionals.h> |
|||
|
|||
#include <string> |
|||
|
|||
#import "client/ios/handler/ios_exception_minidump_generator.h" |
|||
#import "client/mac/crash_generation/ConfigFile.h" |
|||
#import "client/mac/handler/minidump_generator.h" |
|||
#import "client/mac/handler/protected_memory_allocator.h" |
|||
#import "client/mac/sender/uploader.h" |
|||
#import "common/long_string_dictionary.h" |
|||
|
|||
#if !TARGET_OS_TV && !TARGET_OS_WATCH |
|||
#import "client/mac/handler/exception_handler.h" |
|||
#else |
|||
#import "client/ios/exception_handler_no_mach.h" |
|||
#endif // !TARGET_OS_TV && !TARGET_OS_WATCH |
|||
|
|||
#if !defined(__EXCEPTIONS) || (__clang__ && !__has_feature(cxx_exceptions)) |
|||
// This file uses C++ try/catch (but shouldn't). Duplicate the macros from |
|||
// <c++/4.2.1/exception_defines.h> allowing this file to work properly with |
|||
// exceptions disabled even when other C++ libraries are used. #undef the try |
|||
// and catch macros first in case libstdc++ is in use and has already provided |
|||
// its own definitions. |
|||
#undef try |
|||
#define try if (true) |
|||
#undef catch |
|||
#define catch(X) if (false) |
|||
#endif // __EXCEPTIONS |
|||
|
|||
using google_breakpad::ConfigFile; |
|||
using google_breakpad::EnsureDirectoryPathExists; |
|||
using google_breakpad::LongStringDictionary; |
|||
|
|||
//============================================================================= |
|||
// We want any memory allocations which are used by breakpad during the |
|||
// exception handling process (after a crash has happened) to be read-only |
|||
// to prevent them from being smashed before a crash occurs. Unfortunately |
|||
// we cannot protect against smashes to our exception handling thread's |
|||
// stack. |
|||
// |
|||
// NOTE: Any memory allocations which are not used during the exception |
|||
// handling process may be allocated in the normal ways. |
|||
// |
|||
// The ProtectedMemoryAllocator class provides an Allocate() method which |
|||
// we'll using in conjunction with placement operator new() to control |
|||
// allocation of C++ objects. Note that we don't use operator delete() |
|||
// but instead call the objects destructor directly: object->~ClassName(); |
|||
// |
|||
ProtectedMemoryAllocator* gMasterAllocator = NULL; |
|||
ProtectedMemoryAllocator* gKeyValueAllocator = NULL; |
|||
ProtectedMemoryAllocator* gBreakpadAllocator = NULL; |
|||
|
|||
// Mutex for thread-safe access to the key/value dictionary used by breakpad. |
|||
// It's a global instead of an instance variable of Breakpad |
|||
// since it can't live in a protected memory area. |
|||
pthread_mutex_t gDictionaryMutex; |
|||
|
|||
//============================================================================= |
|||
// Stack-based object for thread-safe access to a memory-protected region. |
|||
// It's assumed that normally the memory block (allocated by the allocator) |
|||
// is protected (read-only). Creating a stack-based instance of |
|||
// ProtectedMemoryLocker will unprotect this block after taking the lock. |
|||
// Its destructor will first re-protect the memory then release the lock. |
|||
class ProtectedMemoryLocker { |
|||
public: |
|||
ProtectedMemoryLocker(pthread_mutex_t* mutex, |
|||
ProtectedMemoryAllocator* allocator) |
|||
: mutex_(mutex), |
|||
allocator_(allocator) { |
|||
// Lock the mutex |
|||
__attribute__((unused)) int rv = pthread_mutex_lock(mutex_); |
|||
assert(rv == 0); |
|||
|
|||
// Unprotect the memory |
|||
allocator_->Unprotect(); |
|||
} |
|||
|
|||
~ProtectedMemoryLocker() { |
|||
// First protect the memory |
|||
allocator_->Protect(); |
|||
|
|||
// Then unlock the mutex |
|||
__attribute__((unused)) int rv = pthread_mutex_unlock(mutex_); |
|||
assert(rv == 0); |
|||
} |
|||
|
|||
private: |
|||
ProtectedMemoryLocker(); |
|||
ProtectedMemoryLocker(const ProtectedMemoryLocker&); |
|||
ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&); |
|||
|
|||
pthread_mutex_t* mutex_; |
|||
ProtectedMemoryAllocator* allocator_; |
|||
}; |
|||
|
|||
//============================================================================= |
|||
class Breakpad { |
|||
public: |
|||
// factory method |
|||
static Breakpad* Create(NSDictionary* parameters) { |
|||
// Allocate from our special allocation pool |
|||
Breakpad* breakpad = |
|||
new (gBreakpadAllocator->Allocate(sizeof(Breakpad))) |
|||
Breakpad(); |
|||
|
|||
if (!breakpad) |
|||
return NULL; |
|||
|
|||
if (!breakpad->Initialize(parameters)) { |
|||
// Don't use operator delete() here since we allocated from special pool |
|||
breakpad->~Breakpad(); |
|||
return NULL; |
|||
} |
|||
|
|||
return breakpad; |
|||
} |
|||
|
|||
~Breakpad(); |
|||
|
|||
void SetKeyValue(NSString* key, NSString* value); |
|||
NSString* KeyValue(NSString* key); |
|||
void RemoveKeyValue(NSString* key); |
|||
NSArray* CrashReportsToUpload(); |
|||
NSString* NextCrashReportToUpload(); |
|||
NSDictionary* NextCrashReportConfiguration(); |
|||
NSDictionary* FixedUpCrashReportConfiguration(NSDictionary* configuration); |
|||
NSDate* DateOfMostRecentCrashReport(); |
|||
void UploadNextReport(NSDictionary* server_parameters); |
|||
void UploadReportWithConfiguration(NSDictionary* configuration, |
|||
NSDictionary* server_parameters, |
|||
BreakpadUploadCompletionCallback callback); |
|||
void UploadData(NSData* data, NSString* name, |
|||
NSDictionary* server_parameters); |
|||
void HandleNetworkResponse(NSDictionary* configuration, |
|||
NSData* data, |
|||
NSError* error); |
|||
NSDictionary* GenerateReport(NSDictionary* server_parameters); |
|||
|
|||
private: |
|||
Breakpad() |
|||
: handler_(NULL), |
|||
config_params_(NULL) {} |
|||
|
|||
bool Initialize(NSDictionary* parameters); |
|||
|
|||
bool ExtractParameters(NSDictionary* parameters); |
|||
|
|||
// Dispatches to HandleMinidump() |
|||
static bool HandleMinidumpCallback(const char* dump_dir, |
|||
const char* minidump_id, |
|||
void* context, bool succeeded); |
|||
|
|||
bool HandleMinidump(const char* dump_dir, |
|||
const char* minidump_id); |
|||
|
|||
// NSException handler |
|||
static void UncaughtExceptionHandler(NSException* exception); |
|||
|
|||
// Handle an uncaught NSException. |
|||
void HandleUncaughtException(NSException* exception); |
|||
|
|||
// Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's |
|||
// MachineExceptions.h, we have to explicitly name the handler. |
|||
google_breakpad::ExceptionHandler* handler_; // The actual handler (STRONG) |
|||
|
|||
LongStringDictionary* config_params_; // Create parameters (STRONG) |
|||
|
|||
ConfigFile config_file_; |
|||
|
|||
// A static reference to the current Breakpad instance. Used for handling |
|||
// NSException. |
|||
static Breakpad* current_breakpad_; |
|||
}; |
|||
|
|||
Breakpad* Breakpad::current_breakpad_ = NULL; |
|||
|
|||
#pragma mark - |
|||
#pragma mark Helper functions |
|||
|
|||
//============================================================================= |
|||
// Helper functions |
|||
|
|||
//============================================================================= |
|||
static BOOL IsDebuggerActive() { |
|||
BOOL result = NO; |
|||
NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults]; |
|||
|
|||
// We check both defaults and the environment variable here |
|||
|
|||
BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER]; |
|||
|
|||
if (!ignoreDebugger) { |
|||
char* ignoreDebuggerStr = getenv(IGNORE_DEBUGGER); |
|||
ignoreDebugger = |
|||
(ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0; |
|||
} |
|||
|
|||
if (!ignoreDebugger) { |
|||
pid_t pid = getpid(); |
|||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; |
|||
int mibSize = sizeof(mib) / sizeof(int); |
|||
size_t actualSize; |
|||
|
|||
if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) { |
|||
struct kinfo_proc* info = (struct kinfo_proc*)malloc(actualSize); |
|||
|
|||
if (info) { |
|||
// This comes from looking at the Darwin xnu Kernel |
|||
if (sysctl(mib, mibSize, info, &actualSize, NULL, 0) == 0) |
|||
result = (info->kp_proc.p_flag & P_TRACED) ? YES : NO; |
|||
|
|||
free(info); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
//============================================================================= |
|||
bool Breakpad::HandleMinidumpCallback(const char* dump_dir, |
|||
const char* minidump_id, |
|||
void* context, bool succeeded) { |
|||
Breakpad* breakpad = (Breakpad*)context; |
|||
|
|||
// If our context is damaged or something, just return false to indicate that |
|||
// the handler should continue without us. |
|||
if (!breakpad || !succeeded) |
|||
return false; |
|||
|
|||
return breakpad->HandleMinidump(dump_dir, minidump_id); |
|||
} |
|||
|
|||
//============================================================================= |
|||
void Breakpad::UncaughtExceptionHandler(NSException* exception) { |
|||
NSSetUncaughtExceptionHandler(NULL); |
|||
if (current_breakpad_) { |
|||
current_breakpad_->HandleUncaughtException(exception); |
|||
BreakpadRelease(current_breakpad_); |
|||
} |
|||
} |
|||
|
|||
//============================================================================= |
|||
#pragma mark - |
|||
|
|||
//============================================================================= |
|||
bool Breakpad::Initialize(NSDictionary* parameters) { |
|||
// Initialize |
|||
current_breakpad_ = this; |
|||
config_params_ = NULL; |
|||
handler_ = NULL; |
|||
|
|||
// Gather any user specified parameters |
|||
if (!ExtractParameters(parameters)) { |
|||
return false; |
|||
} |
|||
|
|||
// Check for debugger |
|||
if (IsDebuggerActive()) { |
|||
return true; |
|||
} |
|||
|
|||
// Create the handler (allocating it in our special protected pool) |
|||
handler_ = |
|||
new (gBreakpadAllocator->Allocate( |
|||
sizeof(google_breakpad::ExceptionHandler))) |
|||
google_breakpad::ExceptionHandler( |
|||
config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY), |
|||
0, &HandleMinidumpCallback, this, true, 0); |
|||
NSSetUncaughtExceptionHandler(&Breakpad::UncaughtExceptionHandler); |
|||
return true; |
|||
} |
|||
|
|||
//============================================================================= |
|||
Breakpad::~Breakpad() { |
|||
NSSetUncaughtExceptionHandler(NULL); |
|||
current_breakpad_ = NULL; |
|||
// Note that we don't use operator delete() on these pointers, |
|||
// since they were allocated by ProtectedMemoryAllocator objects. |
|||
// |
|||
if (config_params_) { |
|||
config_params_->~LongStringDictionary(); |
|||
} |
|||
|
|||
if (handler_) |
|||
handler_->~ExceptionHandler(); |
|||
} |
|||
|
|||
//============================================================================= |
|||
bool Breakpad::ExtractParameters(NSDictionary* parameters) { |
|||
NSString* serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE]; |
|||
NSString* display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; |
|||
NSString* product = [parameters objectForKey:@BREAKPAD_PRODUCT]; |
|||
NSString* version = [parameters objectForKey:@BREAKPAD_VERSION]; |
|||
NSString* urlStr = [parameters objectForKey:@BREAKPAD_URL]; |
|||
NSString* vendor = |
|||
[parameters objectForKey:@BREAKPAD_VENDOR]; |
|||
// We check both parameters and the environment variable here. |
|||
char* envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY); |
|||
NSString* dumpSubdirectory = envVarDumpSubdirectory ? |
|||
[NSString stringWithUTF8String:envVarDumpSubdirectory] : |
|||
[parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY]; |
|||
|
|||
NSDictionary* serverParameters = |
|||
[parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT]; |
|||
|
|||
if (!product) |
|||
product = [parameters objectForKey:@"CFBundleName"]; |
|||
|
|||
if (!display) { |
|||
display = [parameters objectForKey:@"CFBundleDisplayName"]; |
|||
if (!display) { |
|||
display = product; |
|||
} |
|||
} |
|||
|
|||
if (!version.length) // Default nil or empty string to CFBundleVersion |
|||
version = [parameters objectForKey:@"CFBundleVersion"]; |
|||
|
|||
if (!vendor) { |
|||
vendor = @"Vendor not specified"; |
|||
} |
|||
|
|||
if (!dumpSubdirectory) { |
|||
NSString* cachePath = |
|||
[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, |
|||
NSUserDomainMask, |
|||
YES) |
|||
objectAtIndex:0]; |
|||
dumpSubdirectory = |
|||
[cachePath stringByAppendingPathComponent:@kDefaultLibrarySubdirectory]; |
|||
|
|||
EnsureDirectoryPathExists(dumpSubdirectory); |
|||
} |
|||
|
|||
// The product, version, and URL are required values. |
|||
if (![product length]) { |
|||
return false; |
|||
} |
|||
|
|||
if (![version length]) { |
|||
return false; |
|||
} |
|||
|
|||
if (![urlStr length]) { |
|||
return false; |
|||
} |
|||
|
|||
config_params_ = |
|||
new (gKeyValueAllocator->Allocate(sizeof(LongStringDictionary))) |
|||
LongStringDictionary(); |
|||
|
|||
LongStringDictionary& dictionary = *config_params_; |
|||
|
|||
dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]); |
|||
dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]); |
|||
dictionary.SetKeyValue(BREAKPAD_PRODUCT, [product UTF8String]); |
|||
dictionary.SetKeyValue(BREAKPAD_VERSION, [version UTF8String]); |
|||
dictionary.SetKeyValue(BREAKPAD_URL, [urlStr UTF8String]); |
|||
dictionary.SetKeyValue(BREAKPAD_VENDOR, [vendor UTF8String]); |
|||
dictionary.SetKeyValue(BREAKPAD_DUMP_DIRECTORY, |
|||
[dumpSubdirectory UTF8String]); |
|||
|
|||
struct timeval tv; |
|||
gettimeofday(&tv, NULL); |
|||
char timeStartedString[32]; |
|||
sprintf(timeStartedString, "%zd", tv.tv_sec); |
|||
dictionary.SetKeyValue(BREAKPAD_PROCESS_START_TIME, timeStartedString); |
|||
|
|||
if (serverParameters) { |
|||
// For each key-value pair, call BreakpadAddUploadParameter() |
|||
NSEnumerator* keyEnumerator = [serverParameters keyEnumerator]; |
|||
NSString* aParameter; |
|||
while ((aParameter = [keyEnumerator nextObject])) { |
|||
BreakpadAddUploadParameter(this, aParameter, |
|||
[serverParameters objectForKey:aParameter]); |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void Breakpad::SetKeyValue(NSString* key, NSString* value) { |
|||
// We allow nil values. This is the same as removing the keyvalue. |
|||
if (!config_params_ || !key) |
|||
return; |
|||
|
|||
config_params_->SetKeyValue([key UTF8String], [value UTF8String]); |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSString* Breakpad::KeyValue(NSString* key) { |
|||
if (!config_params_ || !key) |
|||
return nil; |
|||
|
|||
const std::string value = config_params_->GetValueForKey([key UTF8String]); |
|||
return value.empty() ? nil : [NSString stringWithUTF8String:value.c_str()]; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void Breakpad::RemoveKeyValue(NSString* key) { |
|||
if (!config_params_ || !key) return; |
|||
|
|||
config_params_->RemoveKey([key UTF8String]); |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSArray* Breakpad::CrashReportsToUpload() { |
|||
NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); |
|||
if (!directory) |
|||
return nil; |
|||
NSArray* dirContents = [[NSFileManager defaultManager] |
|||
contentsOfDirectoryAtPath:directory error:nil]; |
|||
NSArray* configs = [dirContents filteredArrayUsingPredicate:[NSPredicate |
|||
predicateWithFormat:@"self BEGINSWITH 'Config-'"]]; |
|||
return configs; |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSString* Breakpad::NextCrashReportToUpload() { |
|||
NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); |
|||
if (!directory) |
|||
return nil; |
|||
NSString* config = [CrashReportsToUpload() lastObject]; |
|||
if (!config) |
|||
return nil; |
|||
return [NSString stringWithFormat:@"%@/%@", directory, config]; |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSDictionary* Breakpad::NextCrashReportConfiguration() { |
|||
NSDictionary* configuration = [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()]; |
|||
return FixedUpCrashReportConfiguration(configuration); |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSDictionary* Breakpad::FixedUpCrashReportConfiguration(NSDictionary* configuration) { |
|||
NSMutableDictionary* fixedConfiguration = [[configuration mutableCopy] autorelease]; |
|||
// kReporterMinidumpDirectoryKey can become stale because the app's data container path includes |
|||
// an UUID that is not guaranteed to stay the same over time. |
|||
[fixedConfiguration setObject:KeyValue(@BREAKPAD_DUMP_DIRECTORY) |
|||
forKey:@kReporterMinidumpDirectoryKey]; |
|||
return fixedConfiguration; |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSDate* Breakpad::DateOfMostRecentCrashReport() { |
|||
NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); |
|||
if (!directory) { |
|||
return nil; |
|||
} |
|||
NSFileManager* fileManager = [NSFileManager defaultManager]; |
|||
NSArray* dirContents = [fileManager contentsOfDirectoryAtPath:directory error:nil]; |
|||
NSArray* dumps = [dirContents filteredArrayUsingPredicate:[NSPredicate |
|||
predicateWithFormat:@"self ENDSWITH '.dmp'"]]; |
|||
NSDate* mostRecentCrashReportDate = nil; |
|||
for (NSString* dump in dumps) { |
|||
NSString* filePath = [directory stringByAppendingPathComponent:dump]; |
|||
NSDate* crashReportDate = |
|||
[[fileManager attributesOfItemAtPath:filePath error:nil] fileCreationDate]; |
|||
if (!mostRecentCrashReportDate) { |
|||
mostRecentCrashReportDate = crashReportDate; |
|||
} else if (crashReportDate) { |
|||
mostRecentCrashReportDate = [mostRecentCrashReportDate laterDate:crashReportDate]; |
|||
} |
|||
} |
|||
return mostRecentCrashReportDate; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void Breakpad::HandleNetworkResponse(NSDictionary* configuration, |
|||
NSData* data, |
|||
NSError* error) { |
|||
Uploader* uploader = [[[Uploader alloc] |
|||
initWithConfig:configuration] autorelease]; |
|||
[uploader handleNetworkResponse:data withError:error]; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void Breakpad::UploadReportWithConfiguration( |
|||
NSDictionary* configuration, |
|||
NSDictionary* server_parameters, |
|||
BreakpadUploadCompletionCallback callback) { |
|||
Uploader* uploader = [[[Uploader alloc] |
|||
initWithConfig:configuration] autorelease]; |
|||
if (!uploader) |
|||
return; |
|||
for (NSString* key in server_parameters) { |
|||
[uploader addServerParameter:[server_parameters objectForKey:key] |
|||
forKey:key]; |
|||
} |
|||
if (callback) { |
|||
[uploader setUploadCompletionBlock:^(NSString* report_id, NSError* error) { |
|||
dispatch_async(dispatch_get_main_queue(), ^{ |
|||
callback(report_id, error); |
|||
}); |
|||
}]; |
|||
} |
|||
[uploader report]; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void Breakpad::UploadNextReport(NSDictionary* server_parameters) { |
|||
NSDictionary* configuration = NextCrashReportConfiguration(); |
|||
if (configuration) { |
|||
return UploadReportWithConfiguration(configuration, server_parameters, |
|||
nullptr); |
|||
} |
|||
} |
|||
|
|||
//============================================================================= |
|||
void Breakpad::UploadData(NSData* data, NSString* name, |
|||
NSDictionary* server_parameters) { |
|||
NSMutableDictionary* config = [NSMutableDictionary dictionary]; |
|||
|
|||
LongStringDictionary::Iterator it(*config_params_); |
|||
while (const LongStringDictionary::Entry* next = it.Next()) { |
|||
[config setValue:[NSString stringWithUTF8String:next->value] |
|||
forKey:[NSString stringWithUTF8String:next->key]]; |
|||
} |
|||
|
|||
Uploader* uploader = |
|||
[[[Uploader alloc] initWithConfig:config] autorelease]; |
|||
for (NSString* key in server_parameters) { |
|||
[uploader addServerParameter:[server_parameters objectForKey:key] |
|||
forKey:key]; |
|||
} |
|||
[uploader uploadData:data name:name]; |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSDictionary* Breakpad::GenerateReport(NSDictionary* server_parameters) { |
|||
NSString* dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY); |
|||
if (!dumpDirAsNSString) |
|||
return nil; |
|||
const char* dumpDir = [dumpDirAsNSString UTF8String]; |
|||
|
|||
google_breakpad::MinidumpGenerator generator(mach_task_self(), |
|||
MACH_PORT_NULL); |
|||
std::string dumpId; |
|||
std::string dumpFilename = generator.UniqueNameInDirectory(dumpDir, &dumpId); |
|||
bool success = generator.Write(dumpFilename.c_str()); |
|||
if (!success) |
|||
return nil; |
|||
|
|||
LongStringDictionary params = *config_params_; |
|||
for (NSString* key in server_parameters) { |
|||
params.SetKeyValue([key UTF8String], |
|||
[[server_parameters objectForKey:key] UTF8String]); |
|||
} |
|||
ConfigFile config_file; |
|||
config_file.WriteFile(dumpDir, ¶ms, dumpDir, dumpId.c_str()); |
|||
|
|||
// Handle results. |
|||
NSMutableDictionary* result = [NSMutableDictionary dictionary]; |
|||
NSString* dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()]; |
|||
[result setValue:dumpFullPath |
|||
forKey:@BREAKPAD_OUTPUT_DUMP_FILE]; |
|||
[result setValue:[NSString stringWithUTF8String:config_file.GetFilePath()] |
|||
forKey:@BREAKPAD_OUTPUT_CONFIG_FILE]; |
|||
return result; |
|||
} |
|||
|
|||
//============================================================================= |
|||
bool Breakpad::HandleMinidump(const char* dump_dir, |
|||
const char* minidump_id) { |
|||
config_file_.WriteFile(dump_dir, |
|||
config_params_, |
|||
dump_dir, |
|||
minidump_id); |
|||
|
|||
// Return true here to indicate that we've processed things as much as we |
|||
// want. |
|||
return true; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void Breakpad::HandleUncaughtException(NSException* exception) { |
|||
// Generate the minidump. |
|||
google_breakpad::IosExceptionMinidumpGenerator generator(exception); |
|||
const std::string minidump_path = |
|||
config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY); |
|||
std::string minidump_id; |
|||
std::string minidump_filename = generator.UniqueNameInDirectory(minidump_path, |
|||
&minidump_id); |
|||
generator.Write(minidump_filename.c_str()); |
|||
|
|||
// Copy the config params and our custom parameter. This is necessary for 2 |
|||
// reasons: |
|||
// 1- config_params_ is protected. |
|||
// 2- If the application crash while trying to handle this exception, a usual |
|||
// report will be generated. This report must not contain these special |
|||
// keys. |
|||
LongStringDictionary params = *config_params_; |
|||
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "type", "exception"); |
|||
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionName", |
|||
[[exception name] UTF8String]); |
|||
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionReason", |
|||
[[exception reason] UTF8String]); |
|||
|
|||
// And finally write the config file. |
|||
ConfigFile config_file; |
|||
config_file.WriteFile(minidump_path.c_str(), |
|||
¶ms, |
|||
minidump_path.c_str(), |
|||
minidump_id.c_str()); |
|||
} |
|||
|
|||
//============================================================================= |
|||
|
|||
#pragma mark - |
|||
#pragma mark Public API |
|||
|
|||
//============================================================================= |
|||
BreakpadRef BreakpadCreate(NSDictionary* parameters) { |
|||
try { |
|||
// This is confusing. Our two main allocators for breakpad memory are: |
|||
// - gKeyValueAllocator for the key/value memory |
|||
// - gBreakpadAllocator for the Breakpad, ExceptionHandler, and other |
|||
// breakpad allocations which are accessed at exception handling time. |
|||
// |
|||
// But in order to avoid these two allocators themselves from being smashed, |
|||
// we'll protect them as well by allocating them with gMasterAllocator. |
|||
// |
|||
// gMasterAllocator itself will NOT be protected, but this doesn't matter, |
|||
// since once it does its allocations and locks the memory, smashes to |
|||
// itself don't affect anything we care about. |
|||
gMasterAllocator = |
|||
new ProtectedMemoryAllocator(sizeof(ProtectedMemoryAllocator) * 2); |
|||
|
|||
gKeyValueAllocator = |
|||
new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator))) |
|||
ProtectedMemoryAllocator(sizeof(LongStringDictionary)); |
|||
|
|||
// Create a mutex for use in accessing the LongStringDictionary |
|||
int mutexResult = pthread_mutex_init(&gDictionaryMutex, NULL); |
|||
if (mutexResult == 0) { |
|||
|
|||
// With the current compiler, gBreakpadAllocator is allocating 1444 bytes. |
|||
// Let's round up to the nearest page size. |
|||
// |
|||
int breakpad_pool_size = 4096; |
|||
|
|||
/* |
|||
sizeof(Breakpad) |
|||
+ sizeof(google_breakpad::ExceptionHandler) |
|||
+ sizeof( STUFF ALLOCATED INSIDE ExceptionHandler ) |
|||
*/ |
|||
|
|||
gBreakpadAllocator = |
|||
new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator))) |
|||
ProtectedMemoryAllocator(breakpad_pool_size); |
|||
|
|||
// Stack-based autorelease pool for Breakpad::Create() obj-c code. |
|||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
|||
Breakpad* breakpad = Breakpad::Create(parameters); |
|||
|
|||
if (breakpad) { |
|||
// Make read-only to protect against memory smashers |
|||
gMasterAllocator->Protect(); |
|||
gKeyValueAllocator->Protect(); |
|||
gBreakpadAllocator->Protect(); |
|||
// Can uncomment this line to figure out how much space was actually |
|||
// allocated using this allocator |
|||
// printf("gBreakpadAllocator allocated size = %d\n", |
|||
// gBreakpadAllocator->GetAllocatedSize() ); |
|||
[pool release]; |
|||
return (BreakpadRef)breakpad; |
|||
} |
|||
|
|||
[pool release]; |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadCreate() : error\n"); |
|||
} |
|||
|
|||
if (gKeyValueAllocator) { |
|||
gKeyValueAllocator->~ProtectedMemoryAllocator(); |
|||
gKeyValueAllocator = NULL; |
|||
} |
|||
|
|||
if (gBreakpadAllocator) { |
|||
gBreakpadAllocator->~ProtectedMemoryAllocator(); |
|||
gBreakpadAllocator = NULL; |
|||
} |
|||
|
|||
delete gMasterAllocator; |
|||
gMasterAllocator = NULL; |
|||
|
|||
return NULL; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void BreakpadRelease(BreakpadRef ref) { |
|||
try { |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (gMasterAllocator) { |
|||
gMasterAllocator->Unprotect(); |
|||
gKeyValueAllocator->Unprotect(); |
|||
gBreakpadAllocator->Unprotect(); |
|||
|
|||
breakpad->~Breakpad(); |
|||
|
|||
// Unfortunately, it's not possible to deallocate this stuff |
|||
// because the exception handling thread is still finishing up |
|||
// asynchronously at this point... OK, it could be done with |
|||
// locks, etc. But since BreakpadRelease() should usually only |
|||
// be called right before the process exits, it's not worth |
|||
// deallocating this stuff. |
|||
#if 0 |
|||
gKeyValueAllocator->~ProtectedMemoryAllocator(); |
|||
gBreakpadAllocator->~ProtectedMemoryAllocator(); |
|||
delete gMasterAllocator; |
|||
|
|||
gMasterAllocator = NULL; |
|||
gKeyValueAllocator = NULL; |
|||
gBreakpadAllocator = NULL; |
|||
#endif |
|||
|
|||
pthread_mutex_destroy(&gDictionaryMutex); |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadRelease() : error\n"); |
|||
} |
|||
} |
|||
|
|||
//============================================================================= |
|||
void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value) { |
|||
try { |
|||
// Not called at exception time |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (breakpad && key && gKeyValueAllocator) { |
|||
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); |
|||
|
|||
breakpad->SetKeyValue(key, value); |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadSetKeyValue() : error\n"); |
|||
} |
|||
} |
|||
|
|||
void BreakpadAddUploadParameter(BreakpadRef ref, |
|||
NSString* key, |
|||
NSString* value) { |
|||
// The only difference, internally, between an upload parameter and |
|||
// a key value one that is set with BreakpadSetKeyValue is that we |
|||
// prepend the keyname with a special prefix. This informs the |
|||
// crash sender that the parameter should be sent along with the |
|||
// POST of the crash dump upload. |
|||
try { |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (breakpad && key && gKeyValueAllocator) { |
|||
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); |
|||
|
|||
NSString* prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX |
|||
stringByAppendingString:key]; |
|||
breakpad->SetKeyValue(prefixedKey, value); |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadSetKeyValue() : error\n"); |
|||
} |
|||
} |
|||
|
|||
void BreakpadRemoveUploadParameter(BreakpadRef ref, |
|||
NSString* key) { |
|||
try { |
|||
// Not called at exception time |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (breakpad && key && gKeyValueAllocator) { |
|||
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); |
|||
|
|||
NSString* prefixedKey = [NSString stringWithFormat:@"%@%@", |
|||
@BREAKPAD_SERVER_PARAMETER_PREFIX, key]; |
|||
breakpad->RemoveKeyValue(prefixedKey); |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadRemoveKeyValue() : error\n"); |
|||
} |
|||
} |
|||
//============================================================================= |
|||
NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key) { |
|||
NSString* value = nil; |
|||
|
|||
try { |
|||
// Not called at exception time |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (!breakpad || !key || !gKeyValueAllocator) |
|||
return nil; |
|||
|
|||
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); |
|||
|
|||
value = breakpad->KeyValue(key); |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadKeyValue() : error\n"); |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key) { |
|||
try { |
|||
// Not called at exception time |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (breakpad && key && gKeyValueAllocator) { |
|||
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); |
|||
|
|||
breakpad->RemoveKeyValue(key); |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadRemoveKeyValue() : error\n"); |
|||
} |
|||
} |
|||
|
|||
//============================================================================= |
|||
int BreakpadGetCrashReportCount(BreakpadRef ref) { |
|||
try { |
|||
// Not called at exception time |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (breakpad) { |
|||
return static_cast<int>([breakpad->CrashReportsToUpload() count]); |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadGetCrashReportCount() : error\n"); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void BreakpadUploadNextReport(BreakpadRef ref) { |
|||
BreakpadUploadNextReportWithParameters(ref, nil, nullptr); |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref) { |
|||
try { |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
if (breakpad) |
|||
return breakpad->NextCrashReportConfiguration(); |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadGetNextReportConfiguration() : error\n"); |
|||
} |
|||
return nil; |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) { |
|||
try { |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
if (breakpad) { |
|||
return breakpad->DateOfMostRecentCrashReport(); |
|||
} |
|||
} catch (...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadGetDateOfMostRecentCrashReport() : error\n"); |
|||
} |
|||
return nil; |
|||
} |
|||
|
|||
//============================================================================= |
|||
void BreakpadUploadReportWithParametersAndConfiguration( |
|||
BreakpadRef ref, |
|||
NSDictionary* server_parameters, |
|||
NSDictionary* configuration, |
|||
BreakpadUploadCompletionCallback callback) { |
|||
try { |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
if (!breakpad || !configuration) |
|||
return; |
|||
breakpad->UploadReportWithConfiguration(configuration, server_parameters, |
|||
callback); |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, |
|||
"BreakpadUploadReportWithParametersAndConfiguration() : error\n"); |
|||
} |
|||
} |
|||
|
|||
//============================================================================= |
|||
void BreakpadUploadNextReportWithParameters( |
|||
BreakpadRef ref, |
|||
NSDictionary* server_parameters, |
|||
BreakpadUploadCompletionCallback callback) { |
|||
try { |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
if (!breakpad) |
|||
return; |
|||
NSDictionary* configuration = breakpad->NextCrashReportConfiguration(); |
|||
if (!configuration) |
|||
return; |
|||
return BreakpadUploadReportWithParametersAndConfiguration( |
|||
ref, server_parameters, configuration, callback); |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadUploadNextReportWithParameters() : error\n"); |
|||
} |
|||
} |
|||
|
|||
void BreakpadHandleNetworkResponse(BreakpadRef ref, |
|||
NSDictionary* configuration, |
|||
NSData* data, |
|||
NSError* error) { |
|||
try { |
|||
// Not called at exception time |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
if (breakpad && configuration) |
|||
breakpad->HandleNetworkResponse(configuration,data, error); |
|||
|
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadHandleNetworkResponse() : error\n"); |
|||
} |
|||
} |
|||
|
|||
//============================================================================= |
|||
void BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name, |
|||
NSDictionary* server_parameters) { |
|||
try { |
|||
// Not called at exception time |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (breakpad) { |
|||
breakpad->UploadData(data, name, server_parameters); |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadUploadData() : error\n"); |
|||
} |
|||
} |
|||
|
|||
//============================================================================= |
|||
NSDictionary* BreakpadGenerateReport(BreakpadRef ref, |
|||
NSDictionary* server_parameters) { |
|||
try { |
|||
// Not called at exception time |
|||
Breakpad* breakpad = (Breakpad*)ref; |
|||
|
|||
if (breakpad) { |
|||
return breakpad->GenerateReport(server_parameters); |
|||
} else { |
|||
return nil; |
|||
} |
|||
} catch(...) { // don't let exceptions leave this C API |
|||
fprintf(stderr, "BreakpadGenerateReport() : error\n"); |
|||
return nil; |
|||
} |
|||
} |
|||
@ -0,0 +1,604 @@ |
|||
// !$*UTF8*$! |
|||
{ |
|||
archiveVersion = 1; |
|||
classes = { |
|||
}; |
|||
objectVersion = 46; |
|||
objects = { |
|||
|
|||
/* Begin PBXBuildFile section */ |
|||
06D561E62700974500F9F2E8 /* encoding_util.h in Headers */ = {isa = PBXBuildFile; fileRef = 06D561E42700974500F9F2E8 /* encoding_util.h */; }; |
|||
06D561E72700974500F9F2E8 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = 06D561E52700974500F9F2E8 /* encoding_util.m */; }; |
|||
14569321182CE29F0029C465 /* ucontext_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569320182CE29F0029C465 /* ucontext_compat.h */; }; |
|||
14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569322182CE2C10029C465 /* mach_vm_compat.h */; }; |
|||
16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */; }; |
|||
16BFA67214E1965A009704F8 /* ios_exception_minidump_generator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */; }; |
|||
16C7CCCB147D4A4300776EAD /* BreakpadDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7C968147D4A4200776EAD /* BreakpadDefines.h */; }; |
|||
16C7CCCC147D4A4300776EAD /* Breakpad.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7C96A147D4A4200776EAD /* Breakpad.h */; }; |
|||
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7C96B147D4A4200776EAD /* Breakpad.mm */; }; |
|||
16C7CDE8147D4A4300776EAD /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CB9E147D4A4300776EAD /* ConfigFile.h */; }; |
|||
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CB9F147D4A4300776EAD /* ConfigFile.mm */; }; |
|||
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */; }; |
|||
16C7CDF6147D4A4300776EAD /* breakpad_nlist_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */; }; |
|||
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBAF147D4A4300776EAD /* dynamic_images.cc */; }; |
|||
16C7CDF8147D4A4300776EAD /* dynamic_images.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB0147D4A4300776EAD /* dynamic_images.h */; }; |
|||
16C7CDF9147D4A4300776EAD /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBB1147D4A4300776EAD /* exception_handler.cc */; }; |
|||
16C7CDFA147D4A4300776EAD /* exception_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB2147D4A4300776EAD /* exception_handler.h */; }; |
|||
16C7CDFC147D4A4300776EAD /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBB4147D4A4300776EAD /* minidump_generator.cc */; }; |
|||
16C7CDFD147D4A4300776EAD /* minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB5147D4A4300776EAD /* minidump_generator.h */; }; |
|||
16C7CDFE147D4A4300776EAD /* protected_memory_allocator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */; }; |
|||
16C7CDFF147D4A4300776EAD /* protected_memory_allocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */; }; |
|||
16C7CE08147D4A4300776EAD /* uploader.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBEA147D4A4300776EAD /* uploader.h */; }; |
|||
16C7CE09147D4A4300776EAD /* uploader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBEB147D4A4300776EAD /* uploader.mm */; }; |
|||
16C7CE18147D4A4300776EAD /* minidump_file_writer-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */; }; |
|||
16C7CE19147D4A4300776EAD /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */; }; |
|||
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC06147D4A4300776EAD /* minidump_file_writer.h */; }; |
|||
16C7CE40147D4A4300776EAD /* convert_UTF.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC4A147D4A4300776EAD /* convert_UTF.cc */; }; |
|||
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC4B147D4A4300776EAD /* convert_UTF.h */; }; |
|||
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC88147D4A4300776EAD /* GTMLogger.h */; }; |
|||
16C7CE79147D4A4300776EAD /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC89147D4A4300776EAD /* GTMLogger.m */; }; |
|||
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */; }; |
|||
16C7CE7B147D4A4300776EAD /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */; }; |
|||
16C7CE83147D4A4300776EAD /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC93147D4A4300776EAD /* file_id.cc */; }; |
|||
16C7CE84147D4A4300776EAD /* file_id.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC94147D4A4300776EAD /* file_id.h */; }; |
|||
16C7CE85147D4A4300776EAD /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC95147D4A4300776EAD /* macho_id.cc */; }; |
|||
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC96147D4A4300776EAD /* macho_id.h */; }; |
|||
16C7CE8A147D4A4300776EAD /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9A147D4A4300776EAD /* macho_utilities.cc */; }; |
|||
16C7CE8B147D4A4300776EAD /* macho_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC9B147D4A4300776EAD /* macho_utilities.h */; }; |
|||
16C7CE8C147D4A4300776EAD /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9C147D4A4300776EAD /* macho_walker.cc */; }; |
|||
16C7CE8D147D4A4300776EAD /* macho_walker.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC9D147D4A4300776EAD /* macho_walker.h */; }; |
|||
16C7CE8F147D4A4300776EAD /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9F147D4A4300776EAD /* string_utilities.cc */; }; |
|||
16C7CE90147D4A4300776EAD /* string_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCA0147D4A4300776EAD /* string_utilities.h */; }; |
|||
16C7CE93147D4A4300776EAD /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CCA4147D4A4300776EAD /* md5.cc */; }; |
|||
16C7CE94147D4A4300776EAD /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCA5147D4A4300776EAD /* md5.h */; }; |
|||
16C7CEA7147D4A4300776EAD /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CCB9147D4A4300776EAD /* string_conversion.cc */; }; |
|||
16C7CEA8147D4A4300776EAD /* string_conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCBA147D4A4300776EAD /* string_conversion.h */; }; |
|||
16C92FAD150DF8330053D7BA /* BreakpadController.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C92FAB150DF8330053D7BA /* BreakpadController.h */; }; |
|||
16C92FAE150DF8330053D7BA /* BreakpadController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C92FAC150DF8330053D7BA /* BreakpadController.mm */; }; |
|||
1EEEB60F1720821900F7E689 /* simple_string_dictionary.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */; }; |
|||
1EEEB6101720821900F7E689 /* simple_string_dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */; }; |
|||
AA747D9F0F9514B9006C5449 /* Breakpad_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */; }; |
|||
AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; |
|||
CF6D547D1F9E6FFE00E95174 /* long_string_dictionary.cc in Sources */ = {isa = PBXBuildFile; fileRef = CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */; }; |
|||
CF706DC11F7C6EFB002C54C7 /* long_string_dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */; }; |
|||
E69213D8265202570071B04F /* HTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = E69213D6265202570071B04F /* HTTPRequest.h */; }; |
|||
E69213D9265202570071B04F /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E69213D7265202570071B04F /* HTTPRequest.m */; }; |
|||
/* End PBXBuildFile section */ |
|||
|
|||
/* Begin PBXFileReference section */ |
|||
06D561E42700974500F9F2E8 /* encoding_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = encoding_util.h; sourceTree = "<group>"; }; |
|||
06D561E52700974500F9F2E8 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = encoding_util.m; sourceTree = "<group>"; }; |
|||
14569320182CE29F0029C465 /* ucontext_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucontext_compat.h; sourceTree = "<group>"; }; |
|||
14569322182CE2C10029C465 /* mach_vm_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_vm_compat.h; sourceTree = "<group>"; }; |
|||
16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_exception_minidump_generator.h; sourceTree = "<group>"; }; |
|||
16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ios_exception_minidump_generator.mm; sourceTree = "<group>"; }; |
|||
16C7C968147D4A4200776EAD /* BreakpadDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakpadDefines.h; sourceTree = "<group>"; }; |
|||
16C7C96A147D4A4200776EAD /* Breakpad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpad.h; sourceTree = "<group>"; }; |
|||
16C7C96B147D4A4200776EAD /* Breakpad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Breakpad.mm; sourceTree = "<group>"; }; |
|||
16C7CB9E147D4A4300776EAD /* ConfigFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigFile.h; sourceTree = "<group>"; }; |
|||
16C7CB9F147D4A4300776EAD /* ConfigFile.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ConfigFile.mm; sourceTree = "<group>"; }; |
|||
16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_64.cc; sourceTree = "<group>"; }; |
|||
16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_64.h; sourceTree = "<group>"; }; |
|||
16C7CBAF147D4A4300776EAD /* dynamic_images.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dynamic_images.cc; sourceTree = "<group>"; }; |
|||
16C7CBB0147D4A4300776EAD /* dynamic_images.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dynamic_images.h; sourceTree = "<group>"; }; |
|||
16C7CBB1147D4A4300776EAD /* exception_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exception_handler.cc; sourceTree = "<group>"; }; |
|||
16C7CBB2147D4A4300776EAD /* exception_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exception_handler.h; sourceTree = "<group>"; }; |
|||
16C7CBB4147D4A4300776EAD /* minidump_generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_generator.cc; sourceTree = "<group>"; }; |
|||
16C7CBB5147D4A4300776EAD /* minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minidump_generator.h; sourceTree = "<group>"; }; |
|||
16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = protected_memory_allocator.cc; sourceTree = "<group>"; }; |
|||
16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = protected_memory_allocator.h; sourceTree = "<group>"; }; |
|||
16C7CBEA147D4A4300776EAD /* uploader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uploader.h; sourceTree = "<group>"; }; |
|||
16C7CBEB147D4A4300776EAD /* uploader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = uploader.mm; sourceTree = "<group>"; }; |
|||
16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "minidump_file_writer-inl.h"; sourceTree = "<group>"; }; |
|||
16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_file_writer.cc; sourceTree = "<group>"; }; |
|||
16C7CC06147D4A4300776EAD /* minidump_file_writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minidump_file_writer.h; sourceTree = "<group>"; }; |
|||
16C7CC07147D4A4300776EAD /* minidump_file_writer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_file_writer_unittest.cc; sourceTree = "<group>"; }; |
|||
16C7CC4A147D4A4300776EAD /* convert_UTF.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = convert_UTF.cc; sourceTree = "<group>"; }; |
|||
16C7CC4B147D4A4300776EAD /* convert_UTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = convert_UTF.h; sourceTree = "<group>"; }; |
|||
16C7CC88147D4A4300776EAD /* GTMLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMLogger.h; sourceTree = "<group>"; }; |
|||
16C7CC89147D4A4300776EAD /* GTMLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMLogger.m; sourceTree = "<group>"; }; |
|||
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPMultipartUpload.h; sourceTree = "<group>"; }; |
|||
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPMultipartUpload.m; sourceTree = "<group>"; }; |
|||
16C7CC93147D4A4300776EAD /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_id.cc; sourceTree = "<group>"; }; |
|||
16C7CC94147D4A4300776EAD /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_id.h; sourceTree = "<group>"; }; |
|||
16C7CC95147D4A4300776EAD /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_id.cc; sourceTree = "<group>"; }; |
|||
16C7CC96147D4A4300776EAD /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_id.h; sourceTree = "<group>"; }; |
|||
16C7CC9A147D4A4300776EAD /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_utilities.cc; sourceTree = "<group>"; }; |
|||
16C7CC9B147D4A4300776EAD /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_utilities.h; sourceTree = "<group>"; }; |
|||
16C7CC9C147D4A4300776EAD /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_walker.cc; sourceTree = "<group>"; }; |
|||
16C7CC9D147D4A4300776EAD /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_walker.h; sourceTree = "<group>"; }; |
|||
16C7CC9F147D4A4300776EAD /* string_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_utilities.cc; sourceTree = "<group>"; }; |
|||
16C7CCA0147D4A4300776EAD /* string_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_utilities.h; sourceTree = "<group>"; }; |
|||
16C7CCA4147D4A4300776EAD /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = md5.cc; sourceTree = "<group>"; }; |
|||
16C7CCA5147D4A4300776EAD /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = "<group>"; }; |
|||
16C7CCB9147D4A4300776EAD /* string_conversion.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_conversion.cc; sourceTree = "<group>"; }; |
|||
16C7CCBA147D4A4300776EAD /* string_conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_conversion.h; sourceTree = "<group>"; }; |
|||
16C92FAB150DF8330053D7BA /* BreakpadController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakpadController.h; sourceTree = "<group>"; }; |
|||
16C92FAC150DF8330053D7BA /* BreakpadController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BreakpadController.mm; sourceTree = "<group>"; }; |
|||
1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_string_dictionary.cc; sourceTree = "<group>"; }; |
|||
1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_string_dictionary.h; sourceTree = "<group>"; }; |
|||
AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpad_Prefix.pch; sourceTree = SOURCE_ROOT; }; |
|||
AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; |
|||
CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = long_string_dictionary.cc; sourceTree = "<group>"; }; |
|||
CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = long_string_dictionary.h; sourceTree = "<group>"; }; |
|||
D2AAC07E0554694100DB518D /* libBreakpad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBreakpad.a; sourceTree = BUILT_PRODUCTS_DIR; }; |
|||
E69213D6265202570071B04F /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRequest.h; sourceTree = "<group>"; }; |
|||
E69213D7265202570071B04F /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPRequest.m; sourceTree = "<group>"; }; |
|||
/* End PBXFileReference section */ |
|||
|
|||
/* Begin PBXFrameworksBuildPhase section */ |
|||
D2AAC07C0554694100DB518D /* Frameworks */ = { |
|||
isa = PBXFrameworksBuildPhase; |
|||
buildActionMask = 2147483647; |
|||
files = ( |
|||
AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */, |
|||
); |
|||
runOnlyForDeploymentPostprocessing = 0; |
|||
}; |
|||
/* End PBXFrameworksBuildPhase section */ |
|||
|
|||
/* Begin PBXGroup section */ |
|||
034768DFFF38A50411DB9C8B /* Products */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
D2AAC07E0554694100DB518D /* libBreakpad.a */, |
|||
); |
|||
name = Products; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
0867D691FE84028FC02AAC07 /* Breakpad */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
08FB77AEFE84172EC02AAC07 /* Classes */, |
|||
32C88DFF0371C24200C91783 /* Other Sources */, |
|||
0867D69AFE84028FC02AAC07 /* Frameworks */, |
|||
034768DFFF38A50411DB9C8B /* Products */, |
|||
); |
|||
name = Breakpad; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
0867D69AFE84028FC02AAC07 /* Frameworks */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
AACBBE490F95108600F1A2B1 /* Foundation.framework */, |
|||
); |
|||
name = Frameworks; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
08FB77AEFE84172EC02AAC07 /* Classes */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C7C965147D4A4200776EAD /* client */, |
|||
16C7CC47147D4A4300776EAD /* common */, |
|||
); |
|||
name = Classes; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16BFA66A14E195E9009704F8 /* handler */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */, |
|||
16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */, |
|||
); |
|||
path = handler; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16C7C965147D4A4200776EAD /* client */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C7C966147D4A4200776EAD /* apple */, |
|||
16C7C969147D4A4200776EAD /* ios */, |
|||
16C7C99E147D4A4200776EAD /* mac */, |
|||
16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */, |
|||
16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */, |
|||
16C7CC06147D4A4300776EAD /* minidump_file_writer.h */, |
|||
16C7CC07147D4A4300776EAD /* minidump_file_writer_unittest.cc */, |
|||
); |
|||
name = client; |
|||
path = ..; |
|||
sourceTree = SOURCE_ROOT; |
|||
}; |
|||
16C7C966147D4A4200776EAD /* apple */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C7C967147D4A4200776EAD /* Framework */, |
|||
); |
|||
path = apple; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16C7C967147D4A4200776EAD /* Framework */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C7C968147D4A4200776EAD /* BreakpadDefines.h */, |
|||
); |
|||
path = Framework; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16C7C969147D4A4200776EAD /* ios */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C92FAB150DF8330053D7BA /* BreakpadController.h */, |
|||
16C92FAC150DF8330053D7BA /* BreakpadController.mm */, |
|||
16BFA66A14E195E9009704F8 /* handler */, |
|||
16C7C96A147D4A4200776EAD /* Breakpad.h */, |
|||
16C7C96B147D4A4200776EAD /* Breakpad.mm */, |
|||
); |
|||
path = ios; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16C7C99E147D4A4200776EAD /* mac */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C7CB9D147D4A4300776EAD /* crash_generation */, |
|||
16C7CBAA147D4A4300776EAD /* handler */, |
|||
16C7CBC8147D4A4300776EAD /* sender */, |
|||
); |
|||
path = mac; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16C7CB9D147D4A4300776EAD /* crash_generation */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C7CB9E147D4A4300776EAD /* ConfigFile.h */, |
|||
16C7CB9F147D4A4300776EAD /* ConfigFile.mm */, |
|||
); |
|||
path = crash_generation; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16C7CBAA147D4A4300776EAD /* handler */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */, |
|||
16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */, |
|||
16C7CBAF147D4A4300776EAD /* dynamic_images.cc */, |
|||
16C7CBB0147D4A4300776EAD /* dynamic_images.h */, |
|||
16C7CBB1147D4A4300776EAD /* exception_handler.cc */, |
|||
16C7CBB2147D4A4300776EAD /* exception_handler.h */, |
|||
14569322182CE2C10029C465 /* mach_vm_compat.h */, |
|||
16C7CBB4147D4A4300776EAD /* minidump_generator.cc */, |
|||
16C7CBB5147D4A4300776EAD /* minidump_generator.h */, |
|||
16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */, |
|||
16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */, |
|||
14569320182CE29F0029C465 /* ucontext_compat.h */, |
|||
); |
|||
path = handler; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16C7CBC8147D4A4300776EAD /* sender */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
16C7CBEA147D4A4300776EAD /* uploader.h */, |
|||
16C7CBEB147D4A4300776EAD /* uploader.mm */, |
|||
); |
|||
path = sender; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
16C7CC47147D4A4300776EAD /* common */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */, |
|||
CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */, |
|||
1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */, |
|||
1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */, |
|||
16C7CC4A147D4A4300776EAD /* convert_UTF.cc */, |
|||
16C7CC4B147D4A4300776EAD /* convert_UTF.h */, |
|||
16C7CC82147D4A4300776EAD /* mac */, |
|||
16C7CCA4147D4A4300776EAD /* md5.cc */, |
|||
16C7CCA5147D4A4300776EAD /* md5.h */, |
|||
16C7CCB9147D4A4300776EAD /* string_conversion.cc */, |
|||
16C7CCBA147D4A4300776EAD /* string_conversion.h */, |
|||
); |
|||
name = common; |
|||
path = ../../common; |
|||
sourceTree = SOURCE_ROOT; |
|||
}; |
|||
16C7CC82147D4A4300776EAD /* mac */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
06D561E42700974500F9F2E8 /* encoding_util.h */, |
|||
06D561E52700974500F9F2E8 /* encoding_util.m */, |
|||
16C7CC88147D4A4300776EAD /* GTMLogger.h */, |
|||
16C7CC89147D4A4300776EAD /* GTMLogger.m */, |
|||
E69213D6265202570071B04F /* HTTPRequest.h */, |
|||
E69213D7265202570071B04F /* HTTPRequest.m */, |
|||
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */, |
|||
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */, |
|||
16C7CC93147D4A4300776EAD /* file_id.cc */, |
|||
16C7CC94147D4A4300776EAD /* file_id.h */, |
|||
16C7CC95147D4A4300776EAD /* macho_id.cc */, |
|||
16C7CC96147D4A4300776EAD /* macho_id.h */, |
|||
16C7CC9A147D4A4300776EAD /* macho_utilities.cc */, |
|||
16C7CC9B147D4A4300776EAD /* macho_utilities.h */, |
|||
16C7CC9C147D4A4300776EAD /* macho_walker.cc */, |
|||
16C7CC9D147D4A4300776EAD /* macho_walker.h */, |
|||
16C7CC9F147D4A4300776EAD /* string_utilities.cc */, |
|||
16C7CCA0147D4A4300776EAD /* string_utilities.h */, |
|||
); |
|||
path = mac; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
32C88DFF0371C24200C91783 /* Other Sources */ = { |
|||
isa = PBXGroup; |
|||
children = ( |
|||
AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */, |
|||
); |
|||
name = "Other Sources"; |
|||
sourceTree = "<group>"; |
|||
}; |
|||
/* End PBXGroup section */ |
|||
|
|||
/* Begin PBXHeadersBuildPhase section */ |
|||
D2AAC07A0554694100DB518D /* Headers */ = { |
|||
isa = PBXHeadersBuildPhase; |
|||
buildActionMask = 2147483647; |
|||
files = ( |
|||
AA747D9F0F9514B9006C5449 /* Breakpad_Prefix.pch in Headers */, |
|||
16C7CCCB147D4A4300776EAD /* BreakpadDefines.h in Headers */, |
|||
16C7CCCC147D4A4300776EAD /* Breakpad.h in Headers */, |
|||
16C7CDE8147D4A4300776EAD /* ConfigFile.h in Headers */, |
|||
14569321182CE29F0029C465 /* ucontext_compat.h in Headers */, |
|||
16C7CDF6147D4A4300776EAD /* breakpad_nlist_64.h in Headers */, |
|||
16C7CDF8147D4A4300776EAD /* dynamic_images.h in Headers */, |
|||
16C7CDFA147D4A4300776EAD /* exception_handler.h in Headers */, |
|||
16C7CDFD147D4A4300776EAD /* minidump_generator.h in Headers */, |
|||
16C7CDFF147D4A4300776EAD /* protected_memory_allocator.h in Headers */, |
|||
16C7CE08147D4A4300776EAD /* uploader.h in Headers */, |
|||
16C7CE18147D4A4300776EAD /* minidump_file_writer-inl.h in Headers */, |
|||
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */, |
|||
06D561E62700974500F9F2E8 /* encoding_util.h in Headers */, |
|||
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */, |
|||
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */, |
|||
E69213D8265202570071B04F /* HTTPRequest.h in Headers */, |
|||
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */, |
|||
16C7CE84147D4A4300776EAD /* file_id.h in Headers */, |
|||
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */, |
|||
16C7CE8B147D4A4300776EAD /* macho_utilities.h in Headers */, |
|||
16C7CE8D147D4A4300776EAD /* macho_walker.h in Headers */, |
|||
16C7CE90147D4A4300776EAD /* string_utilities.h in Headers */, |
|||
16C7CE94147D4A4300776EAD /* md5.h in Headers */, |
|||
16C7CEA8147D4A4300776EAD /* string_conversion.h in Headers */, |
|||
16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */, |
|||
16C92FAD150DF8330053D7BA /* BreakpadController.h in Headers */, |
|||
CF706DC11F7C6EFB002C54C7 /* long_string_dictionary.h in Headers */, |
|||
1EEEB6101720821900F7E689 /* simple_string_dictionary.h in Headers */, |
|||
14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */, |
|||
); |
|||
runOnlyForDeploymentPostprocessing = 0; |
|||
}; |
|||
/* End PBXHeadersBuildPhase section */ |
|||
|
|||
/* Begin PBXNativeTarget section */ |
|||
D2AAC07D0554694100DB518D /* Breakpad */ = { |
|||
isa = PBXNativeTarget; |
|||
buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */; |
|||
buildPhases = ( |
|||
D2AAC07A0554694100DB518D /* Headers */, |
|||
D2AAC07B0554694100DB518D /* Sources */, |
|||
D2AAC07C0554694100DB518D /* Frameworks */, |
|||
); |
|||
buildRules = ( |
|||
); |
|||
dependencies = ( |
|||
); |
|||
name = Breakpad; |
|||
productName = Breakpad; |
|||
productReference = D2AAC07E0554694100DB518D /* libBreakpad.a */; |
|||
productType = "com.apple.product-type.library.static"; |
|||
}; |
|||
/* End PBXNativeTarget section */ |
|||
|
|||
/* Begin PBXProject section */ |
|||
0867D690FE84028FC02AAC07 /* Project object */ = { |
|||
isa = PBXProject; |
|||
attributes = { |
|||
LastUpgradeCheck = 0510; |
|||
}; |
|||
buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Breakpad" */; |
|||
compatibilityVersion = "Xcode 3.2"; |
|||
developmentRegion = English; |
|||
hasScannedForEncodings = 1; |
|||
knownRegions = ( |
|||
English, |
|||
Japanese, |
|||
French, |
|||
German, |
|||
da, |
|||
de, |
|||
es, |
|||
fr, |
|||
it, |
|||
ja, |
|||
nl, |
|||
no, |
|||
sl, |
|||
sv, |
|||
tr, |
|||
); |
|||
mainGroup = 0867D691FE84028FC02AAC07 /* Breakpad */; |
|||
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; |
|||
projectDirPath = ""; |
|||
projectRoot = ""; |
|||
targets = ( |
|||
D2AAC07D0554694100DB518D /* Breakpad */, |
|||
); |
|||
}; |
|||
/* End PBXProject section */ |
|||
|
|||
/* Begin PBXSourcesBuildPhase section */ |
|||
D2AAC07B0554694100DB518D /* Sources */ = { |
|||
isa = PBXSourcesBuildPhase; |
|||
buildActionMask = 2147483647; |
|||
files = ( |
|||
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */, |
|||
E69213D9265202570071B04F /* HTTPRequest.m in Sources */, |
|||
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */, |
|||
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */, |
|||
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */, |
|||
16C7CDF9147D4A4300776EAD /* exception_handler.cc in Sources */, |
|||
16C7CDFC147D4A4300776EAD /* minidump_generator.cc in Sources */, |
|||
16C7CDFE147D4A4300776EAD /* protected_memory_allocator.cc in Sources */, |
|||
16C7CE09147D4A4300776EAD /* uploader.mm in Sources */, |
|||
CF6D547D1F9E6FFE00E95174 /* long_string_dictionary.cc in Sources */, |
|||
16C7CE19147D4A4300776EAD /* minidump_file_writer.cc in Sources */, |
|||
16C7CE40147D4A4300776EAD /* convert_UTF.cc in Sources */, |
|||
16C7CE79147D4A4300776EAD /* GTMLogger.m in Sources */, |
|||
06D561E72700974500F9F2E8 /* encoding_util.m in Sources */, |
|||
16C7CE7B147D4A4300776EAD /* HTTPMultipartUpload.m in Sources */, |
|||
16C7CE83147D4A4300776EAD /* file_id.cc in Sources */, |
|||
16C7CE85147D4A4300776EAD /* macho_id.cc in Sources */, |
|||
16C7CE8A147D4A4300776EAD /* macho_utilities.cc in Sources */, |
|||
16C7CE8C147D4A4300776EAD /* macho_walker.cc in Sources */, |
|||
16C7CE8F147D4A4300776EAD /* string_utilities.cc in Sources */, |
|||
16C7CE93147D4A4300776EAD /* md5.cc in Sources */, |
|||
16C7CEA7147D4A4300776EAD /* string_conversion.cc in Sources */, |
|||
16BFA67214E1965A009704F8 /* ios_exception_minidump_generator.mm in Sources */, |
|||
16C92FAE150DF8330053D7BA /* BreakpadController.mm in Sources */, |
|||
1EEEB60F1720821900F7E689 /* simple_string_dictionary.cc in Sources */, |
|||
); |
|||
runOnlyForDeploymentPostprocessing = 0; |
|||
}; |
|||
/* End PBXSourcesBuildPhase section */ |
|||
|
|||
/* Begin XCBuildConfiguration section */ |
|||
1DEB921F08733DC00010E9CD /* Debug */ = { |
|||
isa = XCBuildConfiguration; |
|||
buildSettings = { |
|||
ALWAYS_SEARCH_USER_PATHS = NO; |
|||
CLANG_CXX_LIBRARY = "libc++"; |
|||
COPY_PHASE_STRIP = NO; |
|||
DSTROOT = /tmp/Breakpad.dst; |
|||
FRAMEWORK_SEARCH_PATHS = ( |
|||
"$(inherited)", |
|||
"\"$(SRCROOT)/../mac/build/Debug\"", |
|||
); |
|||
GCC_DYNAMIC_NO_PIC = NO; |
|||
GCC_MODEL_TUNING = G5; |
|||
GCC_OPTIMIZATION_LEVEL = 0; |
|||
GCC_PRECOMPILE_PREFIX_HEADER = YES; |
|||
GCC_PREFIX_HEADER = Breakpad_Prefix.pch; |
|||
INSTALL_PATH = /usr/local/lib; |
|||
LIBRARY_SEARCH_PATHS = ( |
|||
"$(inherited)", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/i386\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/x86_64\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/i386\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/x86_64\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/i386\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/x86_64\"", |
|||
"\"$(SRCROOT)/../mac/build/Debug\"", |
|||
"\"$(SRCROOT)/../mac/gcov\"", |
|||
); |
|||
PRODUCT_NAME = Breakpad; |
|||
}; |
|||
name = Debug; |
|||
}; |
|||
1DEB922008733DC00010E9CD /* Release */ = { |
|||
isa = XCBuildConfiguration; |
|||
buildSettings = { |
|||
ALWAYS_SEARCH_USER_PATHS = NO; |
|||
CLANG_CXX_LIBRARY = "libc++"; |
|||
DSTROOT = /tmp/Breakpad.dst; |
|||
FRAMEWORK_SEARCH_PATHS = ( |
|||
"$(inherited)", |
|||
"\"$(SRCROOT)/../mac/build/Debug\"", |
|||
); |
|||
GCC_MODEL_TUNING = G5; |
|||
GCC_PRECOMPILE_PREFIX_HEADER = YES; |
|||
GCC_PREFIX_HEADER = Breakpad_Prefix.pch; |
|||
INSTALL_PATH = /usr/local/lib; |
|||
LIBRARY_SEARCH_PATHS = ( |
|||
"$(inherited)", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/i386\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/x86_64\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/i386\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/x86_64\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/i386\"", |
|||
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/x86_64\"", |
|||
"\"$(SRCROOT)/../mac/build/Debug\"", |
|||
"\"$(SRCROOT)/../mac/gcov\"", |
|||
); |
|||
PRODUCT_NAME = Breakpad; |
|||
}; |
|||
name = Release; |
|||
}; |
|||
1DEB922308733DC00010E9CD /* Debug */ = { |
|||
isa = XCBuildConfiguration; |
|||
buildSettings = { |
|||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; |
|||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; |
|||
GCC_C_LANGUAGE_STANDARD = c99; |
|||
GCC_OPTIMIZATION_LEVEL = 0; |
|||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES; |
|||
GCC_WARN_SHADOW = YES; |
|||
GCC_WARN_SIGN_COMPARE = YES; |
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES; |
|||
GCC_WARN_UNKNOWN_PRAGMAS = YES; |
|||
GCC_WARN_UNUSED_FUNCTION = YES; |
|||
GCC_WARN_UNUSED_LABEL = YES; |
|||
GCC_WARN_UNUSED_VARIABLE = YES; |
|||
HEADER_SEARCH_PATHS = ( |
|||
../../, |
|||
../../client/apple/Framework, |
|||
../../common/mac, |
|||
); |
|||
IPHONEOS_DEPLOYMENT_TARGET = 5.0; |
|||
ONLY_ACTIVE_ARCH = YES; |
|||
OTHER_LDFLAGS = "-ObjC"; |
|||
SDKROOT = iphoneos; |
|||
WARNING_CFLAGS = "-Wundef"; |
|||
}; |
|||
name = Debug; |
|||
}; |
|||
1DEB922408733DC00010E9CD /* Release */ = { |
|||
isa = XCBuildConfiguration; |
|||
buildSettings = { |
|||
CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; |
|||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; |
|||
GCC_C_LANGUAGE_STANDARD = c99; |
|||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES; |
|||
GCC_WARN_SHADOW = YES; |
|||
GCC_WARN_SIGN_COMPARE = YES; |
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES; |
|||
GCC_WARN_UNKNOWN_PRAGMAS = YES; |
|||
GCC_WARN_UNUSED_FUNCTION = YES; |
|||
GCC_WARN_UNUSED_LABEL = YES; |
|||
GCC_WARN_UNUSED_VARIABLE = YES; |
|||
HEADER_SEARCH_PATHS = ( |
|||
../../, |
|||
../../client/apple/Framework, |
|||
../../common/mac, |
|||
); |
|||
IPHONEOS_DEPLOYMENT_TARGET = 5.0; |
|||
OTHER_LDFLAGS = "-ObjC"; |
|||
SDKROOT = iphoneos; |
|||
WARNING_CFLAGS = "-Wundef"; |
|||
}; |
|||
name = Release; |
|||
}; |
|||
/* End XCBuildConfiguration section */ |
|||
|
|||
/* Begin XCConfigurationList section */ |
|||
1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */ = { |
|||
isa = XCConfigurationList; |
|||
buildConfigurations = ( |
|||
1DEB921F08733DC00010E9CD /* Debug */, |
|||
1DEB922008733DC00010E9CD /* Release */, |
|||
); |
|||
defaultConfigurationIsVisible = 0; |
|||
defaultConfigurationName = Release; |
|||
}; |
|||
1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Breakpad" */ = { |
|||
isa = XCConfigurationList; |
|||
buildConfigurations = ( |
|||
1DEB922308733DC00010E9CD /* Debug */, |
|||
1DEB922408733DC00010E9CD /* Release */, |
|||
); |
|||
defaultConfigurationIsVisible = 0; |
|||
defaultConfigurationName = Release; |
|||
}; |
|||
/* End XCConfigurationList section */ |
|||
}; |
|||
rootObject = 0867D690FE84028FC02AAC07 /* Project object */; |
|||
} |
|||
@ -0,0 +1,153 @@ |
|||
// Copyright 2012 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_ |
|||
#define CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_ |
|||
|
|||
#import <Foundation/Foundation.h> |
|||
|
|||
#import "client/ios/Breakpad.h" |
|||
|
|||
// This class is used to offer a higher level API around BreakpadRef. It |
|||
// configures it, ensures thread-safety, and sends crash reports back to the |
|||
// collecting server. By default, no crash reports are sent, the user must call |
|||
// |setUploadingEnabled:YES| to start the uploading. |
|||
@interface BreakpadController : NSObject { |
|||
@private |
|||
// The dispatch queue that will own the breakpad reference. |
|||
dispatch_queue_t queue_; |
|||
|
|||
// Instance of Breakpad crash reporter. This is owned by the queue, but can |
|||
// be created on the main thread at startup. |
|||
BreakpadRef breakpadRef_; |
|||
|
|||
// The dictionary that contains configuration for breakpad. Modifying it |
|||
// should only happen when the controller is not started. The initial value |
|||
// is the infoDictionary of the bundle of the application. |
|||
NSMutableDictionary* configuration_; |
|||
|
|||
// Whether or not crash reports should be uploaded. |
|||
BOOL enableUploads_; |
|||
|
|||
// Whether the controller has been started on the main thread. This is only |
|||
// used to assert the initialization order is correct. |
|||
BOOL started_; |
|||
|
|||
// The interval to wait between two uploads. Value is 0 if no upload must be |
|||
// done. |
|||
int uploadIntervalInSeconds_; |
|||
|
|||
// The dictionary that contains additional server parameters to send when |
|||
// uploading crash reports. |
|||
NSDictionary* uploadTimeParameters_; |
|||
|
|||
// The callback to call on report upload completion. |
|||
BreakpadUploadCompletionCallback uploadCompleteCallback_; |
|||
} |
|||
|
|||
// Singleton. |
|||
+ (BreakpadController*)sharedInstance; |
|||
|
|||
// Update the controller configuration. Merges its old configuration with the |
|||
// new one. Merge is done by replacing the old values by the new values. |
|||
- (void)updateConfiguration:(NSDictionary*)configuration; |
|||
|
|||
// Reset the controller configuration to its initial value, which is the |
|||
// infoDictionary of the bundle of the application. |
|||
- (void)resetConfiguration; |
|||
|
|||
// Configure the URL to upload the report to. This must be called at least once |
|||
// if the URL is not in the bundle information. |
|||
- (void)setUploadingURL:(NSString*)url; |
|||
|
|||
// Set the minimal interval between two uploads in seconds. This must be called |
|||
// at least once if the interval is not in the bundle information. A value of 0 |
|||
// will prevent uploads. |
|||
- (void)setUploadInterval:(int)intervalInSeconds; |
|||
|
|||
// Set additional server parameters to send when uploading crash reports. |
|||
- (void)setParametersToAddAtUploadTime:(NSDictionary*)uploadTimeParameters; |
|||
|
|||
// Specify an upload parameter that will be added to the crash report when a |
|||
// crash report is generated. See |BreakpadAddUploadParameter|. |
|||
- (void)addUploadParameter:(NSString*)value forKey:(NSString*)key; |
|||
|
|||
// Sets the callback to be called after uploading a crash report to the server. |
|||
// Only the latest callback registered will be called. |
|||
- (void)setUploadCallback:(BreakpadUploadCompletionCallback)callback; |
|||
|
|||
// Remove a previously-added parameter from the upload parameter set. See |
|||
// |BreakpadRemoveUploadParameter|. |
|||
- (void)removeUploadParameterForKey:(NSString*)key; |
|||
|
|||
// Access the underlying BreakpadRef. This method is asynchronous, and will be |
|||
// executed on the thread owning the BreakpadRef variable. Moreover, if the |
|||
// controller is not started, the block will be called with a NULL parameter. |
|||
- (void)withBreakpadRef:(void(^)(BreakpadRef))callback; |
|||
|
|||
// Starts the BreakpadController by registering crash handlers. If |
|||
// |onCurrentThread| is YES, all setup is done on the current thread, otherwise |
|||
// it is done on a private queue. |
|||
- (void)start:(BOOL)onCurrentThread; |
|||
|
|||
// Unregisters the crash handlers. |
|||
- (void)stop; |
|||
|
|||
// Returns whether or not the controller is started. |
|||
- (BOOL)isStarted; |
|||
|
|||
// Enables or disables uploading of crash reports, but does not stop the |
|||
// BreakpadController. |
|||
- (void)setUploadingEnabled:(BOOL)enabled; |
|||
|
|||
// Check if there is currently a crash report to upload. |
|||
- (void)hasReportToUpload:(void(^)(BOOL))callback; |
|||
|
|||
// Get the number of crash reports waiting to upload. |
|||
- (void)getCrashReportCount:(void(^)(int))callback; |
|||
|
|||
// Get the next report to upload. |
|||
// - If upload is disabled, callback will be called with (nil, -1). |
|||
// - If a delay is to be waited before sending, callback will be called with |
|||
// (nil, n), with n (> 0) being the number of seconds to wait. |
|||
// - if no delay is needed, callback will be called with (0, configuration), |
|||
// configuration being next report to upload, or nil if none is pending. |
|||
- (void)getNextReportConfigurationOrSendDelay: |
|||
(void(^)(NSDictionary*, int))callback; |
|||
|
|||
// Get the date of the most recent crash report. |
|||
- (void)getDateOfMostRecentCrashReport:(void(^)(NSDate *))callback; |
|||
|
|||
// Sends synchronously the report specified by |configuration|. This method is |
|||
// NOT thread safe and must be called from the breakpad thread. |
|||
- (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration |
|||
withBreakpadRef:(BreakpadRef)ref; |
|||
|
|||
@end |
|||
|
|||
#endif // CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_ |
|||
@ -0,0 +1,373 @@ |
|||
// Copyright 2012 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#import "BreakpadController.h" |
|||
|
|||
#import <UIKit/UIKit.h> |
|||
#include <asl.h> |
|||
#include <execinfo.h> |
|||
#include <signal.h> |
|||
#include <unistd.h> |
|||
#include <sys/sysctl.h> |
|||
|
|||
#include <common/scoped_ptr.h> |
|||
|
|||
#pragma mark - |
|||
#pragma mark Private Methods |
|||
|
|||
@interface BreakpadController () |
|||
|
|||
// Init the singleton instance. |
|||
- (id)initSingleton; |
|||
|
|||
// Load a crash report and send it to the server. |
|||
- (void)sendStoredCrashReports; |
|||
|
|||
// Returns when a report can be sent. |-1| means never, |0| means that a report |
|||
// can be sent immediately, a positive number is the number of seconds to wait |
|||
// before being allowed to upload a report. |
|||
- (int)sendDelay; |
|||
|
|||
// Notifies that a report will be sent, and update the last sending time |
|||
// accordingly. |
|||
- (void)reportWillBeSent; |
|||
|
|||
@end |
|||
|
|||
#pragma mark - |
|||
#pragma mark Anonymous namespace |
|||
|
|||
namespace { |
|||
|
|||
// The name of the user defaults key for the last submission to the crash |
|||
// server. |
|||
NSString* const kLastSubmission = @"com.google.Breakpad.LastSubmission"; |
|||
|
|||
// Returns a NSString describing the current platform. |
|||
NSString* GetPlatform() { |
|||
// Name of the system call for getting the platform. |
|||
static const char kHwMachineSysctlName[] = "hw.machine"; |
|||
|
|||
NSString* result = nil; |
|||
|
|||
size_t size = 0; |
|||
if (sysctlbyname(kHwMachineSysctlName, NULL, &size, NULL, 0) || size == 0) |
|||
return nil; |
|||
google_breakpad::scoped_array<char> machine(new char[size]); |
|||
if (sysctlbyname(kHwMachineSysctlName, machine.get(), &size, NULL, 0) == 0) |
|||
result = [NSString stringWithUTF8String:machine.get()]; |
|||
return result; |
|||
} |
|||
|
|||
} // namespace |
|||
|
|||
#pragma mark - |
|||
#pragma mark BreakpadController Implementation |
|||
|
|||
@implementation BreakpadController |
|||
|
|||
+ (BreakpadController*)sharedInstance { |
|||
static dispatch_once_t onceToken; |
|||
static BreakpadController* sharedInstance ; |
|||
dispatch_once(&onceToken, ^{ |
|||
sharedInstance = [[BreakpadController alloc] initSingleton]; |
|||
}); |
|||
return sharedInstance; |
|||
} |
|||
|
|||
- (id)init { |
|||
return nil; |
|||
} |
|||
|
|||
- (id)initSingleton { |
|||
self = [super init]; |
|||
if (self) { |
|||
queue_ = dispatch_queue_create("com.google.BreakpadQueue", NULL); |
|||
enableUploads_ = NO; |
|||
started_ = NO; |
|||
[self resetConfiguration]; |
|||
} |
|||
return self; |
|||
} |
|||
|
|||
// Since this class is a singleton, this method is not expected to be called. |
|||
- (void)dealloc { |
|||
assert(!breakpadRef_); |
|||
dispatch_release(queue_); |
|||
[configuration_ release]; |
|||
[uploadTimeParameters_ release]; |
|||
[super dealloc]; |
|||
} |
|||
|
|||
#pragma mark - |
|||
|
|||
- (void)start:(BOOL)onCurrentThread { |
|||
if (started_) |
|||
return; |
|||
started_ = YES; |
|||
void(^startBlock)() = ^{ |
|||
assert(!breakpadRef_); |
|||
breakpadRef_ = BreakpadCreate(configuration_); |
|||
if (breakpadRef_) { |
|||
BreakpadAddUploadParameter(breakpadRef_, @"platform", GetPlatform()); |
|||
} |
|||
}; |
|||
if (onCurrentThread) |
|||
startBlock(); |
|||
else |
|||
dispatch_async(queue_, startBlock); |
|||
} |
|||
|
|||
- (void)stop { |
|||
if (!started_) |
|||
return; |
|||
started_ = NO; |
|||
dispatch_sync(queue_, ^{ |
|||
if (breakpadRef_) { |
|||
BreakpadRelease(breakpadRef_); |
|||
breakpadRef_ = NULL; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
- (BOOL)isStarted { |
|||
return started_; |
|||
} |
|||
|
|||
// This method must be called from the breakpad queue. |
|||
- (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration |
|||
withBreakpadRef:(BreakpadRef)ref { |
|||
NSAssert(started_, @"The controller must be started before " |
|||
"threadUnsafeSendReportWithConfiguration is called"); |
|||
if (breakpadRef_) { |
|||
BreakpadUploadReportWithParametersAndConfiguration( |
|||
breakpadRef_, uploadTimeParameters_, configuration, |
|||
uploadCompleteCallback_); |
|||
} |
|||
} |
|||
|
|||
- (void)setUploadingEnabled:(BOOL)enabled { |
|||
NSAssert(started_, |
|||
@"The controller must be started before setUploadingEnabled is called"); |
|||
dispatch_async(queue_, ^{ |
|||
if (enabled == enableUploads_) |
|||
return; |
|||
if (enabled) { |
|||
// Set this before calling doSendStoredCrashReport, because that |
|||
// calls sendDelay, which in turn checks this flag. |
|||
enableUploads_ = YES; |
|||
[self sendStoredCrashReports]; |
|||
} else { |
|||
// disable the enableUpload_ flag. |
|||
// sendDelay checks this flag and disables the upload of logs by sendStoredCrashReports |
|||
enableUploads_ = NO; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
- (void)updateConfiguration:(NSDictionary*)configuration { |
|||
NSAssert(!started_, |
|||
@"The controller must not be started when updateConfiguration is called"); |
|||
[configuration_ addEntriesFromDictionary:configuration]; |
|||
NSString *uploadInterval = |
|||
[configuration_ valueForKey:@BREAKPAD_REPORT_INTERVAL]; |
|||
if (uploadInterval) |
|||
[self setUploadInterval:[uploadInterval intValue]]; |
|||
} |
|||
|
|||
- (void)resetConfiguration { |
|||
NSAssert(!started_, |
|||
@"The controller must not be started when resetConfiguration is called"); |
|||
[configuration_ autorelease]; |
|||
configuration_ = [[[NSBundle mainBundle] infoDictionary] mutableCopy]; |
|||
NSString *uploadInterval = |
|||
[configuration_ valueForKey:@BREAKPAD_REPORT_INTERVAL]; |
|||
[self setUploadInterval:[uploadInterval intValue]]; |
|||
[self setParametersToAddAtUploadTime:nil]; |
|||
} |
|||
|
|||
- (void)setUploadingURL:(NSString*)url { |
|||
NSAssert(!started_, |
|||
@"The controller must not be started when setUploadingURL is called"); |
|||
[configuration_ setValue:url forKey:@BREAKPAD_URL]; |
|||
} |
|||
|
|||
- (void)setUploadInterval:(int)intervalInSeconds { |
|||
NSAssert(!started_, |
|||
@"The controller must not be started when setUploadInterval is called"); |
|||
[configuration_ removeObjectForKey:@BREAKPAD_REPORT_INTERVAL]; |
|||
uploadIntervalInSeconds_ = intervalInSeconds; |
|||
if (uploadIntervalInSeconds_ < 0) |
|||
uploadIntervalInSeconds_ = 0; |
|||
} |
|||
|
|||
- (void)setParametersToAddAtUploadTime:(NSDictionary*)uploadTimeParameters { |
|||
NSAssert(!started_, @"The controller must not be started when " |
|||
"setParametersToAddAtUploadTime is called"); |
|||
[uploadTimeParameters_ autorelease]; |
|||
uploadTimeParameters_ = [uploadTimeParameters copy]; |
|||
} |
|||
|
|||
- (void)addUploadParameter:(NSString*)value forKey:(NSString*)key { |
|||
NSAssert(started_, |
|||
@"The controller must be started before addUploadParameter is called"); |
|||
dispatch_async(queue_, ^{ |
|||
if (breakpadRef_) |
|||
BreakpadAddUploadParameter(breakpadRef_, key, value); |
|||
}); |
|||
} |
|||
|
|||
- (void)setUploadCallback:(BreakpadUploadCompletionCallback)callback { |
|||
NSAssert(started_, |
|||
@"The controller must not be started before setUploadCallback is " |
|||
"called"); |
|||
dispatch_async(queue_, ^{ |
|||
uploadCompleteCallback_ = callback; |
|||
}); |
|||
} |
|||
|
|||
- (void)removeUploadParameterForKey:(NSString*)key { |
|||
NSAssert(started_, @"The controller must be started before " |
|||
"removeUploadParameterForKey is called"); |
|||
dispatch_async(queue_, ^{ |
|||
if (breakpadRef_) |
|||
BreakpadRemoveUploadParameter(breakpadRef_, key); |
|||
}); |
|||
} |
|||
|
|||
- (void)withBreakpadRef:(void(^)(BreakpadRef))callback { |
|||
dispatch_async(queue_, ^{ |
|||
callback(started_ ? breakpadRef_ : NULL); |
|||
}); |
|||
} |
|||
|
|||
- (void)hasReportToUpload:(void(^)(BOOL))callback { |
|||
NSAssert(started_, @"The controller must be started before " |
|||
"hasReportToUpload is called"); |
|||
dispatch_async(queue_, ^{ |
|||
callback(breakpadRef_ && (BreakpadGetCrashReportCount(breakpadRef_) > 0)); |
|||
}); |
|||
} |
|||
|
|||
- (void)getCrashReportCount:(void(^)(int))callback { |
|||
NSAssert(started_, @"The controller must be started before " |
|||
"getCrashReportCount is called"); |
|||
dispatch_async(queue_, ^{ |
|||
callback(breakpadRef_ ? BreakpadGetCrashReportCount(breakpadRef_) : 0); |
|||
}); |
|||
} |
|||
|
|||
- (void)getNextReportConfigurationOrSendDelay: |
|||
(void(^)(NSDictionary*, int))callback { |
|||
NSAssert(started_, @"The controller must be started before " |
|||
"getNextReportConfigurationOrSendDelay is called"); |
|||
dispatch_async(queue_, ^{ |
|||
if (!breakpadRef_) { |
|||
callback(nil, -1); |
|||
return; |
|||
} |
|||
int delay = [self sendDelay]; |
|||
if (delay != 0) { |
|||
callback(nil, delay); |
|||
return; |
|||
} |
|||
[self reportWillBeSent]; |
|||
callback(BreakpadGetNextReportConfiguration(breakpadRef_), 0); |
|||
}); |
|||
} |
|||
|
|||
- (void)getDateOfMostRecentCrashReport:(void(^)(NSDate *))callback { |
|||
NSAssert(started_, @"The controller must be started before " |
|||
"getDateOfMostRecentCrashReport is called"); |
|||
dispatch_async(queue_, ^{ |
|||
if (!breakpadRef_) { |
|||
callback(nil); |
|||
return; |
|||
} |
|||
callback(BreakpadGetDateOfMostRecentCrashReport(breakpadRef_)); |
|||
}); |
|||
} |
|||
|
|||
#pragma mark - |
|||
|
|||
- (int)sendDelay { |
|||
if (!breakpadRef_ || uploadIntervalInSeconds_ <= 0 || !enableUploads_) |
|||
return -1; |
|||
|
|||
// To prevent overloading the crash server, crashes are not sent than one |
|||
// report every |uploadIntervalInSeconds_|. A value in the user defaults is |
|||
// used to keep the time of the last upload. |
|||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; |
|||
NSNumber *lastTimeNum = [userDefaults objectForKey:kLastSubmission]; |
|||
NSTimeInterval lastTime = lastTimeNum ? [lastTimeNum floatValue] : 0; |
|||
NSTimeInterval spanSeconds = CFAbsoluteTimeGetCurrent() - lastTime; |
|||
|
|||
if (spanSeconds >= uploadIntervalInSeconds_) |
|||
return 0; |
|||
return uploadIntervalInSeconds_ - static_cast<int>(spanSeconds); |
|||
} |
|||
|
|||
- (void)reportWillBeSent { |
|||
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; |
|||
[userDefaults setObject:[NSNumber numberWithDouble:CFAbsoluteTimeGetCurrent()] |
|||
forKey:kLastSubmission]; |
|||
[userDefaults synchronize]; |
|||
} |
|||
|
|||
// This method must be called from the breakpad queue. |
|||
- (void)sendStoredCrashReports { |
|||
if (BreakpadGetCrashReportCount(breakpadRef_) == 0) |
|||
return; |
|||
|
|||
int timeToWait = [self sendDelay]; |
|||
|
|||
// Unable to ever send report. |
|||
if (timeToWait == -1) |
|||
return; |
|||
|
|||
// A report can be sent now. |
|||
if (timeToWait == 0) { |
|||
[self reportWillBeSent]; |
|||
BreakpadUploadNextReportWithParameters(breakpadRef_, uploadTimeParameters_, |
|||
uploadCompleteCallback_); |
|||
|
|||
// If more reports must be sent, make sure this method is called again. |
|||
if (BreakpadGetCrashReportCount(breakpadRef_) > 0) |
|||
timeToWait = uploadIntervalInSeconds_; |
|||
} |
|||
|
|||
// A report must be sent later. |
|||
if (timeToWait > 0) { |
|||
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeToWait * NSEC_PER_SEC)); |
|||
dispatch_after(delay, queue_, ^{ |
|||
[self sendStoredCrashReports]; |
|||
}); |
|||
} |
|||
} |
|||
|
|||
@end |
|||
@ -0,0 +1,7 @@ |
|||
// |
|||
// Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project. |
|||
// |
|||
|
|||
#ifdef __OBJC__ |
|||
#import <Foundation/Foundation.h> |
|||
#endif |
|||
@ -0,0 +1,265 @@ |
|||
// Copyright 2006 Google LLC
|
|||
//
|
|||
// Redistribution and use in source and binary forms, with or without
|
|||
// modification, are permitted provided that the following conditions are
|
|||
// met:
|
|||
//
|
|||
// * Redistributions of source code must retain the above copyright
|
|||
// notice, this list of conditions and the following disclaimer.
|
|||
// * Redistributions in binary form must reproduce the above
|
|||
// copyright notice, this list of conditions and the following disclaimer
|
|||
// in the documentation and/or other materials provided with the
|
|||
// distribution.
|
|||
// * Neither the name of Google LLC nor the names of its
|
|||
// contributors may be used to endorse or promote products derived from
|
|||
// this software without specific prior written permission.
|
|||
//
|
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
#ifdef HAVE_CONFIG_H
|
|||
#include <config.h> // Must come first
|
|||
#endif
|
|||
|
|||
#include <signal.h>
|
|||
#include <TargetConditionals.h>
|
|||
|
|||
#include "client/mac/handler/minidump_generator.h"
|
|||
#include "client/ios/exception_handler_no_mach.h"
|
|||
|
|||
#ifndef USE_PROTECTED_ALLOCATIONS
|
|||
#if TARGET_OS_TV
|
|||
#define USE_PROTECTED_ALLOCATIONS 1
|
|||
#else
|
|||
#define USE_PROTECTED_ALLOCATIONS 0
|
|||
#endif
|
|||
#endif
|
|||
|
|||
// If USE_PROTECTED_ALLOCATIONS is activated then the
|
|||
// gBreakpadAllocator needs to be setup in other code
|
|||
// ahead of time. Please see ProtectedMemoryAllocator.h
|
|||
// for more details.
|
|||
#if USE_PROTECTED_ALLOCATIONS
|
|||
#include "client/mac/handler/protected_memory_allocator.h"
|
|||
extern ProtectedMemoryAllocator* gBreakpadAllocator; |
|||
#endif
|
|||
|
|||
namespace google_breakpad { |
|||
|
|||
const int kExceptionSignals[] = { |
|||
// Core-generating signals.
|
|||
SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGEMT, |
|||
SIGXCPU, SIGXFSZ, |
|||
// Non-core-generating but terminating signals.
|
|||
SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGPROF, SIGTERM, SIGUSR1, SIGUSR2, |
|||
SIGVTALRM, SIGXCPU, SIGXFSZ, SIGIO, |
|||
}; |
|||
const int kNumHandledSignals = |
|||
sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]); |
|||
struct scoped_ptr<struct sigaction> old_handlers[kNumHandledSignals]; |
|||
|
|||
static union { |
|||
#if USE_PROTECTED_ALLOCATIONS
|
|||
#if defined PAGE_MAX_SIZE
|
|||
char protected_buffer[PAGE_MAX_SIZE] __attribute__((aligned(PAGE_MAX_SIZE))); |
|||
#else
|
|||
char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); |
|||
#endif // defined PAGE_MAX_SIZE
|
|||
#endif // USE_PROTECTED_ALLOCATIONS
|
|||
google_breakpad::ExceptionHandler* handler; |
|||
} gProtectedData; |
|||
|
|||
ExceptionHandler::ExceptionHandler(const string& dump_path, |
|||
FilterCallback filter, |
|||
MinidumpCallback callback, |
|||
void* callback_context, |
|||
bool install_handler, |
|||
const char* port_name) |
|||
: dump_path_(), |
|||
filter_(filter), |
|||
callback_(callback), |
|||
callback_context_(callback_context), |
|||
directCallback_(NULL), |
|||
installed_exception_handler_(false), |
|||
is_in_teardown_(false) { |
|||
// This will update to the ID and C-string pointers
|
|||
set_dump_path(dump_path); |
|||
MinidumpGenerator::GatherSystemInformation(); |
|||
Setup(); |
|||
} |
|||
|
|||
// special constructor if we want to bypass minidump writing and
|
|||
// simply get a callback with the exception information
|
|||
ExceptionHandler::ExceptionHandler(DirectCallback callback, |
|||
void* callback_context, |
|||
bool install_handler) |
|||
: dump_path_(), |
|||
filter_(NULL), |
|||
callback_(NULL), |
|||
callback_context_(callback_context), |
|||
directCallback_(callback), |
|||
installed_exception_handler_(false), |
|||
is_in_teardown_(false) { |
|||
MinidumpGenerator::GatherSystemInformation(); |
|||
Setup(); |
|||
} |
|||
|
|||
ExceptionHandler::~ExceptionHandler() { |
|||
Teardown(); |
|||
} |
|||
|
|||
bool ExceptionHandler::WriteMinidumpWithException( |
|||
int exception_type, |
|||
int exception_code, |
|||
int exception_subcode, |
|||
breakpad_ucontext_t* task_context, |
|||
mach_port_t thread_name, |
|||
bool exit_after_write, |
|||
bool report_current_thread) { |
|||
bool result = false; |
|||
|
|||
#if !TARGET_OS_TV
|
|||
exit_after_write = false; |
|||
#endif // !TARGET_OS_TV
|
|||
|
|||
if (directCallback_) { |
|||
if (directCallback_(callback_context_, |
|||
exception_type, |
|||
exception_code, |
|||
exception_subcode, |
|||
thread_name) ) { |
|||
if (exit_after_write) |
|||
_exit(exception_type); |
|||
} |
|||
} else { |
|||
string minidump_id; |
|||
|
|||
// Putting the MinidumpGenerator in its own context will ensure that the
|
|||
// destructor is executed, closing the newly created minidump file.
|
|||
if (!dump_path_.empty()) { |
|||
MinidumpGenerator md(mach_task_self(), |
|||
report_current_thread ? MACH_PORT_NULL : |
|||
mach_thread_self()); |
|||
md.SetTaskContext(task_context); |
|||
if (exception_type && exception_code) { |
|||
// If this is a real exception, give the filter (if any) a chance to
|
|||
// decide if this should be sent.
|
|||
if (filter_ && !filter_(callback_context_)) |
|||
return false; |
|||
|
|||
md.SetExceptionInformation(exception_type, exception_code, |
|||
exception_subcode, thread_name); |
|||
} |
|||
|
|||
result = md.Write(next_minidump_path_c_); |
|||
} |
|||
|
|||
// Call user specified callback (if any)
|
|||
if (callback_) { |
|||
// If the user callback returned true and we're handling an exception
|
|||
// (rather than just writing out the file), then we should exit without
|
|||
// forwarding the exception to the next handler.
|
|||
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, |
|||
result)) { |
|||
if (exit_after_write) |
|||
_exit(exception_type); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// static
|
|||
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { |
|||
#if USE_PROTECTED_ALLOCATIONS
|
|||
if (gBreakpadAllocator) |
|||
gBreakpadAllocator->Unprotect(); |
|||
#endif
|
|||
gProtectedData.handler->WriteMinidumpWithException( |
|||
EXC_SOFTWARE, |
|||
MD_EXCEPTION_CODE_MAC_ABORT, |
|||
0, |
|||
static_cast<breakpad_ucontext_t*>(uc), |
|||
mach_thread_self(), |
|||
true, |
|||
true); |
|||
#if USE_PROTECTED_ALLOCATIONS
|
|||
if (gBreakpadAllocator) |
|||
gBreakpadAllocator->Protect(); |
|||
#endif
|
|||
} |
|||
|
|||
bool ExceptionHandler::InstallHandlers() { |
|||
// If a handler is already installed, something is really wrong.
|
|||
if (gProtectedData.handler != NULL) |
|||
return false; |
|||
for (int i = 0; i < kNumHandledSignals; ++i) { |
|||
struct sigaction sa; |
|||
memset(&sa, 0, sizeof(sa)); |
|||
sigemptyset(&sa.sa_mask); |
|||
sigaddset(&sa.sa_mask, kExceptionSignals[i]); |
|||
sa.sa_sigaction = ExceptionHandler::SignalHandler; |
|||
sa.sa_flags = SA_ONSTACK | SA_SIGINFO; |
|||
|
|||
if (sigaction(kExceptionSignals[i], &sa, old_handlers[i].get()) == -1) { |
|||
return false; |
|||
} |
|||
} |
|||
gProtectedData.handler = this; |
|||
#if USE_PROTECTED_ALLOCATIONS
|
|||
assert(((size_t)(gProtectedData.protected_buffer) & PAGE_MASK) == 0); |
|||
mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ); |
|||
#endif // USE_PROTECTED_ALLOCATIONS
|
|||
installed_exception_handler_ = true; |
|||
return true; |
|||
} |
|||
|
|||
bool ExceptionHandler::UninstallHandlers() { |
|||
for (int i = 0; i < kNumHandledSignals; ++i) { |
|||
if (old_handlers[i].get()) { |
|||
sigaction(kExceptionSignals[i], old_handlers[i].get(), NULL); |
|||
old_handlers[i].reset(); |
|||
} |
|||
} |
|||
#if USE_PROTECTED_ALLOCATIONS
|
|||
mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ | PROT_WRITE); |
|||
#endif // USE_PROTECTED_ALLOCATIONS
|
|||
gProtectedData.handler = NULL; |
|||
installed_exception_handler_ = false; |
|||
return true; |
|||
} |
|||
|
|||
bool ExceptionHandler::Setup() { |
|||
if (!InstallHandlers()) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
bool ExceptionHandler::Teardown() { |
|||
is_in_teardown_ = true; |
|||
|
|||
if (!UninstallHandlers()) |
|||
return false; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void ExceptionHandler::UpdateNextID() { |
|||
next_minidump_path_ = |
|||
(MinidumpGenerator::UniqueNameInDirectory(dump_path_, &next_minidump_id_)); |
|||
|
|||
next_minidump_path_c_ = next_minidump_path_.c_str(); |
|||
next_minidump_id_c_ = next_minidump_id_.c_str(); |
|||
} |
|||
|
|||
} // namespace google_breakpad
|
|||
@ -0,0 +1,178 @@ |
|||
// Copyright 2006 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef CLIENT_IOS_HANDLER_EXCEPTION_HANDLER_NO_MACH_H__ |
|||
#define CLIENT_IOS_HANDLER_EXCEPTION_HANDLER_NO_MACH_H__ |
|||
|
|||
#include <mach/mach.h> |
|||
#include <TargetConditionals.h> |
|||
|
|||
#include <string> |
|||
|
|||
#include "client/mac/handler/ucontext_compat.h" |
|||
#include "common/scoped_ptr.h" |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
using std::string; |
|||
|
|||
class ExceptionHandler { |
|||
public: |
|||
// A callback function to run before Breakpad performs any substantial |
|||
// processing of an exception. A FilterCallback is called before writing |
|||
// a minidump. context is the parameter supplied by the user as |
|||
// callback_context when the handler was created. |
|||
// |
|||
// If a FilterCallback returns true, Breakpad will continue processing, |
|||
// attempting to write a minidump. If a FilterCallback returns false, Breakpad |
|||
// will immediately report the exception as unhandled without writing a |
|||
// minidump, allowing another handler the opportunity to handle it. |
|||
typedef bool (*FilterCallback)(void* context); |
|||
|
|||
// A callback function to run after the minidump has been written. |
|||
// |minidump_id| is a unique id for the dump, so the minidump |
|||
// file is <dump_dir>/<minidump_id>.dmp. |
|||
// |context| is the value passed into the constructor. |
|||
// |succeeded| indicates whether a minidump file was successfully written. |
|||
// Return true if the exception was fully handled and breakpad should exit. |
|||
// Return false to allow any other exception handlers to process the |
|||
// exception. |
|||
typedef bool (*MinidumpCallback)(const char* dump_dir, |
|||
const char* minidump_id, |
|||
void* context, bool succeeded); |
|||
|
|||
// A callback function which will be called directly if an exception occurs. |
|||
// This bypasses the minidump file writing and simply gives the client |
|||
// the exception information. |
|||
typedef bool (*DirectCallback)(void* context, |
|||
int exception_type, |
|||
int exception_code, |
|||
int exception_subcode, |
|||
mach_port_t thread_name); |
|||
|
|||
// Creates a new ExceptionHandler instance to handle writing minidumps. |
|||
// Minidump files will be written to dump_path, and the optional callback |
|||
// is called after writing the dump file, as described above. |
|||
// If install_handler is true, then a minidump will be written whenever |
|||
// an unhandled exception occurs. If it is false, minidumps will only |
|||
// be written when WriteMinidump is called. |
|||
// If port_name is non-NULL, attempt to perform out-of-process dump generation |
|||
// If port_name is NULL, in-process dump generation will be used. |
|||
ExceptionHandler(const string& dump_path, |
|||
FilterCallback filter, MinidumpCallback callback, |
|||
void* callback_context, bool install_handler, |
|||
const char* port_name); |
|||
|
|||
// A special constructor if we want to bypass minidump writing and |
|||
// simply get a callback with the exception information. |
|||
ExceptionHandler(DirectCallback callback, |
|||
void* callback_context, |
|||
bool install_handler); |
|||
|
|||
~ExceptionHandler(); |
|||
|
|||
// Get and set the minidump path. |
|||
string dump_path() const { return dump_path_; } |
|||
void set_dump_path(const string& dump_path) { |
|||
dump_path_ = dump_path; |
|||
dump_path_c_ = dump_path_.c_str(); |
|||
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. |
|||
} |
|||
|
|||
private: |
|||
// Install the SIG exception handlers. |
|||
bool InstallHandlers(); |
|||
|
|||
// Uninstall the SIG exception handlers. |
|||
bool UninstallHandlers(); |
|||
|
|||
// Setup the handler thread, and if |install_handler| is true, install the |
|||
// mach exception port handler |
|||
bool Setup(); |
|||
|
|||
// Uninstall the mach exception handler (if any) and terminate the helper |
|||
// thread |
|||
bool Teardown(); |
|||
|
|||
// All minidump writing goes through this one routine. |
|||
// |task_context| can be NULL. If not, it will be used to retrieve the |
|||
// context of the current thread, instead of using |thread_get_state|. |
|||
bool WriteMinidumpWithException(int exception_type, |
|||
int exception_code, |
|||
int exception_subcode, |
|||
breakpad_ucontext_t* task_context, |
|||
mach_port_t thread_name, |
|||
bool exit_after_write, |
|||
bool report_current_thread); |
|||
|
|||
// Signal handler for SIG exceptions. |
|||
static void SignalHandler(int sig, siginfo_t* info, void* uc); |
|||
|
|||
// disallow copy ctor and operator= |
|||
explicit ExceptionHandler(const ExceptionHandler&); |
|||
void operator=(const ExceptionHandler&); |
|||
|
|||
// Generates a new ID and stores it in next_minidump_id_, and stores the |
|||
// path of the next minidump to be written in next_minidump_path_. |
|||
void UpdateNextID(); |
|||
|
|||
// The destination directory for the minidump |
|||
string dump_path_; |
|||
|
|||
// The basename of the next minidump w/o extension |
|||
string next_minidump_id_; |
|||
|
|||
// The full path to the next minidump to be written, including extension |
|||
string next_minidump_path_; |
|||
|
|||
// Pointers to the UTF-8 versions of above |
|||
const char* dump_path_c_; |
|||
const char* next_minidump_id_c_; |
|||
const char* next_minidump_path_c_; |
|||
|
|||
// The callback function and pointer to be passed back after the minidump |
|||
// has been written |
|||
FilterCallback filter_; |
|||
MinidumpCallback callback_; |
|||
void* callback_context_; |
|||
|
|||
// The callback function to be passed back when we don't want a minidump |
|||
// file to be written |
|||
DirectCallback directCallback_; |
|||
|
|||
// True, if we've installed the exception handler |
|||
bool installed_exception_handler_; |
|||
|
|||
// True, if we're in the process of uninstalling the exception handler and |
|||
// the thread. |
|||
bool is_in_teardown_; |
|||
}; |
|||
|
|||
} // namespace google_breakpad |
|||
|
|||
#endif // CLIENT_IOS_HANDLER_EXCEPTION_HANDLER_NO_MACH_H__ |
|||
@ -0,0 +1,73 @@ |
|||
// Copyright 2012 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
// ios_exception_minidump_generator.h: Create a fake minidump from a |
|||
// NSException. |
|||
|
|||
#ifndef CLIENT_IOS_HANDLER_IOS_EXCEPTION_MINIDUMP_GENERATOR_H_ |
|||
#define CLIENT_IOS_HANDLER_IOS_EXCEPTION_MINIDUMP_GENERATOR_H_ |
|||
|
|||
#include <Foundation/Foundation.h> |
|||
|
|||
#include "client/mac/handler/minidump_generator.h" |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
class IosExceptionMinidumpGenerator : public MinidumpGenerator { |
|||
public: |
|||
explicit IosExceptionMinidumpGenerator(NSException* exception); |
|||
virtual ~IosExceptionMinidumpGenerator(); |
|||
|
|||
protected: |
|||
virtual bool WriteExceptionStream(MDRawDirectory* exception_stream); |
|||
virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread* thread); |
|||
|
|||
private: |
|||
|
|||
// Get the crashing program counter from the exception. |
|||
uintptr_t GetPCFromException(); |
|||
|
|||
// Get the crashing link register from the exception. |
|||
uintptr_t GetLRFromException(); |
|||
|
|||
// Write a virtual thread context for the crashing site. |
|||
bool WriteCrashingContext(MDLocationDescriptor* register_location); |
|||
// Per-CPU implementations of the above method. |
|||
#ifdef HAS_ARM_SUPPORT |
|||
bool WriteCrashingContextARM(MDLocationDescriptor* register_location); |
|||
#endif |
|||
#ifdef HAS_ARM64_SUPPORT |
|||
bool WriteCrashingContextARM64(MDLocationDescriptor* register_location); |
|||
#endif |
|||
|
|||
NSArray* return_addresses_; |
|||
}; |
|||
|
|||
} // namespace google_breakpad |
|||
|
|||
#endif // CLIENT_IOS_HANDLER_IOS_EXCEPTION_MINIDUMP_GENERATOR_H_ |
|||
@ -0,0 +1,209 @@ |
|||
// Copyright 2012 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#include "client/ios/handler/ios_exception_minidump_generator.h" |
|||
|
|||
#include <pthread.h> |
|||
|
|||
#include "google_breakpad/common/minidump_cpu_arm.h" |
|||
#include "google_breakpad/common/minidump_cpu_arm64.h" |
|||
#include "google_breakpad/common/minidump_exception_mac.h" |
|||
#include "client/minidump_file_writer-inl.h" |
|||
#include "common/scoped_ptr.h" |
|||
|
|||
#if defined(HAS_ARM_SUPPORT) && defined(HAS_ARM64_SUPPORT) |
|||
#error "This file should be compiled for only one architecture at a time" |
|||
#endif |
|||
|
|||
namespace { |
|||
|
|||
const int kExceptionType = EXC_SOFTWARE; |
|||
const int kExceptionCode = MD_EXCEPTION_CODE_MAC_NS_EXCEPTION; |
|||
|
|||
#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) |
|||
const uintptr_t kExpectedFinalFp = sizeof(uintptr_t); |
|||
const uintptr_t kExpectedFinalSp = 0; |
|||
|
|||
// Append the given value to the sp position of the stack represented |
|||
// by memory. |
|||
void AppendToMemory(uint8_t* memory, uintptr_t sp, uintptr_t data) { |
|||
memcpy(memory + sp, &data, sizeof(data)); |
|||
} |
|||
#endif |
|||
|
|||
} // namespace |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
IosExceptionMinidumpGenerator::IosExceptionMinidumpGenerator( |
|||
NSException* exception) |
|||
: MinidumpGenerator(mach_task_self(), 0) { |
|||
return_addresses_ = [[exception callStackReturnAddresses] retain]; |
|||
SetExceptionInformation(kExceptionType, |
|||
kExceptionCode, |
|||
0, |
|||
pthread_mach_thread_np(pthread_self())); |
|||
} |
|||
|
|||
IosExceptionMinidumpGenerator::~IosExceptionMinidumpGenerator() { |
|||
[return_addresses_ release]; |
|||
} |
|||
|
|||
bool IosExceptionMinidumpGenerator::WriteCrashingContext( |
|||
MDLocationDescriptor* register_location) { |
|||
#ifdef HAS_ARM_SUPPORT |
|||
return WriteCrashingContextARM(register_location); |
|||
#elif defined(HAS_ARM64_SUPPORT) |
|||
return WriteCrashingContextARM64(register_location); |
|||
#else |
|||
assert(false); |
|||
return false; |
|||
#endif |
|||
} |
|||
|
|||
#ifdef HAS_ARM_SUPPORT |
|||
bool IosExceptionMinidumpGenerator::WriteCrashingContextARM( |
|||
MDLocationDescriptor* register_location) { |
|||
TypedMDRVA<MDRawContextARM> context(&writer_); |
|||
if (!context.Allocate()) |
|||
return false; |
|||
*register_location = context.location(); |
|||
MDRawContextARM* context_ptr = context.get(); |
|||
memset(context_ptr, 0, sizeof(MDRawContextARM)); |
|||
context_ptr->context_flags = MD_CONTEXT_ARM_FULL; |
|||
context_ptr->iregs[MD_CONTEXT_ARM_REG_IOS_FP] = kExpectedFinalFp; // FP |
|||
context_ptr->iregs[MD_CONTEXT_ARM_REG_SP] = kExpectedFinalSp; // SP |
|||
context_ptr->iregs[MD_CONTEXT_ARM_REG_LR] = GetLRFromException(); // LR |
|||
context_ptr->iregs[MD_CONTEXT_ARM_REG_PC] = GetPCFromException(); // PC |
|||
return true; |
|||
} |
|||
#endif |
|||
|
|||
#ifdef HAS_ARM64_SUPPORT |
|||
bool IosExceptionMinidumpGenerator::WriteCrashingContextARM64( |
|||
MDLocationDescriptor* register_location) { |
|||
TypedMDRVA<MDRawContextARM64_Old> context(&writer_); |
|||
if (!context.Allocate()) |
|||
return false; |
|||
*register_location = context.location(); |
|||
MDRawContextARM64_Old* context_ptr = context.get(); |
|||
memset(context_ptr, 0, sizeof(*context_ptr)); |
|||
context_ptr->context_flags = MD_CONTEXT_ARM64_FULL_OLD; |
|||
context_ptr->iregs[MD_CONTEXT_ARM64_REG_FP] = kExpectedFinalFp; // FP |
|||
context_ptr->iregs[MD_CONTEXT_ARM64_REG_SP] = kExpectedFinalSp; // SP |
|||
context_ptr->iregs[MD_CONTEXT_ARM64_REG_LR] = GetLRFromException(); // LR |
|||
context_ptr->iregs[MD_CONTEXT_ARM64_REG_PC] = GetPCFromException(); // PC |
|||
return true; |
|||
} |
|||
#endif |
|||
|
|||
uintptr_t IosExceptionMinidumpGenerator::GetPCFromException() { |
|||
return [[return_addresses_ objectAtIndex:0] unsignedIntegerValue]; |
|||
} |
|||
|
|||
uintptr_t IosExceptionMinidumpGenerator::GetLRFromException() { |
|||
return [[return_addresses_ objectAtIndex:1] unsignedIntegerValue]; |
|||
} |
|||
|
|||
bool IosExceptionMinidumpGenerator::WriteExceptionStream( |
|||
MDRawDirectory* exception_stream) { |
|||
#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) |
|||
TypedMDRVA<MDRawExceptionStream> exception(&writer_); |
|||
|
|||
if (!exception.Allocate()) |
|||
return false; |
|||
|
|||
exception_stream->stream_type = MD_EXCEPTION_STREAM; |
|||
exception_stream->location = exception.location(); |
|||
MDRawExceptionStream* exception_ptr = exception.get(); |
|||
exception_ptr->thread_id = pthread_mach_thread_np(pthread_self()); |
|||
|
|||
// This naming is confusing, but it is the proper translation from |
|||
// mach naming to minidump naming. |
|||
exception_ptr->exception_record.exception_code = kExceptionType; |
|||
exception_ptr->exception_record.exception_flags = kExceptionCode; |
|||
|
|||
if (!WriteCrashingContext(&exception_ptr->thread_context)) |
|||
return false; |
|||
|
|||
exception_ptr->exception_record.exception_address = GetPCFromException(); |
|||
return true; |
|||
#else |
|||
return MinidumpGenerator::WriteExceptionStream(exception_stream); |
|||
#endif |
|||
} |
|||
|
|||
bool IosExceptionMinidumpGenerator::WriteThreadStream(mach_port_t thread_id, |
|||
MDRawThread* thread) { |
|||
#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) |
|||
if (pthread_mach_thread_np(pthread_self()) != thread_id) |
|||
return MinidumpGenerator::WriteThreadStream(thread_id, thread); |
|||
|
|||
size_t frame_count = [return_addresses_ count]; |
|||
if (frame_count == 0) |
|||
return false; |
|||
UntypedMDRVA memory(&writer_); |
|||
size_t pointer_size = sizeof(uintptr_t); |
|||
size_t frame_record_size = 2 * pointer_size; |
|||
size_t stack_size = frame_record_size * (frame_count - 1) + pointer_size; |
|||
if (!memory.Allocate(stack_size)) |
|||
return false; |
|||
scoped_array<uint8_t> stack_memory(new uint8_t[stack_size]); |
|||
uintptr_t sp = stack_size - pointer_size; |
|||
uintptr_t fp = 0; |
|||
uintptr_t lr = 0; |
|||
for (size_t current_frame = frame_count - 1; |
|||
current_frame > 0; |
|||
--current_frame) { |
|||
AppendToMemory(stack_memory.get(), sp, lr); |
|||
sp -= pointer_size; |
|||
AppendToMemory(stack_memory.get(), sp, fp); |
|||
fp = sp; |
|||
sp -= pointer_size; |
|||
lr = [[return_addresses_ objectAtIndex:current_frame] unsignedIntegerValue]; |
|||
} |
|||
if (!memory.Copy(stack_memory.get(), stack_size)) |
|||
return false; |
|||
assert(sp == kExpectedFinalSp); |
|||
assert(fp == kExpectedFinalFp); |
|||
assert(lr == GetLRFromException()); |
|||
thread->stack.start_of_memory_range = sp; |
|||
thread->stack.memory = memory.location(); |
|||
memory_blocks_.push_back(thread->stack); |
|||
|
|||
if (!WriteCrashingContext(&thread->thread_context)) |
|||
return false; |
|||
|
|||
thread->thread_id = thread_id; |
|||
return true; |
|||
#else |
|||
return MinidumpGenerator::WriteThreadStream(thread_id, thread); |
|||
#endif |
|||
} |
|||
|
|||
} // namespace google_breakpad |
|||
@ -0,0 +1,52 @@ |
|||
// Copyright 2010 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ |
|||
#define CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
class CrashGenerationServer; |
|||
|
|||
class ClientInfo { |
|||
public: |
|||
ClientInfo(pid_t pid, CrashGenerationServer* crash_server) |
|||
: crash_server_(crash_server), |
|||
pid_(pid) {} |
|||
|
|||
CrashGenerationServer* crash_server() const { return crash_server_; } |
|||
pid_t pid() const { return pid_; } |
|||
|
|||
private: |
|||
CrashGenerationServer* crash_server_; |
|||
pid_t pid_; |
|||
}; |
|||
|
|||
} |
|||
|
|||
#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ |
|||
@ -0,0 +1,108 @@ |
|||
// Copyright 2010 Google LLC
|
|||
//
|
|||
// Redistribution and use in source and binary forms, with or without
|
|||
// modification, are permitted provided that the following conditions are
|
|||
// met:
|
|||
//
|
|||
// * Redistributions of source code must retain the above copyright
|
|||
// notice, this list of conditions and the following disclaimer.
|
|||
// * Redistributions in binary form must reproduce the above
|
|||
// copyright notice, this list of conditions and the following disclaimer
|
|||
// in the documentation and/or other materials provided with the
|
|||
// distribution.
|
|||
// * Neither the name of Google LLC nor the names of its
|
|||
// contributors may be used to endorse or promote products derived from
|
|||
// this software without specific prior written permission.
|
|||
//
|
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
#ifdef HAVE_CONFIG_H
|
|||
#include <config.h> // Must come first
|
|||
#endif
|
|||
|
|||
#include "client/linux/crash_generation/crash_generation_client.h"
|
|||
|
|||
#include <stdio.h>
|
|||
#include <sys/socket.h>
|
|||
#include <sys/types.h>
|
|||
|
|||
#include <algorithm>
|
|||
|
|||
#include "common/linux/eintr_wrapper.h"
|
|||
#include "common/linux/ignore_ret.h"
|
|||
#include "third_party/lss/linux_syscall_support.h"
|
|||
|
|||
namespace google_breakpad { |
|||
|
|||
namespace { |
|||
|
|||
class CrashGenerationClientImpl : public CrashGenerationClient { |
|||
public: |
|||
explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {} |
|||
CrashGenerationClientImpl(const CrashGenerationClientImpl&) = delete; |
|||
void operator=(const CrashGenerationClientImpl&) = delete; |
|||
~CrashGenerationClientImpl() override = default; |
|||
|
|||
bool RequestDump(const void* blob, size_t blob_size) override { |
|||
int fds[2]; |
|||
if (sys_pipe(fds) < 0) |
|||
return false; |
|||
static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int)); |
|||
|
|||
struct kernel_iovec iov; |
|||
iov.iov_base = const_cast<void*>(blob); |
|||
iov.iov_len = blob_size; |
|||
|
|||
struct kernel_msghdr msg = { 0 }; |
|||
msg.msg_iov = &iov; |
|||
msg.msg_iovlen = 1; |
|||
char cmsg[kControlMsgSize] = ""; |
|||
msg.msg_control = cmsg; |
|||
msg.msg_controllen = sizeof(cmsg); |
|||
|
|||
struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); |
|||
hdr->cmsg_level = SOL_SOCKET; |
|||
hdr->cmsg_type = SCM_RIGHTS; |
|||
hdr->cmsg_len = CMSG_LEN(sizeof(int)); |
|||
int* p = reinterpret_cast<int*>(CMSG_DATA(hdr)); |
|||
*p = fds[1]; |
|||
|
|||
ssize_t ret = HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0)); |
|||
sys_close(fds[1]); |
|||
if (ret < 0) { |
|||
sys_close(fds[0]); |
|||
return false; |
|||
} |
|||
|
|||
// Wait for an ACK from the server.
|
|||
char b; |
|||
IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1))); |
|||
sys_close(fds[0]); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
private: |
|||
int server_fd_; |
|||
}; |
|||
|
|||
} // namespace
|
|||
|
|||
// static
|
|||
CrashGenerationClient* CrashGenerationClient::TryCreate(int server_fd) { |
|||
if (server_fd < 0) |
|||
return NULL; |
|||
return new CrashGenerationClientImpl(server_fd); |
|||
} |
|||
|
|||
} // namespace google_breakpad
|
|||
@ -0,0 +1,61 @@ |
|||
// Copyright 2010 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ |
|||
#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ |
|||
|
|||
#include <stddef.h> |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
// CrashGenerationClient is an interface for implementing out-of-process crash |
|||
// dumping. The default implementation, accessed via the TryCreate() factory, |
|||
// works in conjunction with the CrashGenerationServer to generate a minidump |
|||
// via a remote process. |
|||
class CrashGenerationClient { |
|||
public: |
|||
CrashGenerationClient() = default; |
|||
CrashGenerationClient(const CrashGenerationClient&) = delete; |
|||
void operator=(const CrashGenerationClient&) = delete; |
|||
virtual ~CrashGenerationClient() = default; |
|||
|
|||
// Request the crash server to generate a dump. |blob| is an opaque |
|||
// CrashContext pointer from exception_handler.h. |
|||
// Returns true if the dump was successful; false otherwise. |
|||
virtual bool RequestDump(const void* blob, size_t blob_size) = 0; |
|||
|
|||
// Returns a new CrashGenerationClient if |server_fd| is valid and |
|||
// connects to a CrashGenerationServer. Otherwise, return NULL. |
|||
// The returned CrashGenerationClient* is owned by the caller of |
|||
// this function. |
|||
static CrashGenerationClient* TryCreate(int server_fd); |
|||
}; |
|||
|
|||
} // namespace google_breakpad |
|||
|
|||
#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ |
|||
@ -0,0 +1,336 @@ |
|||
// Copyright 2010 Google LLC
|
|||
//
|
|||
// Redistribution and use in source and binary forms, with or without
|
|||
// modification, are permitted provided that the following conditions are
|
|||
// met:
|
|||
//
|
|||
// * Redistributions of source code must retain the above copyright
|
|||
// notice, this list of conditions and the following disclaimer.
|
|||
// * Redistributions in binary form must reproduce the above
|
|||
// copyright notice, this list of conditions and the following disclaimer
|
|||
// in the documentation and/or other materials provided with the
|
|||
// distribution.
|
|||
// * Neither the name of Google LLC nor the names of its
|
|||
// contributors may be used to endorse or promote products derived from
|
|||
// this software without specific prior written permission.
|
|||
//
|
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
#ifdef HAVE_CONFIG_H
|
|||
#include <config.h> // Must come first
|
|||
#endif
|
|||
|
|||
#include <assert.h>
|
|||
#include <dirent.h>
|
|||
#include <fcntl.h>
|
|||
#include <limits.h>
|
|||
#include <poll.h>
|
|||
#include <stdio.h>
|
|||
#include <string.h>
|
|||
#include <sys/socket.h>
|
|||
#include <sys/stat.h>
|
|||
#include <sys/types.h>
|
|||
#include <unistd.h>
|
|||
|
|||
#include <vector>
|
|||
|
|||
#include "client/linux/crash_generation/crash_generation_server.h"
|
|||
#include "client/linux/crash_generation/client_info.h"
|
|||
#include "client/linux/handler/exception_handler.h"
|
|||
#include "client/linux/minidump_writer/minidump_writer.h"
|
|||
#include "common/linux/eintr_wrapper.h"
|
|||
#include "common/linux/guid_creator.h"
|
|||
#include "common/linux/safe_readlink.h"
|
|||
|
|||
static const char kCommandQuit = 'x'; |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
CrashGenerationServer::CrashGenerationServer( |
|||
const int listen_fd, |
|||
OnClientDumpRequestCallback dump_callback, |
|||
void* dump_context, |
|||
OnClientExitingCallback exit_callback, |
|||
void* exit_context, |
|||
bool generate_dumps, |
|||
const string* dump_path) : |
|||
server_fd_(listen_fd), |
|||
dump_callback_(dump_callback), |
|||
dump_context_(dump_context), |
|||
exit_callback_(exit_callback), |
|||
exit_context_(exit_context), |
|||
generate_dumps_(generate_dumps), |
|||
started_(false) |
|||
{ |
|||
if (dump_path) |
|||
dump_dir_ = *dump_path; |
|||
else |
|||
dump_dir_ = "/tmp"; |
|||
} |
|||
|
|||
CrashGenerationServer::~CrashGenerationServer() |
|||
{ |
|||
if (started_) |
|||
Stop(); |
|||
} |
|||
|
|||
bool |
|||
CrashGenerationServer::Start() |
|||
{ |
|||
if (started_ || 0 > server_fd_) |
|||
return false; |
|||
|
|||
int control_pipe[2]; |
|||
if (pipe(control_pipe)) |
|||
return false; |
|||
|
|||
if (fcntl(control_pipe[0], F_SETFD, FD_CLOEXEC)) |
|||
return false; |
|||
if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC)) |
|||
return false; |
|||
|
|||
if (fcntl(control_pipe[0], F_SETFL, O_NONBLOCK)) |
|||
return false; |
|||
|
|||
control_pipe_in_ = control_pipe[0]; |
|||
control_pipe_out_ = control_pipe[1]; |
|||
|
|||
if (pthread_create(&thread_, NULL, |
|||
ThreadMain, reinterpret_cast<void*>(this))) |
|||
return false; |
|||
|
|||
started_ = true; |
|||
return true; |
|||
} |
|||
|
|||
void |
|||
CrashGenerationServer::Stop() |
|||
{ |
|||
assert(pthread_self() != thread_); |
|||
|
|||
if (!started_) |
|||
return; |
|||
|
|||
HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1)); |
|||
|
|||
void* dummy; |
|||
pthread_join(thread_, &dummy); |
|||
|
|||
close(control_pipe_in_); |
|||
close(control_pipe_out_); |
|||
|
|||
started_ = false; |
|||
} |
|||
|
|||
//static
|
|||
bool |
|||
CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd) |
|||
{ |
|||
int fds[2]; |
|||
|
|||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds)) |
|||
return false; |
|||
|
|||
static const int on = 1; |
|||
// Enable passcred on the server end of the socket
|
|||
if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) |
|||
return false; |
|||
|
|||
if (fcntl(fds[1], F_SETFL, O_NONBLOCK)) |
|||
return false; |
|||
if (fcntl(fds[1], F_SETFD, FD_CLOEXEC)) |
|||
return false; |
|||
|
|||
*client_fd = fds[0]; |
|||
*server_fd = fds[1]; |
|||
return true; |
|||
} |
|||
|
|||
// The following methods/functions execute on the server thread
|
|||
|
|||
void |
|||
CrashGenerationServer::Run() |
|||
{ |
|||
struct pollfd pollfds[2]; |
|||
memset(&pollfds, 0, sizeof(pollfds)); |
|||
|
|||
pollfds[0].fd = server_fd_; |
|||
pollfds[0].events = POLLIN; |
|||
|
|||
pollfds[1].fd = control_pipe_in_; |
|||
pollfds[1].events = POLLIN; |
|||
|
|||
while (true) { |
|||
// infinite timeout
|
|||
int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1); |
|||
if (-1 == nevents) { |
|||
if (EINTR == errno) { |
|||
continue; |
|||
} else { |
|||
return; |
|||
} |
|||
} |
|||
|
|||
if (pollfds[0].revents && !ClientEvent(pollfds[0].revents)) |
|||
return; |
|||
|
|||
if (pollfds[1].revents && !ControlEvent(pollfds[1].revents)) |
|||
return; |
|||
} |
|||
} |
|||
|
|||
bool |
|||
CrashGenerationServer::ClientEvent(short revents) |
|||
{ |
|||
if (POLLHUP & revents) |
|||
return false; |
|||
assert(POLLIN & revents); |
|||
|
|||
// A process has crashed and has signaled us by writing a datagram
|
|||
// to the death signal socket. The datagram contains the crash context needed
|
|||
// for writing the minidump as well as a file descriptor and a credentials
|
|||
// block so that they can't lie about their pid.
|
|||
|
|||
// The length of the control message:
|
|||
static const unsigned kControlMsgSize = |
|||
CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); |
|||
// The length of the regular payload:
|
|||
static const unsigned kCrashContextSize = |
|||
sizeof(google_breakpad::ExceptionHandler::CrashContext); |
|||
|
|||
struct msghdr msg = {0}; |
|||
struct iovec iov[1]; |
|||
char crash_context[kCrashContextSize]; |
|||
char control[kControlMsgSize]; |
|||
const ssize_t expected_msg_size = sizeof(crash_context); |
|||
|
|||
iov[0].iov_base = crash_context; |
|||
iov[0].iov_len = sizeof(crash_context); |
|||
msg.msg_iov = iov; |
|||
msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]); |
|||
msg.msg_control = control; |
|||
msg.msg_controllen = kControlMsgSize; |
|||
|
|||
const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0)); |
|||
if (msg_size != expected_msg_size) |
|||
return true; |
|||
|
|||
if (msg.msg_controllen != kControlMsgSize || |
|||
msg.msg_flags & ~MSG_TRUNC) |
|||
return true; |
|||
|
|||
// Walk the control payload and extract the file descriptor and validated pid.
|
|||
pid_t crashing_pid = -1; |
|||
int signal_fd = -1; |
|||
for (struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); hdr; |
|||
hdr = CMSG_NXTHDR(&msg, hdr)) { |
|||
if (hdr->cmsg_level != SOL_SOCKET) |
|||
continue; |
|||
if (hdr->cmsg_type == SCM_RIGHTS) { |
|||
const unsigned len = hdr->cmsg_len - |
|||
(((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr); |
|||
assert(len % sizeof(int) == 0u); |
|||
const unsigned num_fds = len / sizeof(int); |
|||
if (num_fds > 1 || num_fds == 0) { |
|||
// A nasty process could try and send us too many descriptors and
|
|||
// force a leak.
|
|||
for (unsigned i = 0; i < num_fds; ++i) |
|||
close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]); |
|||
return true; |
|||
} else { |
|||
signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0]; |
|||
} |
|||
} else if (hdr->cmsg_type == SCM_CREDENTIALS) { |
|||
const struct ucred* cred = |
|||
reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); |
|||
crashing_pid = cred->pid; |
|||
} |
|||
} |
|||
|
|||
if (crashing_pid == -1 || signal_fd == -1) { |
|||
if (signal_fd != -1) |
|||
close(signal_fd); |
|||
return true; |
|||
} |
|||
|
|||
string minidump_filename; |
|||
if (!MakeMinidumpFilename(minidump_filename)) |
|||
return true; |
|||
|
|||
if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), |
|||
crashing_pid, crash_context, |
|||
kCrashContextSize)) { |
|||
close(signal_fd); |
|||
return true; |
|||
} |
|||
|
|||
if (dump_callback_) { |
|||
ClientInfo info(crashing_pid, this); |
|||
|
|||
dump_callback_(dump_context_, &info, &minidump_filename); |
|||
} |
|||
|
|||
// Send the done signal to the process: it can exit now.
|
|||
// (Closing this will make the child's sys_read unblock and return 0.)
|
|||
close(signal_fd); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool |
|||
CrashGenerationServer::ControlEvent(short revents) |
|||
{ |
|||
if (POLLHUP & revents) |
|||
return false; |
|||
assert(POLLIN & revents); |
|||
|
|||
char command; |
|||
if (read(control_pipe_in_, &command, 1)) |
|||
return false; |
|||
|
|||
switch (command) { |
|||
case kCommandQuit: |
|||
return false; |
|||
default: |
|||
assert(0); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool |
|||
CrashGenerationServer::MakeMinidumpFilename(string& outFilename) |
|||
{ |
|||
GUID guid; |
|||
char guidString[kGUIDStringLength+1]; |
|||
|
|||
if (!(CreateGUID(&guid) |
|||
&& GUIDToString(&guid, guidString, sizeof(guidString)))) |
|||
return false; |
|||
|
|||
char path[PATH_MAX]; |
|||
snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString); |
|||
|
|||
outFilename = path; |
|||
return true; |
|||
} |
|||
|
|||
// static
|
|||
void* |
|||
CrashGenerationServer::ThreadMain(void* arg) |
|||
{ |
|||
reinterpret_cast<CrashGenerationServer*>(arg)->Run(); |
|||
return NULL; |
|||
} |
|||
|
|||
} // namespace google_breakpad
|
|||
@ -0,0 +1,134 @@ |
|||
// Copyright 2010 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ |
|||
#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ |
|||
|
|||
#include <pthread.h> |
|||
|
|||
#include <string> |
|||
|
|||
#include "common/using_std_string.h" |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
class ClientInfo; |
|||
|
|||
class CrashGenerationServer { |
|||
public: |
|||
// WARNING: callbacks may be invoked on a different thread |
|||
// than that which creates the CrashGenerationServer. They must |
|||
// be thread safe. |
|||
typedef void (*OnClientDumpRequestCallback)(void* context, |
|||
const ClientInfo* client_info, |
|||
const string* file_path); |
|||
|
|||
typedef void (*OnClientExitingCallback)(void* context, |
|||
const ClientInfo* client_info); |
|||
|
|||
// Create an instance with the given parameters. |
|||
// |
|||
// Parameter listen_fd: The server fd created by CreateReportChannel(). |
|||
// Parameter dump_callback: Callback for a client crash dump request. |
|||
// Parameter dump_context: Context for client crash dump request callback. |
|||
// Parameter exit_callback: Callback for client process exit. |
|||
// Parameter exit_context: Context for client exit callback. |
|||
// Parameter generate_dumps: Whether to automatically generate dumps. |
|||
// Client code of this class might want to generate dumps explicitly |
|||
// in the crash dump request callback. In that case, false can be |
|||
// passed for this parameter. |
|||
// Parameter dump_path: Path for generating dumps; required only if true is |
|||
// passed for generateDumps parameter; NULL can be passed otherwise. |
|||
CrashGenerationServer(const int listen_fd, |
|||
OnClientDumpRequestCallback dump_callback, |
|||
void* dump_context, |
|||
OnClientExitingCallback exit_callback, |
|||
void* exit_context, |
|||
bool generate_dumps, |
|||
const string* dump_path); |
|||
|
|||
~CrashGenerationServer(); |
|||
|
|||
// Perform initialization steps needed to start listening to clients. |
|||
// |
|||
// Return true if initialization is successful; false otherwise. |
|||
bool Start(); |
|||
|
|||
// Stop the server. |
|||
void Stop(); |
|||
|
|||
// Create a "channel" that can be used by clients to report crashes |
|||
// to a CrashGenerationServer. |*server_fd| should be passed to |
|||
// this class's constructor, and |*client_fd| should be passed to |
|||
// the ExceptionHandler constructor in the client process. |
|||
static bool CreateReportChannel(int* server_fd, int* client_fd); |
|||
|
|||
private: |
|||
// Run the server's event loop |
|||
void Run(); |
|||
|
|||
// Invoked when an child process (client) event occurs |
|||
// Returning true => "keep running", false => "exit loop" |
|||
bool ClientEvent(short revents); |
|||
|
|||
// Invoked when the controlling thread (main) event occurs |
|||
// Returning true => "keep running", false => "exit loop" |
|||
bool ControlEvent(short revents); |
|||
|
|||
// Return a unique filename at which a minidump can be written |
|||
bool MakeMinidumpFilename(string& outFilename); |
|||
|
|||
// Trampoline to |Run()| |
|||
static void* ThreadMain(void* arg); |
|||
|
|||
int server_fd_; |
|||
|
|||
OnClientDumpRequestCallback dump_callback_; |
|||
void* dump_context_; |
|||
|
|||
OnClientExitingCallback exit_callback_; |
|||
void* exit_context_; |
|||
|
|||
bool generate_dumps_; |
|||
|
|||
string dump_dir_; |
|||
|
|||
bool started_; |
|||
|
|||
pthread_t thread_; |
|||
int control_pipe_in_; |
|||
int control_pipe_out_; |
|||
|
|||
// disable these |
|||
CrashGenerationServer(const CrashGenerationServer&); |
|||
CrashGenerationServer& operator=(const CrashGenerationServer&); |
|||
}; |
|||
|
|||
} // namespace google_breakpad |
|||
|
|||
#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ |
|||
@ -0,0 +1,3 @@ |
|||
MODULE Linux x86 B8CFDE93002D54DA1900A40AA1BD67690 linux-gate.so |
|||
PUBLIC 400 0 __kernel_vsyscall |
|||
STACK WIN 4 400 100 1 1 0 0 0 0 0 1 |
|||
@ -0,0 +1,3 @@ |
|||
MODULE Linux x86 4FBDA58B5A1DF5A379E3CF19A235EA090 linux-gate.so |
|||
PUBLIC 400 0 __kernel_vsyscall |
|||
STACK WIN 4 400 200 3 3 0 0 0 0 0 1 |
|||
@ -0,0 +1,73 @@ |
|||
// Copyright 2014 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ |
|||
#define CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ |
|||
|
|||
#include <limits.h> |
|||
#include <list> |
|||
#include <stdint.h> |
|||
|
|||
#include "google_breakpad/common/minidump_format.h" |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
// One of these is produced for each mapping in the process (i.e. line in |
|||
// /proc/$x/maps). |
|||
struct MappingInfo { |
|||
// On Android, relocation packing can mean that the reported start |
|||
// address of the mapping must be adjusted by a bias in order to |
|||
// compensate for the compression of the relocation section. The |
|||
// following two members hold (after LateInit) the adjusted mapping |
|||
// range. See crbug.com/606972 for more information. |
|||
uintptr_t start_addr; |
|||
size_t size; |
|||
// When Android relocation packing causes |start_addr| and |size| to |
|||
// be modified with a load bias, we need to remember the unbiased |
|||
// address range. The following structure holds the original mapping |
|||
// address range as reported by the operating system. |
|||
struct { |
|||
uintptr_t start_addr; |
|||
uintptr_t end_addr; |
|||
} system_mapping_info; |
|||
size_t offset; // offset into the backed file. |
|||
bool exec; // true if the mapping has the execute bit set. |
|||
char name[NAME_MAX]; |
|||
}; |
|||
|
|||
struct MappingEntry { |
|||
MappingInfo first; |
|||
uint8_t second[sizeof(MDGUID)]; |
|||
}; |
|||
|
|||
// A list of <MappingInfo, GUID> |
|||
typedef std::list<MappingEntry> MappingList; |
|||
|
|||
} // namespace google_breakpad |
|||
|
|||
#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ |
|||
@ -0,0 +1,60 @@ |
|||
// Copyright 2014 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H |
|||
#define CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H |
|||
|
|||
#include "google_breakpad/common/minidump_format.h" |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
#if defined(__i386__) |
|||
typedef MDRawContextX86 RawContextCPU; |
|||
#elif defined(__x86_64) |
|||
typedef MDRawContextAMD64 RawContextCPU; |
|||
#elif defined(__ARM_EABI__) |
|||
typedef MDRawContextARM RawContextCPU; |
|||
#elif defined(__aarch64__) |
|||
typedef MDRawContextARM64_Old RawContextCPU; |
|||
#elif defined(__mips__) |
|||
typedef MDRawContextMIPS RawContextCPU; |
|||
#elif defined(__riscv) |
|||
# if __riscv_xlen == 32 |
|||
typedef MDRawContextRISCV RawContextCPU; |
|||
# elif __riscv_xlen == 64 |
|||
typedef MDRawContextRISCV64 RawContextCPU; |
|||
# else |
|||
# error "Unexpected __riscv_xlen" |
|||
# endif |
|||
#else |
|||
#error "This code has not been ported to your platform yet." |
|||
#endif |
|||
|
|||
} // namespace google_breakpad |
|||
|
|||
#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H |
|||
@ -0,0 +1,395 @@ |
|||
// Copyright 2014 Google LLC
|
|||
//
|
|||
// Redistribution and use in source and binary forms, with or without
|
|||
// modification, are permitted provided that the following conditions are
|
|||
// met:
|
|||
//
|
|||
// * Redistributions of source code must retain the above copyright
|
|||
// notice, this list of conditions and the following disclaimer.
|
|||
// * Redistributions in binary form must reproduce the above
|
|||
// copyright notice, this list of conditions and the following disclaimer
|
|||
// in the documentation and/or other materials provided with the
|
|||
// distribution.
|
|||
// * Neither the name of Google LLC nor the names of its
|
|||
// contributors may be used to endorse or promote products derived from
|
|||
// this software without specific prior written permission.
|
|||
//
|
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
#ifdef HAVE_CONFIG_H
|
|||
#include <config.h> // Must come first
|
|||
#endif
|
|||
|
|||
#include "client/linux/dump_writer_common/thread_info.h"
|
|||
|
|||
#include <string.h>
|
|||
#include <assert.h>
|
|||
|
|||
#include "common/linux/linux_libc_support.h"
|
|||
#include "google_breakpad/common/minidump_format.h"
|
|||
|
|||
namespace { |
|||
|
|||
#if defined(__i386__)
|
|||
// Write a uint16_t to memory
|
|||
// out: memory location to write to
|
|||
// v: value to write.
|
|||
void U16(void* out, uint16_t v) { |
|||
my_memcpy(out, &v, sizeof(v)); |
|||
} |
|||
|
|||
// Write a uint32_t to memory
|
|||
// out: memory location to write to
|
|||
// v: value to write.
|
|||
void U32(void* out, uint32_t v) { |
|||
my_memcpy(out, &v, sizeof(v)); |
|||
} |
|||
#endif
|
|||
|
|||
} |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
#if defined(__i386__)
|
|||
|
|||
uintptr_t ThreadInfo::GetInstructionPointer() const { |
|||
return regs.eip; |
|||
} |
|||
|
|||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const { |
|||
out->context_flags = MD_CONTEXT_X86_ALL; |
|||
|
|||
out->dr0 = dregs[0]; |
|||
out->dr1 = dregs[1]; |
|||
out->dr2 = dregs[2]; |
|||
out->dr3 = dregs[3]; |
|||
// 4 and 5 deliberatly omitted because they aren't included in the minidump
|
|||
// format.
|
|||
out->dr6 = dregs[6]; |
|||
out->dr7 = dregs[7]; |
|||
|
|||
out->gs = regs.xgs; |
|||
out->fs = regs.xfs; |
|||
out->es = regs.xes; |
|||
out->ds = regs.xds; |
|||
|
|||
out->edi = regs.edi; |
|||
out->esi = regs.esi; |
|||
out->ebx = regs.ebx; |
|||
out->edx = regs.edx; |
|||
out->ecx = regs.ecx; |
|||
out->eax = regs.eax; |
|||
|
|||
out->ebp = regs.ebp; |
|||
out->eip = regs.eip; |
|||
out->cs = regs.xcs; |
|||
out->eflags = regs.eflags; |
|||
out->esp = regs.esp; |
|||
out->ss = regs.xss; |
|||
|
|||
out->float_save.control_word = fpregs.cwd; |
|||
out->float_save.status_word = fpregs.swd; |
|||
out->float_save.tag_word = fpregs.twd; |
|||
out->float_save.error_offset = fpregs.fip; |
|||
out->float_save.error_selector = fpregs.fcs; |
|||
out->float_save.data_offset = fpregs.foo; |
|||
out->float_save.data_selector = fpregs.fos; |
|||
|
|||
// 8 registers * 10 bytes per register.
|
|||
my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8); |
|||
|
|||
// This matches the Intel fpsave format.
|
|||
U16(out->extended_registers + 0, fpregs.cwd); |
|||
U16(out->extended_registers + 2, fpregs.swd); |
|||
U16(out->extended_registers + 4, fpregs.twd); |
|||
U16(out->extended_registers + 6, fpxregs.fop); |
|||
U32(out->extended_registers + 8, fpxregs.fip); |
|||
U16(out->extended_registers + 12, fpxregs.fcs); |
|||
U32(out->extended_registers + 16, fpregs.foo); |
|||
U16(out->extended_registers + 20, fpregs.fos); |
|||
U32(out->extended_registers + 24, fpxregs.mxcsr); |
|||
|
|||
my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128); |
|||
my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128); |
|||
} |
|||
|
|||
#elif defined(__x86_64)
|
|||
|
|||
uintptr_t ThreadInfo::GetInstructionPointer() const { |
|||
return regs.rip; |
|||
} |
|||
|
|||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const { |
|||
out->context_flags = MD_CONTEXT_AMD64_FULL | |
|||
MD_CONTEXT_AMD64_SEGMENTS; |
|||
|
|||
out->cs = regs.cs; |
|||
|
|||
out->ds = regs.ds; |
|||
out->es = regs.es; |
|||
out->fs = regs.fs; |
|||
out->gs = regs.gs; |
|||
|
|||
out->ss = regs.ss; |
|||
out->eflags = regs.eflags; |
|||
|
|||
out->dr0 = dregs[0]; |
|||
out->dr1 = dregs[1]; |
|||
out->dr2 = dregs[2]; |
|||
out->dr3 = dregs[3]; |
|||
// 4 and 5 deliberatly omitted because they aren't included in the minidump
|
|||
// format.
|
|||
out->dr6 = dregs[6]; |
|||
out->dr7 = dregs[7]; |
|||
|
|||
out->rax = regs.rax; |
|||
out->rcx = regs.rcx; |
|||
out->rdx = regs.rdx; |
|||
out->rbx = regs.rbx; |
|||
|
|||
out->rsp = regs.rsp; |
|||
|
|||
out->rbp = regs.rbp; |
|||
out->rsi = regs.rsi; |
|||
out->rdi = regs.rdi; |
|||
out->r8 = regs.r8; |
|||
out->r9 = regs.r9; |
|||
out->r10 = regs.r10; |
|||
out->r11 = regs.r11; |
|||
out->r12 = regs.r12; |
|||
out->r13 = regs.r13; |
|||
out->r14 = regs.r14; |
|||
out->r15 = regs.r15; |
|||
|
|||
out->rip = regs.rip; |
|||
|
|||
out->flt_save.control_word = fpregs.cwd; |
|||
out->flt_save.status_word = fpregs.swd; |
|||
out->flt_save.tag_word = fpregs.ftw; |
|||
out->flt_save.error_opcode = fpregs.fop; |
|||
out->flt_save.error_offset = fpregs.rip; |
|||
out->flt_save.error_selector = 0; // We don't have this.
|
|||
out->flt_save.data_offset = fpregs.rdp; |
|||
out->flt_save.data_selector = 0; // We don't have this.
|
|||
out->flt_save.mx_csr = fpregs.mxcsr; |
|||
out->flt_save.mx_csr_mask = fpregs.mxcr_mask; |
|||
|
|||
my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16); |
|||
my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16); |
|||
} |
|||
|
|||
#elif defined(__ARM_EABI__)
|
|||
|
|||
uintptr_t ThreadInfo::GetInstructionPointer() const { |
|||
return regs.uregs[15]; |
|||
} |
|||
|
|||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const { |
|||
out->context_flags = MD_CONTEXT_ARM_FULL; |
|||
|
|||
for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) |
|||
out->iregs[i] = regs.uregs[i]; |
|||
// No CPSR register in ThreadInfo(it's not accessible via ptrace)
|
|||
out->cpsr = 0; |
|||
#if !defined(__ANDROID__)
|
|||
out->float_save.fpscr = fpregs.fpsr | |
|||
(static_cast<uint64_t>(fpregs.fpcr) << 32); |
|||
// TODO: sort this out, actually collect floating point registers
|
|||
my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); |
|||
my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); |
|||
#endif
|
|||
} |
|||
|
|||
#elif defined(__aarch64__)
|
|||
|
|||
uintptr_t ThreadInfo::GetInstructionPointer() const { |
|||
return regs.pc; |
|||
} |
|||
|
|||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const { |
|||
out->context_flags = MD_CONTEXT_ARM64_FULL_OLD; |
|||
|
|||
out->cpsr = static_cast<uint32_t>(regs.pstate); |
|||
for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) |
|||
out->iregs[i] = regs.regs[i]; |
|||
out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp; |
|||
out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc; |
|||
|
|||
out->float_save.fpsr = fpregs.fpsr; |
|||
out->float_save.fpcr = fpregs.fpcr; |
|||
my_memcpy(&out->float_save.regs, &fpregs.vregs, |
|||
MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); |
|||
} |
|||
|
|||
#elif defined(__mips__)
|
|||
|
|||
uintptr_t ThreadInfo::GetInstructionPointer() const { |
|||
return mcontext.pc; |
|||
} |
|||
|
|||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const { |
|||
#if _MIPS_SIM == _ABI64
|
|||
out->context_flags = MD_CONTEXT_MIPS64_FULL; |
|||
#elif _MIPS_SIM == _ABIO32
|
|||
out->context_flags = MD_CONTEXT_MIPS_FULL; |
|||
#else
|
|||
# error "This mips ABI is currently not supported (n32)"
|
|||
#endif
|
|||
|
|||
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) |
|||
out->iregs[i] = mcontext.gregs[i]; |
|||
|
|||
out->mdhi = mcontext.mdhi; |
|||
out->mdlo = mcontext.mdlo; |
|||
out->dsp_control = mcontext.dsp; |
|||
|
|||
out->hi[0] = mcontext.hi1; |
|||
out->lo[0] = mcontext.lo1; |
|||
out->hi[1] = mcontext.hi2; |
|||
out->lo[1] = mcontext.lo2; |
|||
out->hi[2] = mcontext.hi3; |
|||
out->lo[2] = mcontext.lo3; |
|||
|
|||
out->epc = mcontext.pc; |
|||
out->badvaddr = 0; // Not stored in mcontext
|
|||
out->status = 0; // Not stored in mcontext
|
|||
out->cause = 0; // Not stored in mcontext
|
|||
|
|||
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) |
|||
out->float_save.regs[i] = mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs; |
|||
|
|||
out->float_save.fpcsr = mcontext.fpc_csr; |
|||
#if _MIPS_SIM == _ABIO32
|
|||
out->float_save.fir = mcontext.fpc_eir; |
|||
#endif
|
|||
} |
|||
|
|||
#elif defined(__riscv)
|
|||
|
|||
uintptr_t ThreadInfo::GetInstructionPointer() const { |
|||
return mcontext.__gregs[0]; |
|||
} |
|||
|
|||
void ThreadInfo::FillCPUContext(RawContextCPU* out) const { |
|||
# if __riscv__xlen == 32
|
|||
out->context_flags = MD_CONTEXT_RISCV_FULL; |
|||
# elif __riscv_xlen == 64
|
|||
out->context_flags = MD_CONTEXT_RISCV64_FULL; |
|||
# else
|
|||
# error "Unexpected __riscv_xlen"
|
|||
# endif
|
|||
|
|||
out->pc = mcontext.__gregs[0]; |
|||
out->ra = mcontext.__gregs[1]; |
|||
out->sp = mcontext.__gregs[2]; |
|||
out->gp = mcontext.__gregs[3]; |
|||
out->tp = mcontext.__gregs[4]; |
|||
out->t0 = mcontext.__gregs[5]; |
|||
out->t1 = mcontext.__gregs[6]; |
|||
out->t2 = mcontext.__gregs[7]; |
|||
out->s0 = mcontext.__gregs[8]; |
|||
out->s1 = mcontext.__gregs[9]; |
|||
out->a0 = mcontext.__gregs[10]; |
|||
out->a1 = mcontext.__gregs[11]; |
|||
out->a2 = mcontext.__gregs[12]; |
|||
out->a3 = mcontext.__gregs[13]; |
|||
out->a4 = mcontext.__gregs[14]; |
|||
out->a5 = mcontext.__gregs[15]; |
|||
out->a6 = mcontext.__gregs[16]; |
|||
out->a7 = mcontext.__gregs[17]; |
|||
out->s2 = mcontext.__gregs[18]; |
|||
out->s3 = mcontext.__gregs[19]; |
|||
out->s4 = mcontext.__gregs[20]; |
|||
out->s5 = mcontext.__gregs[21]; |
|||
out->s6 = mcontext.__gregs[22]; |
|||
out->s7 = mcontext.__gregs[23]; |
|||
out->s8 = mcontext.__gregs[24]; |
|||
out->s9 = mcontext.__gregs[25]; |
|||
out->s10 = mcontext.__gregs[26]; |
|||
out->s11 = mcontext.__gregs[27]; |
|||
out->t3 = mcontext.__gregs[28]; |
|||
out->t4 = mcontext.__gregs[29]; |
|||
out->t5 = mcontext.__gregs[30]; |
|||
out->t6 = mcontext.__gregs[31]; |
|||
|
|||
// Breakpad only supports RISCV32 with 32 bit floating point.
|
|||
// Breakpad only supports RISCV64 with 64 bit floating point.
|
|||
#if __riscv_xlen == 32
|
|||
for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) |
|||
out->fpregs[i] = mcontext.__fpregs.__f.__f[i]; |
|||
out->fcsr = mcontext.__fpregs.__f.__fcsr; |
|||
#elif __riscv_xlen == 64
|
|||
for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) |
|||
out->fpregs[i] = mcontext.__fpregs.__d.__f[i]; |
|||
out->fcsr = mcontext.__fpregs.__d.__fcsr; |
|||
#else
|
|||
#error "Unexpected __riscv_xlen"
|
|||
#endif
|
|||
} |
|||
#endif // __riscv
|
|||
|
|||
void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) { |
|||
assert(gp_regs || size); |
|||
#if defined(__mips__)
|
|||
if (gp_regs) |
|||
*gp_regs = mcontext.gregs; |
|||
if (size) |
|||
*size = sizeof(mcontext.gregs); |
|||
#elif defined(__riscv)
|
|||
if (gp_regs) |
|||
*gp_regs = mcontext.__gregs; |
|||
if (size) |
|||
*size = sizeof(mcontext.__gregs); |
|||
#else
|
|||
if (gp_regs) |
|||
*gp_regs = ®s; |
|||
if (size) |
|||
*size = sizeof(regs); |
|||
#endif
|
|||
} |
|||
|
|||
void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) { |
|||
assert(fp_regs || size); |
|||
#if defined(__mips__)
|
|||
if (fp_regs) |
|||
*fp_regs = &mcontext.fpregs; |
|||
if (size) |
|||
*size = sizeof(mcontext.fpregs); |
|||
#elif defined(__riscv)
|
|||
# if __riscv_flen == 32
|
|||
if (fp_regs) |
|||
*fp_regs = &mcontext.__fpregs.__f.__f; |
|||
if (size) |
|||
*size = sizeof(mcontext.__fpregs.__f.__f); |
|||
# elif __riscv_flen == 64
|
|||
if (fp_regs) |
|||
*fp_regs = &mcontext.__fpregs.__d.__f; |
|||
if (size) |
|||
*size = sizeof(mcontext.__fpregs.__d.__f); |
|||
# elif __riscv_flen == 128
|
|||
if (fp_regs) |
|||
*fp_regs = &mcontext.__fpregs.__q.__f; |
|||
if (size) |
|||
*size = sizeof(mcontext.__fpregs.__q.__f); |
|||
# else
|
|||
# error "Unexpected __riscv_flen"
|
|||
# endif
|
|||
#else
|
|||
if (fp_regs) |
|||
*fp_regs = &fpregs; |
|||
if (size) |
|||
*size = sizeof(fpregs); |
|||
#endif
|
|||
} |
|||
|
|||
} // namespace google_breakpad
|
|||
@ -0,0 +1,90 @@ |
|||
// Copyright 2014 Google LLC |
|||
// |
|||
// Redistribution and use in source and binary forms, with or without |
|||
// modification, are permitted provided that the following conditions are |
|||
// met: |
|||
// |
|||
// * Redistributions of source code must retain the above copyright |
|||
// notice, this list of conditions and the following disclaimer. |
|||
// * Redistributions in binary form must reproduce the above |
|||
// copyright notice, this list of conditions and the following disclaimer |
|||
// in the documentation and/or other materials provided with the |
|||
// distribution. |
|||
// * Neither the name of Google LLC nor the names of its |
|||
// contributors may be used to endorse or promote products derived from |
|||
// this software without specific prior written permission. |
|||
// |
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|||
|
|||
#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ |
|||
#define CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ |
|||
|
|||
#include <sys/ucontext.h> |
|||
#include <sys/user.h> |
|||
|
|||
#include "client/linux/dump_writer_common/raw_context_cpu.h" |
|||
#include "common/memory_allocator.h" |
|||
#include "google_breakpad/common/minidump_format.h" |
|||
|
|||
namespace google_breakpad { |
|||
|
|||
#if defined(__i386) || defined(__x86_64) |
|||
typedef __typeof__(((struct user*) 0)->u_debugreg[0]) debugreg_t; |
|||
#endif |
|||
|
|||
// We produce one of these structures for each thread in the crashed process. |
|||
struct ThreadInfo { |
|||
pid_t tgid; // thread group id |
|||
pid_t ppid; // parent process |
|||
|
|||
uintptr_t stack_pointer; // thread stack pointer |
|||
|
|||
|
|||
#if defined(__i386) || defined(__x86_64) |
|||
user_regs_struct regs; |
|||
user_fpregs_struct fpregs; |
|||
static const unsigned kNumDebugRegisters = 8; |
|||
debugreg_t dregs[8]; |
|||
#if defined(__i386) |
|||
user_fpxregs_struct fpxregs; |
|||
#endif // defined(__i386) |
|||
|
|||
#elif defined(__ARM_EABI__) |
|||
// Mimicking how strace does this(see syscall.c, search for GETREGS) |
|||
struct user_regs regs; |
|||
struct user_fpregs fpregs; |
|||
#elif defined(__aarch64__) |
|||
// Use the structures defined in <sys/user.h> |
|||
struct user_regs_struct regs; |
|||
struct user_fpsimd_struct fpregs; |
|||
#elif defined(__mips__) || defined(__riscv) |
|||
// Use the structure defined in <sys/ucontext.h>. |
|||
mcontext_t mcontext; |
|||
#endif |
|||
|
|||
// Returns the instruction pointer (platform-dependent impl.). |
|||
uintptr_t GetInstructionPointer() const; |
|||
|
|||
// Fills a RawContextCPU using the context in the ThreadInfo object. |
|||
void FillCPUContext(RawContextCPU* out) const; |
|||
|
|||
// Returns the pointer and size of general purpose register area. |
|||
void GetGeneralPurposeRegisters(void** gp_regs, size_t* size); |
|||
|
|||
// Returns the pointer and size of float point register area. |
|||
void GetFloatingPointRegisters(void** fp_regs, size_t* size); |
|||
}; |
|||
|
|||
} // namespace google_breakpad |
|||
|
|||
#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ |
|||
@ -0,0 +1,329 @@ |
|||
// Copyright 2014 Google LLC
|
|||
//
|
|||
// Redistribution and use in source and binary forms, with or without
|
|||
// modification, are permitted provided that the following conditions are
|
|||
// met:
|
|||
//
|
|||
// * Redistributions of source code must retain the above copyright
|
|||
// notice, this list of conditions and the following disclaimer.
|
|||
// * Redistributions in binary form must reproduce the above
|
|||
// copyright notice, this list of conditions and the following disclaimer
|
|||
// in the documentation and/or other materials provided with the
|
|||
// distribution.
|
|||
// * Neither the name of Google LLC nor the names of its
|
|||
// contributors may be used to endorse or promote products derived from
|
|||
// this software without specific prior written permission.
|
|||
//
|
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
#ifdef HAVE_CONFIG_H
|
|||
#include <config.h> // Must come first
|
|||
#endif
|
|||
|
|||
#include "client/linux/dump_writer_common/ucontext_reader.h"
|
|||
|
|||
#include "common/linux/linux_libc_support.h"
|
|||
#include "google_breakpad/common/minidump_format.h"
|
|||
|
|||
namespace google_breakpad { |
|||
|
|||
// Minidump defines register structures which are different from the raw
|
|||
// structures which we get from the kernel. These are platform specific
|
|||
// functions to juggle the ucontext_t and user structures into minidump format.
|
|||
|
|||
#if defined(__i386__)
|
|||
|
|||
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.gregs[REG_ESP]; |
|||
} |
|||
|
|||
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.gregs[REG_EIP]; |
|||
} |
|||
|
|||
void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc, |
|||
const fpstate_t* fp) { |
|||
const greg_t* regs = uc->uc_mcontext.gregs; |
|||
|
|||
out->context_flags = MD_CONTEXT_X86_FULL | |
|||
MD_CONTEXT_X86_FLOATING_POINT; |
|||
|
|||
out->gs = regs[REG_GS]; |
|||
out->fs = regs[REG_FS]; |
|||
out->es = regs[REG_ES]; |
|||
out->ds = regs[REG_DS]; |
|||
|
|||
out->edi = regs[REG_EDI]; |
|||
out->esi = regs[REG_ESI]; |
|||
out->ebx = regs[REG_EBX]; |
|||
out->edx = regs[REG_EDX]; |
|||
out->ecx = regs[REG_ECX]; |
|||
out->eax = regs[REG_EAX]; |
|||
|
|||
out->ebp = regs[REG_EBP]; |
|||
out->eip = regs[REG_EIP]; |
|||
out->cs = regs[REG_CS]; |
|||
out->eflags = regs[REG_EFL]; |
|||
out->esp = regs[REG_UESP]; |
|||
out->ss = regs[REG_SS]; |
|||
|
|||
out->float_save.control_word = fp->cw; |
|||
out->float_save.status_word = fp->sw; |
|||
out->float_save.tag_word = fp->tag; |
|||
out->float_save.error_offset = fp->ipoff; |
|||
out->float_save.error_selector = fp->cssel; |
|||
out->float_save.data_offset = fp->dataoff; |
|||
out->float_save.data_selector = fp->datasel; |
|||
|
|||
// 8 registers * 10 bytes per register.
|
|||
my_memcpy(out->float_save.register_area, fp->_st, 10 * 8); |
|||
} |
|||
|
|||
#elif defined(__x86_64)
|
|||
|
|||
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.gregs[REG_RSP]; |
|||
} |
|||
|
|||
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.gregs[REG_RIP]; |
|||
} |
|||
|
|||
void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc, |
|||
const fpstate_t* fpregs) { |
|||
const greg_t* regs = uc->uc_mcontext.gregs; |
|||
|
|||
out->context_flags = MD_CONTEXT_AMD64_FULL; |
|||
|
|||
out->cs = regs[REG_CSGSFS] & 0xffff; |
|||
|
|||
out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff; |
|||
out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff; |
|||
|
|||
out->eflags = regs[REG_EFL]; |
|||
|
|||
out->rax = regs[REG_RAX]; |
|||
out->rcx = regs[REG_RCX]; |
|||
out->rdx = regs[REG_RDX]; |
|||
out->rbx = regs[REG_RBX]; |
|||
|
|||
out->rsp = regs[REG_RSP]; |
|||
out->rbp = regs[REG_RBP]; |
|||
out->rsi = regs[REG_RSI]; |
|||
out->rdi = regs[REG_RDI]; |
|||
out->r8 = regs[REG_R8]; |
|||
out->r9 = regs[REG_R9]; |
|||
out->r10 = regs[REG_R10]; |
|||
out->r11 = regs[REG_R11]; |
|||
out->r12 = regs[REG_R12]; |
|||
out->r13 = regs[REG_R13]; |
|||
out->r14 = regs[REG_R14]; |
|||
out->r15 = regs[REG_R15]; |
|||
|
|||
out->rip = regs[REG_RIP]; |
|||
|
|||
out->flt_save.control_word = fpregs->cwd; |
|||
out->flt_save.status_word = fpregs->swd; |
|||
out->flt_save.tag_word = fpregs->ftw; |
|||
out->flt_save.error_opcode = fpregs->fop; |
|||
out->flt_save.error_offset = fpregs->rip; |
|||
out->flt_save.data_offset = fpregs->rdp; |
|||
out->flt_save.error_selector = 0; // We don't have this.
|
|||
out->flt_save.data_selector = 0; // We don't have this.
|
|||
out->flt_save.mx_csr = fpregs->mxcsr; |
|||
out->flt_save.mx_csr_mask = fpregs->mxcr_mask; |
|||
my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16); |
|||
my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16); |
|||
} |
|||
|
|||
#elif defined(__ARM_EABI__)
|
|||
|
|||
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.arm_sp; |
|||
} |
|||
|
|||
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.arm_pc; |
|||
} |
|||
|
|||
void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) { |
|||
out->context_flags = MD_CONTEXT_ARM_FULL; |
|||
|
|||
out->iregs[0] = uc->uc_mcontext.arm_r0; |
|||
out->iregs[1] = uc->uc_mcontext.arm_r1; |
|||
out->iregs[2] = uc->uc_mcontext.arm_r2; |
|||
out->iregs[3] = uc->uc_mcontext.arm_r3; |
|||
out->iregs[4] = uc->uc_mcontext.arm_r4; |
|||
out->iregs[5] = uc->uc_mcontext.arm_r5; |
|||
out->iregs[6] = uc->uc_mcontext.arm_r6; |
|||
out->iregs[7] = uc->uc_mcontext.arm_r7; |
|||
out->iregs[8] = uc->uc_mcontext.arm_r8; |
|||
out->iregs[9] = uc->uc_mcontext.arm_r9; |
|||
out->iregs[10] = uc->uc_mcontext.arm_r10; |
|||
|
|||
out->iregs[11] = uc->uc_mcontext.arm_fp; |
|||
out->iregs[12] = uc->uc_mcontext.arm_ip; |
|||
out->iregs[13] = uc->uc_mcontext.arm_sp; |
|||
out->iregs[14] = uc->uc_mcontext.arm_lr; |
|||
out->iregs[15] = uc->uc_mcontext.arm_pc; |
|||
|
|||
out->cpsr = uc->uc_mcontext.arm_cpsr; |
|||
|
|||
// TODO: fix this after fixing ExceptionHandler
|
|||
out->float_save.fpscr = 0; |
|||
my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); |
|||
my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); |
|||
} |
|||
|
|||
#elif defined(__aarch64__)
|
|||
|
|||
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.sp; |
|||
} |
|||
|
|||
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.pc; |
|||
} |
|||
|
|||
void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc, |
|||
const struct fpsimd_context* fpregs) { |
|||
out->context_flags = MD_CONTEXT_ARM64_FULL_OLD; |
|||
|
|||
out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate); |
|||
for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) |
|||
out->iregs[i] = uc->uc_mcontext.regs[i]; |
|||
out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp; |
|||
out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc; |
|||
|
|||
out->float_save.fpsr = fpregs->fpsr; |
|||
out->float_save.fpcr = fpregs->fpcr; |
|||
my_memcpy(&out->float_save.regs, &fpregs->vregs, |
|||
MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); |
|||
} |
|||
|
|||
#elif defined(__mips__)
|
|||
|
|||
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]; |
|||
} |
|||
|
|||
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.pc; |
|||
} |
|||
|
|||
void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) { |
|||
#if _MIPS_SIM == _ABI64
|
|||
out->context_flags = MD_CONTEXT_MIPS64_FULL; |
|||
#elif _MIPS_SIM == _ABIO32
|
|||
out->context_flags = MD_CONTEXT_MIPS_FULL; |
|||
#else
|
|||
#error "This mips ABI is currently not supported (n32)"
|
|||
#endif
|
|||
|
|||
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) |
|||
out->iregs[i] = uc->uc_mcontext.gregs[i]; |
|||
|
|||
out->mdhi = uc->uc_mcontext.mdhi; |
|||
out->mdlo = uc->uc_mcontext.mdlo; |
|||
|
|||
out->hi[0] = uc->uc_mcontext.hi1; |
|||
out->hi[1] = uc->uc_mcontext.hi2; |
|||
out->hi[2] = uc->uc_mcontext.hi3; |
|||
out->lo[0] = uc->uc_mcontext.lo1; |
|||
out->lo[1] = uc->uc_mcontext.lo2; |
|||
out->lo[2] = uc->uc_mcontext.lo3; |
|||
out->dsp_control = uc->uc_mcontext.dsp; |
|||
|
|||
out->epc = uc->uc_mcontext.pc; |
|||
out->badvaddr = 0; // Not reported in signal context.
|
|||
out->status = 0; // Not reported in signal context.
|
|||
out->cause = 0; // Not reported in signal context.
|
|||
|
|||
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) |
|||
out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i]; |
|||
|
|||
out->float_save.fpcsr = uc->uc_mcontext.fpc_csr; |
|||
#if _MIPS_SIM == _ABIO32
|
|||
out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
|
|||
#endif
|
|||
} |
|||
|
|||
#elif defined(__riscv)
|
|||
|
|||
uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP]; |
|||
} |
|||
|
|||
uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { |
|||
return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_PC]; |
|||
} |
|||
|
|||
void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) { |
|||
# if __riscv__xlen == 32
|
|||
out->context_flags = MD_CONTEXT_RISCV_FULL; |
|||
# elif __riscv_xlen == 64
|
|||
out->context_flags = MD_CONTEXT_RISCV64_FULL; |
|||
# else
|
|||
# error "Unexpected __riscv_xlen"
|
|||
# endif
|
|||
|
|||
out->pc = uc->uc_mcontext.__gregs[0]; |
|||
out->ra = uc->uc_mcontext.__gregs[1]; |
|||
out->sp = uc->uc_mcontext.__gregs[2]; |
|||
out->gp = uc->uc_mcontext.__gregs[3]; |
|||
out->tp = uc->uc_mcontext.__gregs[4]; |
|||
out->t0 = uc->uc_mcontext.__gregs[5]; |
|||
out->t1 = uc->uc_mcontext.__gregs[6]; |
|||
out->t2 = uc->uc_mcontext.__gregs[7]; |
|||
out->s0 = uc->uc_mcontext.__gregs[8]; |
|||
out->s1 = uc->uc_mcontext.__gregs[9]; |
|||
out->a0 = uc->uc_mcontext.__gregs[10]; |
|||
out->a1 = uc->uc_mcontext.__gregs[11]; |
|||
out->a2 = uc->uc_mcontext.__gregs[12]; |
|||
out->a3 = uc->uc_mcontext.__gregs[13]; |
|||
out->a4 = uc->uc_mcontext.__gregs[14]; |
|||
out->a5 = uc->uc_mcontext.__gregs[15]; |
|||
out->a6 = uc->uc_mcontext.__gregs[16]; |
|||
out->a7 = uc->uc_mcontext.__gregs[17]; |
|||
out->s2 = uc->uc_mcontext.__gregs[18]; |
|||
out->s3 = uc->uc_mcontext.__gregs[19]; |
|||
out->s4 = uc->uc_mcontext.__gregs[20]; |
|||
out->s5 = uc->uc_mcontext.__gregs[21]; |
|||
out->s6 = uc->uc_mcontext.__gregs[22]; |
|||
out->s7 = uc->uc_mcontext.__gregs[23]; |
|||
out->s8 = uc->uc_mcontext.__gregs[24]; |
|||
out->s9 = uc->uc_mcontext.__gregs[25]; |
|||
out->s10 = uc->uc_mcontext.__gregs[26]; |
|||
out->s11 = uc->uc_mcontext.__gregs[27]; |
|||
out->t3 = uc->uc_mcontext.__gregs[28]; |
|||
out->t4 = uc->uc_mcontext.__gregs[29]; |
|||
out->t5 = uc->uc_mcontext.__gregs[30]; |
|||
out->t6 = uc->uc_mcontext.__gregs[31]; |
|||
|
|||
// Breakpad only supports RISCV32 with 32 bit floating point.
|
|||
// Breakpad only supports RISCV64 with 64 bit floating point.
|
|||
#if __riscv_xlen == 32
|
|||
for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) |
|||
out->fpregs[i] = uc->uc_mcontext.__fpregs.__f.__f[i]; |
|||
out->fcsr = uc->uc_mcontext.__fpregs.__f.__fcsr; |
|||
#elif __riscv_xlen == 64
|
|||
for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++) |
|||
out->fpregs[i] = uc->uc_mcontext.__fpregs.__d.__f[i]; |
|||
out->fcsr = uc->uc_mcontext.__fpregs.__d.__fcsr; |
|||
#else
|
|||
#error "Unexpected __riscv_xlen"
|
|||
#endif
|
|||
} |
|||
#endif
|
|||
|
|||
} // namespace google_breakpad
|
|||
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue