Compare commits

...

167 Commits

Author SHA1 Message Date
Maria Mandlis
8f7e09cf6d Handle multiple microdumps in system log.
Properly handle microdump processing, when the system_log file contains an incomplete microdump section at the top. The processor will process the first complete microdump section.

R=primiano@chromium.org

Review URL: https://codereview.chromium.org/1742843002 .
2016-02-26 16:40:40 -08:00
Maria Mandlis
344b79d61a Support processing microdumps for x86 architecture.
BUG=587536
R=primiano@chromium.org

Review URL: https://codereview.chromium.org/1704243002 .
2016-02-18 06:13:56 -08:00
Birunthan Mohanathas
1e24e66fbb Try loading msdiaNNN.dll if CoCreateInstance(CLSID_DiaSource) fails
Because tools/windows/symupload/symupload.cc uses `nullptr` (which
requires VS2010), the CLSID comparison is only performed for msdia100.dll
and later. When compiling with an older (or future) CLSID_DiaSource, we
retain the existing behaviour (i.e. fail if CoCreateInstance fails).

R=ivanpe@chromium.org
BUG=https://bugzilla.mozilla.org/show_bug.cgi?id=1236343
2016-02-17 11:36:19 -05:00
Ted Mielczarek
c05ee94604 Fix buffer overrun in MinidumpModule::debug_identifier with MDCVInfoELF 2016-02-17 06:20:58 -05:00
Mike Frysinger
108d705fdf linux_dumper_unittest_helper: move to a check-only binary
There's no need for this binary outside of local tests, so stop
building/installing it by default.

BUG=chromium:579384
TEST=`make check` passe
R=ivanpe@chromium.org

Review URL: https://codereview.chromium.org/1632933002 .
2016-02-17 00:48:38 -05:00
Ivan Penkov
12bd7fc52b Fixing a flaky Linux exploitability unittest.
BUG=https://code.google.com/p/chromium/issues/detail?id=584174
R=mmandlis@chromium.org

Review URL: https://codereview.chromium.org/1697963002 .
2016-02-16 11:46:04 -08:00
Ted Mielczarek
e5adfac03b Ensure Linux minidump writer flushes minidump header early.
If the Linux minidump writer crashes while writing a dump, the dump
might contain some useful information, but the header will be empty
because TypedMDRVA's destructor flushes the data, and the header var
doesn't go out of scope until the end of the `Dump` method. This
fixes that problem by putting the header in a shorter block scope.

We've seen this problem in some Android dumps in the wild, like:
https://crash-stats.mozilla.com/report/index/cef5b777-02d1-43c2-bf40-133ab2160209

R=thestig@chromium.org
BUG=https://bugzilla.mozilla.org/show_bug.cgi?id=1247978

Review URL: https://codereview.chromium.org/1696573003 .
2016-02-12 15:50:16 -05:00
Veljko Mihailovic
1ac4dcf6f5 Fix for linux make check build failure
Linux make check is failing for mips, mips64, arm, arm64
with error:
"fatal error: mach/arm/vm_types.h: No such file or directory" in case of arm,
"../src/third_party/mac_headers/mach/machine/vm_types.h:37:2: error: #error architecture not supported" in case of mips/mips64

This was partially fixed in https://codereview.chromium.org/1645673002/.

Here excluding src/common/mac/macho_reader_unittest for hosts other than x86/x86-64.

BUG=make check failure for linux mips
TEST=make check pass

Review URL: https://codereview.chromium.org/1692933002 .
2016-02-12 15:17:11 -05:00
Maria Mandlis
7b330814a4 Parse additional line introduced in the microdump format and containing the GPU infromation in the following format:
G GL_VERSION|GL_VENDOR|GL_RENDERER.

The GPU version, vendor and renderer are extracted during microdump parsing and populated in the appropriate fields in the SystemInfo struct.

This is to match the changes introduced in crrev.com/1343713002 and crrev.com/1334473003

BUG=chromium:536769
R=primiano@chromium.org

Review URL: https://codereview.chromium.org/1678463002 .
2016-02-11 10:04:04 -08:00
Lei Zhang
a1d84b2da9 Revert "Added a switch to dump minidump modules in minidump_stackwalk."
This reverts commit cb936a0243.

A=dyen@chromium.org
Original Review: https://codereview.chromium.org/1672773002/

R=dyen@chromium.org

Review URL: https://codereview.chromium.org/1688493003 .
2016-02-10 13:11:20 -08:00
Ted Mielczarek
7a364b1262 Change MDCVInfoELF into something usable.
This patch changes MDCVInfoELF (which is currently unused, apparently
a vestigal bit of code landed as part of Solaris support) into a supported
CodeView format that simply contains a build id as raw bytes.

Modern ELF toolchains support build ids nicely:
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Developer_Guide/compiling-build-id.html

It would be useful to have the original build ids of loaded modules in
Linux minidumps, since tools like Fedora's darkserver allow querying by build
id and the current Breakpad code truncates the build id to the size of a GUID,
which loses information:
https://darkserver.fedoraproject.org/

A follow-up patch will change the Linux minidump generation code to produce
MDCVInfoELF in minidumps instead of MDCVInfoPDB70. This patch should be landed
first to ensure that crash processors are able to handle this format before
dumps are generated containing it.

The full build id is exposed as the return value of Minidump::code_identifier(),
which currently just returns "id" for modules in Linux dumps. For
backwards-compatibility, Minidump::debug_identifier() continues to treat
the build id as a GUID, so debug identifiers for existing modules will not
change.

BUG=
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1675413002 .
2016-02-10 09:00:02 -05:00
Sylvain Defresne
4becb11709 Fix usage of deprecated method sendSynchronousRequest:returningResponse:error:.
The method -[NSURLConnection sendSynchronousRequest:returningResponse:error:]
has been deprecated in 10.11 OS X SDK and 9.0 iOS SDK without replacement. So
emulate a synchronous request by using an asynchronous request and waiting on
a semaphore for the request completion.

BUG=https://bugs.chromium.org/p/google-breakpad/issues/detail?id=675
BUG=569158
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1675243002 .
2016-02-08 17:39:44 +01:00
Sylvain Defresne
450491f4f7 Fix usage of deprecated method stringByAddingPercentEscapesUsingEncoding:.
The method -[NSString stringByAddingPercentEscapesUsingEncoding:] has been
deprecated with 10.11 OS X SDK and 9.0 iOS SDK. The recommended method is
-[NSString stringByAddingPercentEncodingWithAllowedCharacters:] available
since 10.9 OS X SDK and 7.0 iOS SDK.

Use the new method when available using URLQueryAllowedCharacterSet to get
the same encoded string.

BUG=https://bugs.chromium.org/p/google-breakpad/issues/detail?id=675
BUG=569158
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1680663002 .
2016-02-08 17:39:26 +01:00
Sylvain Defresne
cd891cd1ed Fix usage of deprecated function CFPropertyListCreateFromXMLData.
The function CFPropertyListCreateFromXMLData is deprecated in favor of
the function CFPropertyListCreateWithData that is available since the
10.6 OS X SDK and 4.0 iOS SDK.

BUG=https://bugs.chromium.org/p/google-breakpad/issues/detail?id=675
BUG=569158
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1678063002 .
2016-02-08 17:38:33 +01:00
Mike Frysinger
79556b7ca8 [mips64] Support for mips n64
Adding remaining mips n64 support including stackwalker.

BUG=None
TEST=manually tested on Linux/Android
R=vapier@chromium.org

Review URL: https://codereview.chromium.org/1418453011 .
2016-02-06 18:58:39 -05:00
Ivan Penkov
11840d0ffd Remove use of deprecated CFURLCreateDataAndPropertiesFromResource function.
Original change (https://codereview.chromium.org/1527363003/) was failing
in CFReadStreamGetBuffer() call, so changed to CFReadStreamRead() to be
more conservative.

Patch provided by Scott Hancher.

BUG=
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1637433003 .
2016-01-31 18:17:42 -08:00
Lei Zhang
cb936a0243 Added a switch to dump minidump modules in minidump_stackwalk.
In order to figure out what symbols we need associated to a minidump,
it is useful to be able to dump all the modules the minidump contains.

A=dyen@chromium.org
Original Review: https://codereview.chromium.org/1651593002/
BUG=563716
R=dyen@chromium.org

Review URL: https://codereview.chromium.org/1650713002 .
2016-01-29 13:59:17 -08:00
Pavel Labath
4003d20c70 Improvements to GYP build
This updates the GYP build for the processor component (on windows).
- adds/removes references to files which were added or removed from the
  repository
- includes build/common.gypi in the gyp files: needed to correctly
  detect the OS (I think, the generated MSVC solutions were broken
  without it)
- conditionally compiles code platform-specific code for the given
  platform

After this minidump processor nearly compiles with VS2013: the generated
project is correct, but some files still have compilation errors.

Disclaimer: I have not tested the GYP changes on non-windows platform,
as there does not seem to be anyone using it there.

BUG=
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1643633004 .
2016-01-29 11:43:21 +00:00
Mike Frysinger
855ea963fb only build dump_syms_mac for x86 hosts
The dump_syms_mac tool only works for the system it is being built for
(it doesn't support running on ELFs for a diff target), and it builds
only for x86 currently.

If you look at the mac header:
	src/third_party/mac_headers/mach/machine/vm_types.h
it will #error for non x86/arm systems, and the arm header is not in
our source tree.

Tweak the build so it's only compiled when targetting x86 systems.

BUG=chromium:579384
TEST=`make check` pass
R=ted.mielczarek@gmail.com

Review URL: https://codereview.chromium.org/1645673002 .
2016-01-27 16:45:21 -05:00
Mike Frysinger
258591ed4c convert to uint8_t* for binary data to fix -Wnarrowing build errors
Newer gcc versions default to -Werror=narrowing when using newer C++
standards (which we do).  This causes issues when we try to stuff a
value like 0xea into a char -- the value is out of range for signed
char bytes.  That's when gcc throws an error:
.../bytereader_unittest.cc: In member function 'virtual void Reader_DW_EH_PE_absptr4_Test::TestBody()':
.../bytereader_unittest.cc:400:55: error: narrowing conversion of '234' from 'int' to 'char' inside { } [-Wnarrowing]

BUG=chromium:579384
TEST=`make check` passes
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1605153004 .
2016-01-26 15:38:19 -05:00
Mike Frysinger
e8ddeff729 autotools: regen w/latest versions
Should have no real impact on the build.  Just pulling in the latest
versions from the latest autoconf/automake versions.

BUG=chromium:579384
TEST=`make && make install` still works
2016-01-25 19:29:06 -05:00
Mike Frysinger
de54eb133f test: allow use of system gmock/gtest libs
Some systems provide prebuilt copies of gmock/gtest (such as Chromium
OS).  Add a configure flag so they can take advantage of that.  This
allows for a smaller checkout as they don't need to include the full
testing/ tree.

BUG=chromium:579384
TEST=`make check` passes w/--enable-system-test-libs
TEST=`make check` passes w/--disable-system-test-libs
R=thestig@chromium.org

Review URL: https://codereview.chromium.org/1638653002 .
2016-01-25 19:27:56 -05:00
Mike Frysinger
0f0b0f367b build: clean up .dwo files
When building with -gsplit-dwarf, the generated dwo files are left behind
even when you `make clean`.  Fix that up.

BUG=chromium:579384
TEST=`./configure CXXFLAGS='-O -gsplit-dwarf' && make && make clean` removes dwo files now
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1633893002 .
2016-01-25 18:40:56 -05:00
Mike Frysinger
83f0e6a31c test: stop building tons of copies of gtest/gmock objects
The current makefile ends up building ~17 copies of the gtest/gmock
objects -- every test that refers to the cc files directly will have
its own copy.  This is because the build doesn't know if CFLAGS and
such have changed between each target (and in some cases, they are).

Create a new libtesting.a target to hold a single copy of these files
and update all of the unittests to link that in.  This speeds up the
build a bit especially when you aren't using ccache.

This does mean we can no longer build gtest/gmock with unique flags,
but we haven't wanted that so far, so clearly no one wants that.

BUG=chromium:579384
TEST=`make check` passes
R=thestig@chromium.org

Review URL: https://codereview.chromium.org/1633903002 .
2016-01-25 17:41:53 -05:00
Mike Frysinger
b7033b3aa1 linux_client_unittest_shlib: fix cleaning
The EXTRA_PROGRAMS knob does not automatically trigger clean up of
targets listed in it.  Use CLEANFILES so we make sure `make clean`
will delete the linux_client_unittest_shlib lib.

BUG=chromium:579384
TEST=`make check` passes
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1618593002 .
2016-01-25 16:53:16 -05:00
Mike Frysinger
72a02f6cbf tests: unify duplicate build settings
Rather than copy & paste the same set of -I flags many times over,
create a single varible to hold it.

BUG=chromium:579384
TEST=`make check` passes
R=thestig@chromium.org

Review URL: https://codereview.chromium.org/1613763002 .
2016-01-25 15:12:03 -05:00
Mike Frysinger
7f160dbfa2 DEPS: roll test libs up to the latest release
BUG=chromium:579384
TEST=`make check` passes
R=thestig@chromium.org

Review URL: https://codereview.chromium.org/1607413003 .
2016-01-25 15:10:38 -05:00
Olivier Robin
7da8acc8d4 Revert "Fix deprecatation warning when building for recent SDKs on iOS/OS X."
This reverts CL https://codereview.chromium.org/1563223004/
This reverts commit 7cc0d8562b.

CL 1563223004 introduces two bugs on iOS.
- Encoding the minidump name with extra percent causing crash server to fail
  processing the file.
- Using a released pointer causing random crashes on upload. The
  data, resp, err pointers returned in the NSURLSession completion
  handler is released at the end of the block. When used later (to get
  the crash ID), it causes a crash.

BUG=569158
R=blundell@chromium.org, mark@chromium.org

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

Patch from Olivier Robin <olivierrobin@chromium.org>.
2016-01-21 11:34:12 -05:00
Mike Frysinger
585ba07db0 exploitability_unittest: fix warnings
The std::getline function always returns its first arg (which is an
iostream object) and cannot return anything else.  Thus, testing its
value is pointless, and even leads to build errors w/at least gcc-5
due to gtest ASSERT_TRUE funcs only taking bool types:

.../exploitability_unittest.cc: In member function 'virtual void {anonymous}::ExploitabilityLinuxUtilsTest_DisassembleBytesTest_Test::TestBody()':
.../exploitability_unittest.cc:200:136: error: no matching function for call to 'testing::AssertionResult::AssertionResult(std::basic_istream<char>&)'
In file included from .../breakpad_googletest_includes.h:33:0,
                 from .../exploitability_unittest.cc:35:
.../gtest.h:262:12: note: candidate: testing::AssertionResult::AssertionResult(bool)

Since we know this never fails, simply drop the ASSERT_TRUE usage.
The next line already checks the content of the buffer we read.

Further on in the file, we hit some signed warnings:
In file included from .../breakpad_googletest_includes.h:33:0,
                 from .../exploitability_unittest.cc:35:
.../gtest.h: In instantiation of 'testing::AssertionResult testing::internal::CmpHelperEQ(const char*, const char*, const T1&, const T2&) [with T1 = long unsigned int; T2 = int]':
.../gtest.h:1484:23:   required from 'static testing::AssertionResult testing::internal::EqHelper<lhs_is_null_literal>::Compare(const char*, const char*, const T1&, const T2&) [with T1 = long unsigned int; T2 = int; bool lhs_is_null_literal = false]'
.../exploitability_unittest.cc:241:289:   required from here
.../gtest.h:1448:16: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
   if (expected == actual) {

This is because we compare the register value (a uint64_t) directly to
an integer constant, and those are signed by default.  Stick a U suffix
on them to fix things up.

BUG=chromium:579384
TEST=`make check` passes
R=ivanpe@chromium.org

Review URL: https://codereview.chromium.org/1611763002 .
2016-01-21 00:50:28 -05:00
Pavel Labath
d5d13e605e Fix usage of snprintf for MSVC
Older versions of MSVC don't have a snprintf functions. Some files
were already working around that, but not all of them. Instead of
copying the logic into every file, I centralize it into a new
stdio.h wrapper file and make other files include that.

BUG=
R=mark@chromium.org

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

Patch from Pavel Labath <labath@google.com>.
2016-01-19 21:28:44 -05:00
Mike Frysinger
fc134c412a breakpad: fix unittest failure when building with clang.
In C/C++, the result of signed integer overflow is undefined.

The expression "base + size - 1" is parsed as "(base + size) - 1", and
"base + size" can overflow even if "base + (size - 1)" <= INT_MAX.

See http://g/c-compiler-chrome/461JohPKakE/JI3rEBg6FwAJ for more.

BUG=None
TEST='CC=clang CXX=clang++ ./configure && make check'
R=vapier@chromium.org

Review URL: https://codereview.chromium.org/1591793002 .
2016-01-15 13:29:32 -05:00
Mike Frysinger
d38ed334e7 README: add more links to breakpad sites
R=andybons@chromium.org

Review URL: https://codereview.chromium.org/1583163003 .
2016-01-14 13:32:20 -05:00
Mike Frysinger
e8dc9aab0c Move core2md objects to libbreakpad_client.a
This CL exports LinuxCoreDumper and ElfCoreDump in the client library. The ARC collector, which is an alternative to core2md optimized for large core dumps, needs these symbols for core dump parsing and conversion to minidump.

BUG=http://b/25773929
TEST=nm src/client/linux/libbreakpad_client.a | grep LinuxCoreDumper

Review URL: https://codereview.chromium.org/1576053002 .
2016-01-13 15:30:21 -05:00
Pavel Labath
2c03db146a libdisasm: Remove inclusion of windows.h
windows.h defines exception_code as a macro, which conflicts with our
use of the identifier in exception records. It appears that this
particular include of windows.h is not needed, so instead of undefining
the macro, I simply delete the include. Build tested with MSVC 2013.

BUG=
R=mark@chromium.org

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

Patch from Pavel Labath <labath@google.com>.
2016-01-12 10:43:06 -05:00
Pavel Labath
860d7f5da1 Define intptr and uintptr in a more generic way
MSVC does not have the __PTRDIFF_TYPE__ macro defined, so I use the
standard [u]intptr_t types instead. Compilation tested on windows, linux
and mac.

BUG=
R=mark@chromium.org

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

Patch from Pavel Labath <labath@google.com>.
2016-01-11 12:38:28 -05:00
Pavel Labath
104784d8e4 libdisasm: Don't depend on sizeof(void)
Due to operator precedence, the address was first cast to void*
and then incremented, which resulted in an error on windows, as
sizeof(void) is undefined and MSVC takes this seriously. Changing
the precedence to perform the addition first.

R=mark@chromium.org

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

Patch from Pavel Labath <labath@google.com>.
2016-01-08 12:52:04 -05:00
Pavel Labath
1979e59107 disassembler_x86: Remove unused include
This file is not present on windows, and it's causing build errors
there. As far as I can tell, nothing in this file actually uses
that include, so I just remove it.

BUG=
R=mark@chromium.org

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

Patch from Pavel Labath <labath@google.com>.
2016-01-08 10:07:04 -05:00
Sylvain Defresne
ae0fdf6f43 Fix compilation of breakpad on Linux.
Fix some copy/paste errors from commit 41440eaa.

BUG=None
R=thestig@chromium.org

Review URL: https://codereview.chromium.org/1564293002 .
2016-01-08 09:34:27 +01:00
Lei Zhang
cbda3193b1 Check for C++11 support in the configure script.
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1570013002 .
2016-01-08 00:27:48 -08:00
Sylvain Defresne
7cc0d8562b Fix deprecatation warning when building for recent SDKs on iOS/OS X.
Fixes the following compilation warning when using recent version of
the iOS or OS X SDK by using the recommended new API:

../../breakpad/src/common/mac/HTTPMultipartUpload.m:56:10: error: 'stringByAddingPercentEscapesUsingEncoding:' is deprecated: first deprecated in iOS 9.0 - Use -stringByAddingPercentEncodingWithAllowedCharacters: instead, which always uses the recommended UTF-8 encoding, and which encodes for a specific URL component or subcomponent since each URL component or subcomponent has different rules for what characters are valid. [-Werror,-Wdeprecated-declarations]
    [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
         ^
CFURLCreateStringByAddingPercentEscapes

../../breakpad/src/common/mac/HTTPMultipartUpload.m:207:29: error: 'sendSynchronousRequest:returningResponse:error:' is deprecated: first deprecated in iOS 9.0 - Use [NSURLSession dataTaskWithRequest:completionHandler:] (see NSURLSession.h [-Werror,-Wdeprecated-declarations]
    data = [NSURLConnection sendSynchronousRequest:req
                            ^

../../breakpad/src/client/mac/handler/minidump_generator.cc:158:6: error: 'CFPropertyListCreateFromXMLData' is deprecated: first deprecated in iOS 8.0 - Use CFPropertyListCreateWithData instead. [-Werror,-Wdeprecated-declarations]
    (CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable,
     ^

BUG=https://bugs.chromium.org/p/google-breakpad/issues/detail?id=675
BUG=569158
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1563223004 .
2016-01-07 19:48:21 +01:00
Lei Zhang
41440eaa17 Use range-based for loops in linux/minidump_writer/minidump_writer.cc.
Also fix lint errors.

R=mark@chromium.org

Review URL: https://codereview.chromium.org/1562273002 .
2016-01-07 00:53:06 -08:00
Mike Frysinger
0205a1526d switch to git for external projects
Now that all the projects we care about use git and have repos available,
switch to them and away from the old googlecode svn repos.

TEST=`gclient sync` migrated svn->git fine
TEST=`make check` still passes
TEST=manual `diff -ur` on the new/old repos shows same content
BUG=
R=thestig@chromium.org

Review URL: https://codereview.chromium.org/1560913002 .
2016-01-06 19:44:41 -05:00
Lei Zhang
400a1d9aa5 Avoid comparing size_t to be < 0 on AArch64.
cpu_features_entries is empty on AArch64 and causes tautological-compare
warning when compiling with Clang.

A=dskiba@google.com
Original Review: https://codereview.chromium.org/1562223002/

BUG=chromium:539781

Review URL: https://codereview.chromium.org/1566893002 .
2016-01-06 16:16:01 -08:00
Lei Zhang
863883f93f Make minidump-2-core.cc build with -Wformat.
A=thakis@chromium.org
BUG=chromium:574817
Original Review: https://codereview.chromium.org/1562983002/

R=thakis@chromium.org

Review URL: https://codereview.chromium.org/1563043002 .
2016-01-06 14:17:16 -08:00
Lei Zhang
be6ea5e82d Fix -Wunused-function warnings in ASAN builds.
A=thakis@chromium.org
BUG=chromium:573250
Original Review: https://codereview.chromium.org/1551963002/

Review URL: https://codereview.chromium.org/1551983002 .
2015-12-30 15:44:02 -08:00
Lei Zhang
a7ffb8c364 Let breakpad build with -Wall on OS X and Linux.
A=thakis@chromium.org
Original Review: https://codereview.chromium.org/1550933002/

R=thakis@chromium.org

Review URL: https://codereview.chromium.org/1554613002 .
2015-12-29 13:42:49 -08:00
Ivan Penkov
816f242158 Remove use of deprecated CFURLCreateDataAndPropertiesFromResource function.
Patch by Scott Hancher

BUG=
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1527363003 .
2015-12-18 10:26:21 -08:00
Ted Mielczarek
86d5e9e7f9 Fix ExploitabilityLinuxUtilsTest::DisassembleBytesTest to not fail when temp file ends with 0
R=ivanpe@chromium.org
BUG=https://bugs.chromium.org/p/google-breakpad/issues/detail?id=668

Review URL: https://codereview.chromium.org/1482363003 .
2015-11-30 14:05:08 -05:00
Ted Mielczarek
fed9db3634 Rename src/tools/mac/dump_syms binary to dump_syms_mac in autotools build to fix make install
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1474673004 .
2015-11-25 14:27:53 -05:00
Mike Frysinger
9e60a27911 dump_syms: add a -v flag
dump_syms generates a lot of warnings.
This CL puts logging behind a command line flag

URL=https://android-review.googlesource.com/181558
BUG=b:25460551
BUG=google-breakpad:441
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1437763002 .
2015-11-11 13:52:03 -05:00
Mike Frysinger
ff49f92c36 build: detect the right ar tool
Use automake's AM_PROG_AR helper instead of the default of hardcoding
`ar` all the time.  When cross-compiling, this can often be the wrong
one to use.

BUG=google-breakpad:519
R=ted.mielczarek@gmail.com

Review URL: https://codereview.chromium.org/1435813002 .
2015-11-11 13:43:14 -05:00
Mike Frysinger
d4d65cfc36 gitignore: add mac/dump_syms
BUG=google-breakpad:670
2015-11-11 01:47:33 -05:00
Mike Frysinger
b1a39f985d autotools: refresh config.{sub,guess} 2015-11-11 01:38:23 -05:00
Mike Frysinger
27a2e317d7 Don't include libdisasm.a in libbreakpad.a
libbreakpad.a pointlessly contains libdisasm.a

This looks like a left-over from when libtool was used

Since this has no useful effect (as the linker doesn't recursively search
archive members which aren't objects), anything which requires the objects in
libdisasm.a must already be linking with it, so simply remove it.

BUG=https://code.google.com/p/google-breakpad/issues/detail?id=484

Review URL: https://codereview.chromium.org/1399003002 .
2015-11-11 01:17:45 -05:00
Mike Frysinger
8652b9eaed Fix file descriptor leaks in linux CrashGenerationServer
R=ted.mielczarek@gmail.com

Review URL: https://codereview.chromium.org/1137423004 .
2015-11-11 01:12:20 -05:00
Mike Frysinger
b9f9f4e840 Install headers under client/linux/dump_writer_common
Automake did not install headers under c/l/dwc, which caused
compile errors when building against an installed breakpad, since
other headers (e.g. client/linux/handler/exception_handler.h)
depended on it. This commit adds these headers to the list of
automake installed files.

R=vapier@chromium.org

Review URL: https://codereview.chromium.org/1127393006 .
2015-11-11 01:11:00 -05:00
Boris Vidolov
f20be6a6c0 Make dump_syms buildable under newer versions of Xcode.
R=mark@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1438483002 .
2015-11-10 13:23:38 -08:00
Lei Zhang
fe64fd4aa2 Android: Workaround for ftruncate() issues.
This works around a bug in M that prevents Breakpad from using
ftruncate() in the renderer process.

To do this, skip the calls to ftruncate() when allocating bigger
minidump files and strictly depends on write() to append to the end.

It might be less efficient but this is probably less of an issue on
SD cards. It is much better than not getting crash reports.

BUG=542840

Original CL: https://codereview.appspot.com/273880044/
Original CL Author: acleung@chromium.org

Review URL: https://codereview.chromium.org/1407233016 .
2015-11-05 15:45:01 -08:00
Ivan Penkov
4da1cfbad2 Issue in StackwalkerAMD64::GetCallerByFramePointerRecovery.
There is an issue in StackwalkerAMD64::GetCallerByFramePointerRecovery.
Occasionally it produces invalid frames (instruction pointer == 0) which
prevents the AMD64 stack walker from proceeding to do stack scanning and
instead leads to premature termination of the stack walking process.

For more details: http://crbug/537444

BUG=
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1408973002 .
2015-10-15 20:47:15 -07:00
Benjamin Lerman
95719f4b8c Only release current_breakpad_ if it is defined.
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1402453006 .
2015-10-14 17:35:47 +02:00
Mike Frysinger
30fa644c27 Revert "[Docs] Add wiki content to Markdown docs"
This reverts commit 7ed2476eea.

This was supposed to be committed to the linux-syscall-support
project.  The two CLs landing at the sametime confused me.

Note: LSS has been updated via commit 08056836f2b4a5747daff75435d10d6.

Review URL: https://codereview.chromium.org/1395743002 .
2015-10-07 17:04:43 -04:00
Ted Mielczarek
c53ed14310 Fix Windows crash_generation_server for debug builds without -D_DEBUG
Debug Gecko builds don't build with -D_DEBUG, so the ifdef in
crash_generation_server doesn't work right. The MSDN documentation for
assert says that it's enabled based on the absence of the NDEBUG define,
so using that seems sensible.

R=thestig@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1398453002 .
2015-10-07 14:19:23 -04:00
David Major
cf1087c403 Support for multiple upload files in CrashReportSender/HTTPUpload
A=David Major <dmajor@mozilla.com>
BUG=https://bugzilla.mozilla.org/show_bug.cgi?id=1048091
R=ted@mielczarek.org

Review URL: https://bugzilla.mozilla.org/show_bug.cgi?id=1048091 .
2015-10-06 11:05:12 -04:00
Ted Mielczarek
be849f0637 Fix MSVC build (including on 2015), drop some workarounds for MSVC older than 2013.
The Windows client gyp files were missing proc_maps_linux.cc for the
unittest build. Adding that revealed some build errors due to it
unconditionally including <inttypes.h>. Removing the workarounds in
breakpad_types.h (and a few other places) made that build, which means
that Visual C++ 2013 is now our minimum supported version of MSVC.

Additionally I tried building with VC++ 2015 and fixed a few warnings
(which were failing the build because we have /WX enabled) to ensure
that that builds as well.

BUG=https://code.google.com/p/google-breakpad/issues/detail?id=669
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1353893002 .
2015-10-06 08:03:57 -04:00
Ivan Penkov
84d37160a7 Increasing the Breakpad stack walker max scan limit from 30 to 40.
Chrome started hitting some crashes in v8 jitted code which happens to be
non ABI compliant and debuggers (including WinDBG) are unable to produce
meaningful stack traces.

The Breakpad stack walker has some builtin heuristics to deal with such cases.
More specifically, when unable to find a good parent frame, it scans the raw
stack to find a suitable parent frame.  The max scan size was set at 30
pointers which was (apparently) not enough to recover in this case.

I'm increasing it to 40 pointers.  I confirmed that at 34 pointers it was able
to recover however I'm setting it to 40 in order to it some slack.

I needed to update two unittests which were expecting the previous scan limit.

BUG=
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1379433005 .
2015-10-05 11:35:09 -07:00
Pavel Labath
cc7b69a8f2 [mac] Teach dump_syms to handle additional zerofill sections
This patch allows dump_syms to handle S_THREAD_LOCAL_ZEROFILL
and S_GB_ZEROFILL section in the same way as the more common
S_ZEROFILL section.  Previously, dump_syms would fail to dump
a binary containing a __DATA,__thread_bss section, because it
tried to look up its data (and failed).

R=mark@chromium.org

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

Patch from Pavel Labath <labath@google.com>.
2015-09-30 08:20:42 -04:00
Primiano Tucci
9d3e1f1c03 Fix automake files after README.md -> README rename
Minor followup to crrev.com/1357773004 and
crrev.com/1361993002 which moved the README and forgot
to update the automake files.
This is to make "./configure && make" work.

TBR=mark@chromium.org

Review URL: https://codereview.chromium.org/1368363002 .
2015-09-28 14:02:08 +01:00
Primiano Tucci
7ecc65758d Add GPU fingerprint information to breakpad microdumps.
Although strictly the GPU fingerprint is defined by the build fingerprint,
there is not currently a straightforward mapping from build fingerprint
to useful GPU / GL driver information.

In order to aid debugging of WebView crashes that occur in GL drivers,
and to better understand the range of drivers and versions for feature
blacklisting purposes, it is useful to have GPU fingerprints in breakpad
microdumps.

Landing this patch on behalf of Tobias Sargeant<tobiasjs@chromium.org>

BUG=chromium:536769
R=primiano@chromium.org, thestig@chromium.org

Review URL: https://codereview.chromium.org/1334473003 .
2015-09-28 13:52:54 +01:00
Mike Frysinger
7ed2476eea [Docs] Add wiki content to Markdown docs
BUG=none
R=vapier@chromium.org, mseaborn@chromium.org

Review URL: https://codereview.chromium.org/1356253003 .
2015-09-24 11:32:37 -04:00
Mark Mentovai
94b1ccb51f Update configure to look for README.md instead of README
This is required after daed3a4383. configure won't run as-is, reported
in https://codereview.chromium.org/1357773004/.

R=andybons@chromium.org

Review URL: https://codereview.chromium.org/1361993002 .
2015-09-23 10:46:55 -04:00
Andy Bonventre
daed3a4383 [Docs] add markdown docs (converted from Wiki)
BUG=none
R=mark
CC=google-breakpad-dev@googlegroups.com

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

Patch from Andy Bonventre <andybons@chromium.org>.
2015-09-22 17:29:52 -04:00
Primiano Tucci
55ba26e520 Linux ExceptionHandler: don't allocate the CrashContext on the stack
On Android the size of the alternate stack can be very small (8k).
Even if breakpad uses sigaltstack to increase the size of the alternate
stack during initialization, that call affects only the main thread.
On Android, the libc's pthread initializer reset the sigaltstack to 8k.
When entering a signal handler, the kernel typically pushes the context
on the alternate stack. On arm64, sizeof(CrashContext) is ~5k, which
leaves 3k of usable stack for breakpad.
On top of that, breakpad allocates another struct CrashContext on the
stack. In the case of Android arm64, then, breakpad ends up using
5k + 5k > 8k of stack, which causes a stack overflow.
This got unnoticed in Android L, as the alternate stack didn't have
red-zones between them, so breakpad was often happily overflowing onto
the next thread's stack. This is not the case anymore [1].
This CL moves the CrashContext into a global variable. It should be
safe as the ExceptionHandlers are serialized on a mutex.

[1] 595752f623

BUG=374
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1354923002 .
2015-09-22 09:11:24 +01:00
Ted Mielczarek
1be03d4e87 Fixup a bad strcmp call landed in previous commit 2015-09-16 19:25:35 -04:00
Ted Mielczarek
6cee755e09 Fix Mac Breakpad host tools to build in Linux cross-compile
We're working on building our Firefox Mac builds as a Linux cross-compile
(https://bugzilla.mozilla.org/show_bug.cgi?id=921040) and we need symbol
dumping to work. This change ports the Mac dump_syms tool to build and work
on Linux. I've tested it and it produces identical output to running the
tool on Mac.

The bulk of the work here was converting src/common/mac/dump_syms.mm and
src/tools/mac/dump_syms/dump_syms_tool.mm from ObjC++ to C++ and removing
their use of Foundation classes in favor of standard C/C++.

This won't compile out-of-the-box on Linux, it requires some Mac system
headers that are not included in this patch. I have those tentatively in
a separate patch to land in Gecko
(http://hg.mozilla.org/users/tmielczarek_mozilla.com/mc/rev/5fb8da23c83c),
but I wasn't sure if you'd be interested in having them in the Breakpad tree.
We could almost certainly pare down the set of headers included there, I
didn't spend too much time trying to minimize them (we primarily just need
the Mach-O structs and a few associated bits).

I just realized that this patch is missing updating the XCode project files
(ugh). I'll fix that up in a bit.

R=mark@chromium.org
BUG=https://bugzilla.mozilla.org/show_bug.cgi?id=543111

Review URL: https://codereview.chromium.org/1340543002 .
2015-09-16 06:46:55 -04:00
Ted Mielczarek
f766c4d790 Update gitignore to ignore more GYP things
Now that we're using gclient everywhere, the hook to run gyp on the Windows
projects gets run on Linux, so we get Makefiles strewn around the tree.

R=vapier@chromium.org

Review URL: https://codereview.chromium.org/1339653002 .
2015-09-11 14:20:15 -04:00
Mike Frysinger
cf1d2dcef9 solaris: fix spurious ;
As reported in the issue tracker, building on Solaris 8 fails:
.../src/common/solaris/guid_creator.cc:69: error: extra `;'

BUG=google-breakpad:251
R=ted.mielczarek@gmail.com

Review URL: https://codereview.chromium.org/1333243002 .
2015-09-11 12:59:53 -04:00
Mike Frysinger
282996a91e README: update dev documents w/new git flow
BUG=chromium:502355
R=thestig@chromium.org

Review URL: https://codereview.chromium.org/1335483002 .
2015-09-11 01:38:20 -04:00
Mike Frysinger
d9b5c83cc1 deps: switch lss to git
BUG=524777
TEST=`gclient sync` switches lss to git
R=thestig@chromium.org

Review URL: https://codereview.chromium.org/1331783002 .
2015-09-11 01:37:29 -04:00
Will Harris
5f520807ca Fix regression on x86 for "Fix compile error with Windows clang"
R=thakis@chromium.org

Review URL: https://codereview.chromium.org/1318013002 .
2015-09-03 16:38:57 -07:00
Vadim Shtayura
2ad6028981 Change codereview.settings to point to new repo URL.
It changes "Committed: <URL>" in CLs to point to Git repo browser.

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

Review URL: https://codereview.chromium.org/1319083007 .
2015-09-01 17:13:51 -07:00
mmandlis@chromium.org
2ef9e783ab The "CPU architecture" field is being filled from the wrong part of
the microdump. The microdump OS/arch line looks like:
O A arm 04 armv7l 3.4.0-perf-g4d6e88e #1 SMP PREEMPT Mon Mar 30 19:09:30 2015
and currently the field that says "armv7l" or "aarch64" is being used
to fill in the CPU arch field in crash. The problem is that on a
64-bit device this field *always* says "aarch64" even when running in
a 32-bit process, and so currently the crash reports for aarch64 are
a mix of 32-bit and 64-bit crashes. We should be using the first field
instead, which just says "arm" or "arm64" and reflects the actual
version of webview (32-bit or 64-bit) which is running.

BUG=
R=primiano@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1498 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-26 16:18:52 +00:00
Liu.andrew.x@gmail.com
f252ca8ed1 Add check for Linux minidump ending on bad write for exploitability rating.
If a crash occurred as a result to a write to unwritable memory, it is reason
to suggest exploitability. The processor checks for a bad write by
disassembling the command that caused the crash by piping the raw bytes near
the instruction pointer through objdump. This allows the processor to see if
the instruction that caused the crash is a write to memory and where the
target of the address is located.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1497 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-21 16:22:19 +00:00
ted.mielczarek@gmail.com
7b1ec78407 Don't use strtok_s for mingw builds
R=ivanpe at https://codereview.chromium.org/1292503005/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1496 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-20 15:09:16 +00:00
rmcilroy@chromium.org
013acd5326 Add user_regs_struct and user_fpsimd_struct for aarch64 on Android.
Android's sys/user.h is missing user_regs_struct and user_fpsimd_struct.
Add them to the Android specific user.h used by breakpad to workaround
Android / glibc compatibility issues.

A bug has been filed on the Android NDK team to add the missing structures to
the NDK, at which point this hack can be removed.

Also remove the mxcsr_mask hack on x64, which is no longer required since
we have moved to the r10d NDK which fixes this issue.

R=primiano@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1495 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-20 14:30:38 +00:00
wfh@chromium.org
01f9665c63 Fix compile error with Windows clang.
This change fixes the following errors shown during compile with
Windows clang:

error: cannot pass non-trivial object of type 'ATL::CComBSTR' to variadic function; expected type from format string was 'wchar_t *' [-Wnon-pod-varargs]

Original CL: https://codereview.chromium.org/1252913009/

BUG=https://code.google.com/p/google-breakpad/issues/detail?id=662

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1494 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-19 22:28:17 +00:00
primiano@chromium.org
6e30d1ad6d Fix inttypes format macros in src/processor/proc_maps_linux.cc
crrev.com/1298443002 has introduced a build failure by re-defining
__STDC_FORMAT_MACROS. Fixing it.

BUG=
R=mark@chromium.org, ted.mielczarek@gmail.com

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1493 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-19 07:24:21 +00:00
primiano@chromium.org
24a2f501a8 Remove obsolete seccomp_unwinder for legacy (pre-BPF) sandbox
The PopSeccompStackFrame was introduced to deal with stack frames
originated in the legacy seccomp sandbox. The only user of that
sandbox was Google Chrome, but the legacy sandbox has been
deprecated in 2013 (crrev.com/1290643003) in favor of the new
bpf sandbox.
Removing this dead code as it has some small bound checking bug
which causes occasional crashes in WebView (which are totally
unrelated to the sandbox).

Note: this will require a corresponding change in the chromium
GYP/GN build files to roll.

BUG=665,chromium:477444
R=jln@chromium.org, mark@chromium.org, torne@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1492 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-18 08:38:14 +00:00
ted.mielczarek@gmail.com
767d5d5b0c Fix proc_maps_linux compile for non-Linux
R=ivanpe at https://codereview.chromium.org/1298443002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1491 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-17 11:55:15 +00:00
primiano@chromium.org
b51a14f396 [microdump] Move microdump writes to the crash ring-buffer log
So far the microdump_writer dumped the log in logcat using the default
system log. This is simple to achieve but has some drawbacks:
 1. Creates spam in the system log, pushing back other eventual useful
    messages.
 2. There is a high chance that the microdump gets lost if some log
    spam storm happens immediately after a crash and before the log
    is collected by the feedback client.
 3. Since Android L, the logger is smartly throttling messages (to
    reduce logcat spam). Throttling brekpad logs defeats the all
    point of microdumps.

This change is conceptually very simple. Replace the use of
__android_log_write() with __android_log_buf_write(), which takes
an extra bufID argument. The main drawback is that the
__android_log_buf_write is not exported in the NDK and needs to be
dynamically looked up via dlsym.
This choice has been discussed and advocated by Android owners.
See the internal bug b/21753476.

BUG=chromium:512755
R=thestig@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1490 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-17 10:32:26 +00:00
primiano@chromium.org
3fcf2e1eef [microdump] Fix hw architecture indication in build fingerprint line
r1456 introduced the possibility to customize the OS-line of the
microdump, enabling to replace, in the case of android, the generic
uname() info with the Android build fingerprint.
While doing that, it mistakenly removed the HW architecture indication
from the format.
See crbug.com/520075 for more details.

BUG=chromium:520075
R=mmandlis@chromium.org, torne@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1489 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-17 08:02:16 +00:00
Liu.andrew.x@gmail.com
c8dd1d54f9 Add check for executable stack/heap when rating Linux exploitability.
This CL also consequentially adds a public method to get the number of
mappings in a Linux minidump.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1488 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-15 00:37:14 +00:00
Liu.andrew.x@gmail.com
a33bd704c1 Add check to see if stack pointer is off the stack according to the memory
mappings when rating Linux exploitability.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1487 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-15 00:27:27 +00:00
Liu.andrew.x@gmail.com
8a35448388 Fix format specifier in proc maps to support 32-bit architectures.
R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1486 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-13 20:13:55 +00:00
ted.mielczarek@gmail.com
4f96b603fe Actually remove removed files
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1485 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-13 19:49:44 +00:00
ted.mielczarek@gmail.com
baab7a7cb6 Remove some old unused code, add a missing include
R=lei at https://codereview.chromium.org/1211963002



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1484 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-13 16:38:19 +00:00
Liu.andrew.x@gmail.com
383b815ed5 Fix format specifier in proc maps to support 32-bit architectures.
R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1483 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-12 00:53:39 +00:00
Liu.andrew.x@gmail.com
6fa7555947 Allow Print() to be called by const instances of MinidumpLinuxMaps and
MinidumpLinuxMapsList.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1482 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-12 00:21:44 +00:00
Liu.andrew.x@gmail.com
213e3f7853 Change Print method of MinidumpLinuxMaps and MinidumpLinuxMapsList to print
contents of /proc/<pid>/maps instead of just the files mapped to memory.

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1481 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-11 16:05:48 +00:00
ivanpe@chromium.org
c3a641288d Workaround for range map overlaps caused by Android package relocation.
If there is a range overlap, the cause may be the client correction applied for Android packed relocations.  If this is the case, back out the client correction and retry.

Patch from Simon Baldwin <simonb@chromium.org>.

https://code.google.com/p/chromium/issues/detail?id=509110

R=simonb@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1480 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-10 17:03:29 +00:00
cjhopman@chromium.org
413754dfdd Fix breakpad for arm on arm64
On arm64 devices, GETFPREGS fails with errno==EIO. Ignore those failures
on Android arm builds.

BUG=508324
R=thestig@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1479 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-08-05 22:48:48 +00:00
Liu.andrew.x@gmail.com
c625d7cb82 Fix potential null pointer dereference.
If a MinidumpLinuxMapsList was created and destroyed without its Read method,
the program would have a segmentation fault because the destructor did not
check for a null maps_ field. Additional changes include additional
supplementary null checks, a potential memory leak fix, and some comment
removal.

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1478 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-31 15:26:39 +00:00
Liu.andrew.x@gmail.com
8608fe10bf Remove unnecessary dependencies.
Review URL: https://codereview.chromium.org/1266493002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1477 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-29 00:09:22 +00:00
Liu.andrew.x@gmail.com
044c744012 Add support for Linux memory mapping stream and remove ELF header usage
when checking exploitability rating.

Linux minidumps do not support MD_MEMORY_INFO_LIST_STREAM, meaning the
processor cannot retrieve its memory mappings. However, it has its own
stream, MD_LINUX_MAPS, which contains memory mappings specific to Linux
(it contains the contents of /proc/self/maps). This CL allows the minidump
to gather information from the memory mappings for Linux minidumps.

In addition, exploitability rating for Linux dumps now use memory mappings
instead of checking the ELF headers of binaries. The basis for the change
is that checking the ELF headers requires the minidumps to store the memory
from the ELF headers, while the memory mapping data is already present,
meaning the size of a minidump will be unchanged.

As a result, of removing ELF header analysis, two unit tests have been removed.
Arguably, the cases that those unit tests check do not merit a high
exploitability rating and do not warrant a solid conclusion that was given
earlier.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1476 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-28 00:53:44 +00:00
Liu.andrew.x@gmail.com
93c3c398ff Fix incorrect comment.
The exploitability rating for a dump is EXPLOITABILITY_NOT_ANALYZED if the
exploitability engine in not enabled, not EXPLOITABILITY_NONE.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1475 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-27 18:04:54 +00:00
vapier@chromium.org
398384e1cf add aarch64 support to minidump-2-core
The thread info expects the struct names as they expect in asm/ptrace.h,
but the header doesn't include that, it includes sys/user.h.  Rename the
reg structs to match that header.

Rename the elf_siginfo to _elf_siginfo to avoid conflicting with the one
in the sys/procfs.h.  It is only used locally in one place, so we don't
need to update any callers.

Otherwise, drop in aarch64 support into the minidump-2-core file.

BUG=chromium:334368


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1474 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-20 10:21:27 +00:00
vapier@chromium.org
0295bfea40 tests: InstructionPointerMemoryNullPointer: make it work under llvm
When LLVM sees an attempt to dereference a NULL pointer, it will generate
invalid opcodes (undefined behavior) which leads to SIGILL which breaks
this unittest.  Upstream's recommendation in this case is to add volatile
markings to get the actual dereference to happen.

This is documented in the blog post under "Dereferencing a NULL Pointer":
http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1473 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-20 06:19:49 +00:00
Liu.andrew.x@gmail.com
4ef4c7a595 Add ELF header analysis when checking for instruction pointer in code.
If the minidump module containing the instruction pointer has memory
containing the ELF header and program header table, when checking the
exploitability rating, the processor will use the ELF header data to determine
if the instruction pointer lies in an executable region of the module, rather
than just checking if it lies in a module.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1472 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-16 20:42:29 +00:00
wfh@chromium.org
d74d407688 Fix -Wreorder warnings in the Windows code.
This makes the order of fields in constructor initializer lists match
the order in which the fields are declared in (which is the order
they're initialized in). No intended behavior change.

This change was originally reviewed at
https://codereview.chromium.org/1230923005/

BUG=chromium:505304
TBR=thakis@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1471 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-10 20:24:33 +00:00
changluo@google.com
1d2b6ce3cd Default nil or empty version string to CFBundleVersion
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1470 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-10 01:29:50 +00:00
Liu.andrew.x@gmail.com
bd7af02472 Set exception whitelist check as earlier check instead of last check.
When I first added the exception whitelist, I meant to put the check before
checking the location of the instruction pointer. (I didn't notice that it
was after the other check until now.) The whitelist check is to quickly rule
out minidumps, and if checking the instruction pointer provided any useful
information, it would be pretty indicative that the exception causing the
dump is interesting.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1469 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-07-07 21:30:06 +00:00
Liu.andrew.x@gmail.com
ff4d8facbf Use general instruction/stack pointer convenience method instead of manually
finding the instruction/stack pointer for exploitability rating.

There was already a method that found the instruction pointer, so the files
for exploitability ratings had repeated code. Also a method for finding the
stack pointer is implemented in this CL.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1468 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-30 23:22:09 +00:00
Liu.andrew.x@gmail.com
ca21e62ecf Checking for benign exceptions that trigger a minidump.
If the exception reponsible for the crash is benign, such as a floating point
exception, we can rule out the possibility that the code is exploitable. This
CL checks for such exceptions and marks the dump as not exploitable if such an
exception is found.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1467 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-30 20:34:39 +00:00
Liu.andrew.x@gmail.com
a3f0a28b69 This CL adds support for ARM and ARM64 architectures when calculating
exploitability ratings.

The stackwalker will now grab the instruction pointers for ARM and ARM64
architectures, so checking exploitability on ARM and ARM64 will no longer
return EXPLOITABILITY_ERR_PROCESSING.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1466 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-30 18:17:23 +00:00
rmcilroy@chromium.org
5ecc80d579 Adjust breakpad module size to match adjusted start_addr.
When changing a module's start_addr to account for Android packed
relocations, also adjust its size field so that the apparent module
end addr calculated by the breakpad processor does not alter.

Ensures that the mapping entry from a packed library is consistent
with that which an unpacked one would produce.

BUG=499747
R=primiano@chromium.org, rmcilroy@chromium.org

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

Patch from Simon Baldwin <simonb@chromium.org>.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1465 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-30 13:30:22 +00:00
Liu.andrew.x@gmail.com
b559587dd7 Checking location of the instruction pointer to see if it is
in valid code for Linux exploitability rating.

This CL adds to the Linux exploitability checker by verifying that the
instruction pointer is in valid code. Verification is done by obtaining a
memory mapping of the crash and checking if the instruction pointer lies in
an executable region. If there is no memory mapping, the instruction pointer
is checked to determine if it lies within a known module.

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1464 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-25 23:05:16 +00:00
rsesek@chromium.org
cb4f056f12 Update the upload.py code review server.
This is follow-up to r1455.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1463 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-24 16:27:36 +00:00
ivanpe@chromium.org
f681a13afe Reconfigured options for sym_upload to not treat h and ? flags as invalid options.
I'm submitting this on behalf of Andrew Liu.

R=mmandlis@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1462 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-22 21:21:40 +00:00
primiano@chromium.org
8b5c70a438 Fix signal propagation logic for Linux/Android exception handler.
The current code is relying on info->si_pid to figure out whether
the exception handler was triggered by a signal coming from the kernel
(that will re-trigger until the cause that triggered the signal has
been cleared) or from user-space e.g., kill -SIGNAL pid, which will NOT
automatically re-trigger in the next signal handler in the chain.
While the intentions are good (manually re-triggering user-space
signals), the current implementation mistakenly looks at the si_pid
field in siginfo_t, assuming that it is coming from the kernel if
si_pid == 0.
This is wrong. siginfo_t, in fact, is a union and si_pid is meaningful
only for userspace signals. For signals originated by the kernel,
instead, si_pid overlaps with si_addr (the faulting address).
As a matter of facts, the current implementation is mistakenly
re-triggering the signal using tgkill for most of the kernel-space
signals (unless the fault address is exactly 0x0).
This is not completelly correct for the case of SIGSEGV/SIGBUS. The
next handler in the chain will stil see the signal, but the |siginfo|
and the |context| arguments of the handler will be meaningless
(retriggering a signal with tgkill doesn't preserve them).
Therefore, if the next handler in the chain expects those arguments
to be set, it will fail.
Concretelly, this is causing problems to WebView. In some rare
circumstances, the next handler in the chain is a user-space runtime
which does SIGSEGV handling to implement speculative null pointer
managed exceptions (see as an example
http://www.mono-project.com/docs/advanced/runtime/docs/exception-handling/)

The fix herein proposed consists in using the si_code (see SI_FROMUSER
macros) to determine whether a signal is coming form the kernel
(and therefore just re-establish the next signal handler) or from
userspace (and use the tgkill logic).

Repro case:
This issue is visible in Chrome for Android with this simple repro case:
- Add a non-null pointer dereference in the codebase:
  *((volatile int*)0xbeef) = 42
Without this change: the next handler (the libc trap) prints:
  F/libc  (  595): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x487
  where 0x487 is actually the PID of the process (which is wrong).
With this change: the next handler prints:
  F/libc  (  595): Fatal signal 11 (SIGSEGV), code 1, fault addr 0xbeef
  which is the correct answer.

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

Review URL: https://breakpad.appspot.com/6844002.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1461 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-22 11:50:00 +00:00
ivanpe@chromium.org
72c4716d06 Use local variable for out parameter rather than direct use of ivar
- Resolves spurious static analyzer warning about response_ being potentially leaked due to the retain in Xcode 6.3 and later.

I'm submitting this on behalf of Brian Moore.

R=qsr@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1460 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-20 00:32:37 +00:00
rmcilroy@chromium.org
b3b3d2144f Update breakpad for Android packed relocations.
Shared libraries containing Android packed relocations have a load
bias that differs from the start address in /proc/$$/maps. Current
breakpad assumes that the load bias and mapping start address are
the same.

Fixed by changing the client to detect the presence of Android packed
relocations in the address space of a loaded library, and adjusting the
stored mapping start address of any that are packed so that it contains
the linker's load bias.

For this to work properly, it is important that the non-packed library
is symbolized for breakpad. Either packed or non-packed libraries may
be run on the device; the client detects which has been loaded by the
linker.

BUG=499747
R=primiano@chromium.org, rmcilroy@chromium.org

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

Patch from Simon Baldwin <simonb@chromium.org>.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1459 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-06-19 16:30:42 +00:00
vapier@chromium.org
6ccf732733 update more ignore files
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1458 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-05-28 06:16:15 +00:00
primiano@chromium.org
e925c2a8c1 [microdump] Add build fingerprint and product info metadata.
This is to add build fingerprint and product name/version to
microdumps. Conversely to what happens in the case of minidumps
with MIME fields, due to the nature of minidumps, extra metadata
cannot be reliably injected after the dump is completed.
This CL adds the plumbing to inject two optional fields plus the
corresponding tests.

BUG=chromium:410294
R=thestig@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1456 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-05-15 08:43:01 +00:00
mark@chromium.org
3dc3a6d272 Switch code review server to codereview.chromium.org.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1455 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-05-06 17:52:38 +00:00
primiano@chromium.org
5f0fc7acef Fix signal propagation logic for Linux/Android exception handler.
The current code is relying on info->si_pid to figure out whether
the exception handler was triggered by a signal coming from the kernel
(that will re-trigger until the cause that triggered the signal has
been cleared) or from user-space e.g., kill -SIGNAL pid, which will NOT
automatically re-trigger in the next signal handler in the chain.
While the intentions are good (manually re-triggering user-space
signals), the current implementation mistakenly looks at the si_pid
field in siginfo_t, assuming that it is coming from the kernel if
si_pid == 0.
This is wrong. siginfo_t, in fact, is a union and si_pid is meaningful
only for userspace signals. For signals originated by the kernel,
instead, si_pid overlaps with si_addr (the faulting address).
As a matter of facts, the current implementation is mistakenly
re-triggering the signal using tgkill for most of the kernel-space
signals (unless the fault address is exactly 0x0).
This is not completelly correct for the case of SIGSEGV/SIGBUS. The
next handler in the chain will stil see the signal, but the |siginfo|
and the |context| arguments of the handler will be meaningless
(retriggering a signal with tgkill doesn't preserve them).
Therefore, if the next handler in the chain expects those arguments
to be set, it will fail.
Concretelly, this is causing problems to WebView. In some rare
circumstances, the next handler in the chain is a user-space runtime
which does SIGSEGV handling to implement speculative null pointer
managed exceptions (see as an example
http://www.mono-project.com/docs/advanced/runtime/docs/exception-handling/)

The fix herein proposed consists in using the si_code (see SI_FROMUSER
macros) to determine whether a signal is coming form the kernel
(and therefore just re-establish the next signal handler) or from
userspace (and use the tgkill logic).

Repro case:
This issue is visible in Chrome for Android with this simple repro case:
- Add a non-null pointer dereference in the codebase:
  *((volatile int*)0xbeef) = 42
Without this change: the next handler (the libc trap) prints:
  F/libc  (  595): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x487
  where 0x487 is actually the PID of the process (which is wrong).
With this change: the next handler prints:
  F/libc  (  595): Fatal signal 11 (SIGSEGV), code 1, fault addr 0xbeef
  which is the correct answer.

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

Review URL: https://breakpad.appspot.com/6844002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1454 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-30 09:12:54 +00:00
erikchen@chromium.org
b0c09bd7ea Support object files larger than 2**32.
Reviewed at https://breakpad.appspot.com/7834002/#ps340001


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1453 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-22 20:14:24 +00:00
rmcilroy@chromium.org
1d4f1396b2 [MIPS]: Use mcontext_t structure for MIPS
This change removes user_regs_struct and
user_fpregs_struct structures for mips
and uses mcontext_t instead.

R=fdegans@chromium.org, mark@chromium.org, rmcilroy@chromium.org

Review URL: https://breakpad.appspot.com/3744002

Patch from Gordana Cmiljanovic <Gordana.Cmiljanovic@imgtec.com>.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1452 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-21 21:34:14 +00:00
vapier@chromium.org
bffca12384 update svn:ignores
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1451 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-18 03:27:45 +00:00
vapier@chromium.org
27447e58e3 synx with latest upstream gnuconfig
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1450 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-18 03:25:50 +00:00
cjhopman@chromium.org
8f38da092c Fix call to rt_sigaction
Despite the fact that many places imply that sigaction and rt_sigaction
are essentially the same, rt_sigaction's signature is actually
different-- it takes the size of the kernel's sigset_t as an extra argument.

BUG=473973


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1447 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-15 22:57:24 +00:00
mark@chromium.org
097cf4f8ad MIPS64: Initial MIPS64 related change.
With this change Breakpad can be compiled for MIPS64,
but it is not yet functional.

Patch by Gordana Cmiljanovic <Gordana.Cmiljanovic@imgtec.com>
Review URL: https://breakpad.appspot.com/6824002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1446 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-15 19:28:11 +00:00
mark@chromium.org
8cabceb005 Use __NR_rt_sigaction instead of __NR_sigaction
__NR_sigaction is not defined on arm64/x64/etc (or rather, it's defined
in unistd-32.h instead of unistd.h).

Patch by Chris Hopman <cjhopman@chromium.org>
Review URL: https://breakpad.appspot.com/10724002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1443 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-13 23:59:06 +00:00
primiano@chromium.org
1a903f088b Microdump processor: be more tolerant for different logcat formats
The current processor implementation is grepping for /google-breakpad(
in the logcat lines, to filter out microdump lines, which by default
look like this:
W/google-breakpad( 3728): -----BEGIN BREAKPAD MICRODUMP-----

Turns out that logcat format can vary, when passing optional arguments,
and produce something like the following:

04-13 12:30:35.563  6531  6531 W google-breakpad: -----BEGIN ...

In the latter case, the "/google-breakpad(" filter is too aggressive.
This change is relaxing it, so it is compatible also with non-default
logcat arguments.

BUG=640
R=mmandlis@chromium.org

Review URL: https://breakpad.appspot.com/2864002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1442 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-13 17:45:17 +00:00
mark@chromium.org
b8b8f6c6f3 Add address and reason for IN_PAGE_ERROR.
ACCESS_VIOLATION and IN_PAGE_ERROR both specify
read/write/dep flags and address. ACCESS_VIOLATION currently
reports these, but IN_PAGE_ERROR does not. This change makes
IN_PAGE_ERROR report this information as well, and also the
additional NTSTATUS value for the underlying cause.

Patch by bungeman@chromium.org
Review URL: https://breakpad.appspot.com/1794002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1441 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-10 22:05:29 +00:00
mark@chromium.org
aa6268fdf9 Workaround Android sigaction bug
On Android L+, signal and sigaction symbols are provided by libsigchain
that override the system's versions. There is a bug in these functions
where they essentially ignore requests to install SIG_DFL.

Workaround this issue by explicitly performing a syscall to
__NR_rt_sigaction to install SIG_DFL on Android.

BUG=473973

Patch by Chris Hopman <cjhopman@chromium.org>
Review URL: https://breakpad.appspot.com/1804002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1438 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-04-10 17:57:24 +00:00
ted.mielczarek@gmail.com
9d1daff1d2 Fix compilation with gcc --std=c++11
Patch by Jon Turney <jon.turney.1111@gmail.com>
R=ted at https://breakpad.appspot.com/7824002/



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1435 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-03-24 11:25:14 +00:00
primiano@chromium.org
622588226d Fix compatibility with Android NDK r10d.
This is a reland of the previous CL (r1433). r1433 did not achieve what
intended and failed the x86_64 build of Chrome with NDK r10c.
The workaround logic in this CL is identical to r1433, but the #define
magic is applied in a more appropriate proper place this time. Turns
out Breakpad already has an Android compatibility layer, which is
common/android/include. Piggybacking the fix there.

BUG=breakpad:642
R=fdegans@chromium.org, rmcilroy@chromium.org

Review URL: https://breakpad.appspot.com/3794002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1434 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-03-16 14:12:20 +00:00
primiano@chromium.org
be470f3a11 Make breakpad compatible with Android NDK r10d.
r1397 did introduce a workaround to deal with a typo in sys/user.h
in the Android NDK. The typo has been fixed in [1]. However, breakpad
cannot just switch to the fixed version as this would require atomic
rolls of Breakpad and NDK in chromium, which would make reverts hard
to handle.
This change introduces an inelegant yet functional hack which makes
breakpad compatible with both versions of the NDK, with and without
the typo. It can be reverted once Chrome has stably rolled to NDK
r10d.

[1] https://android.googlesource.com/platform/bionic/+/f485547b

BUG=breakpad:642
R=fdegans@chromium.org, rmcilroy@chromium.org

Review URL: https://breakpad.appspot.com/7814002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1433 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-03-10 20:09:06 +00:00
primiano@chromium.org
eb81077a4f Microdump writer: stop using new/malloc in compromised context
A recent change in the client-side microdump write (r1404) ended up
introducing a call to new() to instantiate the line buffer that
microdump uses to dump its lines. new/malloc is a luxury we cannot
afford in a compromised context.
This change switches the line buffer to be backed by the dumper
page allocator, which on Linux/Android ends up requesting pages
via mmap.
Also, the microdump write bails out without crashing if the page
allocator failed (crash during severe OOM).

BUG=640

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1432 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-03-10 20:06:04 +00:00
ted.mielczarek@gmail.com
8ba5453573 Fix Windows dump_syms x64 linking
The dia_sdk GYP target points at the x86 diaguids.lib, it needs to
point at the x64 one for x64 builds.
R=mark at https://breakpad.appspot.com/9784002/

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1431 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-03-06 20:12:00 +00:00
ted.mielczarek@gmail.com
b0fbff302a Formatting tweak for https://breakpad.appspot.com/9774002, add more newlines
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1430 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-27 13:40:41 +00:00
hashimoto@chromium.org
43b75f42a7 Add stack contents output functionality to minidump_stackwalk
This feature is enabled only when "-s" is provided as a commandline option.

minidump_stackwalk.cc:
 - Add a new commandline option "-s" to output stack contents.
 - Instantiate Minidump object in PrintMinidumpProcess() to keep it alive longer so that accessing process_state.thread_memory_regions() in stackwalk_common.cc doesn't result in use-after-free.

stackwalk_common.cc:
 - Add a new function PrintStackContents() to output stack contents.

R=mark@chromium.org

Review URL: https://breakpad.appspot.com/9774002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1429 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-27 04:52:21 +00:00
mark@chromium.org
8ca937a3a7 Update license on convert_UTF.* to the standard Unicode license.
BUG=google-breakpad:270
R=ted.mielczarek@gmail.com

Review URL: https://breakpad.appspot.com/9764002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1428 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-25 21:16:43 +00:00
wfh@chromium.org
2b7360217e Add option to Breakpad to consume INVALID_HANDLE_VALUE exceptions.
BUG=chromium:452613
R=mark@chromium.org

Review URL: https://breakpad.appspot.com/7794002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1427 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-22 02:27:35 +00:00
thestig@chromium.org
4aeb452cdd Cleanup Linux debug link file handling code.
- Handle the case when the debug link points back to the object file.
- Move some checks into a separate SanitizeDebugFile() function.

BUG=636
Review URL: https://breakpad.appspot.com/3784002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1426 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-10 22:36:39 +00:00
mark@chromium.org
19a35ba066 Fix overflow error in breakpad for linux
A computation in the stack unwind algorithm could cause an overflow if a base
pointer read from crashed process is sufficiently close to top of address space.
This causes a memory read that causes the dump thread to crash, resulting in a
failure to generate crash dump. Check fixed to properly detect that this pointer
is greater than actual memory range of current stack.

Patch by Kyle Joswiak <kjoswiak@chromium.org>

Review URL: https://breakpad.appspot.com/3754003/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1425 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-05 23:01:31 +00:00
thestig@chromium.org
5bf649f336 Add unit tests for overlapping functions and externs.
R=mark@chromium.org

Review URL: https://breakpad.appspot.com/3774002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1424 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-04 00:03:58 +00:00
thestig@chromium.org
41f858a4d7 Handle ARM THUMB functions when removing duplicate PUBLIC entries.
In ELF symtab/dynsym sections, THUMB function addresses have bit 0 set,
whereas the DWARF function entries are not.

R=mark@chromium.org

Review URL: https://breakpad.appspot.com/7774002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1423 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-03 23:13:04 +00:00
hashimoto@chromium.org
54d899d631 Follow debug link correctly
As thestig@chromium.org pointed out in https://breakpad.appspot.com/9684002,
LoadSymbols() should return false if |read_gnu_debug_link| is false.

BUG=chromium:453498
R=thestig@chromium.org

Review URL: https://breakpad.appspot.com/2844002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1422 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-03 07:16:04 +00:00
hashimoto@chromium.org
16ab317dfc Demangle symbol name
The spec says it should be demangled.
https://code.google.com/p/google-breakpad/wiki/SymbolFiles

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

Review URL: https://breakpad.appspot.com/2854002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1421 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-03 03:17:30 +00:00
benchan@chromium.org
d6eb7fa1b8 Handle failures of copying process data from a core file.
When LinuxCoreDumper fails to copy process data from a core file, it
fills the return buffer with a repeated sequence of a special marker.
However, MinidumpWriter doesn't know about that and may incorrectly
interpret the data. In many cases, MinidumpWriter simply copies the
gibberish data to the minidump, which isn't too bad. However, the
gibberish data may cause MinidumpWriter to behave badly in some other
cases. For example, when MinidumpWriter tries to iterate through the
linked list of all loaded DSOs via the r_map field of a r_debug struct,
if the linked list is filed with the special marker, the code keeps
iterating through the same address.

This CL addresses the issue by having LinuxCoreDumper::CopyFromProcess()
returns a Boolean value to indicate if the expected data is found from
the core file. MinidumpWriter can then decide how to handle that.

BUG=chromium:453484
TEST=Run core2md with the test data attached to chromium:453484.
R=mark@chromium.org

Review URL: https://breakpad.appspot.com/4724002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1420 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-02 23:27:27 +00:00
ted.mielczarek@gmail.com
d2904bb421 Replace uses of hash_map with unordered_map
hash_map no longer exists in Visual C++ 2015.
A=Brian Smith <brian@briansmith.org>
R=ted at https://bugzilla.mozilla.org/show_bug.cgi?id=1119072

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1419 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-02-02 14:05:45 +00:00
vapier@chromium.org
7c7366dd6d Remove unneeded definitions of O_BINARY
Review URL: https://breakpad.appspot.com/6684002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1418 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-01-28 21:47:31 +00:00
benchan@chromium.org
55f879151c Remove unused variable 'kGUIDStringSize' in microdump_writer_unittest.
R=mark@chromium.org

Review URL: https://breakpad.appspot.com/3754002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1417 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-01-28 18:33:50 +00:00
hashimoto@chromium.org
a4eb2e302c Stop calling memmove when unnecessary
BUG=chromium:450137
R=mark@chromium.org



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1416 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-01-27 03:27:08 +00:00
erikchen@chromium.org
ccc06f4798 Fix some fragile code that is likely to cause future memory corruption
problems.

- The ordering of keys in stl containers cannot change. Make the relevant
members const to guarantee this assumption.
- Add handling and logging for demangle errors.
- Fix a potential double-delete bug if a function passed to AddFunction() is
already present.

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

Review URL: https://breakpad.appspot.com/10704002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1415 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-01-27 01:20:59 +00:00
erikchen@chromium.org
acb33ed38f Fix a source of memory corruption.
This error was causing crashes in official Chrome Mac builds on 10.8.5
machines.

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


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1414 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-01-26 23:19:04 +00:00
primiano@chromium.org
2f77d4e41c Fix the scope on the initialization of kMicrodumpOnConsole to match header.
I whish I knew how this worked for months in chromium as it is clearly wrong.
As reported by azarchs@ it is breaking the cygprofile instrumented build.

BUG=chromium:410294

Review URL: https://breakpad.appspot.com/1784002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1413 4c0a9323-5329-0410-9bdc-e9ce6186880e
2015-01-09 17:58:19 +00:00
wfh@chromium.org
0a5700b594 Modify minidump_stackwalk to be more tolerant of overlapping ranges.
These ranges can be seen in some Android minidumps.

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

Review URL: https://breakpad.appspot.com/9744002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1412 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-12-20 00:47:07 +00:00
jessicag.feedback@gmail.com
e0d5189f74 Add microdump files to project.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1411 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-12-11 19:30:37 +00:00
mdempsky@chromium.org
c32b7ad535 Remove pointers from serialized file format
BUG=breakpad:621
R=thestig@chromium.org

Review URL: https://breakpad.appspot.com/1764002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1410 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-12-11 01:17:43 +00:00
mark@chromium.org
aad5d66fa5 Breakpad: Fix build with new clang versions.
gcc has a single exception setting for all languages. Saying -fno-exceptions
in gcc disables exceptions and cleanups for cc files, but has no effect for mm
files.

In clang, -fno-exceptions only disables c++ exceptions, but keeps objective-c
exceptions and cleanups enabled.

http://llvm.org/viewvc/llvm-project?view=revision&revision=220714 changed
__EXCEPTIONS to be defined for clang when cleanups are enabled, independent of
if c++ exceptions are enabled. (This was necessary to have clang work with
glibc which looks at __EXCEPTIONS to decide if cleanups are enabled.)

Breakpad tried to use __EXCEPTIONS to figure out if c++ exceptions are enabled.
In cc files, this works: -fno-exceptions will disable c++ exceptions and
cleanups. But in mm files, -fno-exceptions will disable c++ exceptions and
objective-c exceptions will still be enabled, and so cleanups must run and hence
__EXCEPTIONS is defined.

To make things work with both old and new compilers, do the try/catch hack in
mm files either if __EXCEPTIONS is not defined (for old compilers) or if the
compiler is clang and __has_feature(cxx_exceptions) isn't set (which will work
for new clangs too, and which cleanly maps to if c++ exceptions are enabled).

Patch by Nico Weber <thakis@chromium.org>

Review URL: https://breakpad.appspot.com/1774002/


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1409 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-12-10 16:08:09 +00:00
mseaborn@chromium.org
e9df0305d3 dump_syms: Fix handling of DW_FORM_ref_addr to work with DWARF 4
Previously, dump_syms did not handle DW_FORM_ref_addr if it appeared
in DWARF 4 debugging info.

Also fix a DW_FORM_ref_addr case so that it doesn't fall through to
the next switch case when assertions are disabled and the DWARF
version isn't recognised.

The following steps will reproduce the problem when using LLVM 3.4:

cat <<END >example1.c
int main() { return 0; }
END
cat <<END >example2.c
void foo(int x) {}
END

clang -emit-llvm -g -c example1.c -o example1.bc
clang -emit-llvm -g -c example2.c -o example2.bc
llvm-link-3.4 example1.bc example2.bc -o combined.bc
clang combined.bc -o executable
./google-breakpad/build/src/tools/linux/dump_syms/dump_syms executable

When using LLVM bitcode linking in this way, LLVM's backend generates
partially-merged DWARF debugging info in which some of the references
to the "int" type go via "DW_FORM_ref_addr".  Since PNaCl uses LLVM
bitcode linking, this dump_syms failure occurs with nexes produced by
the PNaCl toolchain.

BUG= https://code.google.com/p/chromium/issues/detail?id=416368
TEST= see above
R=mark@chromium.org, mcgrathr@chromium.org

Review URL: https://breakpad.appspot.com/5744002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1408 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-12-03 20:39:55 +00:00
primiano@chromium.org
a4283fc4cf Microdumps: support aarch64 and lib mapping from APK
- Filter modules by prot flags (only +x) not extensions. It wouldn't
  otherwise catch the case of Chrome mapping the library from the
  apk (which is mapped r-x but doesn't end in .so).
- Use compile-time detection of target arch, in order to cope with
  multilib OSes, where uname() doesn't reflect the run-time arch.
- Add OS information and CPU arch / count.
- Add support for aarch64.
- Add tests and stackwalk expectations for aarch64.
- Fix a potential overflow bug in the processor.
- Rebaseline the tests using smaller symbols.
- Fix microdump_writer_unittest.cc on 32-bit host.

BUG=chromium:410294

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1407 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-12-02 15:31:25 +00:00
ivanpe@chromium.org
259512f933 Surfacing the process create time in google_breakpad::ProcessState
and updating minidump_stackwalk to show process uptime.

I tested this with a minidump from Chrome and I got a result that
is inline with what the Windows debugger is showing for that dump:

minidump_stackwalk output:
--------------------------
Process uptime: 601 seconds

WinDBG output:
--------------
Process Uptime: 0 days 0:10:01.000

I didn't update the machine readable output of minidump_stackwalk
on purpose in order to avoid breaking someone that uses it.
It can be added later to the machine output if needed.

R=mark@chromium.org

Review URL: https://breakpad.appspot.com/7754002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1406 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-11-25 22:45:23 +00:00
primiano@chromium.org
725a5dff8a Introduce microdump_stackwalk comand line executable
This introduces the microdump_stackwalk binary which takes advantage
of the MicrodumpProcessor to symbolize microdumps.
Its operation is identical to the one of minidump_stackwalk.
This CL, in fact, is also refactoring most of the common bits into
stackwalk_common.

BUG=chromium:410294
R=mmandlis@chromium.org

Review URL: https://breakpad.appspot.com/4704002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1405 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-11-25 11:36:38 +00:00
primiano@chromium.org
63f4e5f479 Fix microdump_writer and add unittest.
This adds some small fixes to the microdump writer and introduces
a unittest.

BUG=chromium:410294
R=mmandlis@chromium.org

Review URL: https://breakpad.appspot.com/2814002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1404 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-11-25 10:35:53 +00:00
mmandlis@chromium.org
7de07eed33 Microdump processing implementation
According to design document: http://goo.gl/B3wIRN
This is an initial implementation version, support ARM architecture only.

BUG=chromium:410294
R=primiano@chromium.org

Review URL: https://breakpad.appspot.com/5714003

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1403 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-11-19 21:33:26 +00:00
262 changed files with 176775 additions and 5367 deletions

38
.gitignore vendored
View File

@ -26,6 +26,39 @@
# (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.
.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/processor/microdump_stackwalk
/src/processor/minidump_dump
/src/processor/minidump_stackwalk
/src/tools/linux/core2md/core2md
/src/tools/linux/dump_syms/dump_syms
/src/tools/linux/md2core/minidump-2-core
/src/tools/linux/symupload/minidump_upload
/src/tools/linux/symupload/sym_upload
/src/tools/mac/dump_syms/dump_syms
# Ignore autotools generated artifacts.
.deps
.dirstamp
autom4te.cache/
/config.cache
config.h
/config.log
/config.status
/Makefile
stamp-h1
# Ignore GYP generated Visual Studio artifacts.
*.filters
*.sdf
@ -34,6 +67,11 @@
*.vcproj
*.vcxproj
# Ignore GYP generated Makefiles
src/Makefile
*.Makefile
*.target.mk
# Ignore compiled Python files.
*.pyc

21
DEPS
View File

@ -35,22 +35,31 @@
deps = {
# Logging code.
"src/src/third_party/glog":
"http://google-glog.googlecode.com/svn/trunk@97",
"https://github.com/google/glog.git" +
"@v0.3.4",
# Testing libraries and utilities.
"src/src/testing": "http://googlemock.googlecode.com/svn/trunk@408",
"src/src/testing/gtest": "http://googletest.googlecode.com/svn/trunk@615",
"src/src/testing":
"https://github.com/google/googlemock.git" +
"@release-1.7.0",
"src/src/testing/gtest":
"https://github.com/google/googletest.git" +
"@release-1.7.0",
# Protobuf.
"src/src/third_party/protobuf/protobuf":
"http://protobuf.googlecode.com/svn/trunk@407",
"https://github.com/google/protobuf.git" +
"@cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac",
# GYP project generator.
"src/src/tools/gyp": "http://gyp.googlecode.com/svn/trunk@1886",
"src/src/tools/gyp":
"https://chromium.googlesource.com/external/gyp/" +
"@e8ab0833a42691cd2184bd4c45d779e43821d3e0",
# Linux syscall support.
"src/src/third_party/lss":
"http://linux-syscall-support.googlecode.com/svn/trunk/lss@24",
"https://chromium.googlesource.com/linux-syscall-support/" +
"@9292030109847793f7a6689adac1ddafb412fe14"
}
hooks = [

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

43
README
View File

@ -1,43 +0,0 @@
Breakpad is a set of client and server components which implement a
crash-reporting system.
-----
Getting started in 32-bit mode (from trunk)
Configure: CXXFLAGS=-m32 CFLAGS=-m32 CPPFLAGS=-m32 ./configure
Build: make
Test: make check
Install: make install
If you need to reconfigure your build be sure to run "make distclean" first.
-----
To request change review:
0. Get access to a read-write copy of source.
Owners at http://code.google.com/p/google-breakpad/ are able to grant
this access.
1. Check out a read-write copy of source using instructions at
http://code.google.com/p/google-breakpad/source/checkout
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. Download http://codereview.appspot.com/static/upload.py
4. Run upload.py from the 'src' directory:
upload.py --server=breakpad.appspot.com
You will be prompted for credential and a description.
5. At http://breakpad.appspot.com you'll find your issue listed; click on it,
and select Publish+Mail, and enter in the code reviewer and CC
google-breakpad-dev@googlegroups.com
6. When applying code review feedback, specify the '-i' option when running
upload.py again and pass the issue number so it updates the existing issue,
rather than creating a new one.
Be sure to rerun upload.py from the same directory as you did for previous
uploads to allow for proper diff calculations.

49
README.md Normal file
View File

@ -0,0 +1,49 @@
# Breakpad
Breakpad is a set of client and server components which implement a
crash-reporting system.
* [Homepage](https://chromium.googlesource.com/breakpad/breakpad/)
* [Documentation](https://chromium.googlesource.com/breakpad/breakpad/+/master/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)
## Getting started in 32-bit mode (from trunk)
```sh
# Configure
CXXFLAGS=-m32 CFLAGS=-m32 CPPFLAGS=-m32 ./configure
# Build
make
# Test
make check
# Install
make install
```
If you need to reconfigure your build be sure to run `make distclean` first.
## To request change review:
1. Get a copy of depot_tools repo.
http://dev.chromium.org/developers/how-tos/install-depot-tools
2. Create a new directory for checking out the source code.
mkdir breakpad && cd breakpad
3. Run the `fetch` tool from depot_tools to download all the source repos.
`fetch breakpad`
4. 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.
5. 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.
6. At https://codereview.chromium.org/ you'll find your issue listed; click on
it, and select Publish+Mail, and enter in the code reviewer and CC
google-breakpad-dev@googlegroups.com

131
aclocal.m4 vendored
View File

@ -1,6 +1,6 @@
# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
# generated automatically by aclocal 1.15 -*- Autoconf -*-
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -20,7 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
# Copyright (C) 2002-2013 Free Software Foundation, Inc.
# Copyright (C) 2002-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -32,10 +32,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.])
# generated from the m4 files accompanying Automake X.Y.
# (This private macro should not be called outside this file.)
AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.14'
[am__api_version='1.15'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
m4_if([$1], [1.14.1], [],
m4_if([$1], [1.15], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@ -51,14 +51,74 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.14.1])dnl
[AM_AUTOMAKE_VERSION([1.15])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
#
# 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.
# AM_PROG_AR([ACT-IF-FAIL])
# -------------------------
# Try to determine the archiver interface, and trigger the ar-lib wrapper
# if it is needed. If the detection of archiver interface fails, run
# ACT-IF-FAIL (default is to abort configure with a proper error message).
AC_DEFUN([AM_PROG_AR],
[AC_BEFORE([$0], [LT_INIT])dnl
AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
AC_REQUIRE_AUX_FILE([ar-lib])dnl
AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
: ${AR=ar}
AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
[AC_LANG_PUSH([C])
am_cv_ar_interface=ar
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
[am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
AC_TRY_EVAL([am_ar_try])
if test "$ac_status" -eq 0; then
am_cv_ar_interface=ar
else
am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
AC_TRY_EVAL([am_ar_try])
if test "$ac_status" -eq 0; then
am_cv_ar_interface=lib
else
am_cv_ar_interface=unknown
fi
fi
rm -f conftest.lib libconftest.a
])
AC_LANG_POP([C])])
case $am_cv_ar_interface in
ar)
;;
lib)
# Microsoft lib, so override with the ar-lib wrapper script.
# FIXME: It is wrong to rewrite AR.
# But if we don't then we get into trouble of one sort or another.
# A longer-term fix would be to have automake use am__AR in this case,
# and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
# similar.
AR="$am_aux_dir/ar-lib $AR"
;;
unknown)
m4_default([$1],
[AC_MSG_ERROR([could not determine $AR interface])])
;;
esac
AC_SUBST([AR])dnl
])
# Figure out how to run the assembler. -*- Autoconf -*-
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -78,7 +138,7 @@ _AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -123,15 +183,14 @@ _AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
[dnl Rely on autoconf to set up CDPATH properly.
AC_PREREQ([2.50])dnl
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
# Expand $ac_aux_dir to an absolute path.
am_aux_dir=`cd "$ac_aux_dir" && pwd`
])
# AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997-2013 Free Software Foundation, Inc.
# Copyright (C) 1997-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -162,7 +221,7 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -353,7 +412,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
# Generate code to set up dependency tracking. -*- Autoconf -*-
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -429,7 +488,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -519,8 +578,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
# We need awk for the "check" target (and possibly the TAP driver). The
# system "awk" is bad on some platforms.
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
@ -593,7 +652,11 @@ to "yes", and re-run configure.
END
AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
fi
fi])
fi
dnl The trailing newline in this macro's definition is deliberate, for
dnl backward compatibility and to allow trailing 'dnl'-style comments
dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
])
dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
@ -622,7 +685,7 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -633,7 +696,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co
# Define $install_sh.
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
if test x"${install_sh}" != xset; then
if test x"${install_sh+set}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@ -643,7 +706,7 @@ if test x"${install_sh}" != xset; then
fi
AC_SUBST([install_sh])])
# Copyright (C) 2003-2013 Free Software Foundation, Inc.
# Copyright (C) 2003-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -665,7 +728,7 @@ AC_SUBST([am__leading_dot])])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -700,7 +763,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
# Check to see how 'make' treats includes. -*- Autoconf -*-
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -750,7 +813,7 @@ rm -f confinc confmf
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
# Copyright (C) 1997-2013 Free Software Foundation, Inc.
# Copyright (C) 1997-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -791,7 +854,7 @@ fi
# Obsolete and "removed" macros, that must however still report explicit
# error messages when used, to smooth transition.
#
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -818,7 +881,7 @@ AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES])
# Helper functions for option handling. -*- Autoconf -*-
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -847,7 +910,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -894,7 +957,7 @@ AC_LANG_POP([C])])
# For backward compatibility.
AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -913,7 +976,7 @@ AC_DEFUN([AM_RUN_LOG],
# Check to make sure that the build environment is sane. -*- Autoconf -*-
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -994,7 +1057,7 @@ AC_CONFIG_COMMANDS_PRE(
rm -f conftest.file
])
# Copyright (C) 2009-2013 Free Software Foundation, Inc.
# Copyright (C) 2009-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -1054,7 +1117,7 @@ AC_SUBST([AM_BACKSLASH])dnl
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
])
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
# Copyright (C) 2001-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -1082,7 +1145,7 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
# Copyright (C) 2006-2013 Free Software Foundation, Inc.
# Copyright (C) 2006-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -1101,7 +1164,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
# Copyright (C) 2004-2013 Free Software Foundation, Inc.
# Copyright (C) 2004-2014 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

270
autotools/ar-lib Executable file
View File

@ -0,0 +1,270 @@
#! /bin/sh
# Wrapper for Microsoft lib.exe
me=ar-lib
scriptversion=2012-03-01.08; # UTC
# Copyright (C) 2010-2014 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 <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>.
# 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*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv in
mingw)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin)
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" | 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

View File

@ -3,7 +3,7 @@
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify

View File

@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2014 Free Software Foundation, Inc.
# Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2014-03-23'
timestamp='2016-01-01'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@ -24,12 +24,12 @@ timestamp='2014-03-23'
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
# Originally written by Per Bothner.
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
#
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
# Please send patches to <config-patches@gnu.org>.
me=`echo "$0" | sed -e 's,.*/,,'`
@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2014 Free Software Foundation, Inc.
Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -168,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
/usr/sbin/$sysctl 2>/dev/null || echo unknown)`
UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
/sbin/$sysctl 2>/dev/null || \
/usr/sbin/$sysctl 2>/dev/null || \
echo unknown)`
case "${UNAME_MACHINE_ARCH}" in
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
earmv*)
arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
machine=${arch}${endian}-unknown
;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently, or will in the future.
case "${UNAME_MACHINE_ARCH}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
@ -197,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
os=netbsd
;;
esac
# Determine ABI tags.
case "${UNAME_MACHINE_ARCH}" in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
;;
esac
# The OS release
# Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need
@ -207,13 +221,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
release='-gnu'
;;
*)
release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}"
echo "${machine}-${os}${release}${abi}"
exit ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
@ -235,6 +249,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
exit ;;
*:Sortix:*:*)
echo ${UNAME_MACHINE}-unknown-sortix
exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
@ -579,8 +596,9 @@ EOF
else
IBM_ARCH=powerpc
fi
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
if [ -x /usr/bin/lslpp ] ; then
IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
else
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
@ -932,6 +950,9 @@ EOF
crisv32:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
e2k:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
frv:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
@ -944,6 +965,9 @@ EOF
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
k1om:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
@ -1020,18 +1044,7 @@ EOF
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;;
x86_64:Linux:*:*)
eval $set_cc_for_build
X86_64_ABI=
# If there is a compiler, see if it is configured for 32-bit objects.
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_X32 >/dev/null
then
X86_64_ABI=x32
fi
fi
echo x86_64-unknown-linux-gnu${X86_64_ABI}
echo ${UNAME_MACHINE}-pc-linux-${LIBC}
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@ -1110,7 +1123,7 @@ EOF
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configury will decide that
# prints for the "djgpp" host, or else GDB configure will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
@ -1380,6 +1393,9 @@ EOF
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
amd64:Isilon\ OneFS:*:*)
echo x86_64-unknown-onefs
exit ;;
esac
cat >&2 <<EOF
@ -1389,9 +1405,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
and
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
If the version you run ($0) is already up to date, please
send the following data and any information you think might be

67
autotools/config.sub vendored
View File

@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2014 Free Software Foundation, Inc.
# Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2014-07-28'
timestamp='2016-01-01'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@ -25,7 +25,7 @@ timestamp='2014-07-28'
# of the GNU General Public License, version 3 ("GPLv3").
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
# Please send patches to <config-patches@gnu.org>.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
@ -33,7 +33,7 @@ timestamp='2014-07-28'
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@ -53,8 +53,7 @@ timestamp='2014-07-28'
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS
$0 [OPTION] ALIAS
Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
Canonicalize a configuration name.
@ -68,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright 1992-2014 Free Software Foundation, Inc.
Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -117,7 +116,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
@ -255,12 +254,13 @@ case $basic_machine in
| arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
| ba \
| be32 | be64 \
| bfin \
| c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx | dvp \
| epiphany \
| fido | fr30 | frv \
| d10v | d30v | dlx | dsp16xx \
| e2k | epiphany \
| fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
| i370 | i860 | i960 | ia64 \
@ -302,9 +302,10 @@ case $basic_machine in
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
| riscv32 | riscv64 \
| rl78 | rx \
| score \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@ -312,6 +313,7 @@ case $basic_machine in
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| visium \
| we32k \
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
@ -326,6 +328,9 @@ case $basic_machine in
c6x)
basic_machine=tic6x-unknown
;;
leon|leon[3-9])
basic_machine=sparc-$basic_machine
;;
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
basic_machine=$basic_machine-unknown
os=-none
@ -371,12 +376,13 @@ case $basic_machine in
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| ba-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
| e2k-* | elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
@ -423,12 +429,13 @@ case $basic_machine in
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
| riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \
@ -436,6 +443,7 @@ case $basic_machine in
| ubicom32-* \
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| visium-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
@ -512,6 +520,9 @@ case $basic_machine in
basic_machine=i386-pc
os=-aros
;;
asmjs)
basic_machine=asmjs-unknown
;;
aux)
basic_machine=m68k-apple
os=-aux
@ -773,6 +784,9 @@ case $basic_machine in
basic_machine=m68k-isi
os=-sysv
;;
leon-*|leon[3-9]-*)
basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
;;
m68knommu)
basic_machine=m68k-unknown
os=-linux
@ -814,24 +828,6 @@ case $basic_machine in
basic_machine=m68k-atari
os=-mint
;;
mipsEE* | ee | ps2)
basic_machine=mips64r5900el-scei
case $os in
-linux*)
;;
*)
os=-elf
;;
esac
;;
iop)
basic_machine=mipsel-scei
os=-irx
;;
dvp)
basic_machine=dvp-scei
os=-elf
;;
mips3*-*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;;
@ -1382,7 +1378,7 @@ case $os in
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* | -aros* \
| -aos* | -aros* | -cloudabi* | -sortix* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
@ -1398,11 +1394,12 @@ case $os in
| -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -irx* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
| -onefs* | -tirtos*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)

View File

@ -3,7 +3,7 @@
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Copyright (C) 1999-2014 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

View File

@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-11-20.07; # UTC
scriptversion=2013-12-25.23; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" "" $nl"
IFS=" $tab$nl"
# set DOITPROG to echo to test this script
# Set DOITPROG to "echo" to test this script.
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
@ -68,17 +64,6 @@ mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
@ -97,7 +82,7 @@ dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@ -137,46 +122,57 @@ while test $# -ne 0; do
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
shift;;
-s) stripcmd=$stripprog;;
-t) 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=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
-*) 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.
@ -207,6 +203,15 @@ if test $# -eq 0; then
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
@ -223,16 +228,16 @@ if test -z "$dir_arg"; then
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw='% 200'
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw=,u+rw
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
@ -269,41 +274,15 @@ do
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
@ -314,74 +293,74 @@ do
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# 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
# 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
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/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.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/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.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
@ -391,53 +370,51 @@ do
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set -f
set fnord $dstdir
shift
$posix_glob set +f
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
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/
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
# 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
@ -472,15 +449,12 @@ do
# 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` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
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 &&
$posix_glob set +f &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
@ -493,24 +467,24 @@ do
# 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 -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# 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 -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$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"
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1

View File

@ -3,7 +3,7 @@
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Copyright (C) 1996-2014 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

View File

@ -3,7 +3,7 @@
scriptversion=2013-07-13.22; # UTC
# Copyright (C) 2011-2013 Free Software Foundation, Inc.
# Copyright (C) 2011-2014 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
@ -106,11 +106,14 @@ trap "st=143; $do_exit" 15
# Test script is run here.
"$@" >$log_file 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
estatus=1
tweaked_estatus=1
else
tweaked_estatus=$estatus
fi
case $estatus:$expect_failure in
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;;
@ -119,6 +122,12 @@ case $estatus:$expect_failure in
*:*) 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"

View File

@ -1,5 +1,5 @@
# This file is used by gcl to get repository specific information.
CODE_REVIEW_SERVER: breakpad.appspot.com
CODE_REVIEW_SERVER: codereview.chromium.org
CC_LIST: google-breakpad-dev@googlegroups.com
TRY_ON_UPLOAD: False
VIEW_VC: http://code.google.com/p/google-breakpad/source/detail?r=
VIEW_VC: https://chromium.googlesource.com/breakpad/breakpad/+/

1201
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@ AC_PREREQ(2.57)
AC_INIT(breakpad, 0.1, google-breakpad-dev@googlegroups.com)
dnl Sanity check: the argument is just a file that should exist.
AC_CONFIG_SRCDIR(README)
AC_CONFIG_SRCDIR(README.md)
AC_CONFIG_AUX_DIR(autotools)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
@ -41,6 +41,7 @@ AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.11.1)
AM_CONFIG_HEADER(src/config.h)
AM_MAINTAINER_MODE
AM_PROG_AR
AM_PROG_AS
AC_PROG_CC
AM_PROG_CC_C_O
@ -75,6 +76,9 @@ m4_include(m4/ax_pthread.m4)
AX_PTHREAD
AC_CHECK_HEADERS([a.out.h])
m4_include(m4/ax_cxx_compile_stdcxx.m4)
AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
# Only build Linux client libs when compiling for Linux
case $host in
*-*-linux* | *-android* )
@ -91,6 +95,14 @@ case $host in
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]
@ -131,6 +143,39 @@ if test x$LINUX_HOST = xfalse -a x$disable_processor = xtrue -a x$disable_tools
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)]),
[case "${enableval}" in
yes)
system_test_libs=true
;;
no)
system_test_libs=false
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --enable-system-test-libs)
;;
esac],
[system_test_libs=false])
AM_CONDITIONAL(SYSTEM_TEST_LIBS, test x$system_test_libs = xtrue)
AC_ARG_VAR([GMOCK_CONFIG], [Path to gmock-config script])
AC_ARG_VAR([GMOCK_CFLAGS], [Compiler flags for gmock])
AC_ARG_VAR([GMOCK_LIBS], [Linker flags for gmock])
AC_ARG_VAR([GTEST_CONFIG], [Path to gtest-config script])
AC_ARG_VAR([GTEST_CFLAGS], [Compiler flags for gtest])
AC_ARG_VAR([GTEST_LIBS], [Linker flags for gtest])
if test x$system_test_libs = xtrue; then
AC_CHECK_TOOL([GMOCK_CONFIG], [gmock-config])
AC_CHECK_TOOL([GTEST_CONFIG], [gtest-config])
GMOCK_CFLAGS=`$GMOCK_CONFIG --cppflags --cxxflags`
GMOCK_LIBS=`$GMOCK_CONFIG --ldflags --libs`
GTEST_CFLAGS=`$GTEST_CONFIG --cppflags --cxxflags`
GTEST_LIBS=`$GTEST_CONFIG --ldflags --libs`
fi
AC_ARG_ENABLE(selftest,
AS_HELP_STRING([--enable-selftest],
[Run extra tests with "make check" ]

1
docs/OWNERS Normal file
View File

@ -0,0 +1 @@
*

BIN
docs/breakpad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

1023
docs/breakpad.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 45 KiB

224
docs/client_design.md Normal file
View File

@ -0,0 +1,224 @@
# 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 programs 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, its a relatively simple matter of making one call to
register a [top-level exception filter]
(http://msdn.microsoft.com/library/en-us/debug/base/setunhandledexceptionfilter.asp)
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 its 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 shouldnt 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 systems 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 stacks 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
Breakpads 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
didnt 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 platforms native crash reporting
system, such as Mac OS X [CrashReporter]
(http://developer.apple.com/technotes/tn2004/tn2123.html) and [Windows Error
Reporting](http://msdn.microsoft.com/isv/resources/wer/).
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 servers 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 platforms 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 weve 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 librarys robustness.
On Windows, we intend to offer tools to make it easier for Breakpads 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
applications launch sequence, including crashes that occur before a programs
main function begins executing.

View File

@ -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.

128
docs/exception_handling.md Normal file
View File

@ -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.

View File

@ -0,0 +1,121 @@
# 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.
![http://google-breakpad.googlecode.com/svn/wiki/breakpad.png]
(http://google-breakpad.googlecode.com/svn/wiki/breakpad.png)
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
http://code.google.com/p/google-breakpad. The following directory structure is
present in the `src` directory:
* `processor` Contains minidump-processing code that is used on the server
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)
* <a
href='http://code.google.com/p/google-breakpad/wiki/WindowsClientIntegration'>Windows
Integration Guide</a>
* <a
href='http://code.google.com/p/google-breakpad/wiki/MacBreakpadStarterGuide'>Mac
Integration Guide</a>
* <a href='http://code.google.com/p/google-breakpad/wiki/LinuxStarterGuide'>
Linux Integration Guide</a>
## Build process specifics(symbol generation)
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.

View File

@ -0,0 +1,97 @@
# 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: ```
# 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:
```
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 <a
href='http://code.google.com/p/google-breakpad/source/browse/trunk/src/client/linux/handler/exception_handler.h'>in
the exception_handler.h source file</a>.
**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 <a
href='http://code.google.com/p/google-breakpad/source/browse/trunk/src/common/linux/linux_libc_support.h'>some
simple reimplementations of libc functions</a>, to avoid calling directly into
libc, as well as <a href='http://code.google.com/p/linux-syscall-support/'>a
header file for making Linux system calls</a> (in **src/third\_party/lss**) to
avoid calling into other shared libraries.
## 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 <a
href='http://code.google.com/p/google-breakpad/source/browse/#svn/trunk/src/common/linux'>some
HTTP upload source</a> that you might find useful, as well as <a
href='http://code.google.com/p/google-breakpad/source/browse/#svn/trunk/src/tools/linux/symupload'>a
minidump upload tool</a>.
## Producing symbols for your application
To produce useful stack traces, Breakpad requires you to convert the debugging
symbols in your binaries to <a
href='http://code.google.com/p/google-breakpad/wiki/SymbolFiles'>text-format
symbol files</a>. 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`: `$ 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 <a
href='http://mxr.mozilla.org/mozilla-central/source/toolkit/crashreporter/tools/symbolstore.py'>symbolstore.py</a>
script in the Mozilla repository useful, as it encapsulates these steps.
## 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.

View File

@ -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.

View File

@ -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.

View File

@ -0,0 +1,84 @@
# 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: http://code.google.com/p/google-breakpad/
* Mailing lists
* [google-breakpad-dev@googlegroups.com]
(http://groups.google.com/group/google-breakpad-dev/)
* [google-breakpad-discuss@googlegroups.com]
(http://groups.google.com/group/google-breakpad-discuss/)
* Ask me (irc.mozilla.org: mento)

230
docs/processor_design.md Normal file
View File

@ -0,0 +1,230 @@
# 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 users computer; in the case of
CrashReporter, the reports are transmitted only to Apple, not to third-party
developers. Other systems, such as [Microsoft](http://www.microsoft.com/)s
[Windows Error Reporting](http://msdn.microsoft.com/isv/resources/wer/) and
SupportSofts 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 Microsofts 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 Microsofts
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 threads 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 Breakpads 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
platforms native executable format, there are complications involved in
accessing the data contained therein without the benefit of the header files
that define an executable formats 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 Breakpads 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 Microsofts 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.
Breakpads symbol file format is text-based, and was defined to be fairly
human-readable and to encompass the needs of multiple platforms. The Breakpad
processor itself does not operate directly with native symbol formats ([DWARF]
(http://dwarf.freestandards.org/) and [STABS]
(http://sourceware.org/gdb/current/onlinedocs/stabs.html) on most Unix-like
systems, [.pdb files]
(http://msdn2.microsoft.com/en-us/library/yd4f8bd1(VS.80).aspx) on Windows),
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, Breakpads symbol files are produced on each platform,
using specific debugging APIs where available, to convert native symbols to
Breakpads 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 Breakpads use using the included `dump_syms` or `symupload` tools, or
another suitable tool, and place the symbol files where the processors symbol
supplier will be able to locate them.
When a dump file is given to the processors `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 processors `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 threads 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.

160
docs/stack_walking.md Normal file
View File

@ -0,0 +1,160 @@
# 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]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/minidump_processor.cc)
class and calling the [MinidumpProcessor::Process]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/minidump_processor.cc#61)
method, providing it a minidump file to process. To produce a useful stack
trace, the MinidumpProcessor requires two other objects which are passed in its
constructor: a [SymbolSupplier]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/symbol_supplier.h)
and a [SourceLineResolverInterface]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h).
The SymbolSupplier object is responsible for locating and providing SymbolFiles
that match modules from the minidump. The SourceLineResolverInterface is
responsible for loading the symbol files and using the information contained
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]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#335)),
the list of modules loaded in the process ([MinidumpModuleList]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#501)),
and information about the exception that caused the process to crash
([MinidumpException]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#615)).
## Enumerating Threads
For each thread in the thread list ([MinidumpThread]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#299)),
the thread memory containing the stack for the thread ([MinidumpMemoryRegion]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#236))
and the CPU context representing the CPU state of the thread at the time the
dump was written ([MinidumpContext]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/minidump.h#171))
are extracted from the minidump. If the thread being processed is the thread
that produced the exception then a CPU context is obtained from the
MinidumpException object instead, which represents the CPU state of the thread
at the point of the exception. A stack walker is then instantiated by calling
the [Stackwalker::StackwalkerForCPU]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/stackwalker.h#77)
method and passing it the CPU context, the thread memory, the module list, as
well as the SymbolSupplier and SourceLineResolverInterface. This method selects
the specific !Stackwalker subclass based on the CPU architecture of the provided
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]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h)
method to obtain a list of frames representing the stack of this thread. The
!Stackwalker starts by calling the GetContextFrame method which returns a
StackFrame representing the top of the stack, with CPU state provided by the
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]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/code_modules.h#56)
method.
### Locating Symbols
If a module is located, the SymbolSupplier is asked to locate symbols
corresponding to the module by calling its [GetCStringSymbolData]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/symbol_supplier.h#87)
method. Typically this is implemented by using the module's debug filename (the
PDB filename for Windows dumps) and debug identifier (a GUID plus one extra
digit) as a lookup key. The [SimpleSymbolSupplier]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/simple_symbol_supplier.cc)
class simply uses these as parts of a file path to locate a flat file on disk.
### Loading Symbols
If a symbol file is located, the SourceLineResolverInterface is then asked to
load the symbol file by calling its [LoadModuleUsingMemoryBuffer]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h#71)
method. The [BasicSourceLineResolver]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/basic_source_line_resolver.cc)
implementation parses the text-format [symbol file](symbol_files.md) into
in-memory data structures to make lookups by address of function names, source
line information, and unwind information easy.
### Getting source line information
If a symbol file has been successfully loaded, the SourceLineResolverInterface's
[FillSourceLineInfo]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h#89)
method is called to provide a function name and source line information for the
current frame. This is done by subtracting the base address of the module
containing the current frame from the instruction pointer of the current frame
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]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/stackwalker.h#186)
method, passing in the current frame. Each !Stackwalker subclass implements
GetCallerFrame differently, but there are common patterns.
Typically the first step is to query the SourceLineResolverInterface for the
presence of detailed unwind information. This is done using its
[FindWindowsFrameInfo]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h#96)
and [FindCFIFrameInfo]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/source_line_resolver_interface.h#102)
methods. These methods look for Windows unwind info extracted from a PDB file
([STACK WIN](SymbolFiles#STACK_WIN_records.md) lines from the symbol file), or
DWARF CFI extracted from a binary ([STACK CFI](SymbolFiles#STACK_CFI_records.md)
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]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/stackwalker.h#131)
method) and using a heuristic to attempt to find a reasonable return address
(implemented in the [Stackwalker::InstructionAddressSeemsValid]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/google_breakpad/processor/stackwalker.h#111)
method).
If no caller frame is found or the caller frame seems invalid, stack walking
stops. If a caller frame was found then these steps repeat using the new frame
as the current frame.

497
docs/symbol_files.md Normal file
View File

@ -0,0 +1,497 @@
# 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.
* A `FUNC` record describes a function present in the source code.
* 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.
# `FUNC` records
A `FUNC` record describes a source-language function. It has the form:
> `FUNC` _address_ _size_ _parameter\_size_ _name_
For example: `FUNC c184 30 0 nsQueryInterfaceWithError::operator()(nsID const&,
void**) const
`
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.
# 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 _address_ _parameter\_size_ _name_
For example: `PUBLIC 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 _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]
(http://code.google.com/p/google-breakpad/source/browse/trunk/src/processor/postfix_evaluator.h#40)
header file explain the language in which the program is written. You should
place the following variables in the dictionary before interpreting the
program:
* `$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
```

View File

@ -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.

558
m4/ax_cxx_compile_stdcxx.m4 Normal file
View File

@ -0,0 +1,558 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXXFLAGS to
# enable support. VERSION may be '11' (for the C++11 standard) or '14'
# (for the C++14 standard).
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# required and that the macro should error out if no mode with that
# support is found. If specified 'optional', then configuration proceeds
# regardless, after defining HAVE_CXX${VERSION} if and only if a
# supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [],
[$1], [14], [],
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
[$2], [noext], [],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++$1 -std=gnu++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
m4_if([$2], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
fi
else
if test x$ac_success = xno; then
HAVE_CXX$1=0
AC_MSG_NOTICE([No compiler with C++$1 support was found])
else
HAVE_CXX$1=1
AC_DEFINE(HAVE_CXX$1,1,
[define if the compiler supports basic C++$1 syntax])
fi
AC_SUBST(HAVE_CXX$1)
fi
])
dnl Test body for checking C++11 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
// If the compiler admits that it is not ready for C++11, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#else
namespace cxx11
{
namespace test_static_assert
{
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
}
namespace test_final_override
{
struct Base
{
virtual void f() {}
};
struct Derived : public Base
{
virtual void f() override {}
};
}
namespace test_double_right_angle_brackets
{
template < typename T >
struct check {};
typedef check<void> single_type;
typedef check<check<void>> double_type;
typedef check<check<check<void>>> triple_type;
typedef check<check<check<check<void>>>> quadruple_type;
}
namespace test_decltype
{
int
f()
{
int a = 1;
decltype(a) b = 2;
return a + b;
}
}
namespace test_type_deduction
{
template < typename T1, typename T2 >
struct is_same
{
static const bool value = false;
};
template < typename T >
struct is_same<T, T>
{
static const bool value = true;
};
template < typename T1, typename T2 >
auto
add(T1 a1, T2 a2) -> decltype(a1 + a2)
{
return a1 + a2;
}
int
test(const int c, volatile int v)
{
static_assert(is_same<int, decltype(0)>::value == true, "");
static_assert(is_same<int, decltype(c)>::value == false, "");
static_assert(is_same<int, decltype(v)>::value == false, "");
auto ac = c;
auto av = v;
auto sumi = ac + av + 'x';
auto sumf = ac + av + 1.0;
static_assert(is_same<int, decltype(ac)>::value == true, "");
static_assert(is_same<int, decltype(av)>::value == true, "");
static_assert(is_same<int, decltype(sumi)>::value == true, "");
static_assert(is_same<int, decltype(sumf)>::value == false, "");
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
return (sumf > 0.0) ? sumi : add(c, v);
}
}
namespace test_noexcept
{
int f() { return 0; }
int g() noexcept { return 0; }
static_assert(noexcept(f()) == false, "");
static_assert(noexcept(g()) == true, "");
}
namespace test_constexpr
{
template < typename CharT >
unsigned long constexpr
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
{
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
}
template < typename CharT >
unsigned long constexpr
strlen_c(const CharT *const s) noexcept
{
return strlen_c_r(s, 0UL);
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("1") == 1UL, "");
static_assert(strlen_c("example") == 7UL, "");
static_assert(strlen_c("another\0example") == 7UL, "");
}
namespace test_rvalue_references
{
template < int N >
struct answer
{
static constexpr int value = N;
};
answer<1> f(int&) { return answer<1>(); }
answer<2> f(const int&) { return answer<2>(); }
answer<3> f(int&&) { return answer<3>(); }
void
test()
{
int i = 0;
const int c = 0;
static_assert(decltype(f(i))::value == 1, "");
static_assert(decltype(f(c))::value == 2, "");
static_assert(decltype(f(0))::value == 3, "");
}
}
namespace test_uniform_initialization
{
struct test
{
static const int zero {};
static const int one {1};
};
static_assert(test::zero == 0, "");
static_assert(test::one == 1, "");
}
namespace test_lambdas
{
void
test1()
{
auto lambda1 = [](){};
auto lambda2 = lambda1;
lambda1();
lambda2();
}
int
test2()
{
auto a = [](int i, int j){ return i + j; }(1, 2);
auto b = []() -> int { return '0'; }();
auto c = [=](){ return a + b; }();
auto d = [&](){ return c; }();
auto e = [a, &b](int x) mutable {
const auto identity = [](int y){ return y; };
for (auto i = 0; i < a; ++i)
a += b--;
return x + identity(a + b);
}(0);
return a + b + c + d + e;
}
int
test3()
{
const auto nullary = [](){ return 0; };
const auto unary = [](int x){ return x; };
using nullary_t = decltype(nullary);
using unary_t = decltype(unary);
const auto higher1st = [](nullary_t f){ return f(); };
const auto higher2nd = [unary](nullary_t f1){
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
};
return higher1st(nullary) + higher2nd(nullary)(unary);
}
}
namespace test_variadic_templates
{
template <int...>
struct sum;
template <int N0, int... N1toN>
struct sum<N0, N1toN...>
{
static constexpr auto value = N0 + sum<N1toN...>::value;
};
template <>
struct sum<>
{
static constexpr auto value = 0;
};
static_assert(sum<>::value == 0, "");
static_assert(sum<1>::value == 1, "");
static_assert(sum<23>::value == 23, "");
static_assert(sum<1, 2>::value == 3, "");
static_assert(sum<5, 5, 11>::value == 21, "");
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
}
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
// because of this.
namespace test_template_alias_sfinae
{
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() { func<foo>(0); }
}
} // namespace cxx11
#endif // __cplusplus >= 201103L
]])
dnl Tests for new features in C++14
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
// If the compiler admits that it is not ready for C++14, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201402L
#error "This is not a C++14 compiler"
#else
namespace cxx14
{
namespace test_polymorphic_lambdas
{
int
test()
{
const auto lambda = [](auto&&... args){
const auto istiny = [](auto x){
return (sizeof(x) == 1UL) ? 1 : 0;
};
const int aretiny[] = { istiny(args)... };
return aretiny[0];
};
return lambda(1, 1L, 1.0f, '1');
}
}
namespace test_binary_literals
{
constexpr auto ivii = 0b0000000000101010;
static_assert(ivii == 42, "wrong value");
}
namespace test_generalized_constexpr
{
template < typename CharT >
constexpr unsigned long
strlen_c(const CharT *const s) noexcept
{
auto length = 0UL;
for (auto p = s; *p; ++p)
++length;
return length;
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("x") == 1UL, "");
static_assert(strlen_c("test") == 4UL, "");
static_assert(strlen_c("another\0test") == 7UL, "");
}
namespace test_lambda_init_capture
{
int
test()
{
auto x = 0;
const auto lambda1 = [a = x](int b){ return a + b; };
const auto lambda2 = [a = lambda1(x)](){ return a; };
return lambda2();
}
}
namespace test_digit_seperators
{
constexpr auto ten_million = 100'000'000;
static_assert(ten_million == 100000000, "");
}
namespace test_return_type_deduction
{
auto f(int& x) { return x; }
decltype(auto) g(int& x) { return x; }
template < typename T1, typename T2 >
struct is_same
{
static constexpr auto value = false;
};
template < typename T >
struct is_same<T, T>
{
static constexpr auto value = true;
};
int
test()
{
auto x = 0;
static_assert(is_same<int, decltype(f(x))>::value, "");
static_assert(is_same<int&, decltype(g(x))>::value, "");
return x;
}
}
} // namespace cxx14
#endif // __cplusplus >= 201402L
]])

View File

@ -30,8 +30,8 @@
#ifndef BREAKPAD_GOOGLETEST_INCLUDES_H__
#define BREAKPAD_GOOGLETEST_INCLUDES_H__
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/include/gmock/gmock.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,

View File

@ -45,7 +45,7 @@
#import "client/mac/handler/protected_memory_allocator.h"
#import "common/simple_string_dictionary.h"
#ifndef __EXCEPTIONS
#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
@ -263,8 +263,8 @@ void Breakpad::UncaughtExceptionHandler(NSException *exception) {
NSSetUncaughtExceptionHandler(NULL);
if (current_breakpad_) {
current_breakpad_->HandleUncaughtException(exception);
BreakpadRelease(current_breakpad_);
}
BreakpadRelease(current_breakpad_);
}
//=============================================================================
@ -341,7 +341,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
}
}
if (!version)
if (!version.length) // Default nil or empty string to CFBundleVersion
version = [parameters objectForKey:@"CFBundleVersion"];
if (!vendor) {

View File

@ -123,6 +123,9 @@ CrashGenerationServer::Stop()
void* dummy;
pthread_join(thread_, &dummy);
close(control_pipe_in_);
close(control_pipe_out_);
started_ = false;
}

View File

@ -1,154 +0,0 @@
// Copyright (c) 2014, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "client/linux/dump_writer_common/seccomp_unwinder.h"
#include <string.h>
#include "google_breakpad/common/minidump_format.h"
#include "common/linux/linux_libc_support.h"
namespace google_breakpad {
void SeccompUnwinder::PopSeccompStackFrame(RawContextCPU* cpu,
const MDRawThread& thread,
uint8_t* stack_copy) {
#if defined(__x86_64)
uint64_t bp = cpu->rbp;
uint64_t top = thread.stack.start_of_memory_range;
for (int i = 4; i--; ) {
if (bp < top ||
bp + sizeof(bp) > thread.stack.start_of_memory_range +
thread.stack.memory.data_size ||
bp & 1) {
break;
}
uint64_t old_top = top;
top = bp;
uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
my_memcpy(&bp, bp_addr, sizeof(bp));
if (bp == 0xDEADBEEFDEADBEEFull) {
struct {
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rdi;
uint64_t rsi;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t deadbeef;
uint64_t rbp;
uint64_t fakeret;
uint64_t ret;
/* char redzone[128]; */
} seccomp_stackframe;
if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
top - offsetof(typeof(seccomp_stackframe), deadbeef) +
sizeof(seccomp_stackframe) >
thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
break;
}
my_memcpy(&seccomp_stackframe,
bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
sizeof(seccomp_stackframe));
cpu->rbx = seccomp_stackframe.rbx;
cpu->rcx = seccomp_stackframe.rcx;
cpu->rdx = seccomp_stackframe.rdx;
cpu->rsi = seccomp_stackframe.rsi;
cpu->rdi = seccomp_stackframe.rdi;
cpu->rbp = seccomp_stackframe.rbp;
cpu->rsp = top + 4*sizeof(uint64_t) + 128;
cpu->r8 = seccomp_stackframe.r8;
cpu->r9 = seccomp_stackframe.r9;
cpu->r10 = seccomp_stackframe.r10;
cpu->r11 = seccomp_stackframe.r11;
cpu->r12 = seccomp_stackframe.r12;
cpu->r13 = seccomp_stackframe.r13;
cpu->r14 = seccomp_stackframe.r14;
cpu->r15 = seccomp_stackframe.r15;
cpu->rip = seccomp_stackframe.fakeret;
return;
}
}
#elif defined(__i386__)
uint32_t bp = cpu->ebp;
uint32_t top = thread.stack.start_of_memory_range;
for (int i = 4; i--; ) {
if (bp < top ||
bp + sizeof(bp) > thread.stack.start_of_memory_range +
thread.stack.memory.data_size ||
bp & 1) {
break;
}
uint32_t old_top = top;
top = bp;
uint8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
my_memcpy(&bp, bp_addr, sizeof(bp));
if (bp == 0xDEADBEEFu) {
struct {
uint32_t edi;
uint32_t esi;
uint32_t edx;
uint32_t ecx;
uint32_t ebx;
uint32_t deadbeef;
uint32_t ebp;
uint32_t fakeret;
uint32_t ret;
} seccomp_stackframe;
if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
top - offsetof(typeof(seccomp_stackframe), deadbeef) +
sizeof(seccomp_stackframe) >
thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
break;
}
my_memcpy(&seccomp_stackframe,
bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
sizeof(seccomp_stackframe));
cpu->ebx = seccomp_stackframe.ebx;
cpu->ecx = seccomp_stackframe.ecx;
cpu->edx = seccomp_stackframe.edx;
cpu->esi = seccomp_stackframe.esi;
cpu->edi = seccomp_stackframe.edi;
cpu->ebp = seccomp_stackframe.ebp;
cpu->esp = top + 4*sizeof(void*);
cpu->eip = seccomp_stackframe.fakeret;
return;
}
}
#endif
}
} // namespace google_breakpad

View File

@ -30,6 +30,7 @@
#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"
@ -178,12 +179,8 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
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;
#if defined (__ANDROID__)
// Internal bug b/18097559
out->flt_save.mx_csr_mask = fpregs.mxcsr_mask;
#else
out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
#endif
my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
}
@ -234,35 +231,75 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
#elif defined(__mips__)
uintptr_t ThreadInfo::GetInstructionPointer() const {
return regs.epc;
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;
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
out->iregs[i] = regs.regs[i];
out->mdhi = regs.hi;
out->mdlo = regs.lo;
for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) {
out->hi[i] = hi[i];
out->lo[i] = lo[i];
}
out->dsp_control = dsp_control;
out->epc = regs.epc;
out->badvaddr = regs.badvaddr;
out->status = regs.status;
out->cause = regs.cause;
for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
out->float_save.regs[i] = fpregs.regs[i];
out->float_save.fpcsr = fpregs.fpcsr;
out->float_save.fir = fpregs.fir;
}
#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
}
#endif // __mips__
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);
#else
if (gp_regs)
*gp_regs = &regs;
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);
#else
if (fp_regs)
*fp_regs = &fpregs;
if (size)
*size = sizeof(fpregs);
#endif
}
} // namespace google_breakpad

View File

@ -40,7 +40,7 @@
namespace google_breakpad {
#if defined(__i386) || defined(__x86_64)
typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t;
typedef __typeof__(((struct user*) 0)->u_debugreg[0]) debugreg_t;
#endif
// We produce one of these structures for each thread in the crashed process.
@ -65,15 +65,12 @@ struct ThreadInfo {
struct user_regs regs;
struct user_fpregs fpregs;
#elif defined(__aarch64__)
// Use the structures defined in <asm/ptrace.h>
struct user_pt_regs regs;
struct user_fpsimd_state fpregs;
// Use the structures defined in <sys/user.h>
struct user_regs_struct regs;
struct user_fpsimd_struct fpregs;
#elif defined(__mips__)
user_regs_struct regs;
user_fpregs_struct fpregs;
uint32_t hi[3];
uint32_t lo[3];
uint32_t dsp_control;
// Use the structure defined in <sys/ucontext.h>.
mcontext_t mcontext;
#endif
// Returns the instruction pointer (platform-dependent impl.).
@ -81,6 +78,12 @@ struct ThreadInfo {
// 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

View File

@ -219,7 +219,13 @@ uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) {
}
void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *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];
@ -244,7 +250,9 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) {
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
}
#endif

View File

@ -188,12 +188,36 @@ void RestoreAlternateStackLocked() {
stack_installed = false;
}
void InstallDefaultHandler(int sig) {
#if defined(__ANDROID__)
// Android L+ expose signal and sigaction symbols that override the system
// ones. There is a bug in these functions where a request to set the handler
// to SIG_DFL is ignored. In that case, an infinite loop is entered as the
// signal is repeatedly sent to breakpad's signal handler.
// To work around this, directly call the system's sigaction.
struct kernel_sigaction sa;
memset(&sa, 0, sizeof(sa));
sys_sigemptyset(&sa.sa_mask);
sa.sa_handler_ = SIG_DFL;
sa.sa_flags = SA_RESTART;
sys_rt_sigaction(sig, &sa, NULL, sizeof(kernel_sigset_t));
#else
signal(sig, SIG_DFL);
#endif
}
// The global exception handler stack. This is needed because there may exist
// multiple ExceptionHandler instances in a process. Each will have itself
// registered in this stack.
std::vector<ExceptionHandler*>* g_handler_stack_ = NULL;
pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER;
// sizeof(CrashContext) can be too big w.r.t the size of alternatate stack
// for SignalHandler(). Keep the crash context as a .bss field. Exception
// handlers are serialized by the |g_handler_stack_mutex_| and at most one at a
// time can use |g_crash_context_|.
ExceptionHandler::CrashContext g_crash_context_;
} // namespace
// Runs before crashing: normal context.
@ -215,7 +239,17 @@ ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor,
!minidump_descriptor_.IsMicrodumpOnConsole())
minidump_descriptor_.UpdatePath();
#if defined(__ANDROID__)
if (minidump_descriptor_.IsMicrodumpOnConsole())
logger::initializeCrashLogWriter();
#endif
pthread_mutex_lock(&g_handler_stack_mutex_);
// Pre-fault the crash context struct. This is to avoid failing due to OOM
// if handling an exception when the process ran out of virtual memory.
memset(&g_crash_context_, 0, sizeof(g_crash_context_));
if (!g_handler_stack_)
g_handler_stack_ = new std::vector<ExceptionHandler*>;
if (install_handler) {
@ -283,7 +317,7 @@ void ExceptionHandler::RestoreHandlersLocked() {
for (int i = 0; i < kNumHandledSignals; ++i) {
if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) {
signal(kExceptionSignals[i], SIG_DFL);
InstallDefaultHandler(kExceptionSignals[i]);
}
}
handlers_installed = false;
@ -323,7 +357,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
if (sigaction(sig, &cur_handler, NULL) == -1) {
// When resetting the handler fails, try to reset the
// default one to avoid an infinite loop here.
signal(sig, SIG_DFL);
InstallDefaultHandler(sig);
}
pthread_mutex_unlock(&g_handler_stack_mutex_);
return;
@ -340,14 +374,15 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
// previously installed handler. Then, when the signal is retriggered, it will
// be delivered to the appropriate handler.
if (handled) {
signal(sig, SIG_DFL);
InstallDefaultHandler(sig);
} else {
RestoreHandlersLocked();
}
pthread_mutex_unlock(&g_handler_stack_mutex_);
if (info->si_pid || sig == SIGABRT) {
// info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise).
if (info->si_code <= 0 || sig == SIGABRT) {
// This signal was triggered by somebody sending us the signal with kill().
// In order to retrigger it, we have to queue a new signal by calling
// kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is
@ -400,36 +435,37 @@ bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) {
sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
}
CrashContext context;
// Fill in all the holes in the struct to make Valgrind happy.
memset(&context, 0, sizeof(context));
memcpy(&context.siginfo, info, sizeof(siginfo_t));
memcpy(&context.context, uc, sizeof(struct ucontext));
memset(&g_crash_context_, 0, sizeof(g_crash_context_));
memcpy(&g_crash_context_.siginfo, info, sizeof(siginfo_t));
memcpy(&g_crash_context_.context, uc, sizeof(struct ucontext));
#if defined(__aarch64__)
struct ucontext *uc_ptr = (struct ucontext*)uc;
struct fpsimd_context *fp_ptr =
struct ucontext* uc_ptr = (struct ucontext*)uc;
struct fpsimd_context* fp_ptr =
(struct fpsimd_context*)&uc_ptr->uc_mcontext.__reserved;
if (fp_ptr->head.magic == FPSIMD_MAGIC) {
memcpy(&context.float_state, fp_ptr, sizeof(context.float_state));
memcpy(&g_crash_context_.float_state, fp_ptr,
sizeof(g_crash_context_.float_state));
}
#elif !defined(__ARM_EABI__) && !defined(__mips__)
#elif !defined(__ARM_EABI__) && !defined(__mips__)
// FP state is not part of user ABI on ARM Linux.
// In case of MIPS Linux FP state is already part of struct ucontext
// and 'float_state' is not a member of CrashContext.
struct ucontext *uc_ptr = (struct ucontext*)uc;
struct ucontext* uc_ptr = (struct ucontext*)uc;
if (uc_ptr->uc_mcontext.fpregs) {
memcpy(&context.float_state,
uc_ptr->uc_mcontext.fpregs,
sizeof(context.float_state));
memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fpregs,
sizeof(g_crash_context_.float_state));
}
#endif
context.tid = syscall(__NR_gettid);
g_crash_context_.tid = syscall(__NR_gettid);
if (crash_handler_ != NULL) {
if (crash_handler_(&context, sizeof(context), callback_context_)) {
if (crash_handler_(&g_crash_context_, sizeof(g_crash_context_),
callback_context_)) {
return true;
}
}
return GenerateDump(&context);
return GenerateDump(&g_crash_context_);
}
// This is a public interface to HandleSignal that allows the client to
@ -551,10 +587,12 @@ void ExceptionHandler::WaitForContinueSignal() {
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
size_t context_size) {
if (minidump_descriptor_.IsMicrodumpOnConsole()) {
return google_breakpad::WriteMicrodump(crashing_process,
context,
context_size,
mapping_list_);
return google_breakpad::WriteMicrodump(
crashing_process,
context,
context_size,
mapping_list_,
*minidump_descriptor_.microdump_extra_info());
}
if (minidump_descriptor_.IsFD()) {
return google_breakpad::WriteMinidump(minidump_descriptor_.fd(),

View File

@ -80,7 +80,11 @@ void FlushInstructionCache(const char* memory, uint32_t memory_size) {
// Provided by Android's <unistd.h>
long begin = reinterpret_cast<long>(memory);
long end = begin + static_cast<long>(memory_size);
#if _MIPS_SIM == _ABIO32
cacheflush(begin, end, 0);
#else
syscall(__NR_cacheflush, begin, end, ICACHE);
#endif
# elif defined(__linux__)
// See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
cacheflush(const_cast<char*>(memory), memory_size, ICACHE);
@ -258,8 +262,6 @@ TEST(ExceptionHandlerTest, ChildCrashWithFD) {
ASSERT_NO_FATAL_FAILURE(ChildCrash(true));
}
#endif // !ADDRESS_SANITIZER
static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor,
void* context,
bool succeeded) {
@ -301,8 +303,6 @@ static bool InstallRaiseSIGKILL() {
return sigaction(SIGSEGV, &sa, NULL) != -1;
}
#ifndef ADDRESS_SANITIZER
static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter,
ExceptionHandler::MinidumpCallback done,
string path) {
@ -770,8 +770,13 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
true, -1);
// Try calling a NULL pointer.
typedef void (*void_function)(void);
void_function memory_function = reinterpret_cast<void_function>(NULL);
// Volatile markings are needed to keep Clang from generating invalid
// opcodes. See http://crbug.com/498354 for details.
volatile void_function memory_function =
reinterpret_cast<void_function>(NULL);
memory_function();
// not reached
exit(1);
}
close(fds[1]);
@ -869,6 +874,8 @@ TEST(ExceptionHandlerTest, ModuleInfo) {
unlink(minidump_desc.path());
}
#ifndef ADDRESS_SANITIZER
static const unsigned kControlMsgSize =
CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
@ -921,8 +928,6 @@ CrashHandler(const void* crash_context, size_t crash_context_size,
return true;
}
#ifndef ADDRESS_SANITIZER
TEST(ExceptionHandlerTest, ExternalDumper) {
int fds[2];
ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1);
@ -955,7 +960,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) {
const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
ASSERT_EQ(static_cast<ssize_t>(kCrashContextSize), n);
ASSERT_EQ(kControlMsgSize, msg.msg_controllen);
ASSERT_EQ(static_cast<typeof(msg.msg_flags)>(0), msg.msg_flags);
ASSERT_EQ(static_cast<__typeof__(msg.msg_flags)>(0), msg.msg_flags);
ASSERT_EQ(0, close(fds[0]));
pid_t crashing_pid = -1;

View File

@ -0,0 +1,48 @@
// Copyright 2015 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_
#define CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_
namespace google_breakpad {
struct MicrodumpExtraInfo {
// Strings pointed to by this struct are not copied, and are
// expected to remain valid for the lifetime of the process.
const char* build_fingerprint;
const char* product_info;
const char* gpu_fingerprint;
MicrodumpExtraInfo()
: build_fingerprint(NULL), product_info(NULL), gpu_fingerprint(NULL) {}
};
}
#endif // CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_

View File

@ -36,14 +36,16 @@
namespace google_breakpad {
//static
const MinidumpDescriptor::MicrodumpOnConsole kMicrodumpOnConsole = {};
const MinidumpDescriptor::MicrodumpOnConsole
MinidumpDescriptor::kMicrodumpOnConsole = {};
MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor)
: mode_(descriptor.mode_),
fd_(descriptor.fd_),
directory_(descriptor.directory_),
c_path_(NULL),
size_limit_(descriptor.size_limit_) {
size_limit_(descriptor.size_limit_),
microdump_extra_info_(descriptor.microdump_extra_info_) {
// The copy constructor is not allowed to be called on a MinidumpDescriptor
// with a valid path_, as getting its c_path_ would require the heap which
// can cause problems in compromised environments.
@ -64,6 +66,7 @@ MinidumpDescriptor& MinidumpDescriptor::operator=(
UpdatePath();
}
size_limit_ = descriptor.size_limit_;
microdump_extra_info_ = descriptor.microdump_extra_info_;
return *this;
}

View File

@ -35,6 +35,7 @@
#include <string>
#include "client/linux/handler/microdump_extra_info.h"
#include "common/using_std_string.h"
// This class describes how a crash dump should be generated, either:
@ -49,9 +50,10 @@ class MinidumpDescriptor {
struct MicrodumpOnConsole {};
static const MicrodumpOnConsole kMicrodumpOnConsole;
MinidumpDescriptor() : mode_(kUninitialized),
fd_(-1),
size_limit_(-1) {}
MinidumpDescriptor()
: mode_(kUninitialized),
fd_(-1),
size_limit_(-1) {}
explicit MinidumpDescriptor(const string& directory)
: mode_(kWriteMinidumpToFile),
@ -99,6 +101,11 @@ class MinidumpDescriptor {
off_t size_limit() const { return size_limit_; }
void set_size_limit(off_t limit) { size_limit_ = limit; }
MicrodumpExtraInfo* microdump_extra_info() {
assert(IsMicrodumpOnConsole());
return &microdump_extra_info_;
};
private:
enum DumpMode {
kUninitialized = 0,
@ -115,13 +122,26 @@ class MinidumpDescriptor {
// The directory where the minidump should be generated.
string directory_;
// The full path to the generated minidump.
string path_;
// The C string of |path_|. Precomputed so it can be access from a compromised
// context.
const char* c_path_;
off_t size_limit_;
// The extra microdump data (e.g. product name/version, build
// fingerprint, gpu fingerprint) that should be appended to the dump
// (microdump only). Microdumps don't have the ability of appending
// extra metadata after the dump is generated (as opposite to
// minidumps MIME fields), therefore the extra data must be provided
// upfront. Any memory pointed to by members of the
// MicrodumpExtraInfo struct must be valid for the lifetime of the
// process (read: the caller has to guarantee that it is stored in
// global static storage.)
MicrodumpExtraInfo microdump_extra_info_;
};
} // namespace google_breakpad

View File

@ -31,15 +31,51 @@
#if defined(__ANDROID__)
#include <android/log.h>
#include <dlfcn.h>
#else
#include "third_party/lss/linux_syscall_support.h"
#endif
namespace logger {
#if defined(__ANDROID__)
namespace {
// __android_log_buf_write() is not exported in the NDK and is being used by
// dynamic runtime linking. Its declaration is taken from Android's
// system/core/include/log/log.h.
using AndroidLogBufferWriteFunc = int (*)(int bufID, int prio, const char *tag,
const char *text);
const int kAndroidCrashLogId = 4; // From LOG_ID_CRASH in log.h.
const char kAndroidLogTag[] = "google-breakpad";
bool g_crash_log_initialized = false;
AndroidLogBufferWriteFunc g_android_log_buf_write = nullptr;
} // namespace
void initializeCrashLogWriter() {
if (g_crash_log_initialized)
return;
g_android_log_buf_write = reinterpret_cast<AndroidLogBufferWriteFunc>(
dlsym(RTLD_DEFAULT, "__android_log_buf_write"));
g_crash_log_initialized = true;
}
int writeToCrashLog(const char* buf) {
// Try writing to the crash log ring buffer. If not available, fall back to
// the standard log buffer.
if (g_android_log_buf_write) {
return g_android_log_buf_write(kAndroidCrashLogId, ANDROID_LOG_FATAL,
kAndroidLogTag, buf);
}
return __android_log_write(ANDROID_LOG_FATAL, kAndroidLogTag, buf);
}
#endif
int write(const char* buf, size_t nbytes) {
#if defined(__ANDROID__)
return __android_log_write(ANDROID_LOG_WARN, "google-breakpad", buf);
return __android_log_write(ANDROID_LOG_WARN, kAndroidLogTag, buf);
#else
return sys_write(2, buf, nbytes);
#endif

View File

@ -36,6 +36,20 @@ namespace logger {
int write(const char* buf, size_t nbytes);
// In the case of Android the log can be written to the default system log
// (default behavior of write() above, or to the crash log (see
// writeToCrashLog() below).
#if defined(__ANDROID__)
// The logger must be initialized in a non-compromised context.
void initializeCrashLogWriter();
// Once initialized, writeToCrashLog is safe to use in a compromised context,
// even if the initialization failed, in which case this will silently fall
// back on write().
int writeToCrashLog(const char* buf);
#endif
} // namespace logger
#endif // CLIENT_LINUX_LOG_LOG_H_

View File

@ -34,13 +34,13 @@
#include <sys/utsname.h>
#include "client/linux/dump_writer_common/seccomp_unwinder.h"
#include "client/linux/dump_writer_common/thread_info.h"
#include "client/linux/dump_writer_common/ucontext_reader.h"
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/microdump_extra_info.h"
#include "client/linux/log/log.h"
#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
#include "common/linux/linux_libc_support.h"
#include "client/linux/log/log.h"
namespace {
@ -49,37 +49,51 @@ using google_breakpad::LinuxDumper;
using google_breakpad::LinuxPtraceDumper;
using google_breakpad::MappingInfo;
using google_breakpad::MappingList;
using google_breakpad::MicrodumpExtraInfo;
using google_breakpad::RawContextCPU;
using google_breakpad::SeccompUnwinder;
using google_breakpad::ThreadInfo;
using google_breakpad::UContextReader;
const size_t kLineBufferSize = 2048;
class MicrodumpWriter {
public:
MicrodumpWriter(const ExceptionHandler::CrashContext* context,
const MappingList& mappings,
const MicrodumpExtraInfo& microdump_extra_info,
LinuxDumper* dumper)
: ucontext_(context ? &context->context : NULL),
#if !defined(__ARM_EABI__) && !defined(__mips__)
float_state_(context ? &context->float_state : NULL),
#endif
dumper_(dumper),
mapping_list_(mappings) { }
mapping_list_(mappings),
microdump_extra_info_(microdump_extra_info),
log_line_(NULL) {
log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize));
if (log_line_)
log_line_[0] = '\0'; // Clear out the log line buffer.
}
~MicrodumpWriter() { dumper_->ThreadsResume(); }
bool Init() {
if (!dumper_->Init())
// In the exceptional case where the system was out of memory and there
// wasn't even room to allocate the line buffer, bail out. There is nothing
// useful we can possibly achieve without the ability to Log. At least let's
// try to not crash.
if (!dumper_->Init() || !log_line_)
return false;
return dumper_->ThreadsSuspend();
return dumper_->ThreadsSuspend() && dumper_->LateInit();
}
bool Dump() {
bool success;
LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
success = DumpOSInformation();
if (success)
success = DumpCrashingThread();
DumpProductInformation();
DumpOSInformation();
DumpGPUInformation();
success = DumpCrashingThread();
if (success)
success = DumpMappings();
LogLine("-----END BREAKPAD MICRODUMP-----");
@ -90,12 +104,17 @@ class MicrodumpWriter {
private:
// Writes one line to the system log.
void LogLine(const char* msg) {
#if defined(__ANDROID__)
logger::writeToCrashLog(msg);
#else
logger::write(msg, my_strlen(msg));
logger::write("\n", 1);
#endif
}
// Stages the given string in the current line buffer.
void LogAppend(const char* str) {
my_strlcat(log_line_, str, sizeof(log_line_));
my_strlcat(log_line_, str, kLineBufferSize);
}
// As above (required to take precedence over template specialization below).
@ -125,14 +144,22 @@ class MicrodumpWriter {
// Writes out the current line buffer on the system log.
void LogCommitLine() {
logger::write(log_line_, my_strlen(log_line_));
my_strlcpy(log_line_, "", sizeof(log_line_));
LogLine(log_line_);
my_strlcpy(log_line_, "", kLineBufferSize);
}
bool DumpOSInformation() {
struct utsname uts;
if (uname(&uts))
return false;
void DumpProductInformation() {
LogAppend("V ");
if (microdump_extra_info_.product_info) {
LogAppend(microdump_extra_info_.product_info);
} else {
LogAppend("UNKNOWN:0.0.0.0");
}
LogCommitLine();
}
void DumpOSInformation() {
const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF));
#if defined(__ANDROID__)
const char kOSId[] = "A";
@ -140,17 +167,66 @@ class MicrodumpWriter {
const char kOSId[] = "L";
#endif
// Dump the runtime architecture. On multiarch devices it might not match the
// hw architecture (the one returned by uname()), for instance in the case of
// a 32-bit app running on a aarch64 device.
#if defined(__aarch64__)
const char kArch[] = "arm64";
#elif defined(__ARMEL__)
const char kArch[] = "arm";
#elif defined(__x86_64__)
const char kArch[] = "x86_64";
#elif defined(__i386__)
const char kArch[] = "x86";
#elif defined(__mips__)
# if _MIPS_SIM == _ABIO32
const char kArch[] = "mips";
# elif _MIPS_SIM == _ABI64
const char kArch[] = "mips64";
# else
# error "This mips ABI is currently not supported (n32)"
#endif
#else
#error "This code has not been ported to your platform yet"
#endif
LogAppend("O ");
LogAppend(kOSId);
LogAppend(" \"");
LogAppend(uts.machine);
LogAppend("\" \"");
LogAppend(uts.release);
LogAppend(" \"");
LogAppend(uts.version);
LogAppend("\"");
LogAppend(" ");
LogAppend(kArch);
LogAppend(" ");
LogAppend(n_cpus);
LogAppend(" ");
// Dump the HW architecture (e.g., armv7l, aarch64).
struct utsname uts;
const bool has_uts_info = (uname(&uts) == 0);
const char* hwArch = has_uts_info ? uts.machine : "unknown_hw_arch";
LogAppend(hwArch);
LogAppend(" ");
// If the client has attached a build fingerprint to the MinidumpDescriptor
// use that one. Otherwise try to get some basic info from uname().
if (microdump_extra_info_.build_fingerprint) {
LogAppend(microdump_extra_info_.build_fingerprint);
} else if (has_uts_info) {
LogAppend(uts.release);
LogAppend(" ");
LogAppend(uts.version);
} else {
LogAppend("no build fingerprint available");
}
LogCommitLine();
}
void DumpGPUInformation() {
LogAppend("G ");
if (microdump_extra_info_.gpu_fingerprint) {
LogAppend(microdump_extra_info_.gpu_fingerprint);
} else {
LogAppend("UNKNOWN");
}
LogCommitLine();
return true;
}
bool DumpThreadStack(uint32_t thread_id,
@ -162,8 +238,9 @@ class MicrodumpWriter {
size_t stack_len;
if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
assert(false);
return false;
// The stack pointer might not be available. In this case we don't hard
// fail, just produce a (almost useless) microdump w/o a stack section.
return true;
}
LogAppend("S 0 ");
@ -225,8 +302,6 @@ class MicrodumpWriter {
#else
UContextReader::FillCPUContext(&cpu, ucontext_);
#endif
if (stack_copy)
SeccompUnwinder::PopSeccompStackFrame(&cpu, thread, stack_copy);
DumpCPUState(&cpu);
}
return true;
@ -296,7 +371,7 @@ class MicrodumpWriter {
LogAppend(module_identifier.data4[5]);
LogAppend(module_identifier.data4[6]);
LogAppend(module_identifier.data4[7]);
LogAppend(" ");
LogAppend("0 "); // Age is always 0 on Linux.
LogAppend(file_name);
LogCommitLine();
}
@ -306,15 +381,13 @@ class MicrodumpWriter {
// First write all the mappings from the dumper
for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
const MappingInfo& mapping = *dumper_->mappings()[i];
// Skip mappings which don't look like libraries.
if (!strstr(mapping.name, ".so") || // dump only libs (skip fonts, apks).
mapping.size < 4096) { // too small to get a signature for.
if (mapping.name[0] == 0 || // only want modules with filenames.
!mapping.exec || // only want executable mappings.
mapping.size < 4096 || // too small to get a signature for.
HaveMappingInfo(mapping)) {
continue;
}
if (HaveMappingInfo(mapping))
continue;
DumpModule(mapping, true, i, NULL);
}
// Next write all the mappings provided by the caller
@ -334,7 +407,8 @@ class MicrodumpWriter {
#endif
LinuxDumper* dumper_;
const MappingList& mapping_list_;
char log_line_[512];
const MicrodumpExtraInfo microdump_extra_info_;
char* log_line_;
};
} // namespace
@ -343,7 +417,8 @@ namespace google_breakpad {
bool WriteMicrodump(pid_t crashing_process,
const void* blob,
size_t blob_size,
const MappingList& mappings) {
const MappingList& mappings,
const MicrodumpExtraInfo& microdump_extra_info) {
LinuxPtraceDumper dumper(crashing_process);
const ExceptionHandler::CrashContext* context = NULL;
if (blob) {
@ -355,7 +430,7 @@ bool WriteMicrodump(pid_t crashing_process,
dumper.set_crash_signal(context->siginfo.si_signo);
dumper.set_crash_thread(context->tid);
}
MicrodumpWriter writer(context, mappings, &dumper);
MicrodumpWriter writer(context, mappings, microdump_extra_info, &dumper);
if (!writer.Init())
return false;
return writer.Dump();

View File

@ -37,6 +37,8 @@
namespace google_breakpad {
struct MicrodumpExtraInfo;
// Writes a microdump (a reduced dump containing only the state of the crashing
// thread) on the console (logcat on Android). These functions do not malloc nor
// use libc functions which may. Thus, it can be used in contexts where the
@ -46,12 +48,17 @@ namespace google_breakpad {
// blob: a blob of data from the crashing process. See exception_handler.h
// blob_size: the length of |blob| in bytes.
// mappings: a list of additional mappings provided by the application.
// build_fingerprint: a (optional) C string which determines the OS
// build fingerprint (e.g., aosp/occam/mako:5.1.1/LMY47W/1234:eng/dev-keys).
// product_info: a (optional) C string which determines the product name and
// version (e.g., WebView:42.0.2311.136).
//
// Returns true iff successful.
bool WriteMicrodump(pid_t crashing_process,
const void* blob,
size_t blob_size,
const MappingList& mappings);
const MappingList& mappings,
const MicrodumpExtraInfo& microdump_extra_info);
} // namespace google_breakpad

View File

@ -0,0 +1,257 @@
// Copyright (c) 2014 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <ctype.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <sstream>
#include <string>
#include "breakpad_googletest_includes.h"
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/microdump_extra_info.h"
#include "client/linux/microdump_writer/microdump_writer.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/ignore_ret.h"
#include "common/scoped_ptr.h"
#include "common/tests/auto_tempdir.h"
#include "common/using_std_string.h"
using namespace google_breakpad;
namespace {
typedef testing::Test MicrodumpWriterTest;
MicrodumpExtraInfo MakeMicrodumpExtraInfo(
const char* build_fingerprint,
const char* product_info,
const char* gpu_fingerprint) {
MicrodumpExtraInfo info;
info.build_fingerprint = build_fingerprint;
info.product_info = product_info;
info.gpu_fingerprint = gpu_fingerprint;
return info;
}
void CrashAndGetMicrodump(
const MappingList& mappings,
const MicrodumpExtraInfo& microdump_extra_info,
scoped_array<char>* buf) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
AutoTempDir temp_dir;
string stderr_file = temp_dir.path() + "/stderr.log";
int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ASSERT_NE(-1, err_fd);
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
char b;
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
// Set a non-zero tid to avoid tripping asserts.
context.tid = child;
// Redirect temporarily stderr to the stderr.log file.
int save_err = dup(STDERR_FILENO);
ASSERT_NE(-1, save_err);
ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO));
ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings,
microdump_extra_info));
// Revert stderr back to the console.
dup2(save_err, STDERR_FILENO);
close(save_err);
// Read back the stderr file and check for the microdump marker.
fsync(err_fd);
lseek(err_fd, 0, SEEK_SET);
const size_t kBufSize = 64 * 1024;
buf->reset(new char[kBufSize]);
ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0);
close(err_fd);
close(fds[1]);
ASSERT_NE(static_cast<char*>(0), strstr(
buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----"));
ASSERT_NE(static_cast<char*>(0), strstr(
buf->get(), "-----END BREAKPAD MICRODUMP-----"));
}
void CheckMicrodumpContents(const string& microdump_content,
const MicrodumpExtraInfo& expected_info) {
std::istringstream iss(microdump_content);
bool did_find_os_info = false;
bool did_find_product_info = false;
bool did_find_gpu_info = false;
for (string line; std::getline(iss, line);) {
if (line.find("O ") == 0) {
std::istringstream os_info_tokens(line);
string token;
os_info_tokens.ignore(2); // Ignore the "O " preamble.
// Check the OS descriptor char (L=Linux, A=Android).
os_info_tokens >> token;
ASSERT_TRUE(token == "L" || token == "A");
os_info_tokens >> token; // HW architecture.
os_info_tokens >> token; // Number of cpus.
for (size_t i = 0; i < token.size(); ++i)
ASSERT_TRUE(isxdigit(token[i]));
os_info_tokens >> token; // SW architecture.
// Check that the build fingerprint is in the right place.
os_info_tokens >> token;
if (expected_info.build_fingerprint)
ASSERT_EQ(expected_info.build_fingerprint, token);
did_find_os_info = true;
} else if (line.find("V ") == 0) {
if (expected_info.product_info)
ASSERT_EQ(string("V ") + expected_info.product_info, line);
did_find_product_info = true;
} else if (line.find("G ") == 0) {
if (expected_info.gpu_fingerprint)
ASSERT_EQ(string("G ") + expected_info.gpu_fingerprint, line);
did_find_gpu_info = true;
}
}
ASSERT_TRUE(did_find_os_info);
ASSERT_TRUE(did_find_product_info);
ASSERT_TRUE(did_find_gpu_info);
}
void CheckMicrodumpContents(const string& microdump_content,
const string& expected_fingerprint,
const string& expected_product_info,
const string& expected_gpu_fingerprint) {
CheckMicrodumpContents(
microdump_content,
MakeMicrodumpExtraInfo(expected_fingerprint.c_str(),
expected_product_info.c_str(),
expected_gpu_fingerprint.c_str()));
}
TEST(MicrodumpWriterTest, BasicWithMappings) {
// Push some extra mapping to check the MappingList logic.
const uint32_t memory_size = sysconf(_SC_PAGESIZE);
const char* kMemoryName = "libfoo.so";
const uint8_t kModuleGUID[sizeof(MDGUID)] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
MappingInfo info;
info.start_addr = memory_size;
info.size = memory_size;
info.offset = 42;
strcpy(info.name, kMemoryName);
MappingList mappings;
MappingEntry mapping;
mapping.first = info;
memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
mappings.push_back(mapping);
scoped_array<char> buf;
CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf);
#ifdef __LP64__
ASSERT_NE(static_cast<char*>(0), strstr(
buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 "
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
#else
ASSERT_NE(static_cast<char*>(0), strstr(
buf.get(), "M 00001000 0000002A 00001000 "
"33221100554477668899AABBCCDDEEFF0 libfoo.so"));
#endif
// In absence of a product info in the minidump, the writer should just write
// an unknown marker.
ASSERT_NE(static_cast<char*>(0), strstr(
buf.get(), "V UNKNOWN:0.0.0.0"));
}
// Ensure that the product info and build fingerprint metadata show up in the
// final microdump if present.
TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) {
const char kProductInfo[] = "MockProduct:42.0.2311.99";
const char kBuildFingerprint[] =
"aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
const char kGPUFingerprint[] =
"Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
const MicrodumpExtraInfo kMicrodumpExtraInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
scoped_array<char> buf;
MappingList no_mappings;
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf);
CheckMicrodumpContents(string(buf.get()), kMicrodumpExtraInfo);
}
TEST(MicrodumpWriterTest, NoProductInfo) {
const char kBuildFingerprint[] = "foobar";
const char kGPUFingerprint[] = "bazqux";
scoped_array<char> buf;
MappingList no_mappings;
const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint));
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf);
CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
"UNKNOWN:0.0.0.0", kGPUFingerprint);
}
TEST(MicrodumpWriterTest, NoGPUInfo) {
const char kProductInfo[] = "bazqux";
const char kBuildFingerprint[] = "foobar";
scoped_array<char> buf;
MappingList no_mappings;
const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo(
MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL));
CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf);
CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
kProductInfo, "UNKNOWN");
}
} // namespace

View File

@ -38,6 +38,10 @@
#include <stdio.h>
#include <string.h>
#include <sys/procfs.h>
#if defined(__mips__) && defined(__ANDROID__)
// To get register definitions.
#include <asm/reg.h>
#endif
#include "common/linux/linux_libc_support.h"
@ -74,7 +78,7 @@ bool LinuxCoreDumper::BuildProcPath(char* path, pid_t pid,
return true;
}
void LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
bool LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
const void* src, size_t length) {
ElfCoreDump::Addr virtual_address = reinterpret_cast<ElfCoreDump::Addr>(src);
// TODO(benchan): Investigate whether the data to be copied could span
@ -84,7 +88,9 @@ void LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
// If the data segment is not found in the core dump, fill the result
// with marker characters.
memset(dest, 0xab, length);
return false;
}
return true;
}
bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
@ -103,7 +109,7 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
#elif defined(__mips__)
stack_pointer =
reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]);
reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
#else
#error "This code hasn't been ported to your platform yet."
#endif
@ -189,18 +195,19 @@ bool LinuxCoreDumper::EnumerateThreads() {
info.tgid = status->pr_pgrp;
info.ppid = status->pr_ppid;
#if defined(__mips__)
#if defined(__ANDROID__)
for (int i = EF_R0; i <= EF_R31; i++)
info.mcontext.gregs[i - EF_R0] = status->pr_reg[i];
#else // __ANDROID__
for (int i = EF_REG0; i <= EF_REG31; i++)
info.regs.regs[i - EF_REG0] = status->pr_reg[i];
info.regs.lo = status->pr_reg[EF_LO];
info.regs.hi = status->pr_reg[EF_HI];
info.regs.epc = status->pr_reg[EF_CP0_EPC];
info.regs.badvaddr = status->pr_reg[EF_CP0_BADVADDR];
info.regs.status = status->pr_reg[EF_CP0_STATUS];
info.regs.cause = status->pr_reg[EF_CP0_CAUSE];
#else
info.mcontext.gregs[i - EF_REG0] = status->pr_reg[i];
#endif // __ANDROID__
info.mcontext.mdlo = status->pr_reg[EF_LO];
info.mcontext.mdhi = status->pr_reg[EF_HI];
info.mcontext.pc = status->pr_reg[EF_CP0_EPC];
#else // __mips__
memcpy(&info.regs, status->pr_reg, sizeof(info.regs));
#endif
#endif // __mips__
if (first_thread) {
crash_thread_ = pid;
crash_signal_ = status->pr_info.si_signo;

View File

@ -68,8 +68,9 @@ class LinuxCoreDumper : public LinuxDumper {
// Copies content of |length| bytes from a given process |child|,
// starting from |src|, into |dest|. This method extracts the content
// the core dump and fills |dest| with a sequence of marker bytes
// if the expected data is not found in the core dump.
virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
// if the expected data is not found in the core dump. Returns true if
// the expected data is found in the core dump.
virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
size_t length);
// Implements LinuxDumper::GetThreadInfoByIndex().

View File

@ -52,6 +52,22 @@
#include "common/linux/safe_readlink.h"
#include "third_party/lss/linux_syscall_support.h"
#if defined(__ANDROID__)
// Android packed relocations definitions are not yet available from the
// NDK header files, so we have to provide them manually here.
#ifndef DT_LOOS
#define DT_LOOS 0x6000000d
#endif
#ifndef DT_ANDROID_REL
static const int DT_ANDROID_REL = DT_LOOS + 2;
#endif
#ifndef DT_ANDROID_RELA
static const int DT_ANDROID_RELA = DT_LOOS + 4;
#endif
#endif // __ANDROID __
static const char kMappedFileUnsafePrefix[] = "/dev/";
static const char kDeletedSuffix[] = " (deleted)";
static const char kReservedFlags[] = " ---p";
@ -92,6 +108,13 @@ bool LinuxDumper::Init() {
return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
}
bool LinuxDumper::LateInit() {
#if defined(__ANDROID__)
LatePostprocessMappings();
#endif
return true;
}
bool
LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
bool member,
@ -395,6 +418,113 @@ bool LinuxDumper::EnumerateMappings() {
return !mappings_.empty();
}
#if defined(__ANDROID__)
bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) {
CopyFromProcess(ehdr, pid_,
reinterpret_cast<const void*>(start_addr),
sizeof(*ehdr));
return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0;
}
void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr,
uintptr_t start_addr,
uintptr_t* min_vaddr_ptr,
uintptr_t* dyn_vaddr_ptr,
size_t* dyn_count_ptr) {
uintptr_t phdr_addr = start_addr + ehdr->e_phoff;
const uintptr_t max_addr = UINTPTR_MAX;
uintptr_t min_vaddr = max_addr;
uintptr_t dyn_vaddr = 0;
size_t dyn_count = 0;
for (size_t i = 0; i < ehdr->e_phnum; ++i) {
ElfW(Phdr) phdr;
CopyFromProcess(&phdr, pid_,
reinterpret_cast<const void*>(phdr_addr),
sizeof(phdr));
if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) {
min_vaddr = phdr.p_vaddr;
}
if (phdr.p_type == PT_DYNAMIC) {
dyn_vaddr = phdr.p_vaddr;
dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn));
}
phdr_addr += sizeof(phdr);
}
*min_vaddr_ptr = min_vaddr;
*dyn_vaddr_ptr = dyn_vaddr;
*dyn_count_ptr = dyn_count;
}
bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias,
uintptr_t dyn_vaddr,
size_t dyn_count) {
uintptr_t dyn_addr = load_bias + dyn_vaddr;
for (size_t i = 0; i < dyn_count; ++i) {
ElfW(Dyn) dyn;
CopyFromProcess(&dyn, pid_,
reinterpret_cast<const void*>(dyn_addr),
sizeof(dyn));
if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) {
return true;
}
dyn_addr += sizeof(dyn);
}
return false;
}
uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr,
uintptr_t start_addr) {
uintptr_t min_vaddr = 0;
uintptr_t dyn_vaddr = 0;
size_t dyn_count = 0;
ParseLoadedElfProgramHeaders(ehdr, start_addr,
&min_vaddr, &dyn_vaddr, &dyn_count);
// If |min_vaddr| is non-zero and we find Android packed relocation tags,
// return the effective load bias.
if (min_vaddr != 0) {
const uintptr_t load_bias = start_addr - min_vaddr;
if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) {
return load_bias;
}
}
// Either |min_vaddr| is zero, or it is non-zero but we did not find the
// expected Android packed relocations tags.
return start_addr;
}
void LinuxDumper::LatePostprocessMappings() {
for (size_t i = 0; i < mappings_.size(); ++i) {
// Only consider exec mappings that indicate a file path was mapped, and
// where the ELF header indicates a mapped shared library.
MappingInfo* mapping = mappings_[i];
if (!(mapping->exec && mapping->name[0] == '/')) {
continue;
}
ElfW(Ehdr) ehdr;
if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) {
continue;
}
if (ehdr.e_type == ET_DYN) {
// Compute the effective load bias for this mapped library, and update
// the mapping to hold that rather than |start_addr|, at the same time
// adjusting |size| to account for the change in |start_addr|. Where
// the library does not contain Android packed relocations,
// GetEffectiveLoadBias() returns |start_addr| and the mapping entry
// is not changed.
const uintptr_t load_bias = GetEffectiveLoadBias(&ehdr,
mapping->start_addr);
mapping->size += mapping->start_addr - load_bias;
mapping->start_addr = load_bias;
}
}
}
#endif // __ANDROID__
// Get information about the stack, given the stack pointer. We don't try to
// walk the stack since we might not have all the information needed to do
// unwind. So we just grab, up to, 32k of stack.

View File

@ -39,6 +39,9 @@
#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
#include <elf.h>
#if defined(__ANDROID__)
#include <link.h>
#endif
#include <linux/limits.h>
#include <stdint.h>
#include <sys/types.h>
@ -52,13 +55,15 @@
namespace google_breakpad {
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
#if defined(__i386) || defined(__ARM_EABI__) || defined(__mips__)
#if defined(__i386) || defined(__ARM_EABI__) || \
(defined(__mips__) && _MIPS_SIM == _ABIO32)
typedef Elf32_auxv_t elf_aux_entry;
#elif defined(__x86_64) || defined(__aarch64__)
#elif defined(__x86_64) || defined(__aarch64__) || \
(defined(__mips__) && _MIPS_SIM != _ABIO32)
typedef Elf64_auxv_t elf_aux_entry;
#endif
typedef typeof(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t;
typedef __typeof__(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t;
// When we find the VDSO mapping in the process's address space, this
// is the name we use for it when writing it to the minidump.
@ -74,6 +79,12 @@ class LinuxDumper {
// Parse the data for |threads| and |mappings|.
virtual bool Init();
// Take any actions that could not be taken in Init(). LateInit() is
// called after all other caller's initialization is complete, and in
// particular after it has called ThreadsSuspend(), so that ptrace is
// available.
virtual bool LateInit();
// Return true if the dumper performs a post-mortem dump.
virtual bool IsPostMortem() const = 0;
@ -100,8 +111,8 @@ class LinuxDumper {
PageAllocator* allocator() { return &allocator_; }
// Copy content of |length| bytes from a given process |child|,
// starting from |src|, into |dest|.
virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
// starting from |src|, into |dest|. Returns true on success.
virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
size_t length) = 0;
// Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
@ -180,6 +191,62 @@ class LinuxDumper {
// Info from /proc/<pid>/auxv
wasteful_vector<elf_aux_val_t> auxv_;
#if defined(__ANDROID__)
private:
// Android M and later support packed ELF relocations in shared libraries.
// Packing relocations changes the vaddr of the LOAD segments, such that
// the effective load bias is no longer the same as the start address of
// the memory mapping containing the executable parts of the library. The
// packing is applied to the stripped library run on the target, but not to
// any other library, and in particular not to the library used to generate
// breakpad symbols. As a result, we need to adjust the |start_addr| for
// any mapping that results from a shared library that contains Android
// packed relocations, so that it properly represents the effective library
// load bias. The following functions support this adjustment.
// Check that a given mapping at |start_addr| is for an ELF shared library.
// If it is, place the ELF header in |ehdr| and return true.
// The first LOAD segment in an ELF shared library has offset zero, so the
// ELF file header is at the start of this map entry, and in already mapped
// memory.
bool GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr);
// For the ELF file mapped at |start_addr|, iterate ELF program headers to
// find the min vaddr of all program header LOAD segments, the vaddr for
// the DYNAMIC segment, and a count of DYNAMIC entries. Return values in
// |min_vaddr_ptr|, |dyn_vaddr_ptr|, and |dyn_count_ptr|.
// The program header table is also in already mapped memory.
void ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr,
uintptr_t start_addr,
uintptr_t* min_vaddr_ptr,
uintptr_t* dyn_vaddr_ptr,
size_t* dyn_count_ptr);
// Search the DYNAMIC tags for the ELF file with the given |load_bias|, and
// return true if the tags indicate that the file contains Android packed
// relocations. Dynamic tags are found at |dyn_vaddr| past the |load_bias|.
bool HasAndroidPackedRelocations(uintptr_t load_bias,
uintptr_t dyn_vaddr,
size_t dyn_count);
// If the ELF file mapped at |start_addr| contained Android packed
// relocations, return the load bias that the system linker (or Chromium
// crazy linker) will have used. If the file did not contain Android
// packed relocations, returns |start_addr|, indicating that no adjustment
// is necessary.
// The effective load bias is |start_addr| adjusted downwards by the
// min vaddr in the library LOAD segments.
uintptr_t GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, uintptr_t start_addr);
// Called from LateInit(). Iterates |mappings_| and rewrites the |start_addr|
// field of any that represent ELF shared libraries with Android packed
// relocations, so that |start_addr| is the load bias that the system linker
// (or Chromium crazy linker) used. This value matches the addresses produced
// when the non-relocation-packed library is used for breakpad symbol
// generation.
void LatePostprocessMappings();
#endif // __ANDROID__
};
} // namespace google_breakpad

View File

@ -130,7 +130,7 @@ bool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid,
return true;
}
void LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
const void* src, size_t length) {
unsigned long tmp = 55;
size_t done = 0;
@ -146,6 +146,7 @@ void LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
my_memcpy(local + done, &tmp, l);
done += l;
}
return true;
}
// Read thread info from /proc/$pid/status.
@ -189,26 +190,34 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
#ifdef PTRACE_GETREGSET
struct iovec io;
io.iov_base = &info->regs;
io.iov_len = sizeof(info->regs);
info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len);
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) {
return false;
}
io.iov_base = &info->fpregs;
io.iov_len = sizeof(info->fpregs);
info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len);
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
return false;
}
#else
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) {
#else // PTRACE_GETREGSET
void* gp_addr;
info->GetGeneralPurposeRegisters(&gp_addr, NULL);
if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) {
return false;
}
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
#if !(defined(__ANDROID__) && defined(__ARM_EABI__))
// When running an arm build on an arm64 device, attempting to get the
// floating point registers fails. On Android, the floating point registers
// aren't written to the cpu context anyway, so just don't get them here.
// See http://crbug.com/508324
void* fp_addr;
info->GetFloatingPointRegisters(&fp_addr, NULL);
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) {
return false;
}
#endif
#endif // PTRACE_GETREGSET
#if defined(__i386)
#if !defined(bit_FXSAVE) // e.g. Clang
@ -240,14 +249,20 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
#endif
#if defined(__mips__)
for (int i = 0; i < 3; ++i) {
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + (i * 2)), &info->hi[i]);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + (i * 2) + 1), &info->lo[i]);
}
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_CONTROL), &info->dsp_control);
reinterpret_cast<void*>(DSP_BASE), &info->mcontext.hi1);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 1), &info->mcontext.lo1);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 2), &info->mcontext.hi2);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 3), &info->mcontext.lo2);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 4), &info->mcontext.hi3);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_BASE + 5), &info->mcontext.lo3);
sys_ptrace(PTRACE_PEEKUSER, tid,
reinterpret_cast<void*>(DSP_CONTROL), &info->mcontext.dsp);
#endif
const uint8_t* stack_pointer;
@ -261,7 +276,7 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
#elif defined(__mips__)
stack_pointer =
reinterpret_cast<uint8_t*>(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]);
reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
#else
#error "This code hasn't been ported to your platform yet."
#endif
@ -282,8 +297,10 @@ bool LinuxPtraceDumper::ThreadsSuspend() {
// If the thread either disappeared before we could attach to it, or if
// it was part of the seccomp sandbox's trusted code, it is OK to
// silently drop it from the minidump.
my_memmove(&threads_[i], &threads_[i+1],
(threads_.size() - i - 1) * sizeof(threads_[i]));
if (i < threads_.size() - 1) {
my_memmove(&threads_[i], &threads_[i + 1],
(threads_.size() - i - 1) * sizeof(threads_[i]));
}
threads_.resize(threads_.size() - 1);
--i;
}

View File

@ -55,8 +55,8 @@ class LinuxPtraceDumper : public LinuxDumper {
// Implements LinuxDumper::CopyFromProcess().
// Copies content of |length| bytes from a given process |child|,
// starting from |src|, into |dest|. This method uses ptrace to extract
// the content from the target process.
virtual void CopyFromProcess(void* dest, pid_t child, const void* src,
// the content from the target process. Always returns true.
virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
size_t length);
// Implements LinuxDumper::GetThreadInfoByIndex().

View File

@ -441,7 +441,7 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
pid_t* process_tid_location = (pid_t*)(one_thread.regs.rcx);
#elif defined(__mips__)
pid_t* process_tid_location =
reinterpret_cast<pid_t*>(one_thread.regs.regs[1]);
reinterpret_cast<pid_t*>(one_thread.mcontext.gregs[1]);
#else
#error This test has not been ported to this platform.
#endif

View File

@ -64,7 +64,6 @@
#include <algorithm>
#include "client/linux/dump_writer_common/seccomp_unwinder.h"
#include "client/linux/dump_writer_common/thread_info.h"
#include "client/linux/dump_writer_common/ucontext_reader.h"
#include "client/linux/handler/exception_handler.h"
@ -75,6 +74,7 @@
#include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
#include "client/minidump_file_writer.h"
#include "common/linux/linux_libc_support.h"
#include "common/minidump_type_helper.h"
#include "google_breakpad/common/minidump_format.h"
#include "third_party/lss/linux_syscall_support.h"
@ -86,6 +86,7 @@ using google_breakpad::CpuSet;
using google_breakpad::LineReader;
using google_breakpad::LinuxDumper;
using google_breakpad::LinuxPtraceDumper;
using google_breakpad::MDTypeHelper;
using google_breakpad::MappingEntry;
using google_breakpad::MappingInfo;
using google_breakpad::MappingList;
@ -93,13 +94,14 @@ using google_breakpad::MinidumpFileWriter;
using google_breakpad::PageAllocator;
using google_breakpad::ProcCpuInfoReader;
using google_breakpad::RawContextCPU;
using google_breakpad::SeccompUnwinder;
using google_breakpad::ThreadInfo;
using google_breakpad::TypedMDRVA;
using google_breakpad::UContextReader;
using google_breakpad::UntypedMDRVA;
using google_breakpad::wasteful_vector;
typedef MDTypeHelper<sizeof(void*)>::MDRawDebug MDRawDebug;
typedef MDTypeHelper<sizeof(void*)>::MDRawLinkMap MDRawLinkMap;
class MinidumpWriter {
public:
@ -150,7 +152,7 @@ class MinidumpWriter {
else if (!minidump_writer_.Open(path_))
return false;
return dumper_->ThreadsSuspend();
return dumper_->ThreadsSuspend() && dumper_->LateInit();
}
~MinidumpWriter() {
@ -166,19 +168,26 @@ class MinidumpWriter {
// of stream which we write.
unsigned kNumWriters = 13;
TypedMDRVA<MDRawHeader> header(&minidump_writer_);
TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
if (!header.Allocate())
return false;
if (!dir.AllocateArray(kNumWriters))
return false;
my_memset(header.get(), 0, sizeof(MDRawHeader));
{
// Ensure the header gets flushed, as that happens in the destructor.
// If a crash occurs somewhere below, at least the header will be
// intact.
TypedMDRVA<MDRawHeader> header(&minidump_writer_);
if (!header.Allocate())
return false;
header.get()->signature = MD_HEADER_SIGNATURE;
header.get()->version = MD_HEADER_VERSION;
header.get()->time_date_stamp = time(NULL);
header.get()->stream_count = kNumWriters;
header.get()->stream_directory_rva = dir.position();
if (!dir.AllocateArray(kNumWriters))
return false;
my_memset(header.get(), 0, sizeof(MDRawHeader));
header.get()->signature = MD_HEADER_SIGNATURE;
header.get()->version = MD_HEADER_VERSION;
header.get()->time_date_stamp = time(NULL);
header.get()->stream_count = kNumWriters;
header.get()->stream_directory_rva = dir.position();
}
unsigned dir_index = 0;
MDRawDirectory dirent;
@ -379,8 +388,6 @@ class MinidumpWriter {
#else
UContextReader::FillCPUContext(cpu.get(), ucontext_);
#endif
if (stack_copy)
SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy);
thread.thread_context = cpu.location();
crashing_thread_context_ = cpu.location();
} else {
@ -401,8 +408,6 @@ class MinidumpWriter {
return false;
my_memset(cpu.get(), 0, sizeof(RawContextCPU));
info.FillCPUContext(cpu.get());
if (stack_copy)
SeccompUnwinder::PopSeccompStackFrame(cpu.get(), thread, stack_copy);
thread.thread_context = cpu.location();
if (dumper_->threads()[i] == GetCrashThread()) {
crashing_thread_context_ = cpu.location();
@ -511,7 +516,7 @@ class MinidumpWriter {
continue;
MDRawModule mod;
if (!FillRawModule(mapping, true, i, mod, NULL))
if (!FillRawModule(mapping, true, i, &mod, NULL))
return false;
list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
}
@ -520,7 +525,7 @@ class MinidumpWriter {
iter != mapping_list_.end();
++iter) {
MDRawModule mod;
if (!FillRawModule(iter->first, false, 0, mod, iter->second))
if (!FillRawModule(iter->first, false, 0, &mod, iter->second))
return false;
list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
}
@ -534,12 +539,12 @@ class MinidumpWriter {
bool FillRawModule(const MappingInfo& mapping,
bool member,
unsigned int mapping_id,
MDRawModule& mod,
MDRawModule* mod,
const uint8_t* identifier) {
my_memset(&mod, 0, MD_MODULE_SIZE);
my_memset(mod, 0, MD_MODULE_SIZE);
mod.base_of_image = mapping.start_addr;
mod.size_of_image = mapping.size;
mod->base_of_image = mapping.start_addr;
mod->size_of_image = mapping.size;
uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
uint8_t* cv_ptr = cv_buf;
@ -574,12 +579,12 @@ class MinidumpWriter {
my_memcpy(cv_ptr, file_name, file_name_len + 1);
cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1);
mod.cv_record = cv.location();
mod->cv_record = cv.location();
MDLocationDescriptor ld;
if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld))
return false;
mod.module_name_rva = ld.rva;
mod->module_name_rva = ld.rva;
return true;
}
@ -654,7 +659,9 @@ class MinidumpWriter {
ElfW(Addr) dyn_addr = 0;
for (; phnum >= 0; phnum--, phdr++) {
ElfW(Phdr) ph;
dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph));
if (!dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph)))
return false;
// Adjust base address with the virtual address of the PT_LOAD segment
// corresponding to offset 0
if (ph.p_type == PT_LOAD && ph.p_offset == 0) {
@ -675,12 +682,20 @@ class MinidumpWriter {
struct r_debug* r_debug = NULL;
uint32_t dynamic_length = 0;
for (int i = 0;;) {
for (int i = 0; ; ++i) {
ElfW(Dyn) dyn;
dynamic_length += sizeof(dyn);
dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic+i++,
sizeof(dyn));
if (dyn.d_tag == DT_DEBUG) {
if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i,
sizeof(dyn))) {
return false;
}
#ifdef __mips__
const int32_t debug_tag = DT_MIPS_RLD_MAP;
#else
const int32_t debug_tag = DT_DEBUG;
#endif
if (dyn.d_tag == debug_tag) {
r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
continue;
} else if (dyn.d_tag == DT_NULL) {
@ -699,11 +714,15 @@ class MinidumpWriter {
// Count the number of loaded DSOs
int dso_count = 0;
struct r_debug debug_entry;
dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
sizeof(debug_entry));
if (!dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
sizeof(debug_entry))) {
return false;
}
for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
struct link_map map;
dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
return false;
ptr = map.l_next;
dso_count++;
}
@ -721,7 +740,9 @@ class MinidumpWriter {
// Iterate over DSOs and write their information to mini dump
for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
struct link_map map;
dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
return false;
ptr = map.l_next;
char filename[257] = { 0 };
if (map.l_name) {
@ -733,8 +754,8 @@ class MinidumpWriter {
return false;
MDRawLinkMap entry;
entry.name = location.rva;
entry.addr = reinterpret_cast<void*>(map.l_addr);
entry.ld = reinterpret_cast<void*>(map.l_ld);
entry.addr = map.l_addr;
entry.ld = reinterpret_cast<uintptr_t>(map.l_ld);
linkmap.CopyIndex(idx++, &entry);
}
}
@ -750,9 +771,9 @@ class MinidumpWriter {
debug.get()->version = debug_entry.r_version;
debug.get()->map = linkmap_rva;
debug.get()->dso_count = dso_count;
debug.get()->brk = reinterpret_cast<void*>(debug_entry.r_brk);
debug.get()->ldbase = reinterpret_cast<void*>(debug_entry.r_ldbase);
debug.get()->dynamic = dynamic;
debug.get()->brk = debug_entry.r_brk;
debug.get()->ldbase = debug_entry.r_ldbase;
debug.get()->dynamic = reinterpret_cast<uintptr_t>(dynamic);
wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length);
// The passed-in size to the constructor (above) is only a hint.
@ -803,7 +824,13 @@ class MinidumpWriter {
// processor_architecture should always be set, do this first
sys_info->processor_architecture =
#if defined(__mips__)
# if _MIPS_SIM == _ABIO32
MD_CPU_ARCHITECTURE_MIPS;
# elif _MIPS_SIM == _ABI64
MD_CPU_ARCHITECTURE_MIPS64;
# else
# error "This mips ABI is currently not supported (n32)"
#endif
#elif defined(__i386__)
MD_CPU_ARCHITECTURE_X86;
#else
@ -819,15 +846,14 @@ class MinidumpWriter {
ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd);
const char* field;
while (reader->GetNextField(&field)) {
for (size_t i = 0;
i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
i++) {
CpuInfoEntry* entry = &cpu_info_table[i];
if (i > 0 && entry->found) {
bool is_first_entry = true;
for (CpuInfoEntry& entry : cpu_info_table) {
if (!is_first_entry && entry.found) {
// except for the 'processor' field, ignore repeated values.
continue;
}
if (!my_strcmp(field, entry->info_name)) {
is_first_entry = false;
if (!my_strcmp(field, entry.info_name)) {
size_t value_len;
const char* value = reader->GetValueAndLen(&value_len);
if (value_len == 0)
@ -837,8 +863,8 @@ class MinidumpWriter {
if (my_read_decimal_ptr(&val, value) == value)
continue;
entry->value = static_cast<int>(val);
entry->found = true;
entry.value = static_cast<int>(val);
entry.found = true;
}
}
@ -854,10 +880,8 @@ class MinidumpWriter {
}
// make sure we got everything we wanted
for (size_t i = 0;
i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
i++) {
if (!cpu_info_table[i].found) {
for (const CpuInfoEntry& entry : cpu_info_table) {
if (!entry.found) {
return false;
}
}
@ -993,18 +1017,15 @@ class MinidumpWriter {
new(allocator) ProcCpuInfoReader(fd);
const char* field;
while (reader->GetNextField(&field)) {
for (size_t i = 0;
i < sizeof(cpu_id_entries)/sizeof(cpu_id_entries[0]);
++i) {
const CpuIdEntry* entry = &cpu_id_entries[i];
if (my_strcmp(entry->field, field) != 0)
for (const CpuIdEntry& entry : cpu_id_entries) {
if (my_strcmp(entry.field, field) != 0)
continue;
uintptr_t result = 0;
const char* value = reader->GetValue();
const char* p = value;
if (value[0] == '0' && value[1] == 'x') {
p = my_read_hex_ptr(&result, value+2);
} else if (entry->format == 'x') {
} else if (entry.format == 'x') {
p = my_read_hex_ptr(&result, value);
} else {
p = my_read_decimal_ptr(&result, value);
@ -1012,8 +1033,8 @@ class MinidumpWriter {
if (p == value)
continue;
result &= (1U << entry->bit_length)-1;
result <<= entry->bit_lshift;
result &= (1U << entry.bit_length)-1;
result <<= entry.bit_lshift;
sys_info->cpu.arm_cpu_info.cpuid |=
static_cast<uint32_t>(result);
}
@ -1067,7 +1088,7 @@ class MinidumpWriter {
const char* tag = value;
size_t tag_len = value_len;
const char* p = my_strchr(tag, ' ');
if (p != NULL) {
if (p) {
tag_len = static_cast<size_t>(p - tag);
value += tag_len + 1;
value_len -= tag_len + 1;
@ -1075,14 +1096,10 @@ class MinidumpWriter {
tag_len = strlen(tag);
value_len = 0;
}
for (size_t i = 0;
i < sizeof(cpu_features_entries)/
sizeof(cpu_features_entries[0]);
++i) {
const CpuFeaturesEntry* entry = &cpu_features_entries[i];
if (tag_len == strlen(entry->tag) &&
!memcmp(tag, entry->tag, tag_len)) {
sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry->hwcaps;
for (const CpuFeaturesEntry& entry : cpu_features_entries) {
if (tag_len == strlen(entry.tag) &&
!memcmp(tag, entry.tag, tag_len)) {
sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry.hwcaps;
break;
}
}

View File

@ -48,7 +48,7 @@
#import "common/mac/MachIPC.h"
#import "common/simple_string_dictionary.h"
#ifndef __EXCEPTIONS
#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

View File

@ -364,7 +364,7 @@ static uint64_t LookupSymbol(const char* symbol_name,
return list.n_value;
}
#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
static bool HasTaskDyldInfo() {
return true;
}
@ -381,13 +381,9 @@ static SInt32 GetOSVersion() {
}
static bool HasTaskDyldInfo() {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
return true;
#else
return GetOSVersion() >= 0x1060;
#endif
}
#endif // TARGET_OS_IPHONE
#endif // TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= 10_6
uint64_t DynamicImages::GetDyldAllImageInfosPointer() {
if (HasTaskDyldInfo()) {

View File

@ -133,25 +133,47 @@ void MinidumpGenerator::GatherSystemInformation() {
vers_path,
kCFURLPOSIXPathStyle,
false);
CFDataRef data;
SInt32 error;
CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL,
&error);
CFReadStreamRef read_stream = CFReadStreamCreateWithFile(NULL, sys_vers);
CFRelease(sys_vers);
if (!read_stream) {
return;
}
if (!CFReadStreamOpen(read_stream)) {
CFRelease(read_stream);
return;
}
CFMutableDataRef data = NULL;
while (true) {
// Actual data file tests: Mac at 480 bytes and iOS at 413 bytes.
const CFIndex kMaxBufferLength = 1024;
UInt8 data_bytes[kMaxBufferLength];
CFIndex num_bytes_read =
CFReadStreamRead(read_stream, data_bytes, kMaxBufferLength);
if (num_bytes_read < 0) {
if (data) {
CFRelease(data);
data = NULL;
}
break;
} else if (num_bytes_read == 0) {
break;
} else if (!data) {
data = CFDataCreateMutable(NULL, 0);
}
CFDataAppendBytes(data, data_bytes, num_bytes_read);
}
CFReadStreamClose(read_stream);
CFRelease(read_stream);
if (!data) {
CFRelease(sys_vers);
return;
}
CFDictionaryRef list = static_cast<CFDictionaryRef>
(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable,
NULL));
CFDictionaryRef list =
static_cast<CFDictionaryRef>(CFPropertyListCreateWithData(
NULL, data, kCFPropertyListImmutable, NULL, NULL));
CFRelease(data);
if (!list) {
CFRelease(sys_vers);
CFRelease(data);
return;
}
CFStringRef build_version = static_cast<CFStringRef>
(CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));
CFStringRef product_version = static_cast<CFStringRef>
@ -160,8 +182,6 @@ void MinidumpGenerator::GatherSystemInformation() {
string product_str = ConvertToString(product_version);
CFRelease(list);
CFRelease(sys_vers);
CFRelease(data);
strlcpy(build_string_, build_str.c_str(), sizeof(build_string_));

View File

@ -610,7 +610,9 @@ TEST_F(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
// Try calling a NULL pointer.
typedef void (*void_function)(void);
void_function memory_function =
// Volatile markings are needed to keep Clang from generating invalid
// opcodes. See http://crbug.com/498354 for details.
volatile void_function memory_function =
reinterpret_cast<void_function>(NULL);
memory_function();
// not reached

View File

@ -44,6 +44,47 @@
#include "third_party/lss/linux_syscall_support.h"
#endif
#if defined(__ANDROID__)
#include <errno.h>
namespace {
bool g_need_ftruncate_workaround = false;
bool g_checked_need_ftruncate_workaround = false;
void CheckNeedsFTruncateWorkAround(int file) {
if (g_checked_need_ftruncate_workaround) {
return;
}
g_checked_need_ftruncate_workaround = true;
// Attempt an idempotent truncate that chops off nothing and see if we
// run into any sort of errors.
off_t offset = sys_lseek(file, 0, SEEK_END);
if (offset == -1) {
// lseek failed. Don't apply work around. It's unlikely that we can write
// to a minidump with either method.
return;
}
int result = ftruncate(file, offset);
if (result == -1 && errno == EACCES) {
// It very likely that we are running into the kernel bug in M devices.
// We are going to deploy the workaround for writing minidump files
// without uses of ftruncate(). This workaround should be fine even
// for kernels without the bug.
// See http://crbug.com/542840 for more details.
g_need_ftruncate_workaround = true;
}
}
bool NeedsFTruncateWorkAround() {
return g_need_ftruncate_workaround;
}
} // namespace
#endif // defined(__ANDROID__)
namespace google_breakpad {
const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1);
@ -75,15 +116,24 @@ void MinidumpFileWriter::SetFile(const int file) {
assert(file_ == -1);
file_ = file;
close_file_when_destroyed_ = false;
#if defined(__ANDROID__)
CheckNeedsFTruncateWorkAround(file);
#endif
}
bool MinidumpFileWriter::Close() {
bool result = true;
if (file_ != -1) {
if (-1 == ftruncate(file_, position_)) {
#if defined(__ANDROID__)
if (!NeedsFTruncateWorkAround() && ftruncate(file_, position_)) {
return false;
}
#else
if (ftruncate(file_, position_)) {
return false;
}
#endif
#if defined(__linux__) && __linux__
result = (sys_close(file_) == 0);
#else
@ -220,6 +270,20 @@ bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
MDRVA MinidumpFileWriter::Allocate(size_t size) {
assert(size);
assert(file_ != -1);
#if defined(__ANDROID__)
if (NeedsFTruncateWorkAround()) {
// If ftruncate() is not available. We simply increase the size beyond the
// current file size. sys_write() will expand the file when data is written
// to it. Because we did not over allocate to fit memory pages, we also
// do not need to ftruncate() the file once we are done.
size_ += size;
// We don't need to seek since the file is unchanged.
MDRVA current_position = position_;
position_ += static_cast<MDRVA>(size);
return current_position;
}
#endif
size_t aligned_size = (size + 7) & ~7; // 64-bit alignment
if (position_ + aligned_size > size_) {
@ -256,14 +320,16 @@ bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
#if defined(__linux__) && __linux__
if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (sys_write(file_, src, size) == size) {
#else
if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (write(file_, src, size) == size) {
#endif
return true;
}
}
#else
if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (write(file_, src, size) == size) {
return true;
}
}
#endif
return false;
}

View File

@ -96,14 +96,14 @@ CrashGenerationClient::CrashGenerationClient(
const CustomClientInfo* custom_info)
: pipe_name_(pipe_name),
pipe_handle_(NULL),
custom_info_(),
dump_type_(dump_type),
thread_id_(0),
server_process_id_(0),
crash_event_(NULL),
crash_generated_(NULL),
server_alive_(NULL),
exception_pointers_(NULL),
custom_info_() {
server_process_id_(0),
thread_id_(0),
exception_pointers_(NULL) {
memset(&assert_info_, 0, sizeof(assert_info_));
if (custom_info) {
custom_info_ = *custom_info;
@ -116,14 +116,14 @@ CrashGenerationClient::CrashGenerationClient(
const CustomClientInfo* custom_info)
: pipe_name_(),
pipe_handle_(pipe_handle),
custom_info_(),
dump_type_(dump_type),
thread_id_(0),
server_process_id_(0),
crash_event_(NULL),
crash_generated_(NULL),
server_alive_(NULL),
exception_pointers_(NULL),
custom_info_() {
server_process_id_(0),
thread_id_(0),
exception_pointers_(NULL) {
memset(&assert_info_, 0, sizeof(assert_info_));
if (custom_info) {
custom_info_ = *custom_info;

View File

@ -85,7 +85,7 @@ static bool IsClientRequestValid(const ProtocolMessage& msg) {
msg.assert_info != NULL);
}
#ifdef _DEBUG
#ifndef NDEBUG
static bool CheckForIOIncomplete(bool success) {
// We should never get an I/O incomplete since we should not execute this
// unless the operation has finished and the overlapped event is signaled. If
@ -121,12 +121,12 @@ CrashGenerationServer::CrashGenerationServer(
upload_request_callback_(upload_request_callback),
upload_context_(upload_context),
generate_dumps_(generate_dumps),
pre_fetch_custom_info_(true),
dump_path_(dump_path ? *dump_path : L""),
server_state_(IPC_SERVER_STATE_UNINITIALIZED),
shutting_down_(false),
overlapped_(),
client_info_(NULL),
pre_fetch_custom_info_(true) {
client_info_(NULL) {
InitializeCriticalSection(&sync_);
}

View File

@ -259,8 +259,9 @@ MinidumpGenerator::MinidumpGenerator(
const MINIDUMP_TYPE dump_type,
const bool is_client_pointers)
: dbghelp_module_(NULL),
write_dump_(NULL),
rpcrt4_module_(NULL),
dump_path_(dump_path),
create_uuid_(NULL),
process_handle_(process_handle),
process_id_(process_id),
thread_id_(thread_id),
@ -269,14 +270,13 @@ MinidumpGenerator::MinidumpGenerator(
assert_info_(assert_info),
dump_type_(dump_type),
is_client_pointers_(is_client_pointers),
dump_path_(dump_path),
dump_file_(INVALID_HANDLE_VALUE),
full_dump_file_(INVALID_HANDLE_VALUE),
dump_file_is_internal_(false),
full_dump_file_is_internal_(false),
additional_streams_(NULL),
callback_info_(NULL),
write_dump_(NULL),
create_uuid_(NULL) {
callback_info_(NULL) {
InitializeCriticalSection(&module_load_sync_);
InitializeCriticalSection(&get_proc_address_sync_);
}

View File

@ -174,6 +174,7 @@ void ExceptionHandler::Initialize(
assertion_ = NULL;
handler_return_value_ = false;
handle_debug_exceptions_ = false;
consume_invalid_handle_exceptions_ = false;
// Attempt to use out-of-process if user has specified a pipe or a
// crash generation client.
@ -481,6 +482,11 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
(code == EXCEPTION_SINGLE_STEP);
if (code == EXCEPTION_INVALID_HANDLE &&
current_handler->consume_invalid_handle_exceptions_) {
return EXCEPTION_CONTINUE_EXECUTION;
}
bool success = false;
if (!is_debug_exception ||

View File

@ -263,6 +263,15 @@ class ExceptionHandler {
handle_debug_exceptions_ = handle_debug_exceptions;
}
// Controls behavior of EXCEPTION_INVALID_HANDLE.
bool get_consume_invalid_handle_exceptions() const {
return consume_invalid_handle_exceptions_;
}
void set_consume_invalid_handle_exceptions(
bool consume_invalid_handle_exceptions) {
consume_invalid_handle_exceptions_ = consume_invalid_handle_exceptions;
}
// Returns whether out-of-process dump generation is used or not.
bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; }
@ -472,6 +481,10 @@ class ExceptionHandler {
// to not interfere with debuggers.
bool handle_debug_exceptions_;
// If true, the handler will consume any EXCEPTION_INVALID_HANDLE exceptions.
// Leave this false (the default) to handle these exceptions as normal.
bool consume_invalid_handle_exceptions_;
// Callers can request additional memory regions to be included in
// the dump.
AppMemoryList app_memory_info_;

View File

@ -59,7 +59,7 @@ CrashReportSender::CrashReportSender(const wstring &checkpoint_file)
ReportResult CrashReportSender::SendCrashReport(
const wstring &url, const map<wstring, wstring> &parameters,
const wstring &dump_file_name, wstring *report_code) {
const map<wstring, wstring> &files, wstring *report_code) {
int today = GetCurrentDate();
if (today == last_sent_date_ &&
max_reports_per_day_ != -1 &&
@ -69,7 +69,7 @@ ReportResult CrashReportSender::SendCrashReport(
int http_response = 0;
bool result = HTTPUpload::SendRequest(
url, parameters, dump_file_name, L"upload_file_minidump", NULL, report_code,
url, parameters, files, NULL, report_code,
&http_response);
if (result) {

View File

@ -77,7 +77,7 @@ class CrashReportSender {
int max_reports_per_day() const { return max_reports_per_day_; }
// Sends the specified minidump file, along with the map of
// Sends the specified files, along with the map of
// name value pairs, as a multipart POST request to the given URL.
// Parameter names must contain only printable ASCII characters,
// and may not contain a quote (") character.
@ -89,7 +89,7 @@ class CrashReportSender {
// (Otherwise, report_code will be unchanged.)
ReportResult SendCrashReport(const wstring &url,
const map<wstring, wstring> &parameters,
const wstring &dump_file_name,
const map<wstring, wstring> &files,
wstring *report_code);
private:

View File

@ -73,7 +73,7 @@ BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
static int kCustomInfoCount = 2;
static size_t kCustomInfoCount = 2;
static CustomInfoEntry kCustomInfoEntries[] = {
CustomInfoEntry(L"prod", L"CrashTestApp"),
CustomInfoEntry(L"ver", L"1.0"),
@ -197,8 +197,8 @@ bool ShowDumpResults(const wchar_t* dump_path,
return succeeded;
}
static void _cdecl ShowClientConnected(void* context,
const ClientInfo* client_info) {
static void ShowClientConnected(void* context,
const ClientInfo* client_info) {
TCHAR* line = new TCHAR[kMaximumLineLength];
line[0] = _T('\0');
int result = swprintf_s(line,
@ -214,9 +214,9 @@ static void _cdecl ShowClientConnected(void* context,
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
}
static void _cdecl ShowClientCrashed(void* context,
const ClientInfo* client_info,
const wstring* dump_path) {
static void ShowClientCrashed(void* context,
const ClientInfo* client_info,
const wstring* dump_path) {
TCHAR* line = new TCHAR[kMaximumLineLength];
line[0] = _T('\0');
int result = swprintf_s(line,
@ -259,8 +259,8 @@ static void _cdecl ShowClientCrashed(void* context,
QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
}
static void _cdecl ShowClientExited(void* context,
const ClientInfo* client_info) {
static void ShowClientExited(void* context,
const ClientInfo* client_info) {
TCHAR* line = new TCHAR[kMaximumLineLength];
line[0] = _T('\0');
int result = swprintf_s(line,

View File

@ -73,6 +73,7 @@
'<(DEPTH)/processor/logging.cc',
'<(DEPTH)/processor/minidump.cc',
'<(DEPTH)/processor/pathname_stripper.cc',
'<(DEPTH)/processor/proc_maps_linux.cc',
]
}
],

View File

@ -50,9 +50,8 @@ const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
int kCustomInfoCount = 2;
google_breakpad::CustomInfoEntry kCustomInfoEntries[] = {
#define arraysize(f) (sizeof(f) / sizeof(*f))
const google_breakpad::CustomInfoEntry kCustomInfoEntries[] = {
google_breakpad::CustomInfoEntry(L"prod", L"CrashGenerationServerTest"),
google_breakpad::CustomInfoEntry(L"ver", L"1.0"),
};
@ -165,7 +164,7 @@ class CrashGenerationServerTest : public ::testing::Test {
}
google_breakpad::CustomClientInfo custom_info = {kCustomInfoEntries,
kCustomInfoCount};
arraysize(kCustomInfoEntries)};
google_breakpad::ProtocolMessage msg(
fault_type == SEND_INVALID_REGISTRATION ?

View File

@ -229,14 +229,27 @@ breakpad_getcontext:
#elif defined(__mips__)
#if _MIPS_SIM != _ABIO32
#error "Unsupported mips ISA. Only mips o32 is supported."
#endif
// This implementation is inspired by implementation of getcontext in glibc.
#if _MIPS_SIM == _ABIO32
#include <asm/asm.h>
#include <asm/regdef.h>
#include <asm/fpregdef.h>
#else
#include <machine/asm.h>
#include <machine/regdef.h>
#endif
// from asm/asm.h
#if _MIPS_SIM == _ABIO32
#define ALSZ 7
#define ALMASK ~7
#define SZREG 4
#else // _MIPS_SIM != _ABIO32
#define ALSZ 15
#define ALMASK ~15
#define SZREG 8
#endif
#include <asm/unistd.h> // for __NR_rt_sigprocmask
#define _NSIG8 128 / 8
@ -244,12 +257,14 @@ breakpad_getcontext:
.text
LOCALS_NUM = 2 // save gp and ra on stack
LOCALS_NUM = 1 // save gp on stack
FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK
RA_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG)
GP_FRAME_OFFSET = FRAME_SIZE - (2 * SZREG)
GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG)
MCONTEXT_REG_SIZE = 8
#if _MIPS_SIM == _ABIO32
NESTED (breakpad_getcontext, FRAME_SIZE, ra)
.mask 0x00000000, 0
.fmask 0x00000000, 0
@ -262,8 +277,7 @@ NESTED (breakpad_getcontext, FRAME_SIZE, ra)
#define _SP a2
addiu sp, -FRAME_SIZE
sw ra, RA_FRAME_OFFSET(sp)
sw gp, GP_FRAME_OFFSET(sp)
.cprestore GP_FRAME_OFFSET
sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
@ -298,12 +312,95 @@ NESTED (breakpad_getcontext, FRAME_SIZE, ra)
li v0, __NR_rt_sigprocmask
syscall
lw ra, RA_FRAME_OFFSET(sp)
lw gp, GP_FRAME_OFFSET(sp)
addiu sp, FRAME_SIZE
jr ra
END (breakpad_getcontext)
#else
#ifndef NESTED
/*
* NESTED - declare nested routine entry point
*/
#define NESTED(symbol, framesize, rpc) \
.globl symbol; \
.align 2; \
.type symbol,@function; \
.ent symbol,0; \
symbol: .frame sp, framesize, rpc;
#endif
/*
* END - mark end of function
*/
#ifndef END
# define END(function) \
.end function; \
.size function,.-function
#endif
/* int getcontext (ucontext_t *ucp) */
NESTED (breakpad_getcontext, FRAME_SIZE, ra)
.mask 0x10000000, 0
.fmask 0x00000000, 0
move a2, sp
#define _SP a2
move a3, gp
#define _GP a3
daddiu sp, -FRAME_SIZE
.cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext
/* Store a magic flag. */
li v1, 1
sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) /* zero */
sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd ra, MCONTEXT_PC_OFFSET(a0)
#ifdef __mips_hard_float
s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
cfc1 v1, $31
sw v1, MCONTEXT_FPC_CSR(a0)
#endif /* __mips_hard_float */
/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
li a3, _NSIG8
daddu a2, a0, UCONTEXT_SIGMASK_OFFSET
move a1, zero
li a0, SIG_BLOCK
li v0, __NR_rt_sigprocmask
syscall
.cpreturn
daddiu sp, FRAME_SIZE
move v0, zero
jr ra
END (breakpad_getcontext)
#endif // _MIPS_SIM == _ABIO32
#elif defined(__x86_64__)
/* The x64 implementation of breakpad_getcontext was derived in part

View File

@ -36,7 +36,8 @@
// TODO(rmcilroy): Remove this file once the ndk is updated for other
// architectures - crbug.com/358831
#if !defined(__aarch64__) && !defined(__x86_64__)
#if !defined(__aarch64__) && !defined(__x86_64__) && \
!(defined(__mips__) && _MIPS_SIM == _ABI64)
#ifdef __cplusplus
extern "C" {

View File

@ -38,6 +38,9 @@
#include <asm/ptrace.h>
#include <sys/cdefs.h>
#if defined (__mips__)
#include <sys/types.h>
#endif
#include <sys/user.h>
#include <unistd.h>
@ -98,8 +101,8 @@ struct elf_prpsinfo {
unsigned int pr_uid;
unsigned int pr_gid;
#elif defined(__mips__)
unsigned long pr_uid;
unsigned long pr_gid;
__kernel_uid_t pr_uid;
__kernel_gid_t pr_gid;
#else
unsigned short pr_uid;
unsigned short pr_gid;

View File

@ -33,85 +33,12 @@
// The purpose of this file is to glue the mismatching headers (Android NDK vs
// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code.
// The following quirks are currently handled by this file:
// - MIPS: Keep using forked definitions of user.h structs. The definition in
// the NDK is completely different.
// Internal bug b/18097715
// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct.
// - aarch64: Add missing user_regs_struct and user_fpsimd_struct structs.
// - Other platforms: Just use the Android NDK unchanged.
#ifdef __mips__
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#define EF_REG0 6
#define EF_REG1 7
#define EF_REG2 8
#define EF_REG3 9
#define EF_REG4 10
#define EF_REG5 11
#define EF_REG6 12
#define EF_REG7 13
#define EF_REG8 14
#define EF_REG9 15
#define EF_REG10 16
#define EF_REG11 17
#define EF_REG12 18
#define EF_REG13 19
#define EF_REG14 20
#define EF_REG15 21
#define EF_REG16 22
#define EF_REG17 23
#define EF_REG18 24
#define EF_REG19 25
#define EF_REG20 26
#define EF_REG21 27
#define EF_REG22 28
#define EF_REG23 29
#define EF_REG24 30
#define EF_REG25 31
/*
* k0/k1 unsaved
*/
#define EF_REG26 32
#define EF_REG27 33
#define EF_REG28 34
#define EF_REG29 35
#define EF_REG30 36
#define EF_REG31 37
/*
* Saved special registers
*/
#define EF_LO 38
#define EF_HI 39
#define EF_CP0_EPC 40
#define EF_CP0_BADVADDR 41
#define EF_CP0_STATUS 42
#define EF_CP0_CAUSE 43
struct user_regs_struct {
unsigned long long regs[32];
unsigned long long lo;
unsigned long long hi;
unsigned long long epc;
unsigned long long badvaddr;
unsigned long long status;
unsigned long long cause;
};
struct user_fpregs_struct {
unsigned long long regs[32];
unsigned int fpcsr;
unsigned int fir;
};
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#else // __mips__
// TODO(primiano): remove these changes after Chromium has stably rolled to
// an NDK with the appropriate fixes.
#include_next <sys/user.h>
@ -125,6 +52,24 @@ typedef struct user_fxsr_struct user_fpxregs_struct;
#endif // __cplusplus
#endif // __i386__
#endif // __mips__
#ifdef __aarch64__
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
struct user_regs_struct {
__u64 regs[31];
__u64 sp;
__u64 pc;
__u64 pstate;
};
struct user_fpsimd_struct {
__uint128_t vregs[32];
__u32 fpsr;
__u32 fpcr;
};
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // __aarch64__
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H

View File

@ -38,6 +38,9 @@
#include_next <wchar.h>
#if !defined(__aarch64__) && !defined(__x86_64__) && \
!(defined(__mips__) && _MIPS_SIM == _ABI64)
// This needs to be in an extern "C" namespace, or Googletest will not
// compile against it.
#ifdef __cplusplus
@ -68,5 +71,6 @@ static int inline wcscasecmp(const wchar_t* s1, const wchar_t* s2) {
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif
#endif // GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H

View File

@ -97,11 +97,19 @@
#elif defined(__mips__)
#if _MIPS_SIM == _ABIO32
#define MCONTEXT_PC_OFFSET 32
#define MCONTEXT_GREGS_OFFSET 40
#define MCONTEXT_FPREGS_OFFSET 296
#define MCONTEXT_FPC_CSR 556
#define UCONTEXT_SIGMASK_OFFSET 616
#else
#define MCONTEXT_GREGS_OFFSET 40
#define MCONTEXT_FPREGS_OFFSET 296
#define MCONTEXT_PC_OFFSET 616
#define MCONTEXT_FPC_CSR 624
#define UCONTEXT_SIGMASK_OFFSET 640
#endif
#elif defined(__x86_64__)

View File

@ -35,6 +35,11 @@
['OS=="linux"', {
'defines': ['HAVE_A_OUT_H'],
}],
['OS!="android"', {'sources/': [['exclude', '(^|/)android/']]}],
['OS!="linux"', {'sources/': [['exclude', '(^|/)linux/']]}],
['OS!="mac"', {'sources/': [['exclude', '(^|/)mac/']]}],
['OS!="solaris"', {'sources/': [['exclude', '(^|/)solaris/']]}],
['OS!="win"', {'sources/': [['exclude', '(^|/)windows/']]}],
],
},
'targets': [
@ -120,7 +125,7 @@
'mac/bootstrap_compat.h',
'mac/byteswap.h',
'mac/dump_syms.h',
'mac/dump_syms.mm',
'mac/dump_syms.cc',
'mac/file_id.cc',
'mac/file_id.h',
'mac/GTMDefines.h',
@ -141,6 +146,7 @@
'mac/scoped_task_suspend-inl.h',
'mac/string_utilities.cc',
'mac/string_utilities.h',
'mac/super_fat_arch.h',
'md5.cc',
'md5.h',
'memory.h',

View File

@ -1,23 +1,39 @@
/*
* Copyright 2001-2004 Unicode, Inc.
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
* Distributed under the Terms of Use in
* http://www.unicode.org/copyright.html.
*
* Disclaimer
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of the Unicode data files and any associated documentation
* (the "Data Files") or Unicode software and any associated documentation
* (the "Software") to deal in the Data Files or Software
* without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, and/or sell copies of
* the Data Files or Software, and to permit persons to whom the Data Files
* or Software are furnished to do so, provided that
* (a) this copyright and permission notice appear with all copies
* of the Data Files or Software,
* (b) this copyright and permission notice appear in associated
* documentation, and
* (c) there is clear notice in each modified Data File or in the Software
* as well as in the documentation associated with the Data File(s) or
* Software that the data or software has been modified.
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
* THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
* Except as contained in this notice, the name of a copyright holder
* shall not be used in advertising or otherwise to promote the sale,
* use or other dealings in these Data Files or Software without prior
* written authorization of the copyright holder.
*/
/* ---------------------------------------------------------------------

View File

@ -1,23 +1,39 @@
/*
* Copyright 2001-2004 Unicode, Inc.
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
* Distributed under the Terms of Use in
* http://www.unicode.org/copyright.html.
*
* Disclaimer
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of the Unicode data files and any associated documentation
* (the "Data Files") or Unicode software and any associated documentation
* (the "Software") to deal in the Data Files or Software
* without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, and/or sell copies of
* the Data Files or Software, and to permit persons to whom the Data Files
* or Software are furnished to do so, provided that
* (a) this copyright and permission notice appear with all copies
* of the Data Files or Software,
* (b) this copyright and permission notice appear in associated
* documentation, and
* (c) there is clear notice in each modified Data File or in the Software
* as well as in the documentation associated with the Data File(s) or
* Software that the data or software has been modified.
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
* THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
* Except as contained in this notice, the name of a copyright holder
* shall not be used in advertising or otherwise to promote the sale,
* use or other dealings in these Data Files or Software without prior
* written authorization of the copyright holder.
*/
#ifndef COMMON_CONVERT_UTF_H_

View File

@ -32,16 +32,15 @@
#include "common/dwarf/bytereader.h"
#include <assert.h>
#include <stdint.h>
namespace dwarf2reader {
inline uint8 ByteReader::ReadOneByte(const char* buffer) const {
inline uint8 ByteReader::ReadOneByte(const uint8_t *buffer) const {
return buffer[0];
}
inline uint16 ByteReader::ReadTwoBytes(const char* signed_buffer) const {
const unsigned char *buffer
= reinterpret_cast<const unsigned char *>(signed_buffer);
inline uint16 ByteReader::ReadTwoBytes(const uint8_t *buffer) const {
const uint16 buffer0 = buffer[0];
const uint16 buffer1 = buffer[1];
if (endian_ == ENDIANNESS_LITTLE) {
@ -51,9 +50,7 @@ inline uint16 ByteReader::ReadTwoBytes(const char* signed_buffer) const {
}
}
inline uint64 ByteReader::ReadFourBytes(const char* signed_buffer) const {
const unsigned char *buffer
= reinterpret_cast<const unsigned char *>(signed_buffer);
inline uint64 ByteReader::ReadFourBytes(const uint8_t *buffer) const {
const uint32 buffer0 = buffer[0];
const uint32 buffer1 = buffer[1];
const uint32 buffer2 = buffer[2];
@ -65,9 +62,7 @@ inline uint64 ByteReader::ReadFourBytes(const char* signed_buffer) const {
}
}
inline uint64 ByteReader::ReadEightBytes(const char* signed_buffer) const {
const unsigned char *buffer
= reinterpret_cast<const unsigned char *>(signed_buffer);
inline uint64 ByteReader::ReadEightBytes(const uint8_t *buffer) const {
const uint64 buffer0 = buffer[0];
const uint64 buffer1 = buffer[1];
const uint64 buffer2 = buffer[2];
@ -89,12 +84,12 @@ inline uint64 ByteReader::ReadEightBytes(const char* signed_buffer) const {
// information, plus one bit saying whether the number continues or
// not.
inline uint64 ByteReader::ReadUnsignedLEB128(const char* buffer,
inline uint64 ByteReader::ReadUnsignedLEB128(const uint8_t *buffer,
size_t* len) const {
uint64 result = 0;
size_t num_read = 0;
unsigned int shift = 0;
unsigned char byte;
uint8_t byte;
do {
byte = *buffer++;
@ -114,12 +109,12 @@ inline uint64 ByteReader::ReadUnsignedLEB128(const char* buffer,
// Read a signed LEB128 number. These are like regular LEB128
// numbers, except the last byte may have a sign bit set.
inline int64 ByteReader::ReadSignedLEB128(const char* buffer,
inline int64 ByteReader::ReadSignedLEB128(const uint8_t *buffer,
size_t* len) const {
int64 result = 0;
unsigned int shift = 0;
size_t num_read = 0;
unsigned char byte;
uint8_t byte;
do {
byte = *buffer++;
@ -134,18 +129,18 @@ inline int64 ByteReader::ReadSignedLEB128(const char* buffer,
return result;
}
inline uint64 ByteReader::ReadOffset(const char* buffer) const {
inline uint64 ByteReader::ReadOffset(const uint8_t *buffer) const {
assert(this->offset_reader_);
return (this->*offset_reader_)(buffer);
}
inline uint64 ByteReader::ReadAddress(const char* buffer) const {
inline uint64 ByteReader::ReadAddress(const uint8_t *buffer) const {
assert(this->address_reader_);
return (this->*address_reader_)(buffer);
}
inline void ByteReader::SetCFIDataBase(uint64 section_base,
const char *buffer_base) {
const uint8_t *buffer_base) {
section_base_ = section_base;
buffer_base_ = buffer_base;
have_section_base_ = true;

View File

@ -27,6 +27,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "common/dwarf/bytereader-inl.h"
@ -62,7 +63,7 @@ void ByteReader::SetAddressSize(uint8 size) {
}
}
uint64 ByteReader::ReadInitialLength(const char* start, size_t* len) {
uint64 ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) {
const uint64 initial_length = ReadFourBytes(start);
start += 4;
@ -100,7 +101,7 @@ bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const {
}
}
uint64 ByteReader::ReadEncodedPointer(const char *buffer,
uint64 ByteReader::ReadEncodedPointer(const uint8_t *buffer,
DwarfPointerEncoding encoding,
size_t *len) const {
// UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't
@ -129,7 +130,7 @@ uint64 ByteReader::ReadEncodedPointer(const char *buffer,
// Round up to the next boundary.
uint64 aligned = (offset + AddressSize() - 1) & -AddressSize();
// Convert back to a pointer.
const char *aligned_buffer = buffer_base_ + (aligned - skew);
const uint8_t *aligned_buffer = buffer_base_ + (aligned - skew);
// Finally, store the length and actually fetch the pointer.
*len = aligned_buffer - buffer + AddressSize();
return ReadAddress(aligned_buffer);

View File

@ -31,7 +31,10 @@
#ifndef COMMON_DWARF_BYTEREADER_H__
#define COMMON_DWARF_BYTEREADER_H__
#include <stdint.h>
#include <string>
#include "common/dwarf/types.h"
#include "common/dwarf/dwarf2enums.h"
@ -59,22 +62,22 @@ class ByteReader {
// Read a single byte from BUFFER and return it as an unsigned 8 bit
// number.
uint8 ReadOneByte(const char* buffer) const;
uint8 ReadOneByte(const uint8_t *buffer) const;
// Read two bytes from BUFFER and return them as an unsigned 16 bit
// number, using this ByteReader's endianness.
uint16 ReadTwoBytes(const char* buffer) const;
uint16 ReadTwoBytes(const uint8_t *buffer) const;
// Read four bytes from BUFFER and return them as an unsigned 32 bit
// number, using this ByteReader's endianness. This function returns
// a uint64 so that it is compatible with ReadAddress and
// ReadOffset. The number it returns will never be outside the range
// of an unsigned 32 bit integer.
uint64 ReadFourBytes(const char* buffer) const;
uint64 ReadFourBytes(const uint8_t *buffer) const;
// Read eight bytes from BUFFER and return them as an unsigned 64
// bit number, using this ByteReader's endianness.
uint64 ReadEightBytes(const char* buffer) const;
uint64 ReadEightBytes(const uint8_t *buffer) const;
// Read an unsigned LEB128 (Little Endian Base 128) number from
// BUFFER and return it as an unsigned 64 bit integer. Set LEN to
@ -93,7 +96,7 @@ class ByteReader {
// In other words, we break VALUE into groups of seven bits, put
// them in little-endian order, and then write them as eight-bit
// bytes with the high bit on all but the last.
uint64 ReadUnsignedLEB128(const char* buffer, size_t* len) const;
uint64 ReadUnsignedLEB128(const uint8_t *buffer, size_t *len) const;
// Read a signed LEB128 number from BUFFER and return it as an
// signed 64 bit integer. Set LEN to the number of bytes read.
@ -112,7 +115,7 @@ class ByteReader {
// In other words, we break VALUE into groups of seven bits, put
// them in little-endian order, and then write them as eight-bit
// bytes with the high bit on all but the last.
int64 ReadSignedLEB128(const char* buffer, size_t* len) const;
int64 ReadSignedLEB128(const uint8_t *buffer, size_t *len) const;
// Indicate that addresses on this architecture are SIZE bytes long. SIZE
// must be either 4 or 8. (DWARF allows addresses to be any number of
@ -135,7 +138,7 @@ class ByteReader {
// Read an address from BUFFER and return it as an unsigned 64 bit
// integer, respecting this ByteReader's endianness and address size. You
// must call SetAddressSize before calling this function.
uint64 ReadAddress(const char* buffer) const;
uint64 ReadAddress(const uint8_t *buffer) const;
// DWARF actually defines two slightly different formats: 32-bit DWARF
// and 64-bit DWARF. This is *not* related to the size of registers or
@ -172,14 +175,14 @@ class ByteReader {
// - The 32-bit value 0xffffffff, followed by a 64-bit byte count,
// indicating that the data whose length is being measured uses
// the 64-bit DWARF format.
uint64 ReadInitialLength(const char* start, size_t* len);
uint64 ReadInitialLength(const uint8_t *start, size_t *len);
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer, respecting the ByteReader's endianness. In 32-bit DWARF, the
// offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes
// long. You must call ReadInitialLength or SetOffsetSize before calling
// this function; see the comments above for details.
uint64 ReadOffset(const char* buffer) const;
uint64 ReadOffset(const uint8_t *buffer) const;
// Return the current offset size, in bytes.
// A return value of 4 indicates that we are reading 32-bit DWARF.
@ -234,7 +237,7 @@ class ByteReader {
// is BUFFER_BASE. This allows us to find the address that a given
// byte in our buffer would have when loaded into the program the
// data describes. We need this to resolve DW_EH_PE_pcrel pointers.
void SetCFIDataBase(uint64 section_base, const char *buffer_base);
void SetCFIDataBase(uint64 section_base, const uint8_t *buffer_base);
// Indicate that the base address of the program's ".text" section
// is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers.
@ -273,13 +276,14 @@ class ByteReader {
// base address this reader hasn't been given, so you should check
// with ValidEncoding and UsableEncoding first if you would rather
// die in a more helpful way.
uint64 ReadEncodedPointer(const char *buffer, DwarfPointerEncoding encoding,
uint64 ReadEncodedPointer(const uint8_t *buffer,
DwarfPointerEncoding encoding,
size_t *len) const;
private:
// Function pointer type for our address and offset readers.
typedef uint64 (ByteReader::*AddressReader)(const char*) const;
typedef uint64 (ByteReader::*AddressReader)(const uint8_t *) const;
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 define offsets as either 4 or 8 bytes,
@ -302,7 +306,7 @@ class ByteReader {
bool have_section_base_, have_text_base_, have_data_base_;
bool have_function_base_;
uint64 section_base_, text_base_, data_base_, function_base_;
const char *buffer_base_;
const uint8_t *buffer_base_;
};
} // namespace dwarf2reader

View File

@ -31,6 +31,8 @@
// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader
#include <stdint.h>
#include <string>
#include "breakpad_googletest_includes.h"
@ -71,7 +73,7 @@ TEST_F(Reader, SimpleConstructor) {
.LEB128(-0x4f337badf4483f83LL)
.D32(0xfec319c9);
ASSERT_TRUE(section.GetContents(&contents));
const char *data = contents.data();
const uint8_t *data = reinterpret_cast<const uint8_t *>(contents.data());
EXPECT_EQ(0xc0U, reader.ReadOneByte(data));
EXPECT_EQ(0xcf0dU, reader.ReadTwoBytes(data + 1));
EXPECT_EQ(0x96fdd219U, reader.ReadFourBytes(data + 3));
@ -375,7 +377,7 @@ TEST_F(Reader, ValidEncodings) {
}
TEST_F(ReaderDeathTest, DW_EH_PE_omit) {
static const char data[1] = { 42 };
static const uint8_t data[] = { 42 };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
EXPECT_DEATH(reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_omit,
@ -384,7 +386,7 @@ TEST_F(ReaderDeathTest, DW_EH_PE_omit) {
}
TEST_F(Reader, DW_EH_PE_absptr4) {
static const char data[] = { 0x27, 0x57, 0xea, 0x40 };
static const uint8_t data[] = { 0x27, 0x57, 0xea, 0x40 };
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
EXPECT_EQ(0x40ea5727U,
@ -394,7 +396,7 @@ TEST_F(Reader, DW_EH_PE_absptr4) {
}
TEST_F(Reader, DW_EH_PE_absptr8) {
static const char data[] = {
static const uint8_t data[] = {
0x60, 0x27, 0x57, 0xea, 0x40, 0xc2, 0x98, 0x05, 0x01, 0x50
};
ByteReader reader(ENDIANNESS_LITTLE);
@ -406,7 +408,7 @@ TEST_F(Reader, DW_EH_PE_absptr8) {
}
TEST_F(Reader, DW_EH_PE_uleb128) {
static const char data[] = { 0x81, 0x84, 0x4c };
static const uint8_t data[] = { 0x81, 0x84, 0x4c };
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
EXPECT_EQ(0x130201U,
@ -416,7 +418,7 @@ TEST_F(Reader, DW_EH_PE_uleb128) {
}
TEST_F(Reader, DW_EH_PE_udata2) {
static const char data[] = { 0xf4, 0x8d };
static const uint8_t data[] = { 0xf4, 0x8d };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
EXPECT_EQ(0xf48dU,
@ -426,7 +428,7 @@ TEST_F(Reader, DW_EH_PE_udata2) {
}
TEST_F(Reader, DW_EH_PE_udata4) {
static const char data[] = { 0xb2, 0x68, 0xa5, 0x62, 0x8f, 0x8b };
static const uint8_t data[] = { 0xb2, 0x68, 0xa5, 0x62, 0x8f, 0x8b };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(8);
EXPECT_EQ(0xa5628f8b,
@ -436,7 +438,7 @@ TEST_F(Reader, DW_EH_PE_udata4) {
}
TEST_F(Reader, DW_EH_PE_udata8Addr8) {
static const char data[] = {
static const uint8_t data[] = {
0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe
};
ByteReader reader(ENDIANNESS_LITTLE);
@ -448,7 +450,7 @@ TEST_F(Reader, DW_EH_PE_udata8Addr8) {
}
TEST_F(Reader, DW_EH_PE_udata8Addr4) {
static const char data[] = {
static const uint8_t data[] = {
0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe
};
ByteReader reader(ENDIANNESS_LITTLE);
@ -460,7 +462,7 @@ TEST_F(Reader, DW_EH_PE_udata8Addr4) {
}
TEST_F(Reader, DW_EH_PE_sleb128) {
static const char data[] = { 0x42, 0xff, 0xfb, 0x73 };
static const uint8_t data[] = { 0x42, 0xff, 0xfb, 0x73 };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
EXPECT_EQ(-0x030201U & 0xffffffff,
@ -470,7 +472,7 @@ TEST_F(Reader, DW_EH_PE_sleb128) {
}
TEST_F(Reader, DW_EH_PE_sdata2) {
static const char data[] = { 0xb9, 0xbf };
static const uint8_t data[] = { 0xb9, 0xbf };
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0xffffffffffffbfb9ULL,
@ -480,7 +482,7 @@ TEST_F(Reader, DW_EH_PE_sdata2) {
}
TEST_F(Reader, DW_EH_PE_sdata4) {
static const char data[] = { 0xa0, 0xca, 0xf2, 0xb8, 0xc2, 0xad };
static const uint8_t data[] = { 0xa0, 0xca, 0xf2, 0xb8, 0xc2, 0xad };
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0xffffffffadc2b8f2ULL,
@ -490,7 +492,7 @@ TEST_F(Reader, DW_EH_PE_sdata4) {
}
TEST_F(Reader, DW_EH_PE_sdata8) {
static const char data[] = {
static const uint8_t data[] = {
0xf6, 0x66, 0x57, 0x79, 0xe0, 0x0c, 0x9b, 0x26, 0x87
};
ByteReader reader(ENDIANNESS_LITTLE);
@ -502,7 +504,9 @@ TEST_F(Reader, DW_EH_PE_sdata8) {
}
TEST_F(Reader, DW_EH_PE_pcrel) {
static const char data[] = { 0x4a, 0x8b, 0x1b, 0x14, 0xc8, 0xc4, 0x02, 0xce };
static const uint8_t data[] = {
0x4a, 0x8b, 0x1b, 0x14, 0xc8, 0xc4, 0x02, 0xce
};
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
DwarfPointerEncoding encoding =
@ -515,7 +519,9 @@ TEST_F(Reader, DW_EH_PE_pcrel) {
}
TEST_F(Reader, DW_EH_PE_textrel) {
static const char data[] = { 0xd9, 0x0d, 0x05, 0x17, 0xc9, 0x7a, 0x42, 0x1e };
static const uint8_t data[] = {
0xd9, 0x0d, 0x05, 0x17, 0xc9, 0x7a, 0x42, 0x1e
};
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
reader.SetTextBase(0xb91beaf0);
@ -528,7 +534,9 @@ TEST_F(Reader, DW_EH_PE_textrel) {
}
TEST_F(Reader, DW_EH_PE_datarel) {
static const char data[] = { 0x16, 0xf2, 0xbb, 0x82, 0x68, 0xa7, 0xbc, 0x39 };
static const uint8_t data[] = {
0x16, 0xf2, 0xbb, 0x82, 0x68, 0xa7, 0xbc, 0x39
};
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(8);
reader.SetDataBase(0xbef308bd25ce74f0ULL);
@ -541,7 +549,9 @@ TEST_F(Reader, DW_EH_PE_datarel) {
}
TEST_F(Reader, DW_EH_PE_funcrel) {
static const char data[] = { 0x84, 0xf8, 0x14, 0x01, 0x61, 0xd1, 0x48, 0xc9 };
static const uint8_t data[] = {
0x84, 0xf8, 0x14, 0x01, 0x61, 0xd1, 0x48, 0xc9
};
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
reader.SetFunctionBase(0x823c3520);
@ -554,7 +564,7 @@ TEST_F(Reader, DW_EH_PE_funcrel) {
}
TEST(UsableBase, CFI) {
static const char data[1] = { 0x42 };
static const uint8_t data[] = { 0x42 };
ByteReader reader(ENDIANNESS_BIG);
reader.SetCFIDataBase(0xb31cbd20, data);
EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
@ -617,12 +627,12 @@ TEST(UsableBase, ClearFunction) {
struct AlignedFixture {
AlignedFixture() : reader(ENDIANNESS_BIG) { reader.SetAddressSize(4); }
static const char data[10];
static const uint8_t data[10];
ByteReader reader;
size_t pointer_size;
};
const char AlignedFixture::data[10] = {
const uint8_t AlignedFixture::data[10] = {
0xfe, 0x6e, 0x93, 0xd8, 0x34, 0xd5, 0x1c, 0xd3, 0xac, 0x2b
};

View File

@ -32,6 +32,7 @@
// See dwarf2diehandler.h for details.
#include <assert.h>
#include <stdint.h>
#include <string>
@ -167,7 +168,7 @@ void DIEDispatcher::ProcessAttributeReference(uint64 offset,
void DIEDispatcher::ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const char* data,
const uint8_t *data,
uint64 len) {
HandlerStack &current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.

View File

@ -156,6 +156,8 @@
#ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__
#define COMMON_DWARF_DWARF2DIEHANDLER_H__
#include <stdint.h>
#include <stack>
#include <string>
@ -206,7 +208,7 @@ class DIEHandler {
uint64 data) { }
virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
enum DwarfForm form,
const char* data,
const uint8_t *data,
uint64 len) { }
virtual void ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
@ -309,7 +311,7 @@ class DIEDispatcher: public Dwarf2Handler {
void ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const char* data,
const uint8_t *data,
uint64 len);
void ProcessAttributeString(uint64 offset,
enum DwarfAttribute attr,

View File

@ -32,6 +32,8 @@
// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher.
#include <stdint.h>
#include <string>
#include <utility>
@ -67,7 +69,7 @@ class MockDIEHandler: public DIEHandler {
MOCK_METHOD3(ProcessAttributeReference,
void(DwarfAttribute, DwarfForm, uint64));
MOCK_METHOD4(ProcessAttributeBuffer,
void(DwarfAttribute, DwarfForm, const char *, uint64));
void(DwarfAttribute, DwarfForm, const uint8_t *, uint64));
MOCK_METHOD3(ProcessAttributeString,
void(DwarfAttribute, DwarfForm, const string &));
MOCK_METHOD3(ProcessAttributeSignature,
@ -86,7 +88,7 @@ class MockRootDIEHandler: public RootDIEHandler {
MOCK_METHOD3(ProcessAttributeReference,
void(DwarfAttribute, DwarfForm, uint64));
MOCK_METHOD4(ProcessAttributeBuffer,
void(DwarfAttribute, DwarfForm, const char *, uint64));
void(DwarfAttribute, DwarfForm, const uint8_t *, uint64));
MOCK_METHOD3(ProcessAttributeString,
void(DwarfAttribute, DwarfForm, const string &));
MOCK_METHOD3(ProcessAttributeSignature,
@ -185,8 +187,9 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
MockRootDIEHandler mock_root_handler;
DIEDispatcher die_dispatcher(&mock_root_handler);
const char buffer[10] = { 0x24, 0x24, 0x35, 0x9a, 0xca,
0xcf, 0xa8, 0x84, 0xa7, 0x18 };
const uint8_t buffer[10] = {
0x24, 0x24, 0x35, 0x9a, 0xca, 0xcf, 0xa8, 0x84, 0xa7, 0x18
};
string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d";
// Set expectations.

View File

@ -83,9 +83,9 @@ void CompilationUnit::ReadAbbrevs() {
// The only way to check whether we are reading over the end of the
// buffer would be to first compute the size of the leb128 data by
// reading it, then go back and read it again.
const char* abbrev_start = iter->second.first +
const uint8_t *abbrev_start = iter->second.first +
header_.abbrev_offset;
const char* abbrevptr = abbrev_start;
const uint8_t *abbrevptr = abbrev_start;
#ifndef NDEBUG
const uint64 abbrev_length = iter->second.second - header_.abbrev_offset;
#endif
@ -132,8 +132,8 @@ void CompilationUnit::ReadAbbrevs() {
}
// Skips a single DIE's attributes.
const char* CompilationUnit::SkipDIE(const char* start,
const Abbrev& abbrev) {
const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start,
const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
@ -143,8 +143,8 @@ const char* CompilationUnit::SkipDIE(const char* start,
}
// Skips a single attribute form's data.
const char* CompilationUnit::SkipAttribute(const char* start,
enum DwarfForm form) {
const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
enum DwarfForm form) {
size_t len;
switch (form) {
@ -171,7 +171,7 @@ const char* CompilationUnit::SkipAttribute(const char* start,
case DW_FORM_ref_sig8:
return start + 8;
case DW_FORM_string:
return start + strlen(start) + 1;
return start + strlen(reinterpret_cast<const char *>(start)) + 1;
case DW_FORM_udata:
case DW_FORM_ref_udata:
reader_->ReadUnsignedLEB128(start, &len);
@ -183,14 +183,15 @@ const char* CompilationUnit::SkipAttribute(const char* start,
case DW_FORM_addr:
return start + reader_->AddressSize();
case DW_FORM_ref_addr:
// DWARF2 and 3 differ on whether ref_addr is address size or
// DWARF2 and 3/4 differ on whether ref_addr is address size or
// offset size.
assert(header_.version == 2 || header_.version == 3);
assert(header_.version >= 2);
if (header_.version == 2) {
return start + reader_->AddressSize();
} else if (header_.version == 3) {
} else if (header_.version >= 3) {
return start + reader_->OffsetSize();
}
break;
case DW_FORM_block1:
return start + 1 + reader_->ReadOneByte(start);
@ -217,7 +218,7 @@ const char* CompilationUnit::SkipAttribute(const char* start,
// the offset in the .debug_abbrev section for our abbrevs, and an
// address size.
void CompilationUnit::ReadHeader() {
const char* headerptr = buffer_;
const uint8_t *headerptr = buffer_;
size_t initial_length_size;
assert(headerptr + 4 < buffer_ + buffer_length_);
@ -304,8 +305,8 @@ uint64 CompilationUnit::Start() {
// If one really wanted, you could merge SkipAttribute and
// ProcessAttribute
// This is all boring data manipulation and calling of the handler.
const char* CompilationUnit::ProcessAttribute(
uint64 dieoffset, const char* start, enum DwarfAttribute attr,
const uint8_t *CompilationUnit::ProcessAttribute(
uint64 dieoffset, const uint8_t *start, enum DwarfAttribute attr,
enum DwarfForm form) {
size_t len;
@ -339,7 +340,7 @@ const char* CompilationUnit::ProcessAttribute(
reader_->ReadEightBytes(start));
return start + 8;
case DW_FORM_string: {
const char* str = start;
const char *str = reinterpret_cast<const char *>(start);
handler_->ProcessAttributeString(dieoffset, attr, form,
str);
return start + strlen(str) + 1;
@ -390,14 +391,14 @@ const char* CompilationUnit::ProcessAttribute(
+ offset_from_section_start_);
return start + len;
case DW_FORM_ref_addr:
// DWARF2 and 3 differ on whether ref_addr is address size or
// DWARF2 and 3/4 differ on whether ref_addr is address size or
// offset size.
assert(header_.version == 2 || header_.version == 3);
assert(header_.version >= 2);
if (header_.version == 2) {
handler_->ProcessAttributeReference(dieoffset, attr, form,
reader_->ReadAddress(start));
return start + reader_->AddressSize();
} else if (header_.version == 3) {
} else if (header_.version >= 3) {
handler_->ProcessAttributeReference(dieoffset, attr, form,
reader_->ReadOffset(start));
return start + reader_->OffsetSize();
@ -439,7 +440,7 @@ const char* CompilationUnit::ProcessAttribute(
const uint64 offset = reader_->ReadOffset(start);
assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_);
const char* str = string_buffer_ + offset;
const char *str = reinterpret_cast<const char *>(string_buffer_ + offset);
handler_->ProcessAttributeString(dieoffset, attr, form,
str);
return start + reader_->OffsetSize();
@ -449,9 +450,9 @@ const char* CompilationUnit::ProcessAttribute(
return NULL;
}
const char* CompilationUnit::ProcessDIE(uint64 dieoffset,
const char* start,
const Abbrev& abbrev) {
const uint8_t *CompilationUnit::ProcessDIE(uint64 dieoffset,
const uint8_t *start,
const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
@ -461,12 +462,12 @@ const char* CompilationUnit::ProcessDIE(uint64 dieoffset,
}
void CompilationUnit::ProcessDIEs() {
const char* dieptr = after_header_;
const uint8_t *dieptr = after_header_;
size_t len;
// lengthstart is the place the length field is based on.
// It is the point in the header after the initial length field
const char* lengthstart = buffer_;
const uint8_t *lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
@ -514,10 +515,12 @@ void CompilationUnit::ProcessDIEs() {
}
}
LineInfo::LineInfo(const char* buffer, uint64 buffer_length,
LineInfo::LineInfo(const uint8_t *buffer, uint64 buffer_length,
ByteReader* reader, LineInfoHandler* handler):
handler_(handler), reader_(reader), buffer_(buffer),
buffer_length_(buffer_length) {
handler_(handler), reader_(reader), buffer_(buffer) {
#ifndef NDEBUG
buffer_length_ = buffer_length;
#endif
header_.std_opcode_lengths = NULL;
}
@ -530,7 +533,7 @@ uint64 LineInfo::Start() {
// The header for a debug_line section is mildly complicated, because
// the line info is very tightly encoded.
void LineInfo::ReadHeader() {
const char* lineptr = buffer_;
const uint8_t *lineptr = buffer_;
size_t initial_length_size;
const uint64 initial_length
@ -577,7 +580,7 @@ void LineInfo::ReadHeader() {
if (*lineptr) {
uint32 dirindex = 1;
while (*lineptr) {
const char* dirname = lineptr;
const char *dirname = reinterpret_cast<const char *>(lineptr);
handler_->DefineDir(dirname, dirindex);
lineptr += strlen(dirname) + 1;
dirindex++;
@ -590,7 +593,7 @@ void LineInfo::ReadHeader() {
uint32 fileindex = 1;
size_t len;
while (*lineptr) {
const char* filename = lineptr;
const char *filename = reinterpret_cast<const char *>(lineptr);
lineptr += strlen(filename) + 1;
uint64 dirindex = reader_->ReadUnsignedLEB128(lineptr, &len);
@ -615,7 +618,7 @@ void LineInfo::ReadHeader() {
bool LineInfo::ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
const struct LineInfoHeader &header,
const char* start,
const uint8_t *start,
struct LineStateMachine* lsm,
size_t* len,
uintptr pc,
@ -756,7 +759,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader,
}
break;
case DW_LNE_define_file: {
const char* filename = start;
const char *filename = reinterpret_cast<const char *>(start);
templen = strlen(filename) + 1;
start += templen;
@ -803,7 +806,7 @@ void LineInfo::ReadLines() {
// lengthstart is the place the length field is based on.
// It is the point in the header after the initial length field
const char* lengthstart = buffer_;
const uint8_t *lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
@ -812,7 +815,7 @@ void LineInfo::ReadLines() {
else
lengthstart += 4;
const char* lineptr = after_header_;
const uint8_t *lineptr = after_header_;
lsm.Reset(header_.default_is_stmt);
// The LineInfoHandler interface expects each line's length along
@ -1311,7 +1314,7 @@ class CallFrameInfo::State {
const Entry *entry_;
// The next instruction to process.
const char *cursor_;
const uint8_t *cursor_;
// The current set of rules.
RuleMap rules_;
@ -1409,7 +1412,8 @@ bool CallFrameInfo::State::ParseOperands(const char *format,
if (len > bytes_left || expression_length > bytes_left - len)
return ReportIncomplete();
cursor_ += len;
operands->expression = string(cursor_, expression_length);
operands->expression = string(reinterpret_cast<const char *>(cursor_),
expression_length);
cursor_ += expression_length;
break;
}
@ -1762,8 +1766,8 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) {
return DoRule(reg, rule);
}
bool CallFrameInfo::ReadEntryPrologue(const char *cursor, Entry *entry) {
const char *buffer_end = buffer_ + buffer_length_;
bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) {
const uint8_t *buffer_end = buffer_ + buffer_length_;
// Initialize enough of ENTRY for use in error reporting.
entry->offset = cursor - buffer_;
@ -1841,7 +1845,7 @@ bool CallFrameInfo::ReadEntryPrologue(const char *cursor, Entry *entry) {
}
bool CallFrameInfo::ReadCIEFields(CIE *cie) {
const char *cursor = cie->fields;
const uint8_t *cursor = cie->fields;
size_t len;
assert(cie->kind == kCIE);
@ -1872,13 +1876,14 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
return false;
}
const char *augmentation_start = cursor;
const void *augmentation_end =
memchr(augmentation_start, '\0', cie->end - augmentation_start);
const uint8_t *augmentation_start = cursor;
const uint8_t *augmentation_end =
reinterpret_cast<const uint8_t *>(memchr(augmentation_start, '\0',
cie->end - augmentation_start));
if (! augmentation_end) return ReportIncomplete(cie);
cursor = static_cast<const char *>(augmentation_end);
cie->augmentation = string(augmentation_start,
cursor - augmentation_start);
cursor = augmentation_end;
cie->augmentation = string(reinterpret_cast<const char *>(augmentation_start),
cursor - augmentation_start);
// Skip the terminating '\0'.
cursor++;
@ -1924,9 +1929,9 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
if (size_t(cie->end - cursor) < len + data_size)
return ReportIncomplete(cie);
cursor += len;
const char *data = cursor;
const uint8_t *data = cursor;
cursor += data_size;
const char *data_end = cursor;
const uint8_t *data_end = cursor;
cie->has_z_lsda = false;
cie->has_z_personality = false;
@ -2018,7 +2023,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
}
bool CallFrameInfo::ReadFDEFields(FDE *fde) {
const char *cursor = fde->fields;
const uint8_t *cursor = fde->fields;
size_t size;
fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding,
@ -2084,10 +2089,10 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) {
}
bool CallFrameInfo::Start() {
const char *buffer_end = buffer_ + buffer_length_;
const char *cursor;
const uint8_t *buffer_end = buffer_ + buffer_length_;
const uint8_t *cursor;
bool all_ok = true;
const char *entry_end;
const uint8_t *entry_end;
bool ok;
// Traverse all the entries in buffer_, skipping CIEs and offering

View File

@ -40,6 +40,8 @@
#ifndef COMMON_DWARF_DWARF2READER_H__
#define COMMON_DWARF_DWARF2READER_H__
#include <stdint.h>
#include <list>
#include <map>
#include <string>
@ -58,7 +60,7 @@ class LineInfoHandler;
// This maps from a string naming a section to a pair containing a
// the data for the section, and the size of the section.
typedef std::map<string, std::pair<const char*, uint64> > SectionMap;
typedef std::map<string, std::pair<const uint8_t *, uint64> > SectionMap;
typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> >
AttributeList;
typedef AttributeList::iterator AttributeIterator;
@ -85,7 +87,7 @@ class LineInfo {
// to the beginning and length of the line information to read.
// Reader is a ByteReader class that has the endianness set
// properly.
LineInfo(const char* buffer_, uint64 buffer_length,
LineInfo(const uint8_t *buffer_, uint64 buffer_length,
ByteReader* reader, LineInfoHandler* handler);
virtual ~LineInfo() {
@ -111,7 +113,7 @@ class LineInfo {
static bool ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
const struct LineInfoHeader &header,
const char* start,
const uint8_t *start,
struct LineStateMachine* lsm,
size_t* len,
uintptr pc,
@ -139,9 +141,11 @@ class LineInfo {
// buffer is the buffer for our line info, starting at exactly where
// the line info to read is. after_header is the place right after
// the end of the line information header.
const char* buffer_;
const uint8_t *buffer_;
#ifndef NDEBUG
uint64 buffer_length_;
const char* after_header_;
#endif
const uint8_t *after_header_;
};
// This class is the main interface between the line info reader and
@ -266,29 +270,27 @@ class CompilationUnit {
// Processes a single DIE for this compilation unit and return a new
// pointer just past the end of it
const char* ProcessDIE(uint64 dieoffset,
const char* start,
const Abbrev& abbrev);
const uint8_t *ProcessDIE(uint64 dieoffset,
const uint8_t *start,
const Abbrev& abbrev);
// Processes a single attribute and return a new pointer just past the
// end of it
const char* ProcessAttribute(uint64 dieoffset,
const char* start,
enum DwarfAttribute attr,
enum DwarfForm form);
const uint8_t *ProcessAttribute(uint64 dieoffset,
const uint8_t *start,
enum DwarfAttribute attr,
enum DwarfForm form);
// Processes all DIEs for this compilation unit
void ProcessDIEs();
// Skips the die with attributes specified in ABBREV starting at
// START, and return the new place to position the stream to.
const char* SkipDIE(const char* start,
const Abbrev& abbrev);
const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev);
// Skips the attribute starting at START, with FORM, and return the
// new place to position the stream to.
const char* SkipAttribute(const char* start,
enum DwarfForm form);
const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form);
// Offset from section start is the offset of this compilation unit
// from the beginning of the .debug_info section.
@ -297,9 +299,9 @@ class CompilationUnit {
// buffer is the buffer for our CU, starting at .debug_info + offset
// passed in from constructor.
// after_header points to right after the compilation unit header.
const char* buffer_;
const uint8_t *buffer_;
uint64 buffer_length_;
const char* after_header_;
const uint8_t *after_header_;
// The associated ByteReader that handles endianness issues for us
ByteReader* reader_;
@ -318,7 +320,7 @@ class CompilationUnit {
// String section buffer and length, if we have a string section.
// This is here to avoid doing a section lookup for strings in
// ProcessAttribute, which is in the hot path for DWARF2 reading.
const char* string_buffer_;
const uint8_t *string_buffer_;
uint64 string_buffer_length_;
};
@ -381,7 +383,7 @@ class Dwarf2Handler {
virtual void ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const char* data,
const uint8_t *data,
uint64 len) { }
// Called when we have an attribute with string data to give to our handler.
@ -637,7 +639,7 @@ class CallFrameInfo {
// The mechanics of C++ exception handling, personality routines,
// and language-specific data areas are described here, rather nicely:
// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
CallFrameInfo(const char *buffer, size_t buffer_length,
CallFrameInfo(const uint8_t *buffer, size_t buffer_length,
ByteReader *reader, Handler *handler, Reporter *reporter,
bool eh_frame = false)
: buffer_(buffer), buffer_length_(buffer_length),
@ -665,7 +667,7 @@ class CallFrameInfo {
size_t offset;
// The start of this entry in the buffer.
const char *start;
const uint8_t *start;
// Which kind of entry this is.
//
@ -676,16 +678,16 @@ class CallFrameInfo {
// The end of this entry's common prologue (initial length and id), and
// the start of this entry's kind-specific fields.
const char *fields;
const uint8_t *fields;
// The start of this entry's instructions.
const char *instructions;
const uint8_t *instructions;
// The address past the entry's last byte in the buffer. (Note that
// since offset points to the entry's initial length field, and the
// length field is the number of bytes after that field, this is not
// simply buffer_ + offset + length.)
const char *end;
const uint8_t *end;
// For both DWARF CFI and .eh_frame sections, this is the CIE id in a
// CIE, and the offset of the associated CIE in an FDE.
@ -762,7 +764,7 @@ class CallFrameInfo {
// true. On failure, report the problem, and return false. Even if we
// return false, set ENTRY->end to the first byte after the entry if we
// were able to figure that out, or NULL if we weren't.
bool ReadEntryPrologue(const char *cursor, Entry *entry);
bool ReadEntryPrologue(const uint8_t *cursor, Entry *entry);
// Parse the fields of a CIE after the entry prologue, including any 'z'
// augmentation data. Assume that the 'Entry' fields of CIE are
@ -790,7 +792,7 @@ class CallFrameInfo {
}
// The contents of the DWARF .debug_info section we're parsing.
const char *buffer_;
const uint8_t *buffer_;
size_t buffer_length_;
// For reading multi-byte values with the appropriate endianness.

View File

@ -31,6 +31,7 @@
// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo
#include <stdint.h>
#include <stdlib.h>
#include <string>
@ -186,7 +187,7 @@ class CFI: public CFIFixture, public Test { };
TEST_F(CFI, EmptyRegion) {
EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(handler, End()).Times(0);
static const char data[1] = { 42 };
static const uint8_t data[] = { 42 };
ByteReader byte_reader(ENDIANNESS_BIG);
CallFrameInfo parser(data, 0, &byte_reader, &handler, &reporter);
@ -213,7 +214,8 @@ TEST_F(CFI, IncompleteLength32) {
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(8);
CallFrameInfo parser(contents.data(), contents.size() - 2,
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size() - 2,
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
}
@ -238,7 +240,8 @@ TEST_F(CFI, IncompleteLength64) {
ByteReader byte_reader(ENDIANNESS_LITTLE);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(contents.data(), contents.size() - 4,
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size() - 4,
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
}
@ -262,7 +265,8 @@ TEST_F(CFI, IncompleteId32) {
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(8);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
}
@ -288,7 +292,8 @@ TEST_F(CFI, BadId32) {
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(8);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
}
@ -309,7 +314,8 @@ TEST_F(CFI, SingleCIE) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_LITTLE);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
}
@ -339,7 +345,8 @@ TEST_F(CFI, OneFDE) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
}
@ -382,7 +389,8 @@ TEST_F(CFI, TwoFDEsOneCIE) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
}
@ -431,7 +439,8 @@ TEST_F(CFI, TwoFDEsTwoCIEs) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_LITTLE);
byte_reader.SetAddressSize(8);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
}
@ -475,7 +484,8 @@ TEST_F(CFI, BadVersion) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
}
@ -519,7 +529,8 @@ TEST_F(CFI, BadAugmentation) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
}
@ -553,7 +564,8 @@ TEST_F(CFI, CIEVersion1ReturnColumn) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
}
@ -587,7 +599,8 @@ TEST_F(CFI, CIEVersion3ReturnColumn) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
}
@ -668,7 +681,8 @@ struct CFIInsnFixture: public CFIFixture {
}
ByteReader byte_reader(endianness);
byte_reader.SetAddressSize(section->AddressSize());
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
if (succeeds)
EXPECT_TRUE(parser.Start());
@ -1989,10 +2003,12 @@ struct EHFrameFixture: public CFIInsnFixture {
}
ByteReader byte_reader(endianness);
byte_reader.SetAddressSize(section->AddressSize());
byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi, contents.data());
byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi,
reinterpret_cast<const uint8_t *>(contents.data()));
byte_reader.SetTextBase(encoded_pointer_bases.text);
byte_reader.SetDataBase(encoded_pointer_bases.data);
CallFrameInfo parser(contents.data(), contents.size(),
CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter, true);
if (succeeds)
EXPECT_TRUE(parser.Start());

View File

@ -31,6 +31,7 @@
// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit
#include <stdint.h>
#include <stdlib.h>
#include <iostream>
@ -91,7 +92,7 @@ class MockDwarf2Handler: public Dwarf2Handler {
MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const char* data,
const uint8_t *data,
uint64 len));
MOCK_METHOD4(ProcessAttributeString, void(uint64 offset,
enum DwarfAttribute attr,
@ -132,9 +133,11 @@ struct DIEFixture {
assert(info.GetContents(&info_contents));
assert(abbrevs.GetContents(&abbrevs_contents));
section_map.clear();
section_map[".debug_info"].first = info_contents.data();
section_map[".debug_info"].first
= reinterpret_cast<const uint8_t *>(info_contents.data());
section_map[".debug_info"].second = info_contents.size();
section_map[".debug_abbrev"].first = abbrevs_contents.data();
section_map[".debug_abbrev"].first
= reinterpret_cast<const uint8_t *>(abbrevs_contents.data());
section_map[".debug_abbrev"].second = abbrevs_contents.size();
return section_map;
}

View File

@ -45,11 +45,7 @@ typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
#ifdef __PTRDIFF_TYPE__
typedef __PTRDIFF_TYPE__ intptr;
typedef unsigned __PTRDIFF_TYPE__ uintptr;
#else
#error "Can't find pointer-sized integral types."
#endif
typedef intptr_t intptr;
typedef uintptr_t uintptr;
#endif // _COMMON_DWARF_TYPES_H__

View File

@ -43,6 +43,7 @@
#include <cxxabi.h>
#endif
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <algorithm>
@ -140,7 +141,7 @@ DwarfCUToModule::FileContext::~FileContext() {
}
void DwarfCUToModule::FileContext::AddSectionToSectionMap(
const string& name, const char* contents, uint64 length) {
const string& name, const uint8_t *contents, uint64 length) {
section_map_[name] = std::make_pair(contents, length);
}
@ -351,9 +352,15 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
break;
case dwarf2reader::DW_AT_MIPS_linkage_name: {
char* demangled = NULL;
#if !defined(__ANDROID__)
demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL);
int status = -1;
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, &status);
#endif
if (status != 0) {
cu_context_->reporter->DemangleError(data, status);
demangled_name_ = "";
break;
}
if (demangled) {
demangled_name_ = AddStringToPool(demangled);
free(reinterpret_cast<void*>(demangled));
@ -396,6 +403,18 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
enclosing_name = &parent_context_->name;
}
// Prepare the return value before upcoming mutations possibly invalidate the
// existing pointers.
string return_value;
if (qualified_name) {
return_value = *qualified_name;
} else {
// Combine the enclosing name and unqualified name to produce our
// own fully-qualified name.
return_value = cu_context_->language->MakeQualifiedName(*enclosing_name,
*unqualified_name);
}
// If this DIE was marked as a declaration, record its names in the
// specification table.
if (declaration_) {
@ -409,13 +428,7 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
cu_context_->file_context->file_private_->specifications[offset_] = spec;
}
if (qualified_name)
return *qualified_name;
// Combine the enclosing name and unqualified name to produce our
// own fully-qualified name.
return cu_context_->language->MakeQualifiedName(*enclosing_name,
*unqualified_name);
return return_value;
}
// A handler class for DW_TAG_subprogram DIEs.
@ -528,18 +541,19 @@ void DwarfCUToModule::FuncHandler::Finish() {
// functions that were never used), but all the ones we're
// interested in cover a non-empty range of bytes.
if (low_pc_ < high_pc_) {
// Create a Module::Function based on the data we've gathered, and
// add it to the functions_ list.
scoped_ptr<Module::Function> func(new Module::Function);
// Malformed DWARF may omit the name, but all Module::Functions must
// have names.
string name;
if (!name_.empty()) {
func->name = name_;
name = name_;
} else {
cu_context_->reporter->UnnamedFunction(offset_);
func->name = "<name omitted>";
name = "<name omitted>";
}
func->address = low_pc_;
// Create a Module::Function based on the data we've gathered, and
// add it to the functions_ list.
scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
func->size = high_pc_ - low_pc_;
func->parameter_size = 0;
if (func->address) {
@ -661,6 +675,13 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
filename_.c_str(), offset);
}
void DwarfCUToModule::WarningReporter::DemangleError(
const string &input, int error) {
CUHeading();
fprintf(stderr, "%s: warning: failed to demangle %s with error %d\n",
filename_.c_str(), input.c_str(), error);
}
void DwarfCUToModule::WarningReporter::UnhandledInterCUReference(
uint64 offset, uint64 target) {
CUHeading();
@ -794,7 +815,7 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) {
cu_context_->reporter->MissingSection(".debug_line");
return;
}
const char *section_start = map_entry->second.first;
const uint8_t *section_start = map_entry->second.first;
uint64 section_length = map_entry->second.second;
if (offset >= section_length) {
cu_context_->reporter->BadLineInfoOffset(offset);

View File

@ -39,6 +39,8 @@
#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__
#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__
#include <stdint.h>
#include <string>
#include "common/language.h"
@ -84,7 +86,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// Add CONTENTS of size LENGTH to the section map as NAME.
void AddSectionToSectionMap(const string& name,
const char* contents,
const uint8_t *contents,
uint64 length);
// Clear the section map for testing.
@ -140,7 +142,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// mappings, given a pointer to some DWARF line number data
// PROGRAM, and an overestimate of its size. Add no zero-length
// lines to LINES.
virtual void ReadProgram(const char *program, uint64 length,
virtual void ReadProgram(const uint8_t *program, uint64 length,
Module *module, vector<Module::Line> *lines) = 0;
};
@ -199,6 +201,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// link.
virtual void UnnamedFunction(uint64 offset);
// __cxa_demangle() failed to demangle INPUT.
virtual void DemangleError(const string &input, int error);
// The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
// FilePrivate did not retain the inter-CU specification data.
virtual void UnhandledInterCUReference(uint64 offset, uint64 target);

View File

@ -31,6 +31,8 @@
// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule.
#include <stdint.h>
#include <string>
#include <utility>
#include <vector>
@ -65,7 +67,7 @@ using ::testing::ValuesIn;
class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler {
public:
MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir));
MOCK_METHOD4(ReadProgram, void(const char* program, uint64 length,
MOCK_METHOD4(ReadProgram, void(const uint8_t *program, uint64 length,
Module *module, vector<Module::Line> *lines));
};
@ -81,6 +83,7 @@ class MockWarningReporter: public DwarfCUToModule::WarningReporter {
MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
MOCK_METHOD2(DemangleError, void(const string &input, int error));
MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target));
};
@ -110,7 +113,7 @@ class CUFixtureBase {
public:
explicit AppendLinesFunctor(
const vector<Module::Line> *lines) : lines_(lines) { }
void operator()(const char *program, uint64 length,
void operator()(const uint8_t *program, uint64 length,
Module *module, vector<Module::Line> *lines) {
lines->insert(lines->end(), lines_->begin(), lines_->end());
}
@ -284,7 +287,7 @@ class CUFixtureBase {
// Mock line program reader.
MockLineToModuleHandler line_reader_;
AppendLinesFunctor appender_;
static const char dummy_line_program_[];
static const uint8_t dummy_line_program_[];
static const size_t dummy_line_size_;
MockWarningReporter reporter_;
@ -301,7 +304,7 @@ class CUFixtureBase {
bool functions_filled_;
};
const char CUFixtureBase::dummy_line_program_[] = "lots of fun data";
const uint8_t CUFixtureBase::dummy_line_program_[] = "lots of fun data";
const size_t CUFixtureBase::dummy_line_size_ =
sizeof(CUFixtureBase::dummy_line_program_);
@ -374,7 +377,7 @@ void CUFixtureBase::ProcessStrangeAttributes(
handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f,
(DwarfForm) 0x829e038a,
0x50fddef44734fdecULL);
static const char buffer[10] = "frobynode";
static const uint8_t buffer[10] = "frobynode";
handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51,
(DwarfForm) 0x2f43b041,
buffer, sizeof(buffer));
@ -1712,16 +1715,14 @@ TEST_F(CUErrors, BadCURootDIETag) {
// produce) output, so their results need to be checked by hand.
struct Reporter: public Test {
Reporter()
: reporter("filename", 0x123456789abcdef0ULL) {
: reporter("filename", 0x123456789abcdef0ULL),
function("function name", 0x19c45c30770c1eb0ULL),
file("source file name") {
reporter.SetCUName("compilation-unit-name");
function.name = "function name";
function.address = 0x19c45c30770c1eb0ULL;
function.size = 0x89808a5bdfa0a6a3ULL;
function.parameter_size = 0x6a329f18683dcd51ULL;
file.name = "source file name";
line.address = 0x3606ac6267aebeccULL;
line.size = 0x5de482229f32556aULL;
line.file = &file;

View File

@ -39,6 +39,7 @@
#include <errno.h>
#include <fcntl.h>
#include <link.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -95,6 +96,15 @@ using google_breakpad::scoped_ptr;
#define EM_AARCH64 183
#endif
// Define SHT_ANDROID_REL and SHT_ANDROID_RELA if not defined by the host.
// Sections with this type contain Android packed relocations.
#ifndef SHT_ANDROID_REL
#define SHT_ANDROID_REL (SHT_LOOS + 1)
#endif
#ifndef SHT_ANDROID_RELA
#define SHT_ANDROID_RELA (SHT_LOOS + 2)
#endif
//
// FDWrapper
//
@ -211,7 +221,7 @@ class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler {
void StartCompilationUnit(const string& compilation_dir) {
compilation_dir_ = compilation_dir;
}
void ReadProgram(const char* program, uint64 length,
void ReadProgram(const uint8_t *program, uint64 length,
Module* module, std::vector<Module::Line>* lines) {
DwarfLineToModule handler(module, compilation_dir_, lines);
dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
@ -249,8 +259,8 @@ bool LoadDwarf(const string& dwarf_filename,
string name = GetOffset<ElfClass, char>(elf_header,
section_names->sh_offset) +
section->sh_name;
const char* contents = GetOffset<ElfClass, char>(elf_header,
section->sh_offset);
const uint8_t *contents = GetOffset<ElfClass, uint8_t>(elf_header,
section->sh_offset);
file_context.AddSectionToSectionMap(name, contents, section->sh_size);
}
@ -259,7 +269,7 @@ bool LoadDwarf(const string& dwarf_filename,
dwarf2reader::SectionMap::const_iterator debug_info_entry =
file_context.section_map().find(".debug_info");
assert(debug_info_entry != file_context.section_map().end());
const std::pair<const char*, uint64>& debug_info_section =
const std::pair<const uint8_t *, uint64>& debug_info_section =
debug_info_entry->second;
// This should never have been called if the file doesn't have a
// .debug_info section.
@ -336,8 +346,8 @@ bool LoadDwarfCFI(const string& dwarf_filename,
dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
// Find the call frame information and its size.
const char* cfi =
GetOffset<ElfClass, char>(elf_header, section->sh_offset);
const uint8_t *cfi =
GetOffset<ElfClass, uint8_t>(elf_header, section->sh_offset);
size_t cfi_size = section->sh_size;
// Plug together the parser, handler, and their entourages.
@ -413,14 +423,24 @@ bool ElfEndianness(const typename ElfClass::Ehdr* elf_header,
return false;
}
// Given |left_abspath|, find the absolute path for |right_path| and see if the
// two absolute paths are the same.
bool IsSameFile(const char* left_abspath, const string& right_path) {
char right_abspath[PATH_MAX];
if (!realpath(right_path.c_str(), right_abspath))
return false;
return strcmp(left_abspath, right_abspath) == 0;
}
// Read the .gnu_debuglink and get the debug file name. If anything goes
// wrong, return an empty string.
string ReadDebugLink(const char* debuglink,
string ReadDebugLink(const uint8_t *debuglink,
const size_t debuglink_size,
const bool big_endian,
const string& obj_file,
const std::vector<string>& debug_dirs) {
size_t debuglink_len = strlen(debuglink) + 5; // Include '\0' + CRC32.
// Include '\0' + CRC32 (4 bytes).
size_t debuglink_len = strlen(reinterpret_cast<const char *>(debuglink)) + 5;
debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes.
// Sanity check.
@ -430,14 +450,28 @@ string ReadDebugLink(const char* debuglink,
return string();
}
bool found = false;
int debuglink_fd = -1;
char obj_file_abspath[PATH_MAX];
if (!realpath(obj_file.c_str(), obj_file_abspath)) {
fprintf(stderr, "Cannot resolve absolute path for %s\n", obj_file.c_str());
return string();
}
std::vector<string> searched_paths;
string debuglink_path;
std::vector<string>::const_iterator it;
for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) {
const string& debug_dir = *it;
debuglink_path = debug_dir + "/" + debuglink;
debuglink_fd = open(debuglink_path.c_str(), O_RDONLY);
debuglink_path = debug_dir + "/" +
reinterpret_cast<const char *>(debuglink);
// There is the annoying case of /path/to/foo.so having foo.so as the
// debug link file name. Thus this may end up opening /path/to/foo.so again,
// and there is a small chance of the two files having the same CRC.
if (IsSameFile(obj_file_abspath, debuglink_path))
continue;
searched_paths.push_back(debug_dir);
int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY);
if (debuglink_fd < 0)
continue;
@ -469,21 +503,19 @@ string ReadDebugLink(const char* debuglink,
debuglink_path.c_str());
continue;
}
found = true;
break;
// Found debug file.
return debuglink_path;
}
if (!found) {
fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n",
obj_file.c_str());
for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) {
const string debug_dir = *it;
fprintf(stderr, " %s/%s\n", debug_dir.c_str(), debuglink);
}
return string();
// Not found case.
fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n",
obj_file.c_str());
for (it = searched_paths.begin(); it < searched_paths.end(); ++it) {
const string& debug_dir = *it;
fprintf(stderr, " %s/%s\n", debug_dir.c_str(), debuglink);
}
return debuglink_path;
return string();
}
//
@ -591,6 +623,28 @@ bool LoadSymbols(const string& obj_file,
bool found_debug_info_section = false;
bool found_usable_info = false;
// Reject files that contain Android packed relocations. The pre-packed
// version of the file should be symbolized; the packed version is only
// intended for use on the target system.
if (FindElfSectionByName<ElfClass>(".rel.dyn", SHT_ANDROID_REL,
sections, names,
names_end, elf_header->e_shnum)) {
fprintf(stderr, "%s: file contains a \".rel.dyn\" section "
"with type SHT_ANDROID_REL\n", obj_file.c_str());
fprintf(stderr, "Files containing Android packed relocations "
"may not be symbolized.\n");
return false;
}
if (FindElfSectionByName<ElfClass>(".rela.dyn", SHT_ANDROID_RELA,
sections, names,
names_end, elf_header->e_shnum)) {
fprintf(stderr, "%s: file contains a \".rela.dyn\" section "
"with type SHT_ANDROID_RELA\n", obj_file.c_str());
fprintf(stderr, "Files containing Android packed relocations "
"may not be symbolized.\n");
return false;
}
if (options.symbol_data != ONLY_CFI) {
#ifndef NO_STABS_SUPPORT
// Look for STABS debugging information, and load it if present.
@ -628,6 +682,35 @@ bool LoadSymbols(const string& obj_file,
"DWARF debugging information\n", obj_file.c_str());
}
}
// See if there are export symbols available.
const Shdr* dynsym_section =
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
sections, names, names_end,
elf_header->e_shnum);
const Shdr* dynstr_section =
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
sections, names, names_end,
elf_header->e_shnum);
if (dynsym_section && dynstr_section) {
info->LoadedSection(".dynsym");
const uint8_t* dynsyms =
GetOffset<ElfClass, uint8_t>(elf_header,
dynsym_section->sh_offset);
const uint8_t* dynstrs =
GetOffset<ElfClass, uint8_t>(elf_header,
dynstr_section->sh_offset);
bool result =
ELFSymbolsToModule(dynsyms,
dynsym_section->sh_size,
dynstrs,
dynstr_section->sh_size,
big_endian,
ElfClass::kAddrSize,
module);
found_usable_info = found_usable_info || result;
}
}
if (options.symbol_data != NO_CFI) {
@ -689,11 +772,9 @@ bool LoadSymbols(const string& obj_file,
names_end, elf_header->e_shnum);
if (gnu_debuglink_section) {
if (!info->debug_dirs().empty()) {
found_debug_info_section = true;
const char* debuglink_contents =
GetOffset<ElfClass, char>(elf_header,
gnu_debuglink_section->sh_offset);
const uint8_t *debuglink_contents =
GetOffset<ElfClass, uint8_t>(elf_header,
gnu_debuglink_section->sh_offset);
string debuglink_file =
ReadDebugLink(debuglink_contents,
gnu_debuglink_section->sh_size,
@ -709,45 +790,18 @@ bool LoadSymbols(const string& obj_file,
fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n",
obj_file.c_str());
}
} else {
// Return true if some usable information was found, since the caller
// doesn't want to use .gnu_debuglink.
return found_usable_info;
}
// No debug info was found, let the user try again with .gnu_debuglink
// if present.
return false;
}
if (options.symbol_data != ONLY_CFI) {
const Shdr* dynsym_section =
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
sections, names, names_end,
elf_header->e_shnum);
const Shdr* dynstr_section =
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
sections, names, names_end,
elf_header->e_shnum);
if (dynsym_section && dynstr_section) {
info->LoadedSection(".dynsym");
const uint8_t* dynsyms =
GetOffset<ElfClass, uint8_t>(elf_header,
dynsym_section->sh_offset);
const uint8_t* dynstrs =
GetOffset<ElfClass, uint8_t>(elf_header,
dynstr_section->sh_offset);
bool result =
ELFSymbolsToModule(dynsyms,
dynsym_section->sh_size,
dynstrs,
dynstr_section->sh_size,
big_endian,
ElfClass::kAddrSize,
module);
found_usable_info = found_usable_info || result;
}
}
if (read_gnu_debug_link) {
return found_debug_info_section;
}
// Return true if some usable information was found
return found_usable_info;
return true;
}
// Return the breakpad symbol file identifier for the architecture of
@ -800,14 +854,44 @@ string BaseFileName(const string &filename) {
return base;
}
template<typename ElfClass>
bool SanitizeDebugFile(const typename ElfClass::Ehdr* debug_elf_header,
const string& debuglink_file,
const string& obj_filename,
const char* obj_file_architecture,
const bool obj_file_is_big_endian) {
const char* debug_architecture =
ElfArchitecture<ElfClass>(debug_elf_header);
if (!debug_architecture) {
fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
debuglink_file.c_str(), debug_elf_header->e_machine);
return false;
}
if (strcmp(obj_file_architecture, debug_architecture)) {
fprintf(stderr, "%s with ELF machine architecture %s does not match "
"%s with ELF architecture %s\n",
debuglink_file.c_str(), debug_architecture,
obj_filename.c_str(), obj_file_architecture);
return false;
}
bool debug_big_endian;
if (!ElfEndianness<ElfClass>(debug_elf_header, &debug_big_endian))
return false;
if (debug_big_endian != obj_file_is_big_endian) {
fprintf(stderr, "%s and %s does not match in endianness\n",
obj_filename.c_str(), debuglink_file.c_str());
return false;
}
return true;
}
template<typename ElfClass>
bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
const string& obj_filename,
const std::vector<string>& debug_dirs,
const DumpOptions& options,
Module** out_module) {
const string& obj_filename,
const std::vector<string>& debug_dirs,
const DumpOptions& options,
Module** out_module) {
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Shdr Shdr;
*out_module = NULL;
@ -849,34 +933,13 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
MmapWrapper debug_map_wrapper;
Ehdr* debug_elf_header = NULL;
if (!LoadELF(debuglink_file, &debug_map_wrapper,
reinterpret_cast<void**>(&debug_elf_header)))
return false;
// Sanity checks to make sure everything matches up.
const char *debug_architecture =
ElfArchitecture<ElfClass>(debug_elf_header);
if (!debug_architecture) {
fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
debuglink_file.c_str(), debug_elf_header->e_machine);
return false;
}
if (strcmp(architecture, debug_architecture)) {
fprintf(stderr, "%s with ELF machine architecture %s does not match "
"%s with ELF architecture %s\n",
debuglink_file.c_str(), debug_architecture,
obj_filename.c_str(), architecture);
reinterpret_cast<void**>(&debug_elf_header)) ||
!SanitizeDebugFile<ElfClass>(debug_elf_header, debuglink_file,
obj_filename, architecture, big_endian)) {
return false;
}
bool debug_big_endian;
if (!ElfEndianness<ElfClass>(debug_elf_header, &debug_big_endian))
return false;
if (debug_big_endian != big_endian) {
fprintf(stderr, "%s and %s does not match in endianness\n",
obj_filename.c_str(), debuglink_file.c_str());
return false;
}
if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian,
if (!LoadSymbols<ElfClass>(debuglink_file, big_endian,
debug_elf_header, false, &info,
options, module.get())) {
return false;

View File

@ -37,7 +37,7 @@
//
#define HANDLE_EINTR(x) ({ \
typeof(x) eintr_wrapper_result; \
__typeof__(x) eintr_wrapper_result; \
do { \
eintr_wrapper_result = (x); \
} while (eintr_wrapper_result == -1 && errno == EINTR); \
@ -45,7 +45,7 @@
})
#define IGNORE_EINTR(x) ({ \
typeof(x) eintr_wrapper_result; \
__typeof__(x) eintr_wrapper_result; \
do { \
eintr_wrapper_result = (x); \
if (eintr_wrapper_result == -1 && errno == EINTR) { \

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