Backed out changeset 1adfbab318a6 (bug 1264367) for breaking crash stacks CLOSED TREE

--HG--
extra : amend_source : 3dc85338e38502f95b5f667babbd6cf0282c70d1
This commit is contained in:
Wes Kocher 2016-10-03 14:50:27 -07:00
Родитель 04c44176b6
Коммит 265355461f
167 изменённых файлов: 3008 добавлений и 19663 удалений

Просмотреть файл

@ -3,39 +3,49 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdio.h>
#include <string>
#include "common/linux/file_id.h"
#include "common/memory.h"
using std::string;
//TODO: move this somewhere common, this is copied from dump_symbols.cc
// Format the Elf file identifier in IDENTIFIER as a UUID with the
// dashes removed.
void FormatIdentifier(unsigned char identifier[google_breakpad::kMDGUIDSize],
char result_guid[40]) {
char identifier_str[40];
google_breakpad::FileID::ConvertIdentifierToString(
identifier,
identifier_str,
sizeof(identifier_str));
int bufpos = 0;
for (int i = 0; identifier_str[i] != '\0'; ++i)
if (identifier_str[i] != '-')
result_guid[bufpos++] = identifier_str[i];
// Add an extra "0" by the end. PDB files on Windows have an 'age'
// number appended to the end of the file identifier; this isn't
// really used or necessary on other platforms, but let's preserve
// the pattern.
result_guid[bufpos++] = '0';
// And null terminate.
result_guid[bufpos] = '\0';
}
using google_breakpad::auto_wasteful_vector;
using google_breakpad::FileID;
using google_breakpad::PageAllocator;
int main(int argc, char** argv)
{
if (argc != 2) {
fprintf(stderr, "usage: fileid <elf file>\n");
return 1;
}
PageAllocator allocator;
auto_wasteful_vector<uint8_t, sizeof(MDGUID)> identifier(&allocator);
FileID file_id(argv[1]);
unsigned char identifier[google_breakpad::kMDGUIDSize];
google_breakpad::FileID file_id(argv[1]);
if (!file_id.ElfFileIdentifier(identifier)) {
fprintf(stderr, "%s: unable to generate file identifier\n",
argv[1]);
return 1;
}
string result_guid = FileID::ConvertIdentifierToUUIDString(identifier);
// Add an extra "0" at the end. PDB files on Windows have an 'age'
// number appended to the end of the file identifier; this isn't
// really used or necessary on other platforms, but be consistent.
printf("%s0\n", result_guid.c_str());
char result_guid[40];
FormatIdentifier(identifier, result_guid);
printf("%s\n", result_guid);
return 0;
}

Просмотреть файл

@ -31,7 +31,6 @@
# Ignore common compiled artifacts.
*~
*.dwo
*.o
lib*.a
/breakpad.pc
@ -46,7 +45,6 @@ lib*.a
/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

Просмотреть файл

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

Просмотреть файл

@ -1 +1 @@
704f41ec901c419f8c321742114b415e6f5ceacc
c53ed143108948eb7e2d7ee77dc8c0d92050ce7c

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -6,7 +6,7 @@ on Android, and later generate valid stack traces from the minidumps
it generates.
This release supports ARM, x86 and MIPS based Android systems.
This release requires NDK release r11c or higher.
This release requires NDK release r10c or higher.
I. Building the client library:
===============================

Просмотреть файл

@ -3,80 +3,45 @@
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)
* Tests: [![Build Status](https://travis-ci.org/google/breakpad.svg?branch=master)](https://travis-ci.org/google/breakpad)
* Coverage [![Coverity Status](https://scan.coverity.com/projects/9215/badge.svg)](https://scan.coverity.com/projects/google-breakpad)
## Getting started in 32-bit mode (from trunk)
## Getting started (from master)
1. First, [download depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools)
and ensure that theyre in your `PATH`.
2. Create a new directory for checking out the source code (it must be named
breakpad).
```sh
mkdir breakpad && cd breakpad
```
3. Run the `fetch` tool from depot_tools to download all the source repos.
```sh
fetch breakpad
cd src
```
4. Build the source.
```sh
./configure && make
```
You can also cd to another directory and run configure from there to build
outside the source tree.
This will build the processor tools (`src/processor/minidump_stackwalk`,
`src/processor/minidump_dump`, etc), and when building on Linux it will
also build the client libraries and some tools
(`src/tools/linux/dump_syms/dump_syms`,
`src/tools/linux/md2core/minidump-2-core`, etc).
5. Optionally, run tests.
```sh
make check
```
6. Optionally, install the built libraries
```sh
make install
```
```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 update an existing checkout to a newer revision, you can
`git pull` as usual, but then you should run `gclient sync` to ensure that the
dependent repos are up-to-date.
## To request change review:
## To request change review
1. Get a copy of depot_tools repo.
http://dev.chromium.org/developers/how-tos/install-depot-tools
1. Follow the steps above to get the source and build it.
2. Create a new directory for checking out the source code.
mkdir breakpad && cd breakpad
2. Make changes. Build and test your changes.
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.
3. Commit your changes to your local repo and upload them to the server.
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.
4. At https://chromium-review.googlesource.com/ you'll find your issue listed;
click on it, then “Add reviewer”, and enter in the code reviewer. Depending
on your settings, you may not see an email, but the reviewer has been
notified with google-breakpad-dev@googlegroups.com always CCd.
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
## Documentation
Visit https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/

Просмотреть файл

@ -56,66 +56,6 @@ 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-2014 Free Software Foundation, Inc.

Просмотреть файл

@ -71,12 +71,9 @@ LOCAL_ARM_MODE := arm
# List of client source files, directly taken from Makefile.am
LOCAL_SRC_FILES := \
src/client/linux/crash_generation/crash_generation_client.cc \
src/client/linux/dump_writer_common/thread_info.cc \
src/client/linux/dump_writer_common/ucontext_reader.cc \
src/client/linux/handler/exception_handler.cc \
src/client/linux/handler/minidump_descriptor.cc \
src/client/linux/log/log.cc \
src/client/linux/microdump_writer/microdump_writer.cc \
src/client/linux/minidump_writer/linux_dumper.cc \
src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
src/client/linux/minidump_writer/minidump_writer.cc \

Просмотреть файл

@ -29,4 +29,3 @@
APP_STL := stlport_static
APP_ABI := all
APP_CXXFLAGS := -std=c++11 -D__STDC_LIMIT_MACROS

Просмотреть файл

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

Просмотреть файл

@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2016 Free Software Foundation, Inc.
# Copyright 1992-2015 Free Software Foundation, Inc.
timestamp='2016-01-01'
timestamp='2015-03-04'
# 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
@ -27,7 +27,7 @@ timestamp='2016-01-01'
# 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
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
#
# Please send patches to <config-patches@gnu.org>.
@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2016 Free Software Foundation, Inc.
Copyright 1992-2015 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."
@ -221,7 +221,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
release='-gnu'
;;
*)
release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
@ -249,9 +249,6 @@ 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)
@ -965,9 +962,6 @@ 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 ;;
@ -1044,7 +1038,7 @@ EOF
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;;
x86_64:Linux:*:*)
echo ${UNAME_MACHINE}-pc-linux-${LIBC}
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@ -1123,7 +1117,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 configure will decide that
# prints for the "djgpp" host, or else GDB configury will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
@ -1393,9 +1387,6 @@ EOF
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
amd64:Isilon\ OneFS:*:*)
echo x86_64-unknown-onefs
exit ;;
esac
cat >&2 <<EOF
@ -1405,9 +1396,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
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
and
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
If the version you run ($0) is already up to date, please
send the following data and any information you think might be

Просмотреть файл

@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2016 Free Software Foundation, Inc.
# Copyright 1992-2015 Free Software Foundation, Inc.
timestamp='2016-01-01'
timestamp='2015-03-08'
# 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
@ -33,7 +33,7 @@ timestamp='2016-01-01'
# 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
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@ -53,7 +53,8 @@ timestamp='2016-01-01'
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
Usage: $0 [OPTION] CPU-MFR-OPSYS
$0 [OPTION] ALIAS
Canonicalize a configuration name.
@ -67,7 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright 1992-2016 Free Software Foundation, Inc.
Copyright 1992-2015 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."
@ -254,7 +255,6 @@ 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 \
@ -305,7 +305,7 @@ case $basic_machine in
| riscv32 | riscv64 \
| rl78 | rx \
| score \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| 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 \
@ -376,7 +376,6 @@ 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-* \
@ -429,13 +428,12 @@ 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*-* \
@ -520,7 +518,7 @@ case $basic_machine in
basic_machine=i386-pc
os=-aros
;;
asmjs)
asmjs)
basic_machine=asmjs-unknown
;;
aux)
@ -1378,7 +1376,7 @@ case $os in
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* | -aros* | -cloudabi* | -sortix* \
| -aos* | -aros* | -cloudabi* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
@ -1398,8 +1396,7 @@ case $os in
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
| -onefs* | -tirtos*)
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)

Просмотреть файл

@ -3,7 +3,7 @@
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by

Просмотреть файл

@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2013-12-25.23; # UTC
scriptversion=2011-11-20.07; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@ -41,15 +41,19 @@ scriptversion=2013-12-25.23; # UTC
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
IFS=" "" $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-}
doit_exec=${doit:-exec}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
@ -64,6 +68,17 @@ 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.
@ -82,7 +97,7 @@ dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@ -122,57 +137,46 @@ 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
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
shift;;
-s) stripcmd=$stripprog;;
-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) dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
-T) no_target_directory=true;;
--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.
@ -203,15 +207,6 @@ 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
@ -228,16 +223,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
@ -274,15 +269,41 @@ 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 "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
# 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'
`
test -d "$dstdir"
dstdir_status=$?
fi
@ -293,74 +314,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
@ -370,51 +391,53 @@ 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=/
set -f
$posix_glob set -f
set fnord $dstdir
shift
set +f
$posix_glob 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
@ -449,12 +472,15 @@ 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` &&
set -f &&
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 &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
@ -467,24 +493,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

Просмотреть файл

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

Просмотреть файл

@ -3,7 +3,7 @@
scriptversion=2013-07-13.22; # UTC
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
# Copyright (C) 2011-2013 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -106,14 +106,11 @@ 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
tweaked_estatus=1
else
tweaked_estatus=$estatus
estatus=1
fi
case $tweaked_estatus:$expect_failure in
case $estatus:$expect_failure in
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
0:*) col=$grn res=PASS recheck=no gcopy=no;;
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
@ -122,12 +119,6 @@ case $tweaked_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"

Просмотреть файл

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

1186
toolkit/crashreporter/google-breakpad/configure поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -41,7 +41,6 @@ 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
@ -76,9 +75,6 @@ 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* )
@ -95,14 +91,6 @@ 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]
@ -143,39 +131,6 @@ 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" ]

Просмотреть файл

@ -30,8 +30,8 @@
#ifndef BREAKPAD_GOOGLETEST_INCLUDES_H__
#define BREAKPAD_GOOGLETEST_INCLUDES_H__
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/include/gmock/gmock.h"
// If AddressSanitizer is used, NULL pointer dereferences generate SIGILL
// (illegal instruction) instead of SIGSEGV (segmentation fault). Also,

Просмотреть файл

@ -263,8 +263,8 @@ void Breakpad::UncaughtExceptionHandler(NSException *exception) {
NSSetUncaughtExceptionHandler(NULL);
if (current_breakpad_) {
current_breakpad_->HandleUncaughtException(exception);
BreakpadRelease(current_breakpad_);
}
BreakpadRelease(current_breakpad_);
}
//=============================================================================

Просмотреть файл

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

Просмотреть файл

@ -235,13 +235,7 @@ uintptr_t ThreadInfo::GetInstructionPointer() const {
}
void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
#if _MIPS_SIM == _ABI64
out->context_flags = MD_CONTEXT_MIPS64_FULL;
#elif _MIPS_SIM == _ABIO32
out->context_flags = MD_CONTEXT_MIPS_FULL;
#else
# error "This mips ABI is currently not supported (n32)"
#endif
for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
out->iregs[i] = mcontext.gregs[i];

Просмотреть файл

@ -219,13 +219,7 @@ 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];

Просмотреть файл

@ -118,7 +118,7 @@ namespace {
// all these signals must be Core (see man 7 signal) because we rethrow the
// signal after handling it and expect that it'll be fatal.
const int kExceptionSignals[] = {
SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGTRAP
SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS
};
const int kNumHandledSignals =
sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]);

Просмотреть файл

@ -45,6 +45,7 @@
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/eintr_wrapper.h"
#include "common/linux/file_id.h"
#include "common/linux/ignore_ret.h"
#include "common/linux/linux_libc_support.h"
#include "common/tests/auto_tempdir.h"
@ -93,6 +94,10 @@ void FlushInstructionCache(const char* memory, uint32_t memory_size) {
#endif
}
// Length of a formatted GUID string =
// sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator)
const int kGUIDStringSize = 37;
void sigchld_handler(int signo) { }
int CreateTMPFile(const string& dir, string* path) {
@ -257,6 +262,8 @@ TEST(ExceptionHandlerTest, ChildCrashWithFD) {
ASSERT_NO_FATAL_FAILURE(ChildCrash(true));
}
#endif // !ADDRESS_SANITIZER
static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor,
void* context,
bool succeeded) {
@ -298,6 +305,8 @@ static bool InstallRaiseSIGKILL() {
return sigaction(SIGSEGV, &sa, NULL) != -1;
}
#ifndef ADDRESS_SANITIZER
static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter,
ExceptionHandler::MinidumpCallback done,
string path) {
@ -812,7 +821,19 @@ TEST(ExceptionHandlerTest, ModuleInfo) {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
char module_identifier_buffer[kGUIDStringSize];
FileID::ConvertIdentifierToString(kModuleGUID,
module_identifier_buffer,
sizeof(module_identifier_buffer));
string module_identifier(module_identifier_buffer);
// Strip out dashes
size_t pos;
while ((pos = module_identifier.find('-')) != string::npos) {
module_identifier.erase(pos, 1);
}
// And append a zero, because module IDs include an "age" field
// which is always zero on Linux.
module_identifier += "0";
// Get some memory.
char* memory =
@ -857,8 +878,6 @@ TEST(ExceptionHandlerTest, ModuleInfo) {
unlink(minidump_desc.path());
}
#ifndef ADDRESS_SANITIZER
static const unsigned kControlMsgSize =
CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
@ -911,6 +930,8 @@ 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);

Просмотреть файл

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

Просмотреть файл

@ -32,8 +32,6 @@
#include "client/linux/microdump_writer/microdump_writer.h"
#include <limits>
#include <sys/utsname.h>
#include "client/linux/dump_writer_common/thread_info.h"
@ -42,15 +40,11 @@
#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/file_id.h"
#include "common/linux/linux_libc_support.h"
#include "common/memory.h"
namespace {
using google_breakpad::auto_wasteful_vector;
using google_breakpad::ExceptionHandler;
using google_breakpad::kDefaultBuildIdSize;
using google_breakpad::LinuxDumper;
using google_breakpad::LinuxPtraceDumper;
using google_breakpad::MappingInfo;
@ -62,72 +56,6 @@ using google_breakpad::UContextReader;
const size_t kLineBufferSize = 2048;
#if !defined(__LP64__)
// The following are only used by DumpFreeSpace, so need to be compiled
// in conditionally in the same way.
template <typename Dst, typename Src>
Dst saturated_cast(Src src) {
if (src >= std::numeric_limits<Dst>::max())
return std::numeric_limits<Dst>::max();
if (src <= std::numeric_limits<Dst>::min())
return std::numeric_limits<Dst>::min();
return static_cast<Dst>(src);
}
int Log2Floor(uint64_t n) {
// Copied from chromium src/base/bits.h
if (n == 0)
return -1;
int log = 0;
uint64_t value = n;
for (int i = 5; i >= 0; --i) {
int shift = (1 << i);
uint64_t x = value >> shift;
if (x != 0) {
value = x;
log += shift;
}
}
assert(value == 1u);
return log;
}
bool MappingsAreAdjacent(const MappingInfo& a, const MappingInfo& b) {
// Because of load biasing, we can end up with a situation where two
// mappings actually overlap. So we will define adjacency to also include a
// b start address that lies within a's address range (including starting
// immediately after a).
// Because load biasing only ever moves the start address backwards, the end
// address should still increase.
return a.start_addr <= b.start_addr && a.start_addr + a.size >= b.start_addr;
}
bool MappingLessThan(const MappingInfo* a, const MappingInfo* b) {
// Return true if mapping a is before mapping b.
// For the same reason (load biasing) we compare end addresses, which - unlike
// start addresses - will not have been modified.
return a->start_addr + a->size < b->start_addr + b->size;
}
size_t NextOrderedMapping(
const google_breakpad::wasteful_vector<MappingInfo*>& mappings,
size_t curr) {
// Find the mapping that directly follows mappings[curr].
// If no such mapping exists, return |invalid| to indicate this.
const size_t invalid = std::numeric_limits<size_t>::max();
size_t best = invalid;
for (size_t next = 0; next < mappings.size(); ++next) {
if (MappingLessThan(mappings[curr], mappings[next]) &&
(best == invalid || MappingLessThan(mappings[next], mappings[best]))) {
best = next;
}
}
return best;
}
#endif // !__LP64__
class MicrodumpWriter {
public:
MicrodumpWriter(const ExceptionHandler::CrashContext* context,
@ -164,11 +92,7 @@ class MicrodumpWriter {
LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
DumpProductInformation();
DumpOSInformation();
DumpProcessType();
DumpGPUInformation();
#if !defined(__LP64__)
DumpFreeSpace();
#endif
success = DumpCrashingThread();
if (success)
success = DumpMappings();
@ -234,16 +158,6 @@ class MicrodumpWriter {
LogCommitLine();
}
void DumpProcessType() {
LogAppend("P ");
if (microdump_extra_info_.process_type) {
LogAppend(microdump_extra_info_.process_type);
} else {
LogAppend("UNKNOWN");
}
LogCommitLine();
}
void DumpOSInformation() {
const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF));
@ -265,13 +179,7 @@ class MicrodumpWriter {
#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
@ -422,31 +330,21 @@ class MicrodumpWriter {
bool member,
unsigned int mapping_id,
const uint8_t* identifier) {
auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
dumper_->allocator());
MDGUID module_identifier;
if (identifier) {
// GUID was provided by caller.
identifier_bytes.insert(identifier_bytes.end(),
identifier,
identifier + sizeof(MDGUID));
my_memcpy(&module_identifier, identifier, sizeof(MDGUID));
} else {
dumper_->ElfFileIdentifierForMapping(
mapping,
member,
mapping_id,
identifier_bytes);
reinterpret_cast<uint8_t*>(&module_identifier));
}
// Copy as many bytes of |identifier| as will fit into a MDGUID
MDGUID module_identifier = {0};
memcpy(&module_identifier, &identifier_bytes[0],
std::min(sizeof(MDGUID), identifier_bytes.size()));
char file_name[NAME_MAX];
char file_path[NAME_MAX];
dumper_->GetMappingEffectiveNameAndPath(
LinuxDumper::GetMappingEffectiveNameAndPath(
mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
LogAppend("M ");
@ -472,80 +370,6 @@ class MicrodumpWriter {
LogCommitLine();
}
#if !defined(__LP64__)
void DumpFreeSpace() {
const google_breakpad::wasteful_vector<MappingInfo*>& mappings =
dumper_->mappings();
if (mappings.size() == 0) return;
// This is complicated by the fact that mappings is not in order. It should
// be mostly in order, however the mapping that contains the entry point for
// the process is always at the front of the vector.
static const int HBITS = sizeof(size_t) * 8;
size_t hole_histogram[HBITS];
my_memset(hole_histogram, 0, sizeof(hole_histogram));
// Find the lowest address mapping.
size_t curr = 0;
for (size_t i = 1; i < mappings.size(); ++i) {
if (mappings[i]->start_addr < mappings[curr]->start_addr) curr = i;
}
uintptr_t lo_addr = mappings[curr]->start_addr;
size_t hole_cnt = 0;
size_t hole_max = 0;
size_t hole_sum = 0;
while (true) {
// Skip to the end of an adjacent run of mappings. This is an optimization
// for the fact that mappings is mostly sorted.
while (curr != mappings.size() - 1 &&
MappingsAreAdjacent(*mappings[curr], *mappings[curr + 1])) {
++curr;
}
size_t next = NextOrderedMapping(mappings, curr);
if (next == std::numeric_limits<size_t>::max())
break;
uintptr_t hole_lo = mappings[curr]->start_addr + mappings[curr]->size;
uintptr_t hole_hi = mappings[next]->start_addr;
if (hole_hi > hole_lo) {
size_t hole_sz = hole_hi - hole_lo;
hole_sum += hole_sz;
hole_max = std::max(hole_sz, hole_max);
++hole_cnt;
++hole_histogram[Log2Floor(hole_sz)];
}
curr = next;
}
uintptr_t hi_addr = mappings[curr]->start_addr + mappings[curr]->size;
LogAppend("H ");
LogAppend(lo_addr);
LogAppend(" ");
LogAppend(hi_addr);
LogAppend(" ");
LogAppend(saturated_cast<uint16_t>(hole_cnt));
LogAppend(" ");
LogAppend(hole_max);
LogAppend(" ");
LogAppend(hole_sum);
for (unsigned int i = 0; i < HBITS; ++i) {
if (!hole_histogram[i]) continue;
LogAppend(" ");
LogAppend(saturated_cast<uint8_t>(i));
LogAppend(":");
LogAppend(saturated_cast<uint8_t>(hole_histogram[i]));
}
LogCommitLine();
}
#endif
// Write information about the mappings in effect.
bool DumpMappings() {
// First write all the mappings from the dumper

Просмотреть файл

@ -49,9 +49,8 @@ namespace google_breakpad {
LinuxCoreDumper::LinuxCoreDumper(pid_t pid,
const char* core_path,
const char* procfs_path,
const char* root_prefix)
: LinuxDumper(pid, root_prefix),
const char* procfs_path)
: LinuxDumper(pid),
core_path_(core_path),
procfs_path_(procfs_path),
thread_infos_(&allocator_, 8) {

Просмотреть файл

@ -47,9 +47,7 @@ class LinuxCoreDumper : public LinuxDumper {
// its proc files at |procfs_path|. If |procfs_path| is a copy of
// /proc/<pid>, it should contain the following files:
// auxv, cmdline, environ, exe, maps, status
// See LinuxDumper for the purpose of |root_prefix|.
LinuxCoreDumper(pid_t pid, const char* core_path, const char* procfs_path,
const char* root_prefix = "");
LinuxCoreDumper(pid_t pid, const char* core_path, const char* procfs_path);
// Implements LinuxDumper::BuildProcPath().
// Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).

Просмотреть файл

@ -39,16 +39,6 @@
using namespace google_breakpad;
TEST(LinuxCoreDumperTest, GetMappingAbsolutePath) {
const LinuxCoreDumper dumper(getpid(), "core", "/tmp", "/mnt/root");
const MappingInfo mapping = { 0, 0, 0, false, "/usr/lib/libc.so" };
char path[PATH_MAX];
dumper.GetMappingAbsolutePath(mapping, path);
EXPECT_STREQ("/mnt/root/usr/lib/libc.so", path);
}
TEST(LinuxCoreDumperTest, BuildProcPath) {
const pid_t pid = getpid();
const char procfs_path[] = "/procfs_copy";

Просмотреть файл

@ -85,186 +85,17 @@ inline static bool IsMappedFileOpenUnsafe(
namespace google_breakpad {
#if defined(__CHROMEOS__)
namespace {
// Recover memory mappings before writing dump on ChromeOS
//
// On Linux, breakpad relies on /proc/[pid]/maps to associate symbols from
// addresses. ChromeOS' hugepage implementation replaces some segments with
// anonymous private pages, which is a restriction of current implementation
// in Linux kernel at the time of writing. Thus, breakpad can no longer
// symbolize addresses from those text segments replaced with hugepages.
//
// This postprocess tries to recover the mappings. Because hugepages are always
// inserted in between some .text sections, it tries to infer the names and
// offsets of the segments, by looking at segments immediately precede and
// succeed them.
//
// For example, a text segment before hugepage optimization
// 02001000-03002000 r-xp /opt/google/chrome/chrome
//
// can be broken into
// 02001000-02200000 r-xp /opt/google/chrome/chrome
// 02200000-03000000 r-xp
// 03000000-03002000 r-xp /opt/google/chrome/chrome
//
// For more details, see:
// crbug.com/628040 ChromeOS' use of hugepages confuses crash symbolization
// Copied from CrOS' hugepage implementation, which is unlikely to change.
// The hugepage size is 2M.
const unsigned int kHpageShift = 21;
const size_t kHpageSize = (1 << kHpageShift);
const size_t kHpageMask = (~(kHpageSize - 1));
// Find and merge anonymous r-xp segments with surrounding named segments.
// There are two cases:
// Case 1: curr, next
// curr is anonymous
// curr is r-xp
// curr.size >= 2M
// curr.size is a multiple of 2M.
// next is backed by some file.
// curr and next are contiguous.
// offset(next) == sizeof(curr)
void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) {
// Merged segments are marked with size = 0.
if (curr->size == 0 || next->size == 0)
return;
if (curr->size >= kHpageSize &&
curr->exec &&
(curr->size & kHpageMask) == curr->size &&
(curr->start_addr & kHpageMask) == curr->start_addr &&
curr->name[0] == '\0' &&
next->name[0] != '\0' &&
curr->start_addr + curr->size == next->start_addr &&
curr->size == next->offset) {
// matched
my_strlcpy(curr->name, next->name, NAME_MAX);
if (next->exec) {
// (curr, next)
curr->size += next->size;
next->size = 0;
}
}
}
// Case 2: prev, curr, next
// curr is anonymous
// curr is r-xp
// curr.size >= 2M
// curr.size is a multiple of 2M.
// next and prev are backed by the same file.
// prev, curr and next are contiguous.
// offset(next) == offset(prev) + sizeof(prev) + sizeof(curr)
void TryRecoverMappings(MappingInfo *prev, MappingInfo *curr,
MappingInfo *next) {
// Merged segments are marked with size = 0.
if (prev->size == 0 || curr->size == 0 || next->size == 0)
return;
if (curr->size >= kHpageSize &&
curr->exec &&
(curr->size & kHpageMask) == curr->size &&
(curr->start_addr & kHpageMask) == curr->start_addr &&
curr->name[0] == '\0' &&
next->name[0] != '\0' &&
curr->start_addr + curr->size == next->start_addr &&
prev->start_addr + prev->size == curr->start_addr &&
my_strncmp(prev->name, next->name, NAME_MAX) == 0 &&
next->offset == prev->offset + prev->size + curr->size) {
// matched
my_strlcpy(curr->name, prev->name, NAME_MAX);
if (prev->exec) {
curr->offset = prev->offset;
curr->start_addr = prev->start_addr;
if (next->exec) {
// (prev, curr, next)
curr->size += prev->size + next->size;
prev->size = 0;
next->size = 0;
} else {
// (prev, curr), next
curr->size += prev->size;
prev->size = 0;
}
} else {
curr->offset = prev->offset + prev->size;
if (next->exec) {
// prev, (curr, next)
curr->size += next->size;
next->size = 0;
} else {
// prev, curr, next
}
}
}
}
// mappings_ is sorted excepted for the first entry.
// This function tries to merge segemnts into the first entry,
// then check for other sorted entries.
// See LinuxDumper::EnumerateMappings().
void CrOSPostProcessMappings(wasteful_vector<MappingInfo*>& mappings) {
// Find the candidate "next" to first segment, which is the only one that
// could be out-of-order.
size_t l = 1;
size_t r = mappings.size();
size_t next = mappings.size();
while (l < r) {
int m = (l + r) / 2;
if (mappings[m]->start_addr > mappings[0]->start_addr)
r = next = m;
else
l = m + 1;
}
// Try to merge segments into the first.
if (next < mappings.size()) {
TryRecoverMappings(mappings[0], mappings[next]);
if (next - 1 > 0)
TryRecoverMappings(mappings[next - 1], mappings[0], mappings[next]);
}
// Iterate through normal, sorted cases.
// Normal case 1.
for (size_t i = 1; i < mappings.size() - 1; i++)
TryRecoverMappings(mappings[i], mappings[i + 1]);
// Normal case 2.
for (size_t i = 1; i < mappings.size() - 2; i++)
TryRecoverMappings(mappings[i], mappings[i + 1], mappings[i + 2]);
// Collect merged (size == 0) segments.
size_t f, e;
for (f = e = 0; e < mappings.size(); e++)
if (mappings[e]->size > 0)
mappings[f++] = mappings[e];
mappings.resize(f);
}
} // namespace
#endif // __CHROMEOS__
// All interesting auvx entry types are below AT_SYSINFO_EHDR
#define AT_MAX AT_SYSINFO_EHDR
LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix)
LinuxDumper::LinuxDumper(pid_t pid)
: pid_(pid),
root_prefix_(root_prefix),
crash_address_(0),
crash_signal_(0),
crash_thread_(pid),
threads_(&allocator_, 8),
mappings_(&allocator_),
auxv_(&allocator_, AT_MAX + 1) {
assert(root_prefix_ && my_strlen(root_prefix_) < PATH_MAX);
// The passed-in size to the constructor (above) is only a hint.
// Must call .resize() to do actual initialization of the elements.
auxv_.resize(AT_MAX + 1);
@ -281,11 +112,6 @@ bool LinuxDumper::LateInit() {
#if defined(__ANDROID__)
LatePostprocessMappings();
#endif
#if defined(__CHROMEOS__)
CrOSPostProcessMappings(mappings_);
#endif
return true;
}
@ -293,8 +119,9 @@ bool
LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
bool member,
unsigned int mapping_id,
wasteful_vector<uint8_t>& identifier) {
uint8_t identifier[sizeof(MDGUID)]) {
assert(!member || mapping_id < mappings_.size());
my_memset(identifier, 0, sizeof(MDGUID));
if (IsMappedFileOpenUnsafe(mapping))
return false;
@ -312,9 +139,14 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
}
char filename[PATH_MAX];
if (!GetMappingAbsolutePath(mapping, filename))
char filename[NAME_MAX];
size_t filename_len = my_strlen(mapping.name);
if (filename_len >= NAME_MAX) {
assert(false);
return false;
}
my_memcpy(filename, mapping.name, filename_len);
filename[filename_len] = '\0';
bool filename_modified = HandleDeletedFileInMapping(filename);
MemoryMappedFile mapped_file(filename, mapping.offset);
@ -324,19 +156,13 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
bool success =
FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
if (success && member && filename_modified) {
mappings_[mapping_id]->name[my_strlen(mapping.name) -
mappings_[mapping_id]->name[filename_len -
sizeof(kDeletedSuffix) + 1] = '\0';
}
return success;
}
bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping,
char path[PATH_MAX]) const {
return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX &&
my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX;
}
namespace {
bool ElfFileSoNameFromMappedFile(
const void* elf_base, char* soname, size_t soname_size) {
@ -386,16 +212,23 @@ bool ElfFileSoNameFromMappedFile(
// for |mapping|. If the SONAME is found copy it into the passed buffer
// |soname| and return true. The size of the buffer is |soname_size|.
// The SONAME will be truncated if it is too long to fit in the buffer.
bool ElfFileSoName(const LinuxDumper& dumper,
bool ElfFileSoName(
const MappingInfo& mapping, char* soname, size_t soname_size) {
if (IsMappedFileOpenUnsafe(mapping)) {
// Not safe
return false;
}
char filename[PATH_MAX];
if (!dumper.GetMappingAbsolutePath(mapping, filename))
char filename[NAME_MAX];
size_t filename_len = my_strlen(mapping.name);
if (filename_len >= NAME_MAX) {
assert(false);
// name too long
return false;
}
my_memcpy(filename, mapping.name, filename_len);
filename[filename_len] = '\0';
MemoryMappedFile mapped_file(filename, mapping.offset);
if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
@ -409,6 +242,7 @@ bool ElfFileSoName(const LinuxDumper& dumper,
} // namespace
// static
void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
char* file_path,
size_t file_path_size,
@ -421,10 +255,8 @@ void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
// apk on Android). We try to find the name of the shared object (SONAME) by
// looking in the file for ELF sections.
bool mapped_from_archive = false;
if (mapping.exec && mapping.offset != 0) {
mapped_from_archive =
ElfFileSoName(*this, mapping, file_name, file_name_size);
}
if (mapping.exec && mapping.offset != 0)
mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size);
if (mapped_from_archive) {
// Some tools (e.g., stackwalk) extract the basename from the pathname. In
@ -748,13 +580,10 @@ bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
// Check |path| against the /proc/pid/exe 'symlink'.
char exe_link[NAME_MAX];
char new_path[NAME_MAX];
if (!BuildProcPath(exe_link, pid_, "exe"))
return false;
MappingInfo new_mapping = {0};
if (!SafeReadLink(exe_link, new_mapping.name))
return false;
char new_path[PATH_MAX];
if (!GetMappingAbsolutePath(new_mapping, new_path))
if (!SafeReadLink(exe_link, new_path))
return false;
if (my_strcmp(path, new_path) != 0)
return false;

Просмотреть файл

@ -49,7 +49,6 @@
#include "client/linux/dump_writer_common/mapping_info.h"
#include "client/linux/dump_writer_common/thread_info.h"
#include "common/linux/file_id.h"
#include "common/memory.h"
#include "google_breakpad/common/minidump_format.h"
@ -73,9 +72,7 @@ const char kLinuxGateLibraryName[] = "linux-gate.so";
class LinuxDumper {
public:
// The |root_prefix| is prepended to mapping paths before opening them, which
// is useful if the crash originates from a chroot.
explicit LinuxDumper(pid_t pid, const char* root_prefix = "");
explicit LinuxDumper(pid_t pid);
virtual ~LinuxDumper();
@ -130,7 +127,7 @@ class LinuxDumper {
bool ElfFileIdentifierForMapping(const MappingInfo& mapping,
bool member,
unsigned int mapping_id,
wasteful_vector<uint8_t>& identifier);
uint8_t identifier[sizeof(MDGUID)]);
uintptr_t crash_address() const { return crash_address_; }
void set_crash_address(uintptr_t crash_address) {
@ -143,21 +140,16 @@ class LinuxDumper {
pid_t crash_thread() const { return crash_thread_; }
void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
// Concatenates the |root_prefix_| and |mapping| path. Writes into |path| and
// returns true unless the string is too long.
bool GetMappingAbsolutePath(const MappingInfo& mapping,
char path[PATH_MAX]) const;
// Extracts the effective path and file name of from |mapping|. In most cases
// the effective name/path are just the mapping's path and basename. In some
// other cases, however, a library can be mapped from an archive (e.g., when
// loading .so libs from an apk on Android) and this method is able to
// reconstruct the original file name.
void GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
char* file_path,
size_t file_path_size,
char* file_name,
size_t file_name_size);
static void GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
char* file_path,
size_t file_path_size,
char* file_name,
size_t file_name_size);
protected:
bool ReadAuxv();
@ -180,9 +172,6 @@ class LinuxDumper {
// ID of the crashed process.
const pid_t pid_;
// Path of the root directory to which mapping paths are relative.
const char* const root_prefix_;
// Virtual address at which the process crashed.
uintptr_t crash_address_;

Просмотреть файл

@ -66,7 +66,6 @@ using namespace google_breakpad;
namespace {
typedef wasteful_vector<uint8_t> id_vector;
typedef testing::Test LinuxPtraceDumperTest;
/* Fixture for running tests in a child process. */
@ -106,17 +105,11 @@ class LinuxPtraceDumperChildTest : public testing::Test {
* This is achieved by defining a TestBody macro further below.
*/
virtual void RealTestBody() = 0;
id_vector make_vector() {
return id_vector(&allocator, kDefaultBuildIdSize);
}
private:
static const int kFatalFailure = 1;
static const int kNonFatalFailure = 2;
pid_t child_pid_;
PageAllocator allocator;
};
} // namespace
@ -317,15 +310,14 @@ TEST_F(LinuxPtraceDumperChildTest, LinuxGateMappingID) {
// Need to suspend the child so ptrace actually works.
ASSERT_TRUE(dumper.ThreadsSuspend());
id_vector identifier(make_vector());
uint8_t identifier[sizeof(MDGUID)];
ASSERT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[index],
true,
index,
identifier));
id_vector empty_identifier(make_vector());
empty_identifier.resize(kDefaultBuildIdSize, 0);
EXPECT_NE(empty_identifier, identifier);
uint8_t empty_identifier[sizeof(MDGUID)];
memset(empty_identifier, 0, sizeof(empty_identifier));
EXPECT_NE(0, memcmp(empty_identifier, identifier, sizeof(identifier)));
EXPECT_TRUE(dumper.ThreadsResume());
}
#endif
@ -351,18 +343,19 @@ TEST_F(LinuxPtraceDumperChildTest, FileIDsMatch) {
}
ASSERT_TRUE(found_exe);
id_vector identifier1(make_vector());
id_vector identifier2(make_vector());
uint8_t identifier1[sizeof(MDGUID)];
uint8_t identifier2[sizeof(MDGUID)];
EXPECT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[i], true, i,
identifier1));
FileID fileid(exe_name);
EXPECT_TRUE(fileid.ElfFileIdentifier(identifier2));
string identifier_string1 =
FileID::ConvertIdentifierToUUIDString(identifier1);
string identifier_string2 =
FileID::ConvertIdentifierToUUIDString(identifier2);
EXPECT_EQ(identifier_string1, identifier_string2);
char identifier_string1[37];
char identifier_string2[37];
FileID::ConvertIdentifierToString(identifier1, identifier_string1,
37);
FileID::ConvertIdentifierToString(identifier2, identifier_string2,
37);
EXPECT_STREQ(identifier_string1, identifier_string2);
}
/* Get back to normal behavior of TEST*() macros wrt TestBody. */

Просмотреть файл

@ -73,7 +73,6 @@
#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
#include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
#include "client/minidump_file_writer.h"
#include "common/linux/file_id.h"
#include "common/linux/linux_libc_support.h"
#include "common/minidump_type_helper.h"
#include "google_breakpad/common/minidump_format.h"
@ -82,10 +81,8 @@
namespace {
using google_breakpad::AppMemoryList;
using google_breakpad::auto_wasteful_vector;
using google_breakpad::ExceptionHandler;
using google_breakpad::CpuSet;
using google_breakpad::kDefaultBuildIdSize;
using google_breakpad::LineReader;
using google_breakpad::LinuxDumper;
using google_breakpad::LinuxPtraceDumper;
@ -274,14 +271,6 @@ class MinidumpWriter {
if (max_stack_len >= 0 &&
stack_len > static_cast<unsigned int>(max_stack_len)) {
stack_len = max_stack_len;
// Skip empty chunks of length max_stack_len.
uintptr_t int_stack = reinterpret_cast<uintptr_t>(stack);
if (max_stack_len > 0) {
while (int_stack + max_stack_len < stack_pointer) {
int_stack += max_stack_len;
}
}
stack = reinterpret_cast<const void*>(int_stack);
}
if (!memory.Allocate(stack_len))
return false;
@ -526,7 +515,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);
}
@ -535,7 +524,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);
}
@ -549,51 +538,52 @@ 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;
auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
dumper_->allocator());
uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
uint8_t* cv_ptr = cv_buf;
const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
cv_ptr += sizeof(cv_signature);
uint8_t* signature = cv_ptr;
cv_ptr += sizeof(MDGUID);
if (identifier) {
// GUID was provided by caller.
identifier_bytes.insert(identifier_bytes.end(),
identifier,
identifier + sizeof(MDGUID));
my_memcpy(signature, identifier, sizeof(MDGUID));
} else {
// Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
dumper_->ElfFileIdentifierForMapping(mapping,
member,
mapping_id,
identifier_bytes);
}
if (!identifier_bytes.empty()) {
UntypedMDRVA cv(&minidump_writer_);
if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size()))
return false;
const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE;
cv.Copy(&cv_signature, sizeof(cv_signature));
cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0],
identifier_bytes.size());
mod->cv_record = cv.location();
dumper_->ElfFileIdentifierForMapping(mapping, member,
mapping_id, signature);
}
my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
cv_ptr += sizeof(uint32_t);
char file_name[NAME_MAX];
char file_path[NAME_MAX];
dumper_->GetMappingEffectiveNameAndPath(
LinuxDumper::GetMappingEffectiveNameAndPath(
mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
const size_t file_name_len = my_strlen(file_name);
UntypedMDRVA cv(&minidump_writer_);
if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1))
return false;
// Write pdb_file_name
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();
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;
}
@ -700,14 +690,17 @@ class MinidumpWriter {
}
#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) {
if (dyn.d_tag == DT_MIPS_RLD_MAP) {
r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
continue;
} else if (dyn.d_tag == DT_NULL) {
}
#else
if (dyn.d_tag == DT_DEBUG) {
r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
continue;
}
#endif
else if (dyn.d_tag == DT_NULL) {
break;
}
}
@ -833,13 +826,7 @@ 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
@ -855,14 +842,15 @@ class MinidumpWriter {
ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd);
const char* field;
while (reader->GetNextField(&field)) {
bool is_first_entry = true;
for (CpuInfoEntry& entry : cpu_info_table) {
if (!is_first_entry && entry.found) {
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) {
// except for the 'processor' field, ignore repeated values.
continue;
}
is_first_entry = false;
if (!my_strcmp(field, entry.info_name)) {
if (!my_strcmp(field, entry->info_name)) {
size_t value_len;
const char* value = reader->GetValueAndLen(&value_len);
if (value_len == 0)
@ -872,8 +860,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;
}
}
@ -889,8 +877,10 @@ class MinidumpWriter {
}
// make sure we got everything we wanted
for (const CpuInfoEntry& entry : cpu_info_table) {
if (!entry.found) {
for (size_t i = 0;
i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
i++) {
if (!cpu_info_table[i].found) {
return false;
}
}
@ -1026,15 +1016,18 @@ class MinidumpWriter {
new(allocator) ProcCpuInfoReader(fd);
const char* field;
while (reader->GetNextField(&field)) {
for (const CpuIdEntry& entry : cpu_id_entries) {
if (my_strcmp(entry.field, field) != 0)
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)
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);
@ -1042,8 +1035,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);
}
@ -1097,7 +1090,7 @@ class MinidumpWriter {
const char* tag = value;
size_t tag_len = value_len;
const char* p = my_strchr(tag, ' ');
if (p) {
if (p != NULL) {
tag_len = static_cast<size_t>(p - tag);
value += tag_len + 1;
value_len -= tag_len + 1;
@ -1105,10 +1098,14 @@ class MinidumpWriter {
tag_len = strlen(tag);
value_len = 0;
}
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;
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;
break;
}
}

Просмотреть файл

@ -54,6 +54,10 @@
using namespace google_breakpad;
// Length of a formatted GUID string =
// sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator)
const int kGUIDStringSize = 37;
namespace {
typedef testing::Test MinidumpWriterTest;
@ -133,7 +137,19 @@ TEST(MinidumpWriterTest, MappingInfo) {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
char module_identifier_buffer[kGUIDStringSize];
FileID::ConvertIdentifierToString(kModuleGUID,
module_identifier_buffer,
sizeof(module_identifier_buffer));
string module_identifier(module_identifier_buffer);
// Strip out dashes
size_t pos;
while ((pos = module_identifier.find('-')) != string::npos) {
module_identifier.erase(pos, 1);
}
// And append a zero, because module IDs include an "age" field
// which is always zero on Linux.
module_identifier += "0";
// Get some memory.
char* memory =
@ -169,7 +185,6 @@ TEST(MinidumpWriterTest, MappingInfo) {
info.start_addr = kMemoryAddress;
info.size = memory_size;
info.offset = 0;
info.exec = false;
strcpy(info.name, kMemoryName);
MappingList mappings;
@ -215,53 +230,6 @@ TEST(MinidumpWriterTest, MappingInfo) {
close(fds[1]);
}
// Test that a binary with a longer-than-usual build id note
// makes its way all the way through to the minidump unscathed.
// The linux_client_unittest is linked with an explicit --build-id
// in Makefile.am.
TEST(MinidumpWriterTest, BuildIDLong) {
int fds[2];
ASSERT_NE(-1, pipe(fds));
const pid_t child = fork();
if (child == 0) {
close(fds[1]);
char b;
IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
close(fds[0]);
syscall(__NR_exit);
}
close(fds[0]);
ExceptionHandler::CrashContext context;
memset(&context, 0, sizeof(context));
ASSERT_EQ(0, getcontext(&context.context));
context.tid = child;
AutoTempDir temp_dir;
const string dump_path = temp_dir.path() + kMDWriterUnitTestFileName;
EXPECT_TRUE(WriteMinidump(dump_path.c_str(),
child, &context, sizeof(context)));
close(fds[1]);
// Read the minidump. Load the module list, and ensure that
// the main module has the correct debug id and code id.
Minidump minidump(dump_path);
ASSERT_TRUE(minidump.Read());
MinidumpModuleList* module_list = minidump.GetModuleList();
ASSERT_TRUE(module_list);
const MinidumpModule* module = module_list->GetMainModule();
ASSERT_TRUE(module);
const string module_identifier = "030201000504070608090A0B0C0D0E0F0";
// This is passed explicitly to the linker in Makefile.am
const string build_id =
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
EXPECT_EQ(module_identifier, module->debug_identifier());
EXPECT_EQ(build_id, module->code_identifier());
}
// Test that mapping info can be specified, and that it overrides
// existing mappings that are wholly contained within the specified
// range.
@ -277,7 +245,19 @@ TEST(MinidumpWriterTest, MappingInfoContained) {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
char module_identifier_buffer[kGUIDStringSize];
FileID::ConvertIdentifierToString(kModuleGUID,
module_identifier_buffer,
sizeof(module_identifier_buffer));
string module_identifier(module_identifier_buffer);
// Strip out dashes
size_t pos;
while ((pos = module_identifier.find('-')) != string::npos) {
module_identifier.erase(pos, 1);
}
// And append a zero, because module IDs include an "age" field
// which is always zero on Linux.
module_identifier += "0";
// mmap a file
AutoTempDir temp_dir;
@ -324,7 +304,6 @@ TEST(MinidumpWriterTest, MappingInfoContained) {
info.start_addr = kMemoryAddress - memory_size;
info.size = memory_size * 3;
info.offset = 0;
info.exec = false;
strcpy(info.name, kMemoryName);
MappingList mappings;
@ -431,10 +410,12 @@ TEST(MinidumpWriterTest, DeletedBinary) {
EXPECT_STREQ(binpath.c_str(), module->code_file().c_str());
// Check that the file ID is correct.
FileID fileid(helper_path.c_str());
PageAllocator allocator;
wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize);
uint8_t identifier[sizeof(MDGUID)];
EXPECT_TRUE(fileid.ElfFileIdentifier(identifier));
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
char identifier_string[kGUIDStringSize];
FileID::ConvertIdentifierToString(identifier,
identifier_string,
kGUIDStringSize);
string module_identifier(identifier_string);
// Strip out dashes
size_t pos;

Просмотреть файл

@ -583,6 +583,7 @@
4DBE4769134A4F080072546A /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
8B31007011F0CD3C00FCF3E4 /* GTMDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GTMDefines.h; path = ../../common/mac/GTMDefines.h; sourceTree = SOURCE_ROOT; };
8B3101E911F0CDE300FCF3E4 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
8B31022211F0CE1000FCF3E4 /* GTMGarbageCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GTMGarbageCollection.h; path = ../../common/mac/GTMGarbageCollection.h; sourceTree = SOURCE_ROOT; };
8B31027711F0D3AF00FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; };
8B31027811F0D3AF00FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; };
8B31FFF611F0C90500FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; };
@ -954,6 +955,7 @@
children = (
162F64F0161C577500CD68D5 /* arch_utilities.cc */,
162F64F1161C577500CD68D5 /* arch_utilities.h */,
8B31022211F0CE1000FCF3E4 /* GTMGarbageCollection.h */,
8B31007011F0CD3C00FCF3E4 /* GTMDefines.h */,
F9C77E0F0F7DDF650045F7DB /* testing */,
F9C44EE70EF0A3C1003AEBAA /* GTMLogger.h */,

Просмотреть файл

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

Просмотреть файл

@ -133,47 +133,25 @@ void MinidumpGenerator::GatherSystemInformation() {
vers_path,
kCFURLPOSIXPathStyle,
false);
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);
CFDataRef data;
SInt32 error;
CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL,
&error);
if (!data) {
CFRelease(sys_vers);
return;
}
CFDictionaryRef list =
static_cast<CFDictionaryRef>(CFPropertyListCreateWithData(
NULL, data, kCFPropertyListImmutable, NULL, NULL));
CFRelease(data);
CFDictionaryRef list = static_cast<CFDictionaryRef>
(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable,
NULL));
if (!list) {
CFRelease(sys_vers);
CFRelease(data);
return;
}
CFStringRef build_version = static_cast<CFStringRef>
(CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));
CFStringRef product_version = static_cast<CFStringRef>
@ -182,6 +160,8 @@ 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_));

Просмотреть файл

@ -44,47 +44,6 @@
#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);
@ -116,24 +75,15 @@ 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 defined(__ANDROID__)
if (!NeedsFTruncateWorkAround() && ftruncate(file_, position_)) {
if (-1 == ftruncate(file_, position_)) {
return false;
}
#else
if (ftruncate(file_, position_)) {
return false;
}
#endif
#if defined(__linux__) && __linux__
result = (sys_close(file_) == 0);
#else
@ -270,20 +220,6 @@ 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_) {
@ -320,16 +256,14 @@ 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) {
return true;
}
}
#else
if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (write(file_, src, size) == size) {
#endif
return true;
}
}
#endif
return false;
}

Просмотреть файл

@ -41,6 +41,12 @@
namespace google_breakpad {
static const int kWaitForHandlerThreadMs = 60000;
static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
// As documented on MSDN, on failure SuspendThread returns (DWORD) -1
static const DWORD kFailedToSuspendThread = static_cast<DWORD>(-1);
// This is passed as the context to the MinidumpWriteDump callback.
typedef struct {
AppMemoryList::const_iterator iter;
@ -211,7 +217,6 @@ void ExceptionHandler::Initialize(
// Don't attempt to create the thread if we could not create the semaphores.
if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) {
DWORD thread_id;
const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
handler_thread_ = CreateThread(NULL, // lpThreadAttributes
kExceptionHandlerThreadInitialStackSize,
ExceptionHandlerThreadMain,
@ -348,7 +353,6 @@ ExceptionHandler::~ExceptionHandler() {
// inside DllMain.
is_shutdown_ = true;
ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
const int kWaitForHandlerThreadMs = 60000;
WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);
#else
TerminateThread(handler_thread_, 1);
@ -777,8 +781,6 @@ bool ExceptionHandler::WriteMinidumpForChild(HANDLE child,
EXCEPTION_RECORD ex;
CONTEXT ctx;
EXCEPTION_POINTERS exinfo = { NULL, NULL };
// As documented on MSDN, on failure SuspendThread returns (DWORD) -1
const DWORD kFailedToSuspendThread = static_cast<DWORD>(-1);
DWORD last_suspend_count = kFailedToSuspendThread;
HANDLE child_thread_handle = OpenThread(THREAD_GET_CONTEXT |
THREAD_QUERY_INFORMATION |

Просмотреть файл

@ -101,8 +101,8 @@ struct elf_prpsinfo {
unsigned int pr_uid;
unsigned int pr_gid;
#elif defined(__mips__)
__kernel_uid_t pr_uid;
__kernel_gid_t pr_gid;
unsigned long pr_uid;
unsigned long pr_gid;
#else
unsigned short pr_uid;
unsigned short pr_gid;

Просмотреть файл

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

Просмотреть файл

@ -35,11 +35,6 @@
['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': [
@ -75,8 +70,6 @@
'dwarf/dwarf2reader.cc',
'dwarf/dwarf2reader.h',
'dwarf/dwarf2reader_test_common.h',
'dwarf/elf_reader.cc',
'dwarf/elf_reader.h',
'dwarf/functioninfo.cc',
'dwarf/functioninfo.h',
'dwarf/line_state_machine.h',

Просмотреть файл

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

Просмотреть файл

@ -27,7 +27,6 @@
// 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"
@ -63,7 +62,7 @@ void ByteReader::SetAddressSize(uint8 size) {
}
}
uint64 ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) {
uint64 ByteReader::ReadInitialLength(const char* start, size_t* len) {
const uint64 initial_length = ReadFourBytes(start);
start += 4;
@ -101,7 +100,7 @@ bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const {
}
}
uint64 ByteReader::ReadEncodedPointer(const uint8_t *buffer,
uint64 ByteReader::ReadEncodedPointer(const char *buffer,
DwarfPointerEncoding encoding,
size_t *len) const {
// UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't
@ -130,7 +129,7 @@ uint64 ByteReader::ReadEncodedPointer(const uint8_t *buffer,
// Round up to the next boundary.
uint64 aligned = (offset + AddressSize() - 1) & -AddressSize();
// Convert back to a pointer.
const uint8_t *aligned_buffer = buffer_base_ + (aligned - skew);
const char *aligned_buffer = buffer_base_ + (aligned - skew);
// Finally, store the length and actually fetch the pointer.
*len = aligned_buffer - buffer + AddressSize();
return ReadAddress(aligned_buffer);
@ -243,8 +242,4 @@ uint64 ByteReader::ReadEncodedPointer(const uint8_t *buffer,
return pointer;
}
Endianness ByteReader::GetEndianness() const {
return endian_;
}
} // namespace dwarf2reader

Просмотреть файл

@ -31,10 +31,7 @@
#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"
@ -62,22 +59,22 @@ class ByteReader {
// Read a single byte from BUFFER and return it as an unsigned 8 bit
// number.
uint8 ReadOneByte(const uint8_t *buffer) const;
uint8 ReadOneByte(const char* buffer) const;
// Read two bytes from BUFFER and return them as an unsigned 16 bit
// number, using this ByteReader's endianness.
uint16 ReadTwoBytes(const uint8_t *buffer) const;
uint16 ReadTwoBytes(const char* 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 uint8_t *buffer) const;
uint64 ReadFourBytes(const char* buffer) const;
// Read eight bytes from BUFFER and return them as an unsigned 64
// bit number, using this ByteReader's endianness.
uint64 ReadEightBytes(const uint8_t *buffer) const;
uint64 ReadEightBytes(const char* 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
@ -96,7 +93,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 uint8_t *buffer, size_t *len) const;
uint64 ReadUnsignedLEB128(const char* 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.
@ -115,7 +112,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 uint8_t *buffer, size_t *len) const;
int64 ReadSignedLEB128(const char* 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
@ -138,7 +135,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 uint8_t *buffer) const;
uint64 ReadAddress(const char* 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
@ -175,14 +172,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 uint8_t *start, size_t *len);
uint64 ReadInitialLength(const char* 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 uint8_t *buffer) const;
uint64 ReadOffset(const char* buffer) const;
// Return the current offset size, in bytes.
// A return value of 4 indicates that we are reading 32-bit DWARF.
@ -237,7 +234,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 uint8_t *buffer_base);
void SetCFIDataBase(uint64 section_base, const char *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.
@ -276,15 +273,13 @@ 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 uint8_t *buffer,
DwarfPointerEncoding encoding,
uint64 ReadEncodedPointer(const char *buffer, DwarfPointerEncoding encoding,
size_t *len) const;
Endianness GetEndianness() const;
private:
// Function pointer type for our address and offset readers.
typedef uint64 (ByteReader::*AddressReader)(const uint8_t *) const;
typedef uint64 (ByteReader::*AddressReader)(const char*) 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,
@ -307,7 +302,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 uint8_t *buffer_base_;
const char *buffer_base_;
};
} // namespace dwarf2reader

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -149,10 +149,7 @@ enum DwarfForm {
DW_FORM_sec_offset = 0x17,
DW_FORM_exprloc = 0x18,
DW_FORM_flag_present = 0x19,
DW_FORM_ref_sig8 = 0x20,
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
DW_FORM_GNU_addr_index = 0x1f01,
DW_FORM_GNU_str_index = 0x1f02
DW_FORM_ref_sig8 = 0x20
};
// Attribute names and codes
@ -267,13 +264,6 @@ enum DwarfAttribute {
DW_AT_body_begin = 0x2105,
DW_AT_body_end = 0x2106,
DW_AT_GNU_vector = 0x2107,
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
DW_AT_GNU_dwo_name = 0x2130,
DW_AT_GNU_dwo_id = 0x2131,
DW_AT_GNU_ranges_base = 0x2132,
DW_AT_GNU_addr_base = 0x2133,
DW_AT_GNU_pubnames = 0x2134,
DW_AT_GNU_pubtypes = 0x2135,
// VMS extensions.
DW_AT_VMS_rtnbeg_pd_address = 0x2201,
// UPC extension.
@ -501,22 +491,7 @@ enum DwarfOpcode {
DW_OP_lo_user =0xe0,
DW_OP_hi_user =0xff,
// GNU extensions
DW_OP_GNU_push_tls_address =0xe0,
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
DW_OP_GNU_addr_index =0xfb,
DW_OP_GNU_const_index =0xfc
};
// Section identifiers for DWP files
enum DwarfSectionId {
DW_SECT_INFO = 1,
DW_SECT_TYPES = 2,
DW_SECT_ABBREV = 3,
DW_SECT_LINE = 4,
DW_SECT_LOC = 5,
DW_SECT_STR_OFFSETS = 6,
DW_SECT_MACINFO = 7,
DW_SECT_MACRO = 8
DW_OP_GNU_push_tls_address =0xe0
};
// Source languages. These are values for DW_AT_language.

Просмотреть файл

@ -44,8 +44,6 @@
#include <string>
#include <utility>
#include <sys/stat.h>
#include "common/dwarf/bytereader-inl.h"
#include "common/dwarf/bytereader.h"
#include "common/dwarf/line_state_machine.h"
@ -53,38 +51,11 @@
namespace dwarf2reader {
CompilationUnit::CompilationUnit(const string& path,
const SectionMap& sections, uint64 offset,
CompilationUnit::CompilationUnit(const SectionMap& sections, uint64 offset,
ByteReader* reader, Dwarf2Handler* handler)
: path_(path), offset_from_section_start_(offset), reader_(reader),
sections_(sections), handler_(handler), abbrevs_(),
string_buffer_(NULL), string_buffer_length_(0),
str_offsets_buffer_(NULL), str_offsets_buffer_length_(0),
addr_buffer_(NULL), addr_buffer_length_(0),
is_split_dwarf_(false), dwo_id_(0), dwo_name_(),
skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0),
have_checked_for_dwp_(false), dwp_path_(),
dwp_byte_reader_(), dwp_reader_() {}
// Initialize a compilation unit from a .dwo or .dwp file.
// In this case, we need the .debug_addr section from the
// executable file that contains the corresponding skeleton
// compilation unit. We also inherit the Dwarf2Handler from
// the executable file, and call it as if we were still
// processing the original compilation unit.
void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer,
uint64 addr_buffer_length,
uint64 addr_base,
uint64 ranges_base,
uint64 dwo_id) {
is_split_dwarf_ = true;
addr_buffer_ = addr_buffer;
addr_buffer_length_ = addr_buffer_length;
addr_base_ = addr_base;
ranges_base_ = ranges_base;
skeleton_dwo_id_ = dwo_id;
}
: offset_from_section_start_(offset), reader_(reader),
sections_(sections), handler_(handler), abbrevs_(NULL),
string_buffer_(NULL), string_buffer_length_(0) {}
// Read a DWARF2/3 abbreviation section.
// Each abbrev consists of a abbreviation number, a tag, a byte
@ -112,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 uint8_t *abbrev_start = iter->second.first +
const char* abbrev_start = iter->second.first +
header_.abbrev_offset;
const uint8_t *abbrevptr = abbrev_start;
const char* abbrevptr = abbrev_start;
#ifndef NDEBUG
const uint64 abbrev_length = iter->second.second - header_.abbrev_offset;
#endif
@ -161,8 +132,8 @@ void CompilationUnit::ReadAbbrevs() {
}
// Skips a single DIE's attributes.
const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start,
const Abbrev& abbrev) {
const char* CompilationUnit::SkipDIE(const char* start,
const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
@ -172,8 +143,8 @@ const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start,
}
// Skips a single attribute form's data.
const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
enum DwarfForm form) {
const char* CompilationUnit::SkipAttribute(const char* start,
enum DwarfForm form) {
size_t len;
switch (form) {
@ -200,11 +171,9 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
case DW_FORM_ref_sig8:
return start + 8;
case DW_FORM_string:
return start + strlen(reinterpret_cast<const char *>(start)) + 1;
return start + strlen(start) + 1;
case DW_FORM_udata:
case DW_FORM_ref_udata:
case DW_FORM_GNU_str_index:
case DW_FORM_GNU_addr_index:
reader_->ReadUnsignedLEB128(start, &len);
return start + len;
@ -249,7 +218,7 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
// the offset in the .debug_abbrev section for our abbrevs, and an
// address size.
void CompilationUnit::ReadHeader() {
const uint8_t *headerptr = buffer_;
const char* headerptr = buffer_;
size_t initial_length_size;
assert(headerptr + 4 < buffer_ + buffer_length_);
@ -266,9 +235,7 @@ void CompilationUnit::ReadHeader() {
header_.abbrev_offset = reader_->ReadOffset(headerptr);
headerptr += reader_->OffsetSize();
// Compare against less than or equal because this may be the last
// section in the file.
assert(headerptr + 1 <= buffer_ + buffer_length_);
assert(headerptr + 1 < buffer_ + buffer_length_);
header_.address_size = reader_->ReadOneByte(headerptr);
reader_->SetAddressSize(header_.address_size);
headerptr += 1;
@ -329,39 +296,17 @@ uint64 CompilationUnit::Start() {
string_buffer_length_ = iter->second.second;
}
// Set the string offsets section if we have one.
iter = sections_.find(".debug_str_offsets");
if (iter != sections_.end()) {
str_offsets_buffer_ = iter->second.first;
str_offsets_buffer_length_ = iter->second.second;
}
// Set the address section if we have one.
iter = sections_.find(".debug_addr");
if (iter != sections_.end()) {
addr_buffer_ = iter->second.first;
addr_buffer_length_ = iter->second.second;
}
// Now that we have our abbreviations, start processing DIE's.
ProcessDIEs();
// If this is a skeleton compilation unit generated with split DWARF,
// and the client needs the full debug info, we need to find the full
// compilation unit in a .dwo or .dwp file.
if (!is_split_dwarf_
&& dwo_name_ != NULL
&& handler_->NeedSplitDebugInfo())
ProcessSplitDwarf();
return ourlength;
}
// If one really wanted, you could merge SkipAttribute and
// ProcessAttribute
// This is all boring data manipulation and calling of the handler.
const uint8_t *CompilationUnit::ProcessAttribute(
uint64 dieoffset, const uint8_t *start, enum DwarfAttribute attr,
const char* CompilationUnit::ProcessAttribute(
uint64 dieoffset, const char* start, enum DwarfAttribute attr,
enum DwarfForm form) {
size_t len;
@ -375,46 +320,48 @@ const uint8_t *CompilationUnit::ProcessAttribute(
return ProcessAttribute(dieoffset, start, attr, form);
case DW_FORM_flag_present:
ProcessAttributeUnsigned(dieoffset, attr, form, 1);
handler_->ProcessAttributeUnsigned(dieoffset, attr, form, 1);
return start;
case DW_FORM_data1:
case DW_FORM_flag:
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadOneByte(start));
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadOneByte(start));
return start + 1;
case DW_FORM_data2:
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadTwoBytes(start));
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadTwoBytes(start));
return start + 2;
case DW_FORM_data4:
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadFourBytes(start));
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadFourBytes(start));
return start + 4;
case DW_FORM_data8:
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadEightBytes(start));
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadEightBytes(start));
return start + 8;
case DW_FORM_string: {
const char *str = reinterpret_cast<const char *>(start);
ProcessAttributeString(dieoffset, attr, form, str);
const char* str = start;
handler_->ProcessAttributeString(dieoffset, attr, form,
str);
return start + strlen(str) + 1;
}
case DW_FORM_udata:
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadUnsignedLEB128(start, &len));
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadUnsignedLEB128(start,
&len));
return start + len;
case DW_FORM_sdata:
ProcessAttributeSigned(dieoffset, attr, form,
reader_->ReadSignedLEB128(start, &len));
handler_->ProcessAttributeSigned(dieoffset, attr, form,
reader_->ReadSignedLEB128(start, &len));
return start + len;
case DW_FORM_addr:
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadAddress(start));
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadAddress(start));
return start + reader_->AddressSize();
case DW_FORM_sec_offset:
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadOffset(start));
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadOffset(start));
return start + reader_->OffsetSize();
case DW_FORM_ref1:
@ -493,66 +440,34 @@ const uint8_t *CompilationUnit::ProcessAttribute(
const uint64 offset = reader_->ReadOffset(start);
assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_);
const char *str = reinterpret_cast<const char *>(string_buffer_ + offset);
ProcessAttributeString(dieoffset, attr, form, str);
const char* str = string_buffer_ + offset;
handler_->ProcessAttributeString(dieoffset, attr, form,
str);
return start + reader_->OffsetSize();
}
case DW_FORM_GNU_str_index: {
uint64 str_index = reader_->ReadUnsignedLEB128(start, &len);
const uint8_t* offset_ptr =
str_offsets_buffer_ + str_index * reader_->OffsetSize();
const uint64 offset = reader_->ReadOffset(offset_ptr);
if (offset >= string_buffer_length_) {
return NULL;
}
const char* str = reinterpret_cast<const char *>(string_buffer_) + offset;
ProcessAttributeString(dieoffset, attr, form, str);
return start + len;
break;
}
case DW_FORM_GNU_addr_index: {
uint64 addr_index = reader_->ReadUnsignedLEB128(start, &len);
const uint8_t* addr_ptr =
addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize();
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadAddress(addr_ptr));
return start + len;
}
}
fprintf(stderr, "Unhandled form type\n");
return NULL;
}
const uint8_t *CompilationUnit::ProcessDIE(uint64 dieoffset,
const uint8_t *start,
const Abbrev& abbrev) {
const char* CompilationUnit::ProcessDIE(uint64 dieoffset,
const char* start,
const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
start = ProcessAttribute(dieoffset, start, i->first, i->second);
}
// If this is a compilation unit in a split DWARF object, verify that
// the dwo_id matches. If it does not match, we will ignore this
// compilation unit.
if (abbrev.tag == DW_TAG_compile_unit
&& is_split_dwarf_
&& dwo_id_ != skeleton_dwo_id_) {
return NULL;
}
return start;
}
void CompilationUnit::ProcessDIEs() {
const uint8_t *dieptr = after_header_;
const char* 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 uint8_t *lengthstart = buffer_;
const char* lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
@ -600,313 +515,10 @@ void CompilationUnit::ProcessDIEs() {
}
}
// Check for a valid ELF file and return the Address size.
// Returns 0 if not a valid ELF file.
inline int GetElfWidth(const ElfReader& elf) {
if (elf.IsElf32File())
return 4;
if (elf.IsElf64File())
return 8;
return 0;
}
void CompilationUnit::ProcessSplitDwarf() {
struct stat statbuf;
if (!have_checked_for_dwp_) {
// Look for a .dwp file in the same directory as the executable.
have_checked_for_dwp_ = true;
string dwp_suffix(".dwp");
dwp_path_ = path_ + dwp_suffix;
if (stat(dwp_path_.c_str(), &statbuf) != 0) {
// Fall back to a split .debug file in the same directory.
string debug_suffix(".debug");
dwp_path_ = path_;
size_t found = path_.rfind(debug_suffix);
if (found + debug_suffix.length() == path_.length())
dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix);
}
if (stat(dwp_path_.c_str(), &statbuf) == 0) {
ElfReader* elf = new ElfReader(dwp_path_);
int width = GetElfWidth(*elf);
if (width != 0) {
dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness()));
dwp_byte_reader_->SetAddressSize(width);
dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf));
dwp_reader_->Initialize();
} else {
delete elf;
}
}
}
bool found_in_dwp = false;
if (dwp_reader_) {
// If we have a .dwp file, read the debug sections for the requested CU.
SectionMap sections;
dwp_reader_->ReadDebugSectionsForCU(dwo_id_, &sections);
if (!sections.empty()) {
found_in_dwp = true;
CompilationUnit dwp_comp_unit(dwp_path_, sections, 0,
dwp_byte_reader_.get(), handler_);
dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_,
ranges_base_, dwo_id_);
dwp_comp_unit.Start();
}
}
if (!found_in_dwp) {
// If no .dwp file, try to open the .dwo file.
if (stat(dwo_name_, &statbuf) == 0) {
ElfReader elf(dwo_name_);
int width = GetElfWidth(elf);
if (width != 0) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(width);
SectionMap sections;
ReadDebugSectionsFromDwo(&elf, &sections);
CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader,
handler_);
dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_,
addr_base_, ranges_base_, dwo_id_);
dwo_comp_unit.Start();
}
}
}
}
void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader,
SectionMap* sections) {
static const char* const section_names[] = {
".debug_abbrev",
".debug_info",
".debug_str_offsets",
".debug_str"
};
for (unsigned int i = 0u;
i < sizeof(section_names)/sizeof(*(section_names)); ++i) {
string base_name = section_names[i];
string dwo_name = base_name + ".dwo";
size_t section_size;
const char* section_data = elf_reader->GetSectionByName(dwo_name,
&section_size);
if (section_data != NULL)
sections->insert(std::make_pair(
base_name, std::make_pair(
reinterpret_cast<const uint8_t *>(section_data),
section_size)));
}
}
DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader)
: elf_reader_(elf_reader), byte_reader_(byte_reader),
cu_index_(NULL), cu_index_size_(0), string_buffer_(NULL),
string_buffer_size_(0), version_(0), ncolumns_(0), nunits_(0),
nslots_(0), phash_(NULL), pindex_(NULL), shndx_pool_(NULL),
offset_table_(NULL), size_table_(NULL), abbrev_data_(NULL),
abbrev_size_(0), info_data_(NULL), info_size_(0),
str_offsets_data_(NULL), str_offsets_size_(0) {}
DwpReader::~DwpReader() {
if (elf_reader_) delete elf_reader_;
}
void DwpReader::Initialize() {
cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index",
&cu_index_size_);
if (cu_index_ == NULL) {
return;
}
// The .debug_str.dwo section is shared by all CUs in the file.
string_buffer_ = elf_reader_->GetSectionByName(".debug_str.dwo",
&string_buffer_size_);
version_ = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(cu_index_));
if (version_ == 1) {
nslots_ = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(cu_index_)
+ 3 * sizeof(uint32));
phash_ = cu_index_ + 4 * sizeof(uint32);
pindex_ = phash_ + nslots_ * sizeof(uint64);
shndx_pool_ = pindex_ + nslots_ * sizeof(uint32);
if (shndx_pool_ >= cu_index_ + cu_index_size_) {
version_ = 0;
}
} else if (version_ == 2) {
ncolumns_ = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(cu_index_) + sizeof(uint32));
nunits_ = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(cu_index_) + 2 * sizeof(uint32));
nslots_ = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(cu_index_) + 3 * sizeof(uint32));
phash_ = cu_index_ + 4 * sizeof(uint32);
pindex_ = phash_ + nslots_ * sizeof(uint64);
offset_table_ = pindex_ + nslots_ * sizeof(uint32);
size_table_ = offset_table_ + ncolumns_ * (nunits_ + 1) * sizeof(uint32);
abbrev_data_ = elf_reader_->GetSectionByName(".debug_abbrev.dwo",
&abbrev_size_);
info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_);
str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo",
&str_offsets_size_);
if (size_table_ >= cu_index_ + cu_index_size_) {
version_ = 0;
}
}
}
void DwpReader::ReadDebugSectionsForCU(uint64 dwo_id,
SectionMap* sections) {
if (version_ == 1) {
int slot = LookupCU(dwo_id);
if (slot == -1) {
return;
}
// The index table points to the section index pool, where we
// can read a list of section indexes for the debug sections
// for the CU whose dwo_id we are looking for.
int index = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(pindex_)
+ slot * sizeof(uint32));
const char* shndx_list = shndx_pool_ + index * sizeof(uint32);
for (;;) {
if (shndx_list >= cu_index_ + cu_index_size_) {
version_ = 0;
return;
}
unsigned int shndx = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(shndx_list));
shndx_list += sizeof(uint32);
if (shndx == 0)
break;
const char* section_name = elf_reader_->GetSectionName(shndx);
size_t section_size;
const char* section_data;
// We're only interested in these four debug sections.
// The section names in the .dwo file end with ".dwo", but we
// add them to the sections table with their normal names.
if (!strncmp(section_name, ".debug_abbrev", strlen(".debug_abbrev"))) {
section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
sections->insert(std::make_pair(
".debug_abbrev",
std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
section_size)));
} else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) {
section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
sections->insert(std::make_pair(
".debug_info",
std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
section_size)));
} else if (!strncmp(section_name, ".debug_str_offsets",
strlen(".debug_str_offsets"))) {
section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
sections->insert(std::make_pair(
".debug_str_offsets",
std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
section_size)));
}
}
sections->insert(std::make_pair(
".debug_str",
std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_),
string_buffer_size_)));
} else if (version_ == 2) {
uint32 index = LookupCUv2(dwo_id);
if (index == 0) {
return;
}
// The index points to a row in each of the section offsets table
// and the section size table, where we can read the offsets and sizes
// of the contributions to each debug section from the CU whose dwo_id
// we are looking for. Row 0 of the section offsets table has the
// section ids for each column of the table. The size table begins
// with row 1.
const char* id_row = offset_table_;
const char* offset_row = offset_table_
+ index * ncolumns_ * sizeof(uint32);
const char* size_row =
size_table_ + (index - 1) * ncolumns_ * sizeof(uint32);
if (size_row + ncolumns_ * sizeof(uint32) > cu_index_ + cu_index_size_) {
version_ = 0;
return;
}
for (unsigned int col = 0u; col < ncolumns_; ++col) {
uint32 section_id =
byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t *>(id_row)
+ col * sizeof(uint32));
uint32 offset = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(offset_row)
+ col * sizeof(uint32));
uint32 size = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(size_row) + col * sizeof(uint32));
if (section_id == DW_SECT_ABBREV) {
sections->insert(std::make_pair(
".debug_abbrev",
std::make_pair(reinterpret_cast<const uint8_t *> (abbrev_data_)
+ offset, size)));
} else if (section_id == DW_SECT_INFO) {
sections->insert(std::make_pair(
".debug_info",
std::make_pair(reinterpret_cast<const uint8_t *> (info_data_)
+ offset, size)));
} else if (section_id == DW_SECT_STR_OFFSETS) {
sections->insert(std::make_pair(
".debug_str_offsets",
std::make_pair(reinterpret_cast<const uint8_t *> (str_offsets_data_)
+ offset, size)));
}
}
sections->insert(std::make_pair(
".debug_str",
std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_),
string_buffer_size_)));
}
}
int DwpReader::LookupCU(uint64 dwo_id) {
uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1);
uint64 probe = byte_reader_.ReadEightBytes(
reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
if (probe != 0 && probe != dwo_id) {
uint32 secondary_hash =
(static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1;
do {
slot = (slot + secondary_hash) & (nslots_ - 1);
probe = byte_reader_.ReadEightBytes(
reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
} while (probe != 0 && probe != dwo_id);
}
if (probe == 0)
return -1;
return slot;
}
uint32 DwpReader::LookupCUv2(uint64 dwo_id) {
uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1);
uint64 probe = byte_reader_.ReadEightBytes(
reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
uint32 index = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32));
if (index != 0 && probe != dwo_id) {
uint32 secondary_hash =
(static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1;
do {
slot = (slot + secondary_hash) & (nslots_ - 1);
probe = byte_reader_.ReadEightBytes(
reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
index = byte_reader_.ReadFourBytes(
reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32));
} while (index != 0 && probe != dwo_id);
}
return index;
}
LineInfo::LineInfo(const uint8_t *buffer, uint64 buffer_length,
LineInfo::LineInfo(const char* buffer, uint64 buffer_length,
ByteReader* reader, LineInfoHandler* handler):
handler_(handler), reader_(reader), buffer_(buffer) {
#ifndef NDEBUG
buffer_length_ = buffer_length;
#endif
handler_(handler), reader_(reader), buffer_(buffer),
buffer_length_(buffer_length) {
header_.std_opcode_lengths = NULL;
}
@ -919,7 +531,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 uint8_t *lineptr = buffer_;
const char* lineptr = buffer_;
size_t initial_length_size;
const uint64 initial_length
@ -966,7 +578,7 @@ void LineInfo::ReadHeader() {
if (*lineptr) {
uint32 dirindex = 1;
while (*lineptr) {
const char *dirname = reinterpret_cast<const char *>(lineptr);
const char* dirname = lineptr;
handler_->DefineDir(dirname, dirindex);
lineptr += strlen(dirname) + 1;
dirindex++;
@ -979,7 +591,7 @@ void LineInfo::ReadHeader() {
uint32 fileindex = 1;
size_t len;
while (*lineptr) {
const char *filename = reinterpret_cast<const char *>(lineptr);
const char* filename = lineptr;
lineptr += strlen(filename) + 1;
uint64 dirindex = reader_->ReadUnsignedLEB128(lineptr, &len);
@ -1004,7 +616,7 @@ void LineInfo::ReadHeader() {
bool LineInfo::ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
const struct LineInfoHeader &header,
const uint8_t *start,
const char* start,
struct LineStateMachine* lsm,
size_t* len,
uintptr pc,
@ -1145,7 +757,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader,
}
break;
case DW_LNE_define_file: {
const char *filename = reinterpret_cast<const char *>(start);
const char* filename = start;
templen = strlen(filename) + 1;
start += templen;
@ -1192,7 +804,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 uint8_t *lengthstart = buffer_;
const char* lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
@ -1201,7 +813,7 @@ void LineInfo::ReadLines() {
else
lengthstart += 4;
const uint8_t *lineptr = after_header_;
const char* lineptr = after_header_;
lsm.Reset(header_.default_is_stmt);
// The LineInfoHandler interface expects each line's length along
@ -1700,7 +1312,7 @@ class CallFrameInfo::State {
const Entry *entry_;
// The next instruction to process.
const uint8_t *cursor_;
const char *cursor_;
// The current set of rules.
RuleMap rules_;
@ -1798,8 +1410,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format,
if (len > bytes_left || expression_length > bytes_left - len)
return ReportIncomplete();
cursor_ += len;
operands->expression = string(reinterpret_cast<const char *>(cursor_),
expression_length);
operands->expression = string(cursor_, expression_length);
cursor_ += expression_length;
break;
}
@ -2152,8 +1763,8 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) {
return DoRule(reg, rule);
}
bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) {
const uint8_t *buffer_end = buffer_ + buffer_length_;
bool CallFrameInfo::ReadEntryPrologue(const char *cursor, Entry *entry) {
const char *buffer_end = buffer_ + buffer_length_;
// Initialize enough of ENTRY for use in error reporting.
entry->offset = cursor - buffer_;
@ -2231,7 +1842,7 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) {
}
bool CallFrameInfo::ReadCIEFields(CIE *cie) {
const uint8_t *cursor = cie->fields;
const char *cursor = cie->fields;
size_t len;
assert(cie->kind == kCIE);
@ -2262,14 +1873,13 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
return false;
}
const uint8_t *augmentation_start = cursor;
const uint8_t *augmentation_end =
reinterpret_cast<const uint8_t *>(memchr(augmentation_start, '\0',
cie->end - augmentation_start));
const char *augmentation_start = cursor;
const void *augmentation_end =
memchr(augmentation_start, '\0', cie->end - augmentation_start);
if (! augmentation_end) return ReportIncomplete(cie);
cursor = augmentation_end;
cie->augmentation = string(reinterpret_cast<const char *>(augmentation_start),
cursor - augmentation_start);
cursor = static_cast<const char *>(augmentation_end);
cie->augmentation = string(augmentation_start,
cursor - augmentation_start);
// Skip the terminating '\0'.
cursor++;
@ -2315,9 +1925,9 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
if (size_t(cie->end - cursor) < len + data_size)
return ReportIncomplete(cie);
cursor += len;
const uint8_t *data = cursor;
const char *data = cursor;
cursor += data_size;
const uint8_t *data_end = cursor;
const char *data_end = cursor;
cie->has_z_lsda = false;
cie->has_z_personality = false;
@ -2409,7 +2019,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
}
bool CallFrameInfo::ReadFDEFields(FDE *fde) {
const uint8_t *cursor = fde->fields;
const char *cursor = fde->fields;
size_t size;
fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding,
@ -2475,10 +2085,10 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) {
}
bool CallFrameInfo::Start() {
const uint8_t *buffer_end = buffer_ + buffer_length_;
const uint8_t *cursor;
const char *buffer_end = buffer_ + buffer_length_;
const char *cursor;
bool all_ok = true;
const uint8_t *entry_end;
const char *entry_end;
bool ok;
// Traverse all the entries in buffer_, skipping CIEs and offering

Просмотреть файл

@ -40,30 +40,25 @@
#ifndef COMMON_DWARF_DWARF2READER_H__
#define COMMON_DWARF_DWARF2READER_H__
#include <stdint.h>
#include <list>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <memory>
#include "common/dwarf/bytereader.h"
#include "common/dwarf/dwarf2enums.h"
#include "common/dwarf/types.h"
#include "common/using_std_string.h"
#include "common/dwarf/elf_reader.h"
namespace dwarf2reader {
struct LineStateMachine;
class Dwarf2Handler;
class LineInfoHandler;
class DwpReader;
// 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 uint8_t *, uint64> > SectionMap;
typedef std::map<string, std::pair<const char*, uint64> > SectionMap;
typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> >
AttributeList;
typedef AttributeList::iterator AttributeIterator;
@ -90,7 +85,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 uint8_t *buffer_, uint64 buffer_length,
LineInfo(const char* buffer_, uint64 buffer_length,
ByteReader* reader, LineInfoHandler* handler);
virtual ~LineInfo() {
@ -116,7 +111,7 @@ class LineInfo {
static bool ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
const struct LineInfoHeader &header,
const uint8_t *start,
const char* start,
struct LineStateMachine* lsm,
size_t* len,
uintptr pc,
@ -144,11 +139,9 @@ 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 uint8_t *buffer_;
#ifndef NDEBUG
const char* buffer_;
uint64 buffer_length_;
#endif
const uint8_t *after_header_;
const char* after_header_;
};
// This class is the main interface between the line info reader and
@ -187,106 +180,6 @@ class LineInfoHandler {
uint32 file_num, uint32 line_num, uint32 column_num) { }
};
// This class is the main interface between the reader and the
// client. The virtual functions inside this get called for
// interesting events that happen during DWARF2 reading.
// The default implementation skips everything.
class Dwarf2Handler {
public:
Dwarf2Handler() { }
virtual ~Dwarf2Handler() { }
// Start to process a compilation unit at OFFSET from the beginning of the
// .debug_info section. Return false if you would like to skip this
// compilation unit.
virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
uint8 offset_size, uint64 cu_length,
uint8 dwarf_version) { return false; }
// When processing a skeleton compilation unit, resulting from a split
// DWARF compilation, once the skeleton debug info has been read,
// the reader will call this function to ask the client if it needs
// the full debug info from the .dwo or .dwp file. Return true if
// you need it, or false to skip processing the split debug info.
virtual bool NeedSplitDebugInfo() { return true; }
// Start to process a split compilation unit at OFFSET from the beginning of
// the debug_info section in the .dwp/.dwo file. Return false if you would
// like to skip this compilation unit.
virtual bool StartSplitCompilationUnit(uint64 offset,
uint64 cu_length) { return false; }
// Start to process a DIE at OFFSET from the beginning of the .debug_info
// section. Return false if you would like to skip this DIE.
virtual bool StartDIE(uint64 offset, enum DwarfTag tag) { return false; }
// Called when we have an attribute with unsigned data to give to our
// handler. The attribute is for the DIE at OFFSET from the beginning of the
// .debug_info section. Its name is ATTR, its form is FORM, and its value is
// DATA.
virtual void ProcessAttributeUnsigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) { }
// Called when we have an attribute with signed data to give to our handler.
// The attribute is for the DIE at OFFSET from the beginning of the
// .debug_info section. Its name is ATTR, its form is FORM, and its value is
// DATA.
virtual void ProcessAttributeSigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
int64 data) { }
// Called when we have an attribute whose value is a reference to
// another DIE. The attribute belongs to the DIE at OFFSET from the
// beginning of the .debug_info section. Its name is ATTR, its form
// is FORM, and the offset of the DIE being referred to from the
// beginning of the .debug_info section is DATA.
virtual void ProcessAttributeReference(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) { }
// Called when we have an attribute with a buffer of data to give to our
// handler. The attribute is for the DIE at OFFSET from the beginning of the
// .debug_info section. Its name is ATTR, its form is FORM, DATA points to
// the buffer's contents, and its length in bytes is LENGTH. The buffer is
// owned by the caller, not the callee, and may not persist for very long.
// If you want the data to be available later, it needs to be copied.
virtual void ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const uint8_t *data,
uint64 len) { }
// Called when we have an attribute with string data to give to our handler.
// The attribute is for the DIE at OFFSET from the beginning of the
// .debug_info section. Its name is ATTR, its form is FORM, and its value is
// DATA.
virtual void ProcessAttributeString(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data) { }
// Called when we have an attribute whose value is the 64-bit signature
// of a type unit in the .debug_types section. OFFSET is the offset of
// the DIE whose attribute we're reporting. ATTR and FORM are the
// attribute's name and form. SIGNATURE is the type unit's signature.
virtual void ProcessAttributeSignature(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 signature) { }
// Called when finished processing the DIE at OFFSET.
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
// before ends of the previous DIE, as we process children before
// ending the parent.
virtual void EndDIE(uint64 offset) { }
};
// The base of DWARF2/3 debug info is a DIE (Debugging Information
// Entry.
// DWARF groups DIE's into a tree and calls the root of this tree a
@ -328,21 +221,12 @@ class CompilationUnit {
// Initialize a compilation unit. This requires a map of sections,
// the offset of this compilation unit in the .debug_info section, a
// ByteReader, and a Dwarf2Handler class to call callbacks in.
CompilationUnit(const string& path, const SectionMap& sections, uint64 offset,
CompilationUnit(const SectionMap& sections, uint64 offset,
ByteReader* reader, Dwarf2Handler* handler);
virtual ~CompilationUnit() {
if (abbrevs_) delete abbrevs_;
}
// Initialize a compilation unit from a .dwo or .dwp file.
// In this case, we need the .debug_addr section from the
// executable file that contains the corresponding skeleton
// compilation unit. We also inherit the Dwarf2Handler from
// the executable file, and call it as if we were still
// processing the original compilation unit.
void SetSplitDwarf(const uint8_t* addr_buffer, uint64 addr_buffer_length,
uint64 addr_base, uint64 ranges_base, uint64 dwo_id);
// Begin reading a Dwarf2 compilation unit, and calling the
// callbacks in the Dwarf2Handler
@ -382,104 +266,29 @@ class CompilationUnit {
// Processes a single DIE for this compilation unit and return a new
// pointer just past the end of it
const uint8_t *ProcessDIE(uint64 dieoffset,
const uint8_t *start,
const Abbrev& abbrev);
const char* ProcessDIE(uint64 dieoffset,
const char* start,
const Abbrev& abbrev);
// Processes a single attribute and return a new pointer just past the
// end of it
const uint8_t *ProcessAttribute(uint64 dieoffset,
const uint8_t *start,
enum DwarfAttribute attr,
enum DwarfForm form);
// Called when we have an attribute with unsigned data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
// If we see a DW_AT_GNU_dwo_id attribute, save the value so that
// we can find the debug info in a .dwo or .dwp file.
void ProcessAttributeUnsigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) {
if (attr == DW_AT_GNU_dwo_id) {
dwo_id_ = data;
}
else if (attr == DW_AT_GNU_addr_base) {
addr_base_ = data;
}
else if (attr == DW_AT_GNU_ranges_base) {
ranges_base_ = data;
}
// TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5,
// that base will apply to DW_AT_ranges attributes in the
// skeleton CU as well as in the .dwo/.dwp files.
else if (attr == DW_AT_ranges && is_split_dwarf_) {
data += ranges_base_;
}
handler_->ProcessAttributeUnsigned(offset, attr, form, data);
}
// Called when we have an attribute with signed data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
void ProcessAttributeSigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
int64 data) {
handler_->ProcessAttributeSigned(offset, attr, form, data);
}
// Called when we have an attribute with a buffer of data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA, and the
// length of the buffer is LENGTH.
void ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const uint8_t* data,
uint64 len) {
handler_->ProcessAttributeBuffer(offset, attr, form, data, len);
}
// Called when we have an attribute with string data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
// FORM, and the actual data of the attribute is in DATA.
// If we see a DW_AT_GNU_dwo_name attribute, save the value so
// that we can find the debug info in a .dwo or .dwp file.
void ProcessAttributeString(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const char* data) {
if (attr == DW_AT_GNU_dwo_name)
dwo_name_ = data;
handler_->ProcessAttributeString(offset, attr, form, data);
}
const char* ProcessAttribute(uint64 dieoffset,
const char* 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 uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev);
const char* SkipDIE(const char* start,
const Abbrev& abbrev);
// Skips the attribute starting at START, with FORM, and return the
// new place to position the stream to.
const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form);
// Process the actual debug information in a split DWARF file.
void ProcessSplitDwarf();
// Read the debug sections from a .dwo file.
void ReadDebugSectionsFromDwo(ElfReader* elf_reader,
SectionMap* sections);
// Path of the file containing the debug information.
const string path_;
const char* SkipAttribute(const char* start,
enum DwarfForm form);
// Offset from section start is the offset of this compilation unit
// from the beginning of the .debug_info section.
@ -488,9 +297,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 uint8_t *buffer_;
const char* buffer_;
uint64 buffer_length_;
const uint8_t *after_header_;
const char* after_header_;
// The associated ByteReader that handles endianness issues for us
ByteReader* reader_;
@ -509,143 +318,96 @@ 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 uint8_t *string_buffer_;
const char* string_buffer_;
uint64 string_buffer_length_;
// String offsets section buffer and length, if we have a string offsets
// section (.debug_str_offsets or .debug_str_offsets.dwo).
const uint8_t* str_offsets_buffer_;
uint64 str_offsets_buffer_length_;
// Address section buffer and length, if we have an address section
// (.debug_addr).
const uint8_t* addr_buffer_;
uint64 addr_buffer_length_;
// Flag indicating whether this compilation unit is part of a .dwo
// or .dwp file. If true, we are reading this unit because a
// skeleton compilation unit in an executable file had a
// DW_AT_GNU_dwo_name or DW_AT_GNU_dwo_id attribute.
// In a .dwo file, we expect the string offsets section to
// have a ".dwo" suffix, and we will use the ".debug_addr" section
// associated with the skeleton compilation unit.
bool is_split_dwarf_;
// The value of the DW_AT_GNU_dwo_id attribute, if any.
uint64 dwo_id_;
// The value of the DW_AT_GNU_dwo_name attribute, if any.
const char* dwo_name_;
// If this is a split DWARF CU, the value of the DW_AT_GNU_dwo_id attribute
// from the skeleton CU.
uint64 skeleton_dwo_id_;
// The value of the DW_AT_GNU_ranges_base attribute, if any.
uint64 ranges_base_;
// The value of the DW_AT_GNU_addr_base attribute, if any.
uint64 addr_base_;
// True if we have already looked for a .dwp file.
bool have_checked_for_dwp_;
// Path to the .dwp file.
string dwp_path_;
// ByteReader for the DWP file.
std::unique_ptr<ByteReader> dwp_byte_reader_;
// DWP reader.
std::unique_ptr<DwpReader> dwp_reader_;
};
// A Reader for a .dwp file. Supports the fetching of DWARF debug
// info for a given dwo_id.
//
// There are two versions of .dwp files. In both versions, the
// .dwp file is an ELF file containing only debug sections.
// In Version 1, the file contains many copies of each debug
// section, one for each .dwo file that is packaged in the .dwp
// file, and the .debug_cu_index section maps from the dwo_id
// to a set of section indexes. In Version 2, the file contains
// one of each debug section, and the .debug_cu_index section
// maps from the dwo_id to a set of offsets and lengths that
// identify each .dwo file's contribution to the larger sections.
// This class is the main interface between the reader and the
// client. The virtual functions inside this get called for
// interesting events that happen during DWARF2 reading.
// The default implementation skips everything.
class DwpReader {
class Dwarf2Handler {
public:
DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader);
Dwarf2Handler() { }
~DwpReader();
virtual ~Dwarf2Handler() { }
// Read the CU index and initialize data members.
void Initialize();
// Start to process a compilation unit at OFFSET from the beginning of the
// .debug_info section. Return false if you would like to skip this
// compilation unit.
virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
uint8 offset_size, uint64 cu_length,
uint8 dwarf_version) { return false; }
// Read the debug sections for the given dwo_id.
void ReadDebugSectionsForCU(uint64 dwo_id, SectionMap* sections);
// Start to process a DIE at OFFSET from the beginning of the .debug_info
// section. Return false if you would like to skip this DIE.
virtual bool StartDIE(uint64 offset, enum DwarfTag tag) { return false; }
private:
// Search a v1 hash table for "dwo_id". Returns the slot index
// where the dwo_id was found, or -1 if it was not found.
int LookupCU(uint64 dwo_id);
// Called when we have an attribute with unsigned data to give to our
// handler. The attribute is for the DIE at OFFSET from the beginning of the
// .debug_info section. Its name is ATTR, its form is FORM, and its value is
// DATA.
virtual void ProcessAttributeUnsigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) { }
// Search a v2 hash table for "dwo_id". Returns the row index
// in the offsets and sizes tables, or 0 if it was not found.
uint32 LookupCUv2(uint64 dwo_id);
// Called when we have an attribute with signed data to give to our handler.
// The attribute is for the DIE at OFFSET from the beginning of the
// .debug_info section. Its name is ATTR, its form is FORM, and its value is
// DATA.
virtual void ProcessAttributeSigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
int64 data) { }
// The ELF reader for the .dwp file.
ElfReader* elf_reader_;
// Called when we have an attribute whose value is a reference to
// another DIE. The attribute belongs to the DIE at OFFSET from the
// beginning of the .debug_info section. Its name is ATTR, its form
// is FORM, and the offset of the DIE being referred to from the
// beginning of the .debug_info section is DATA.
virtual void ProcessAttributeReference(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) { }
// The ByteReader for the .dwp file.
const ByteReader& byte_reader_;
// Called when we have an attribute with a buffer of data to give to our
// handler. The attribute is for the DIE at OFFSET from the beginning of the
// .debug_info section. Its name is ATTR, its form is FORM, DATA points to
// the buffer's contents, and its length in bytes is LENGTH. The buffer is
// owned by the caller, not the callee, and may not persist for very long.
// If you want the data to be available later, it needs to be copied.
virtual void ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const char* data,
uint64 len) { }
// Pointer to the .debug_cu_index section.
const char* cu_index_;
// Called when we have an attribute with string data to give to our handler.
// The attribute is for the DIE at OFFSET from the beginning of the
// .debug_info section. Its name is ATTR, its form is FORM, and its value is
// DATA.
virtual void ProcessAttributeString(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data) { }
// Size of the .debug_cu_index section.
size_t cu_index_size_;
// Called when we have an attribute whose value is the 64-bit signature
// of a type unit in the .debug_types section. OFFSET is the offset of
// the DIE whose attribute we're reporting. ATTR and FORM are the
// attribute's name and form. SIGNATURE is the type unit's signature.
virtual void ProcessAttributeSignature(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 signature) { }
// Pointer to the .debug_str.dwo section.
const char* string_buffer_;
// Called when finished processing the DIE at OFFSET.
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
// before ends of the previous DIE, as we process children before
// ending the parent.
virtual void EndDIE(uint64 offset) { }
// Size of the .debug_str.dwo section.
size_t string_buffer_size_;
// Version of the .dwp file. We support versions 1 and 2 currently.
int version_;
// Number of columns in the section tables (version 2).
unsigned int ncolumns_;
// Number of units in the section tables (version 2).
unsigned int nunits_;
// Number of slots in the hash table.
unsigned int nslots_;
// Pointer to the beginning of the hash table.
const char* phash_;
// Pointer to the beginning of the index table.
const char* pindex_;
// Pointer to the beginning of the section index pool (version 1).
const char* shndx_pool_;
// Pointer to the beginning of the section offset table (version 2).
const char* offset_table_;
// Pointer to the beginning of the section size table (version 2).
const char* size_table_;
// Contents of the sections of interest (version 2).
const char* abbrev_data_;
size_t abbrev_size_;
const char* info_data_;
size_t info_size_;
const char* str_offsets_data_;
size_t str_offsets_size_;
};
// This class is a reader for DWARF's Call Frame Information. CFI
@ -875,7 +637,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 uint8_t *buffer, size_t buffer_length,
CallFrameInfo(const char *buffer, size_t buffer_length,
ByteReader *reader, Handler *handler, Reporter *reporter,
bool eh_frame = false)
: buffer_(buffer), buffer_length_(buffer_length),
@ -903,7 +665,7 @@ class CallFrameInfo {
size_t offset;
// The start of this entry in the buffer.
const uint8_t *start;
const char *start;
// Which kind of entry this is.
//
@ -914,16 +676,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 uint8_t *fields;
const char *fields;
// The start of this entry's instructions.
const uint8_t *instructions;
const char *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 uint8_t *end;
const char *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.
@ -1000,7 +762,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 uint8_t *cursor, Entry *entry);
bool ReadEntryPrologue(const char *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
@ -1028,7 +790,7 @@ class CallFrameInfo {
}
// The contents of the DWARF .debug_info section we're parsing.
const uint8_t *buffer_;
const char *buffer_;
size_t buffer_length_;
// For reading multi-byte values with the appropriate endianness.

Просмотреть файл

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

Просмотреть файл

@ -31,7 +31,6 @@
// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit
#include <stdint.h>
#include <stdlib.h>
#include <iostream>
@ -92,7 +91,7 @@ class MockDwarf2Handler: public Dwarf2Handler {
MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const uint8_t *data,
const char* data,
uint64 len));
MOCK_METHOD4(ProcessAttributeString, void(uint64 offset,
enum DwarfAttribute attr,
@ -133,11 +132,9 @@ struct DIEFixture {
assert(info.GetContents(&info_contents));
assert(abbrevs.GetContents(&abbrevs_contents));
section_map.clear();
section_map[".debug_info"].first
= reinterpret_cast<const uint8_t *>(info_contents.data());
section_map[".debug_info"].first = info_contents.data();
section_map[".debug_info"].second = info_contents.size();
section_map[".debug_abbrev"].first
= reinterpret_cast<const uint8_t *>(abbrevs_contents.data());
section_map[".debug_abbrev"].first = abbrevs_contents.data();
section_map[".debug_abbrev"].second = abbrevs_contents.size();
return section_map;
}
@ -199,7 +196,7 @@ TEST_P(DwarfHeader, Header) {
ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler);
CompilationUnit parser(MakeSectionMap(), 0, &byte_reader, &handler);
EXPECT_EQ(parser.Start(), info_contents.size());
}
@ -277,7 +274,7 @@ struct DwarfFormsFixture: public DIEFixture {
void ParseCompilationUnit(const DwarfHeaderParams &params, uint64 offset=0) {
ByteReader byte_reader(params.endianness == kLittleEndian ?
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler);
CompilationUnit parser(MakeSectionMap(), offset, &byte_reader, &handler);
EXPECT_EQ(offset + parser.Start(), info_contents.size());
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,166 +0,0 @@
// Copyright 2005 Google Inc. All Rights Reserved.
// Author: chatham@google.com (Andrew Chatham)
// Author: satorux@google.com (Satoru Takabayashi)
//
// ElfReader handles reading in ELF. It can extract symbols from the
// current process, which may be used to symbolize stack traces
// without having to make a potentially dangerous call to fork().
//
// ElfReader dynamically allocates memory, so it is not appropriate to
// use once the address space might be corrupted, such as during
// process death.
//
// ElfReader supports both 32-bit and 64-bit ELF binaries.
#ifndef COMMON_DWARF_ELF_READER_H__
#define COMMON_DWARF_ELF_READER_H__
#include <string>
#include <vector>
#include "common/dwarf/types.h"
using std::string;
using std::vector;
using std::pair;
namespace dwarf2reader {
class SymbolMap;
class Elf32;
class Elf64;
template<typename ElfArch>
class ElfReaderImpl;
class ElfReader {
public:
explicit ElfReader(const string &path);
~ElfReader();
// Parse the ELF prologue of this file and return whether it was
// successfully parsed and matches the word size and byte order of
// the current process.
bool IsNativeElfFile() const;
// Similar to IsNativeElfFile but checks if it's a 32-bit ELF file.
bool IsElf32File() const;
// Similar to IsNativeElfFile but checks if it's a 64-bit ELF file.
bool IsElf64File() const;
// Checks if it's an ELF file of type ET_DYN (shared object file).
bool IsDynamicSharedObject();
// Add symbols in the given ELF file into the provided SymbolMap,
// assuming that the file has been loaded into the specified
// offset.
//
// The remaining arguments are typically taken from a
// ProcMapsIterator (base/sysinfo.h) and describe which portions of
// the ELF file are mapped into which parts of memory:
//
// mem_offset - position at which the segment is mapped into memory
// file_offset - offset in the file where the mapping begins
// length - length of the mapped segment
void AddSymbols(SymbolMap *symbols,
uint64 mem_offset, uint64 file_offset,
uint64 length);
class SymbolSink {
public:
virtual ~SymbolSink() {}
virtual void AddSymbol(const char *name, uint64 address, uint64 size) = 0;
};
// Like AddSymbols above, but with no address correction.
// Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section.
void VisitSymbols(SymbolSink *sink);
// Like VisitSymbols above, but for a specific symbol binding/type.
// A negative value for the binding and type parameters means any
// binding or type.
void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type);
// Like VisitSymbols above but can optionally export raw symbol values instead
// of adjusted ones.
void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type,
bool get_raw_symbol_values);
// p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD
// segments are present. This is the address an ELF image was linked
// (by static linker) to be loaded at. Usually (but not always) 0 for
// shared libraries and position-independent executables.
uint64 VaddrOfFirstLoadSegment();
// Return the name of section "shndx". Returns NULL if the section
// is not found.
const char *GetSectionName(int shndx);
// Return the number of sections in the given ELF file.
uint64 GetNumSections();
// Get section "shndx" from the given ELF file. On success, return
// the pointer to the section and store the size in "size".
// On error, return NULL. The returned section data is only valid
// until the ElfReader gets destroyed.
const char *GetSectionByIndex(int shndx, size_t *size);
// Get section with "section_name" (ex. ".text", ".symtab") in the
// given ELF file. On success, return the pointer to the section
// and store the size in "size". On error, return NULL. The
// returned section data is only valid until the ElfReader gets
// destroyed.
const char *GetSectionByName(const string &section_name, size_t *size);
// This is like GetSectionByName() but it returns a lot of extra information
// about the section. The SectionInfo structure is almost identical to
// the typedef struct Elf64_Shdr defined in <elf.h>, but is redefined
// here so that the many short macro names in <elf.h> don't have to be
// added to our already cluttered namespace.
struct SectionInfo {
uint32 type; // Section type (SHT_xxx constant from elf.h).
uint64 flags; // Section flags (SHF_xxx constants from elf.h).
uint64 addr; // Section virtual address at execution.
uint64 offset; // Section file offset.
uint64 size; // Section size in bytes.
uint32 link; // Link to another section.
uint32 info; // Additional section information.
uint64 addralign; // Section alignment.
uint64 entsize; // Entry size if section holds a table.
};
const char *GetSectionInfoByName(const string &section_name,
SectionInfo *info);
// Check if "path" is an ELF binary that has not been stripped of symbol
// tables. This function supports both 32-bit and 64-bit ELF binaries.
static bool IsNonStrippedELFBinary(const string &path);
// Check if "path" is an ELF binary that has not been stripped of debug
// info. Unlike IsNonStrippedELFBinary, this function will return
// false for binaries passed through "strip -S".
static bool IsNonDebugStrippedELFBinary(const string &path);
// Match a requested section name with the section name as it
// appears in the elf-file, adjusting for compressed debug section
// names. For example, returns true if name == ".debug_abbrev" and
// sh_name == ".zdebug_abbrev"
static bool SectionNamesMatch(const string &name, const string &sh_name);
private:
// Lazily initialize impl32_ and return it.
ElfReaderImpl<Elf32> *GetImpl32();
// Ditto for impl64_.
ElfReaderImpl<Elf64> *GetImpl64();
// Path of the file we're reading.
const string path_;
// Read-only file descriptor for the file. May be -1 if there was an
// error during open.
int fd_;
ElfReaderImpl<Elf32> *impl32_;
ElfReaderImpl<Elf64> *impl64_;
};
} // namespace dwarf2reader
#endif // COMMON_DWARF_ELF_READER_H__

Просмотреть файл

@ -9,7 +9,6 @@ HOST_SOURCES += [
'bytereader.cc',
'dwarf2diehandler.cc',
'dwarf2reader.cc',
'elf_reader.cc',
'functioninfo.cc',
]
HOST_CXXFLAGS += [
@ -27,9 +26,4 @@ HOST_CXXFLAGS += [
'-funsigned-char',
]
if CONFIG['OS_ARCH'] == 'Darwin':
HOST_CXXFLAGS += [
'-stdlib=libc++',
]
include('/toolkit/crashreporter/crashreporter.mozbuild')

Просмотреть файл

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

Просмотреть файл

@ -43,7 +43,6 @@
#include <cxxabi.h>
#endif
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <algorithm>
@ -141,7 +140,7 @@ DwarfCUToModule::FileContext::~FileContext() {
}
void DwarfCUToModule::FileContext::AddSectionToSectionMap(
const string& name, const uint8_t *contents, uint64 length) {
const string& name, const char* contents, uint64 length) {
section_map_[name] = std::make_pair(contents, length);
}
@ -417,8 +416,7 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
// If this DIE was marked as a declaration, record its names in the
// specification table.
if ((declaration_ && qualified_name) ||
(unqualified_name && enclosing_name)) {
if (declaration_ && qualified_name || (unqualified_name && enclosing_name)) {
Specification spec;
if (qualified_name) {
spec.qualified_name = *qualified_name;
@ -816,7 +814,7 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) {
cu_context_->reporter->MissingSection(".debug_line");
return;
}
const uint8_t *section_start = map_entry->second.first;
const char *section_start = map_entry->second.first;
uint64 section_length = map_entry->second.second;
if (offset >= section_length) {
cu_context_->reporter->BadLineInfoOffset(offset);

Просмотреть файл

@ -39,8 +39,6 @@
#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"
@ -86,7 +84,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// Add CONTENTS of size LENGTH to the section map as NAME.
void AddSectionToSectionMap(const string& name,
const uint8_t *contents,
const char* contents,
uint64 length);
// Clear the section map for testing.
@ -142,7 +140,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 uint8_t *program, uint64 length,
virtual void ReadProgram(const char *program, uint64 length,
Module *module, vector<Module::Line> *lines) = 0;
};

Просмотреть файл

@ -31,8 +31,6 @@
// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule.
#include <stdint.h>
#include <string>
#include <utility>
#include <vector>
@ -67,7 +65,7 @@ using ::testing::ValuesIn;
class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler {
public:
MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir));
MOCK_METHOD4(ReadProgram, void(const uint8_t *program, uint64 length,
MOCK_METHOD4(ReadProgram, void(const char* program, uint64 length,
Module *module, vector<Module::Line> *lines));
};
@ -113,7 +111,7 @@ class CUFixtureBase {
public:
explicit AppendLinesFunctor(
const vector<Module::Line> *lines) : lines_(lines) { }
void operator()(const uint8_t *program, uint64 length,
void operator()(const char *program, uint64 length,
Module *module, vector<Module::Line> *lines) {
lines->insert(lines->end(), lines_->begin(), lines_->end());
}
@ -287,7 +285,7 @@ class CUFixtureBase {
// Mock line program reader.
MockLineToModuleHandler line_reader_;
AppendLinesFunctor appender_;
static const uint8_t dummy_line_program_[];
static const char dummy_line_program_[];
static const size_t dummy_line_size_;
MockWarningReporter reporter_;
@ -304,7 +302,7 @@ class CUFixtureBase {
bool functions_filled_;
};
const uint8_t CUFixtureBase::dummy_line_program_[] = "lots of fun data";
const char CUFixtureBase::dummy_line_program_[] = "lots of fun data";
const size_t CUFixtureBase::dummy_line_size_ =
sizeof(CUFixtureBase::dummy_line_program_);
@ -377,7 +375,7 @@ void CUFixtureBase::ProcessStrangeAttributes(
handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f,
(DwarfForm) 0x829e038a,
0x50fddef44734fdecULL);
static const uint8_t buffer[10] = "frobynode";
static const char buffer[10] = "frobynode";
handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51,
(DwarfForm) 0x2f43b041,
buffer, sizeof(buffer));

Просмотреть файл

@ -39,7 +39,6 @@
#include <errno.h>
#include <fcntl.h>
#include <link.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -65,7 +64,6 @@
#include "common/linux/elfutils-inl.h"
#include "common/linux/elf_symbols_to_module.h"
#include "common/linux/file_id.h"
#include "common/memory.h"
#include "common/module.h"
#include "common/scoped_ptr.h"
#ifndef NO_STABS_SUPPORT
@ -89,18 +87,14 @@ using google_breakpad::DwarfLineToModule;
using google_breakpad::ElfClass;
using google_breakpad::ElfClass32;
using google_breakpad::ElfClass64;
using google_breakpad::FileID;
using google_breakpad::FindElfSectionByName;
using google_breakpad::GetOffset;
using google_breakpad::IsValidElf;
using google_breakpad::kDefaultBuildIdSize;
using google_breakpad::Module;
using google_breakpad::PageAllocator;
#ifndef NO_STABS_SUPPORT
using google_breakpad::StabsToModule;
#endif
using google_breakpad::scoped_ptr;
using google_breakpad::wasteful_vector;
// Define AARCH64 ELF architecture if host machine does not include this define.
#ifndef EM_AARCH64
@ -232,7 +226,7 @@ class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler {
void StartCompilationUnit(const string& compilation_dir) {
compilation_dir_ = compilation_dir;
}
void ReadProgram(const uint8_t *program, uint64 length,
void ReadProgram(const char* program, uint64 length,
Module* module, std::vector<Module::Line>* lines) {
DwarfLineToModule handler(module, compilation_dir_, lines);
dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
@ -270,8 +264,8 @@ bool LoadDwarf(const string& dwarf_filename,
string name = GetOffset<ElfClass, char>(elf_header,
section_names->sh_offset) +
section->sh_name;
const uint8_t *contents = GetOffset<ElfClass, uint8_t>(elf_header,
section->sh_offset);
const char* contents = GetOffset<ElfClass, char>(elf_header,
section->sh_offset);
file_context.AddSectionToSectionMap(name, contents, section->sh_size);
}
@ -280,7 +274,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 uint8_t *, uint64>& debug_info_section =
const std::pair<const char*, uint64>& debug_info_section =
debug_info_entry->second;
// This should never have been called if the file doesn't have a
// .debug_info section.
@ -294,8 +288,7 @@ bool LoadDwarf(const string& dwarf_filename,
// Make a Dwarf2Handler that drives the DIEHandler.
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET.
dwarf2reader::CompilationUnit reader(dwarf_filename,
file_context.section_map(),
dwarf2reader::CompilationUnit reader(file_context.section_map(),
offset,
&byte_reader,
&die_dispatcher);
@ -358,8 +351,8 @@ bool LoadDwarfCFI(const string& dwarf_filename,
dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
// Find the call frame information and its size.
const uint8_t *cfi =
GetOffset<ElfClass, uint8_t>(elf_header, section->sh_offset);
const char* cfi =
GetOffset<ElfClass, char>(elf_header, section->sh_offset);
size_t cfi_size = section->sh_size;
// Plug together the parser, handler, and their entourages.
@ -492,13 +485,12 @@ bool IsSameFile(const char* left_abspath, const string& right_path) {
// Read the .gnu_debuglink and get the debug file name. If anything goes
// wrong, return an empty string.
string ReadDebugLink(const uint8_t *debuglink,
string ReadDebugLink(const char* debuglink,
const size_t debuglink_size,
const bool big_endian,
const string& obj_file,
const std::vector<string>& debug_dirs) {
// Include '\0' + CRC32 (4 bytes).
size_t debuglink_len = strlen(reinterpret_cast<const char *>(debuglink)) + 5;
size_t debuglink_len = strlen(debuglink) + 5; // Include '\0' + CRC32.
debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes.
// Sanity check.
@ -519,8 +511,7 @@ string ReadDebugLink(const uint8_t *debuglink,
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 + "/" +
reinterpret_cast<const char *>(debuglink);
debuglink_path = debug_dir + "/" + 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,
@ -742,61 +733,32 @@ bool LoadSymbols(const string& obj_file,
}
// See if there are export symbols available.
const Shdr* symtab_section =
FindElfSectionByName<ElfClass>(".symtab", SHT_SYMTAB,
sections, names, names_end,
elf_header->e_shnum);
const Shdr* strtab_section =
FindElfSectionByName<ElfClass>(".strtab", SHT_STRTAB,
sections, names, names_end,
elf_header->e_shnum);
if (symtab_section && strtab_section) {
info->LoadedSection(".symtab");
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* symtab =
const uint8_t* dynsyms =
GetOffset<ElfClass, uint8_t>(elf_header,
symtab_section->sh_offset);
const uint8_t* strtab =
dynsym_section->sh_offset);
const uint8_t* dynstrs =
GetOffset<ElfClass, uint8_t>(elf_header,
strtab_section->sh_offset);
dynstr_section->sh_offset);
bool result =
ELFSymbolsToModule(symtab,
symtab_section->sh_size,
strtab,
strtab_section->sh_size,
ELFSymbolsToModule(dynsyms,
dynsym_section->sh_size,
dynstrs,
dynstr_section->sh_size,
big_endian,
ElfClass::kAddrSize,
module);
found_usable_info = found_usable_info || result;
} else {
// Look in dynsym only if full symbol table was not 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;
}
}
}
@ -882,9 +844,9 @@ bool LoadSymbols(const string& obj_file,
names_end, elf_header->e_shnum);
if (gnu_debuglink_section) {
if (!info->debug_dirs().empty()) {
const uint8_t *debuglink_contents =
GetOffset<ElfClass, uint8_t>(elf_header,
gnu_debuglink_section->sh_offset);
const char* debuglink_contents =
GetOffset<ElfClass, char>(elf_header,
gnu_debuglink_section->sh_offset);
string debuglink_file =
ReadDebugLink(debuglink_contents,
gnu_debuglink_section->sh_size,
@ -935,6 +897,25 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) {
}
}
// Format the Elf file identifier in IDENTIFIER as a UUID with the
// dashes removed.
string FormatIdentifier(unsigned char identifier[16]) {
char identifier_str[40];
google_breakpad::FileID::ConvertIdentifierToString(
identifier,
identifier_str,
sizeof(identifier_str));
string id_no_dash;
for (int i = 0; identifier_str[i] != '\0'; ++i)
if (identifier_str[i] != '-')
id_no_dash += identifier_str[i];
// Add an extra "0" by the end. PDB files on Windows have an 'age'
// number appended to the end of the file identifier; this isn't
// really used or necessary on other platforms, but be consistent.
id_no_dash += '0';
return id_no_dash;
}
// Return the non-directory portion of FILENAME: the portion after the
// last slash, or the whole filename if there are no slashes.
string BaseFileName(const string &filename) {
@ -977,12 +958,19 @@ bool SanitizeDebugFile(const typename ElfClass::Ehdr* debug_elf_header,
}
template<typename ElfClass>
bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
const string& obj_filename,
scoped_ptr<Module>& module) {
PageAllocator allocator;
wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize);
if (!FileID::ElfFileIdentifierFromMappedFile(elf_header, identifier)) {
bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
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;
unsigned char identifier[16];
if (!google_breakpad::FileID::ElfFileIdentifierFromMappedFile(elf_header,
identifier)) {
fprintf(stderr, "%s: unable to generate file identifier\n",
obj_filename.c_str());
return false;
@ -995,41 +983,17 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
return false;
}
string name = BaseFileName(obj_filename);
string os = "Linux";
// Add an extra "0" at the end. PDB files on Windows have an 'age'
// number appended to the end of the file identifier; this isn't
// really used or necessary on other platforms, but be consistent.
string id = FileID::ConvertIdentifierToUUIDString(identifier) + "0";
// This is just the raw Build ID in hex.
string code_id = FileID::ConvertIdentifierToString(identifier);
module.reset(new Module(name, os, architecture, id, code_id));
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) {
typedef typename ElfClass::Ehdr Ehdr;
*out_module = NULL;
scoped_ptr<Module> module;
if (!InitModuleForElfClass<ElfClass>(elf_header, obj_filename, module)) {
return false;
}
// Figure out what endianness this file is.
bool big_endian;
if (!ElfEndianness<ElfClass>(elf_header, &big_endian))
return false;
string name = BaseFileName(obj_filename);
string os = "Linux";
string id = FormatIdentifier(identifier);
LoadSymbolsInfo<ElfClass> info(debug_dirs);
scoped_ptr<Module> module(new Module(name, os, architecture, id));
if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header,
!debug_dirs.empty(), &info,
options, module.get())) {
@ -1044,9 +1008,7 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
if (!LoadELF(debuglink_file, &debug_map_wrapper,
reinterpret_cast<void**>(&debug_elf_header)) ||
!SanitizeDebugFile<ElfClass>(debug_elf_header, debuglink_file,
obj_filename,
module->architecture().c_str(),
big_endian)) {
obj_filename, architecture, big_endian)) {
return false;
}
@ -1104,45 +1066,6 @@ bool WriteSymbolFile(const string &obj_file,
return result;
}
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
// it and return false.
bool WriteSymbolFileHeader(const string& obj_file,
std::ostream &sym_stream) {
MmapWrapper map_wrapper;
void* elf_header = NULL;
if (!LoadELF(obj_file, &map_wrapper, &elf_header)) {
fprintf(stderr, "Could not load ELF file: %s\n", obj_file.c_str());
return false;
}
if (!IsValidElf(elf_header)) {
fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str());
return false;
}
int elfclass = ElfClass(elf_header);
scoped_ptr<Module> module;
if (elfclass == ELFCLASS32) {
if (!InitModuleForElfClass<ElfClass32>(
reinterpret_cast<const Elf32_Ehdr*>(elf_header), obj_file, module)) {
fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str());
return false;
}
} else if (elfclass == ELFCLASS64) {
if (!InitModuleForElfClass<ElfClass64>(
reinterpret_cast<const Elf64_Ehdr*>(elf_header), obj_file, module)) {
fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str());
return false;
}
} else {
fprintf(stderr, "Unsupported module file: %s\n", obj_file.c_str());
return false;
}
return module->Write(sym_stream, ALL_SYMBOL_DATA);
}
bool ReadSymbolData(const string& obj_file,
const std::vector<string>& debug_dirs,
const DumpOptions& options,

Просмотреть файл

@ -67,12 +67,6 @@ bool WriteSymbolFile(const string &obj_file,
const DumpOptions& options,
std::ostream &sym_stream);
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
// it and return false.
bool WriteSymbolFileHeader(const string& obj_file,
std::ostream &sym_stream);
// As above, but simply return the debugging information in MODULE
// instead of writing it to a stream. The caller owns the resulting
// Module object and must delete it when finished.

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -39,20 +39,15 @@
#include <string.h>
#include <algorithm>
#include <string>
#include "common/linux/elf_gnu_compat.h"
#include "common/linux/elfutils.h"
#include "common/linux/linux_libc_support.h"
#include "common/linux/memory_mapped_file.h"
#include "common/using_std_string.h"
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
// Used in a few places for backwards-compatibility.
const size_t kMDGUIDSize = sizeof(MDGUID);
FileID::FileID(const char* path) : path_(path) {}
// ELF note name and desc are 32-bits word padded.
@ -63,7 +58,7 @@ FileID::FileID(const char* path) : path_(path) {}
template<typename ElfClass>
static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
wasteful_vector<uint8_t>& identifier) {
uint8_t identifier[kMDGUIDSize]) {
typedef typename ElfClass::Nhdr Nhdr;
const void* section_end = reinterpret_cast<const char*>(section) + length;
@ -81,19 +76,21 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
return false;
}
const uint8_t* build_id = reinterpret_cast<const uint8_t*>(note_header) +
const char* build_id = reinterpret_cast<const char*>(note_header) +
sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz);
identifier.insert(identifier.end(),
build_id,
build_id + note_header->n_descsz);
// Copy as many bits of the build ID as will fit
// into the GUID space.
my_memset(identifier, 0, kMDGUIDSize);
memcpy(identifier, build_id,
std::min(kMDGUIDSize, (size_t)note_header->n_descsz));
return true;
}
// Attempt to locate a .note.gnu.build-id section in an ELF binary
// and copy it into |identifier|.
static bool FindElfBuildIDNote(const void* elf_mapped_base,
wasteful_vector<uint8_t>& identifier) {
// and copy as many bytes of it as will fit into |identifier|.
static bool FindElfBuildIDNote(const void *elf_mapped_base,
uint8_t identifier[kMDGUIDSize]) {
void* note_section;
size_t note_size;
int elfclass;
@ -119,10 +116,8 @@ static bool FindElfBuildIDNote(const void* elf_mapped_base,
// Attempt to locate the .text section of an ELF binary and generate
// a simple hash by XORing the first page worth of bytes into |identifier|.
static bool HashElfTextSection(const void* elf_mapped_base,
wasteful_vector<uint8_t>& identifier) {
identifier.resize(kMDGUIDSize);
static bool HashElfTextSection(const void *elf_mapped_base,
uint8_t identifier[kMDGUIDSize]) {
void* text_section;
size_t text_size;
if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS,
@ -131,9 +126,7 @@ static bool HashElfTextSection(const void* elf_mapped_base,
return false;
}
// Only provide |kMDGUIDSize| bytes to keep identifiers produced by this
// function backwards-compatible.
my_memset(&identifier[0], 0, kMDGUIDSize);
my_memset(identifier, 0, kMDGUIDSize);
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section);
const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096));
while (ptr < ptr_end) {
@ -146,7 +139,7 @@ static bool HashElfTextSection(const void* elf_mapped_base,
// static
bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
wasteful_vector<uint8_t>& identifier) {
uint8_t identifier[kMDGUIDSize]) {
// Look for a build id note first.
if (FindElfBuildIDNote(base, identifier))
return true;
@ -155,7 +148,7 @@ bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
return HashElfTextSection(base, identifier);
}
bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) {
bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
MemoryMappedFile mapped_file(path_.c_str(), 0);
if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)?
return false;
@ -163,26 +156,13 @@ bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) {
return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
}
// These three functions are not ever called in an unsafe context, so it's OK
// to allocate memory and use libc.
static string bytes_to_hex_string(const uint8_t* bytes, size_t count) {
string result;
for (unsigned int idx = 0; idx < count; ++idx) {
char buf[3];
snprintf(buf, sizeof(buf), "%02X", bytes[idx]);
result.append(buf);
}
return result;
}
// static
string FileID::ConvertIdentifierToUUIDString(
const wasteful_vector<uint8_t>& identifier) {
uint8_t identifier_swapped[kMDGUIDSize] = { 0 };
void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
char* buffer, int buffer_length) {
uint8_t identifier_swapped[kMDGUIDSize];
// Endian-ness swap to match dump processor expectation.
memcpy(identifier_swapped, &identifier[0],
std::min(kMDGUIDSize, identifier.size()));
memcpy(identifier_swapped, identifier, kMDGUIDSize);
uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped);
*data1 = htonl(*data1);
uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4);
@ -190,13 +170,22 @@ string FileID::ConvertIdentifierToUUIDString(
uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
*data3 = htons(*data3);
return bytes_to_hex_string(identifier_swapped, kMDGUIDSize);
}
int buffer_idx = 0;
for (unsigned int idx = 0;
(buffer_idx < buffer_length) && (idx < kMDGUIDSize);
++idx) {
int hi = (identifier_swapped[idx] >> 4) & 0x0F;
int lo = (identifier_swapped[idx]) & 0x0F;
// static
string FileID::ConvertIdentifierToString(
const wasteful_vector<uint8_t>& identifier) {
return bytes_to_hex_string(&identifier[0], identifier.size());
if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
buffer[buffer_idx++] = '-';
buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
}
// NULL terminate
buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
}
} // namespace google_breakpad

Просмотреть файл

@ -37,15 +37,10 @@
#include <string>
#include "common/linux/guid_creator.h"
#include "common/memory.h"
namespace google_breakpad {
// GNU binutils' ld defaults to 'sha1', which is 160 bits == 20 bytes,
// so this is enough to fit that, which most binaries will use.
// This is just a sensible default for auto_wasteful_vector so most
// callers can get away with stack allocation.
static const size_t kDefaultBuildIdSize = 20;
static const size_t kMDGUIDSize = sizeof(MDGUID);
class FileID {
public:
@ -53,29 +48,25 @@ class FileID {
~FileID() {}
// Load the identifier for the elf file path specified in the constructor into
// |identifier|.
//
// |identifier|. Return false if the identifier could not be created for the
// file.
// The current implementation will look for a .note.gnu.build-id
// section and use that as the file id, otherwise it falls back to
// XORing the first 4096 bytes of the .text section to generate an identifier.
bool ElfFileIdentifier(wasteful_vector<uint8_t>& identifier);
bool ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]);
// Load the identifier for the elf file mapped into memory at |base| into
// |identifier|. Return false if the identifier could not be created for this
// |identifier|. Return false if the identifier could not be created for the
// file.
static bool ElfFileIdentifierFromMappedFile(
const void* base,
wasteful_vector<uint8_t>& identifier);
static bool ElfFileIdentifierFromMappedFile(const void* base,
uint8_t identifier[kMDGUIDSize]);
// Convert the |identifier| data to a string. The string will
// be formatted as a UUID in all uppercase without dashes.
// (e.g., 22F065BBFC9C49F780FE26A7CEBD7BCE).
static std::string ConvertIdentifierToUUIDString(
const wasteful_vector<uint8_t>& identifier);
// Convert the entire |identifier| data to a hex string.
static std::string ConvertIdentifierToString(
const wasteful_vector<uint8_t>& identifier);
// Convert the |identifier| data to a NULL terminated string. The string will
// be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE).
// The |buffer| should be at least 37 bytes long to receive all of the data
// and termination. Shorter buffers will contain truncated data.
static void ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
char* buffer, int buffer_length);
private:
// Storage for the path specified

Просмотреть файл

@ -33,7 +33,6 @@
#include <stdlib.h>
#include <string>
#include <vector>
#include "common/linux/elf_gnu_compat.h"
#include "common/linux/elfutils.h"
@ -46,11 +45,13 @@
#include "breakpad_googletest_includes.h"
using namespace google_breakpad;
using google_breakpad::ElfClass32;
using google_breakpad::ElfClass64;
using google_breakpad::SafeReadLink;
using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::Notes;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::Section;
using std::vector;
using ::testing::Types;
namespace {
@ -63,8 +64,6 @@ void PopulateSection(Section* section, int size, int prime_number) {
section->Append(1, (i % prime_number) % 256);
}
typedef wasteful_vector<uint8_t> id_vector;
} // namespace
#ifndef __ANDROID__
@ -88,20 +87,19 @@ TEST(FileIDStripTest, StripSelf) {
sprintf(cmdline, "strip \"%s\"", templ.c_str());
ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline;
PageAllocator allocator;
id_vector identifier1(&allocator, kDefaultBuildIdSize);
id_vector identifier2(&allocator, kDefaultBuildIdSize);
uint8_t identifier1[sizeof(MDGUID)];
uint8_t identifier2[sizeof(MDGUID)];
FileID fileid1(exe_name);
EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1));
FileID fileid2(templ.c_str());
EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2));
string identifier_string1 =
FileID::ConvertIdentifierToUUIDString(identifier1);
string identifier_string2 =
FileID::ConvertIdentifierToUUIDString(identifier2);
EXPECT_EQ(identifier_string1, identifier_string2);
char identifier_string1[37];
char identifier_string2[37];
FileID::ConvertIdentifierToString(identifier1, identifier_string1,
37);
FileID::ConvertIdentifierToString(identifier2, identifier_string2,
37);
EXPECT_STREQ(identifier_string1, identifier_string2);
}
#endif // !__ANDROID__
@ -118,22 +116,8 @@ public:
elfdata = &elfdata_v[0];
}
id_vector make_vector() {
return id_vector(&allocator, kDefaultBuildIdSize);
}
template<size_t N>
string get_file_id(const uint8_t (&data)[N]) {
id_vector expected_identifier(make_vector());
expected_identifier.insert(expected_identifier.end(),
&data[0],
data + N);
return FileID::ConvertIdentifierToUUIDString(expected_identifier);
}
vector<uint8_t> elfdata_v;
uint8_t* elfdata;
PageAllocator allocator;
};
typedef Types<ElfClass32, ElfClass64> ElfClasses;
@ -141,8 +125,10 @@ typedef Types<ElfClass32, ElfClass64> ElfClasses;
TYPED_TEST_CASE(FileIDTest, ElfClasses);
TYPED_TEST(FileIDTest, ElfClass) {
uint8_t identifier[sizeof(MDGUID)];
const char expected_identifier_string[] =
"80808080808000000000008080808080";
"80808080-8080-0000-0000-008080808080";
char identifier_string[sizeof(expected_identifier_string)];
const size_t kTextSectionSize = 128;
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
@ -154,106 +140,58 @@ TYPED_TEST(FileIDTest, ElfClass) {
elf.Finish();
this->GetElfContents(elf);
id_vector identifier(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier));
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
EXPECT_EQ(expected_identifier_string, identifier_string);
FileID::ConvertIdentifierToString(identifier, identifier_string,
sizeof(identifier_string));
EXPECT_STREQ(expected_identifier_string, identifier_string);
}
TYPED_TEST(FileIDTest, BuildID) {
const uint8_t kExpectedIdentifierBytes[] =
const uint8_t kExpectedIdentifier[sizeof(MDGUID)] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13};
const string expected_identifier_string =
this->get_file_id(kExpectedIdentifierBytes);
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
char expected_identifier_string[] =
"00000000-0000-0000-0000-000000000000";
FileID::ConvertIdentifierToString(kExpectedIdentifier,
expected_identifier_string,
sizeof(expected_identifier_string));
uint8_t identifier[sizeof(MDGUID)];
char identifier_string[sizeof(expected_identifier_string)];
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
Section text(kLittleEndian);
text.Append(4096, 0);
elf.AddSection(".text", text, SHT_PROGBITS);
Notes notes(kLittleEndian);
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
sizeof(kExpectedIdentifierBytes));
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifier,
sizeof(kExpectedIdentifier));
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
elf.Finish();
this->GetElfContents(elf);
id_vector identifier(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier));
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
EXPECT_EQ(expected_identifier_string, identifier_string);
}
// Test that a build id note with fewer bytes than usual is handled.
TYPED_TEST(FileIDTest, BuildIDShort) {
const uint8_t kExpectedIdentifierBytes[] =
{0x00, 0x01, 0x02, 0x03};
const string expected_identifier_string =
this->get_file_id(kExpectedIdentifierBytes);
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
Section text(kLittleEndian);
text.Append(4096, 0);
elf.AddSection(".text", text, SHT_PROGBITS);
Notes notes(kLittleEndian);
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
sizeof(kExpectedIdentifierBytes));
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
elf.Finish();
this->GetElfContents(elf);
id_vector identifier(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier));
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
EXPECT_EQ(expected_identifier_string, identifier_string);
}
// Test that a build id note with more bytes than usual is handled.
TYPED_TEST(FileIDTest, BuildIDLong) {
const uint8_t kExpectedIdentifierBytes[] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
const string expected_identifier_string =
this->get_file_id(kExpectedIdentifierBytes);
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
Section text(kLittleEndian);
text.Append(4096, 0);
elf.AddSection(".text", text, SHT_PROGBITS);
Notes notes(kLittleEndian);
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
sizeof(kExpectedIdentifierBytes));
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
elf.Finish();
this->GetElfContents(elf);
id_vector identifier(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier));
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
EXPECT_EQ(expected_identifier_string, identifier_string);
FileID::ConvertIdentifierToString(identifier, identifier_string,
sizeof(identifier_string));
EXPECT_STREQ(expected_identifier_string, identifier_string);
}
TYPED_TEST(FileIDTest, BuildIDPH) {
const uint8_t kExpectedIdentifierBytes[] =
const uint8_t kExpectedIdentifier[sizeof(MDGUID)] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13};
const string expected_identifier_string =
this->get_file_id(kExpectedIdentifierBytes);
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
char expected_identifier_string[] =
"00000000-0000-0000-0000-000000000000";
FileID::ConvertIdentifierToString(kExpectedIdentifier,
expected_identifier_string,
sizeof(expected_identifier_string));
uint8_t identifier[sizeof(MDGUID)];
char identifier_string[sizeof(expected_identifier_string)];
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
Section text(kLittleEndian);
@ -262,25 +200,31 @@ TYPED_TEST(FileIDTest, BuildIDPH) {
Notes notes(kLittleEndian);
notes.AddNote(0, "Linux",
reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4);
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
sizeof(kExpectedIdentifierBytes));
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifier,
sizeof(kExpectedIdentifier));
int note_idx = elf.AddSection(".note", notes, SHT_NOTE);
elf.AddSegment(note_idx, note_idx, PT_NOTE);
elf.Finish();
this->GetElfContents(elf);
id_vector identifier(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier));
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
EXPECT_EQ(expected_identifier_string, identifier_string);
FileID::ConvertIdentifierToString(identifier, identifier_string,
sizeof(identifier_string));
EXPECT_STREQ(expected_identifier_string, identifier_string);
}
// Test to make sure two files with different text sections produce
// different hashes when not using a build id.
TYPED_TEST(FileIDTest, UniqueHashes) {
char identifier_string_1[] =
"00000000-0000-0000-0000-000000000000";
char identifier_string_2[] =
"00000000-0000-0000-0000-000000000000";
uint8_t identifier_1[sizeof(MDGUID)];
uint8_t identifier_2[sizeof(MDGUID)];
{
ELF elf1(EM_386, TypeParam::kClass, kLittleEndian);
Section foo_1(kLittleEndian);
@ -293,11 +237,10 @@ TYPED_TEST(FileIDTest, UniqueHashes) {
this->GetElfContents(elf1);
}
id_vector identifier_1(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier_1));
string identifier_string_1 =
FileID::ConvertIdentifierToUUIDString(identifier_1);
FileID::ConvertIdentifierToString(identifier_1, identifier_string_1,
sizeof(identifier_string_1));
{
ELF elf2(EM_386, TypeParam::kClass, kLittleEndian);
@ -311,28 +254,10 @@ TYPED_TEST(FileIDTest, UniqueHashes) {
this->GetElfContents(elf2);
}
id_vector identifier_2(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier_2));
string identifier_string_2 =
FileID::ConvertIdentifierToUUIDString(identifier_2);
FileID::ConvertIdentifierToString(identifier_2, identifier_string_2,
sizeof(identifier_string_2));
EXPECT_NE(identifier_string_1, identifier_string_2);
}
TYPED_TEST(FileIDTest, ConvertIdentifierToString) {
const uint8_t kIdentifierBytes[] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
const char* kExpected =
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F";
id_vector identifier(this->make_vector());
identifier.insert(identifier.end(),
kIdentifierBytes,
kIdentifierBytes + sizeof(kIdentifierBytes));
ASSERT_EQ(kExpected,
FileID::ConvertIdentifierToString(identifier));
EXPECT_STRNE(identifier_string_1, identifier_string_2);
}

Просмотреть файл

@ -72,9 +72,7 @@ bool HTTPUpload::SendRequest(const string &url,
// We may have been linked statically; if curl_easy_init is in the
// current binary, no need to search for a dynamic version.
void* curl_lib = dlopen(NULL, RTLD_NOW);
if (!CheckCurlLib(curl_lib)) {
fprintf(stderr,
"Failed to open curl lib from binary, use libcurl.so instead\n");
if (!curl_lib || dlsym(curl_lib, "curl_easy_init") == NULL) {
dlerror(); // Clear dlerror before attempting to open libraries.
dlclose(curl_lib);
curl_lib = NULL;
@ -115,10 +113,6 @@ bool HTTPUpload::SendRequest(const string &url,
*(void**) (&curl_easy_setopt) = dlsym(curl_lib, "curl_easy_setopt");
(*curl_easy_setopt)(curl, CURLOPT_URL, url.c_str());
(*curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent);
// Support multithread by disabling timeout handling, would get SIGSEGV with
// Curl_resolv_timeout in stack trace otherwise.
// See https://curl.haxx.se/libcurl/c/threadsafe.html
(*curl_easy_setopt)(curl, CURLOPT_NOSIGNAL, 1);
// Set proxy information if necessary.
if (!proxy.empty())
(*curl_easy_setopt)(curl, CURLOPT_PROXY, proxy.c_str());
@ -203,13 +197,6 @@ bool HTTPUpload::SendRequest(const string &url,
return err_code == CURLE_OK;
}
// static
bool HTTPUpload::CheckCurlLib(void* curl_lib) {
return curl_lib &&
dlsym(curl_lib, "curl_easy_init") &&
dlsym(curl_lib, "curl_easy_setopt");
}
// static
bool HTTPUpload::CheckParameters(const map<string, string> &parameters) {
for (map<string, string>::const_iterator pos = parameters.begin();

Просмотреть файл

@ -74,9 +74,6 @@ class HTTPUpload {
// any quote (") characters. Returns true if so.
static bool CheckParameters(const map<string, string> &parameters);
// Checks the curl_lib parameter points to a valid curl lib.
static bool CheckCurlLib(void* curl_lib);
// No instances of this class should be created.
// Disallow all constructors, destructors, and operator=.
HTTPUpload();

Просмотреть файл

@ -35,6 +35,6 @@
// the call fails, IGNORE_RET() can be used to mark the return code as ignored.
// This avoids spurious compiler warnings.
#define IGNORE_RET(x) do { if (x) {} } while (0)
#define IGNORE_RET(x) do { if (x); } while (0)
#endif // COMMON_LINUX_IGNORE_RET_H_

Просмотреть файл

@ -43,7 +43,7 @@ namespace google_breakpad {
class LibcurlWrapper {
public:
LibcurlWrapper();
virtual ~LibcurlWrapper();
~LibcurlWrapper();
virtual bool Init();
virtual bool SetProxy(const string& proxy_host,
const string& proxy_userpwd);

Просмотреть файл

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

Просмотреть файл

@ -1,155 +0,0 @@
// Copyright (c) 2011 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.
// symbol_upload.cc: implemented google_breakpad::sym_upload::Start, a helper
// function for linux symbol upload tool.
#include "common/linux/http_upload.h"
#include "common/linux/symbol_upload.h"
#include <assert.h>
#include <stdio.h>
#include <functional>
#include <vector>
namespace google_breakpad {
namespace sym_upload {
void TokenizeByChar(const string &source_string, int c,
std::vector<string> *results) {
assert(results);
string::size_type cur_pos = 0, next_pos = 0;
while ((next_pos = source_string.find(c, cur_pos)) != string::npos) {
if (next_pos != cur_pos)
results->push_back(source_string.substr(cur_pos, next_pos - cur_pos));
cur_pos = next_pos + 1;
}
if (cur_pos < source_string.size() && next_pos != cur_pos)
results->push_back(source_string.substr(cur_pos));
}
//=============================================================================
// Parse out the module line which have 5 parts.
// MODULE <os> <cpu> <uuid> <module-name>
bool ModuleDataForSymbolFile(const string &file,
std::vector<string> *module_parts) {
assert(module_parts);
const size_t kModulePartNumber = 5;
FILE* fp = fopen(file.c_str(), "r");
if (fp) {
char buffer[1024];
if (fgets(buffer, sizeof(buffer), fp)) {
string line(buffer);
string::size_type line_break_pos = line.find_first_of('\n');
if (line_break_pos == string::npos) {
assert(0 && "The file is invalid!");
fclose(fp);
return false;
}
line.resize(line_break_pos);
const char kDelimiter = ' ';
TokenizeByChar(line, kDelimiter, module_parts);
if (module_parts->size() != kModulePartNumber)
module_parts->clear();
}
fclose(fp);
}
return module_parts->size() == kModulePartNumber;
}
//=============================================================================
string CompactIdentifier(const string &uuid) {
std::vector<string> components;
TokenizeByChar(uuid, '-', &components);
string result;
for (size_t i = 0; i < components.size(); ++i)
result += components[i];
return result;
}
//=============================================================================
void Start(Options *options) {
std::map<string, string> parameters;
options->success = false;
std::vector<string> module_parts;
if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) {
fprintf(stderr, "Failed to parse symbol file!\n");
return;
}
string compacted_id = CompactIdentifier(module_parts[3]);
// Add parameters
if (!options->version.empty())
parameters["version"] = options->version;
// MODULE <os> <cpu> <uuid> <module-name>
// 0 1 2 3 4
parameters["os"] = module_parts[1];
parameters["cpu"] = module_parts[2];
parameters["debug_file"] = module_parts[4];
parameters["code_file"] = module_parts[4];
parameters["debug_identifier"] = compacted_id;
std::map<string, string> files;
files["symbol_file"] = options->symbolsPath;
string response, error;
long response_code;
bool success = HTTPUpload::SendRequest(options->uploadURLStr,
parameters,
files,
options->proxy,
options->proxy_user_pwd,
"",
&response,
&response_code,
&error);
if (!success) {
printf("Failed to send symbol file: %s\n", error.c_str());
printf("Response code: %ld\n", response_code);
printf("Response:\n");
printf("%s\n", response.c_str());
} else if (response_code == 0) {
printf("Failed to send symbol file: No response code\n");
} else if (response_code != 200) {
printf("Failed to send symbol file: Response code %ld\n", response_code);
printf("Response:\n");
printf("%s\n", response.c_str());
} else {
printf("Successfully sent the symbol file.\n");
}
options->success = success;
}
} // namespace sym_upload
} // namespace google_breakpad

Просмотреть файл

@ -1,59 +0,0 @@
// -*- mode: c++ -*-
// Copyright (c) 2011 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.
// symbol_upload.h: helper functions for linux symbol upload tool.
#ifndef COMMON_LINUX_SYMBOL_UPLOAD_H_
#define COMMON_LINUX_SYMBOL_UPLOAD_H_
#include <string>
#include "common/using_std_string.h"
namespace google_breakpad {
namespace sym_upload {
typedef struct {
string symbolsPath;
string uploadURLStr;
string proxy;
string proxy_user_pwd;
string version;
bool success;
} Options;
// Starts upload to symbol server with options.
void Start(Options* options);
} // namespace sym_upload
} // namespace google_breakpad
#endif // COMMON_LINUX_SYMBOL_UPLOAD_H_

Просмотреть файл

@ -213,10 +213,8 @@ void ELF::Finish() {
SymbolTable::SymbolTable(Endianness endianness,
size_t addr_size,
StringTable& table) : Section(endianness),
addr_size_(addr_size),
table_(table) {
#ifndef NDEBUG
addr_size_ = addr_size;
#endif
assert(addr_size_ == 4 || addr_size_ == 8);
}

Просмотреть файл

@ -173,9 +173,7 @@ class SymbolTable : public Section {
uint64_t size, unsigned info, uint16_t shndx);
private:
#ifndef NDEBUG
size_t addr_size_;
#endif
StringTable& table_;
};

Просмотреть файл

@ -27,6 +27,12 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ARCHS = $(ARCHS_STANDARD_32_64_BIT)
SDKROOT = macosx10.5
GCC_VERSION = 4.2
GCC_VERSION[sdk=macosx10.4][arch=*] = 4.0
GCC_C_LANGUAGE_STANDARD = c99
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
@ -35,10 +41,7 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = NO
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
GCC_WARN_ABOUT_RETURN_TYPE = YES
GCC_WARN_MISSING_PARENTHESES = YES
// Once https://bugs.chromium.org/p/google-breakpad/issues/detail?id=697
// is fixed this should be reenabled.
//GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
GCC_WARN_ABOUT_MISSING_NEWLINE = YES
GCC_WARN_SIGN_COMPARE = YES
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
@ -48,5 +51,6 @@ GCC_WARN_UNUSED_VARIABLE = YES
GCC_TREAT_WARNINGS_AS_ERRORS = YES
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
DEBUG_INFORMATION_FORMAT[sdk=macosx10.4][arch=*] = stabs
ALWAYS_SEARCH_USER_PATHS = NO

Просмотреть файл

@ -30,65 +30,6 @@
#import "HTTPMultipartUpload.h"
#import "GTMDefines.h"
// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been
// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it
// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when
// using those SDKs.
static NSString *PercentEncodeNSString(NSString *key) {
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
(defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
defined(MAC_OS_X_VERSION_10_11) && \
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
return [key stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet URLQueryAllowedCharacterSet]];
#else
return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
#endif
}
// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
// it using -[NSURLSession dataTaskWithRequest:completionHandler:] when using
// those SDKs.
static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
NSURLResponse **out_response,
NSError **out_error) {
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
(defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
defined(MAC_OS_X_VERSION_10_11) && \
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
__block NSData* result = nil;
__block NSError* error = nil;
__block NSURLResponse* response = nil;
dispatch_semaphore_t wait_semaphone = dispatch_semaphore_create(0);
[[[NSURLSession sharedSession]
dataTaskWithRequest:req
completionHandler:^(NSData *data,
NSURLResponse *resp,
NSError *err) {
if (out_error)
error = [err retain];
if (out_response)
response = [resp retain];
if (err == nil)
result = [data retain];
dispatch_semaphore_signal(wait_semaphone);
}] resume];
dispatch_semaphore_wait(wait_semaphone, DISPATCH_TIME_FOREVER);
dispatch_release(wait_semaphone);
if (out_error)
*out_error = [error autorelease];
if (out_response)
*out_response = [response autorelease];
return [result autorelease];
#else
return [NSURLConnection sendSynchronousRequest:req
returningResponse:out_response
error:out_error];
#endif
}
@interface HTTPMultipartUpload(PrivateMethods)
- (NSString *)multipartBoundary;
// Each of the following methods will append the starting multipart boundary,
@ -111,7 +52,8 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
//=============================================================================
- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value {
NSString *escaped = PercentEncodeNSString(key);
NSString *escaped =
[key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *fmt =
@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
@ -122,7 +64,8 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
//=============================================================================
- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name {
NSMutableData *data = [NSMutableData data];
NSString *escaped = PercentEncodeNSString(name);
NSString *escaped =
[name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; "
"filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped];
@ -253,7 +196,9 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
[[req HTTPBody] writeToURL:[req URL] options:0 error:error];
} else {
NSURLResponse *response = nil;
data = SendSynchronousNSURLRequest(req, &response, error);
data = [NSURLConnection sendSynchronousRequest:req
returningResponse:&response
error:error];
response_ = (NSHTTPURLResponse *)[response retain];
}
[req release];

Просмотреть файл

@ -41,7 +41,6 @@
#include <libgen.h>
#include <mach-o/arch.h>
#include <mach-o/fat.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
@ -317,7 +316,7 @@ class DumpSymbols::DumperLineToModule:
compilation_dir_ = compilation_dir;
}
void ReadProgram(const uint8_t *program, uint64 length,
void ReadProgram(const char *program, uint64 length,
Module *module, vector<Module::Line> *lines) {
DwarfLineToModule handler(module, compilation_dir_, lines);
dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
@ -328,65 +327,6 @@ class DumpSymbols::DumperLineToModule:
dwarf2reader::ByteReader *byte_reader_; // WEAK
};
bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
// Select an object file, if SetArchitecture hasn't been called to set one
// explicitly.
if (!selected_object_file_) {
// If there's only one architecture, that's the one.
if (object_files_.size() == 1)
selected_object_file_ = &object_files_[0];
else {
// Look for an object file whose architecture matches our own.
const NXArchInfo *local_arch = NXGetLocalArchInfo();
if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
fprintf(stderr, "%s: object file contains more than one"
" architecture, none of which match the current"
" architecture; specify an architecture explicitly"
" with '-a ARCH' to resolve the ambiguity\n",
object_filename_.c_str());
return false;
}
}
}
assert(selected_object_file_);
// Find the name of the selected file's architecture, to appear in
// the MODULE record and in error messages.
const NXArchInfo *selected_arch_info =
google_breakpad::BreakpadGetArchInfoFromCpuType(
selected_object_file_->cputype, selected_object_file_->cpusubtype);
const char *selected_arch_name = selected_arch_info->name;
if (strcmp(selected_arch_name, "i386") == 0)
selected_arch_name = "x86";
// Produce a name to use in error messages that includes the
// filename, and the architecture, if there is more than one.
selected_object_name_ = object_filename_;
if (object_files_.size() > 1) {
selected_object_name_ += ", architecture ";
selected_object_name_ + selected_arch_name;
}
// Compute a module name, to appear in the MODULE record.
string module_name = object_filename_;
module_name = basename(&module_name[0]);
// Choose an identifier string, to appear in the MODULE record.
string identifier = Identifier();
if (identifier.empty())
return false;
identifier += "0";
// Create a module to hold the debugging information.
module.reset(new Module(module_name,
"mac",
selected_arch_name,
identifier));
return true;
}
bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
const mach_o::Reader &macho_reader,
const mach_o::SectionMap &dwarf_sections,
@ -406,7 +346,7 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
it != dwarf_sections.end(); ++it) {
file_context.AddSectionToSectionMap(
it->first,
it->second.contents.start,
reinterpret_cast<const char *>(it->second.contents.start),
it->second.contents.Size());
}
@ -414,7 +354,7 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
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 uint8_t *, uint64>& debug_info_section =
const std::pair<const char*, uint64>& debug_info_section =
debug_info_entry->second;
// There had better be a __debug_info section!
if (!debug_info_section.first) {
@ -437,8 +377,7 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
// Make a Dwarf2Handler that drives our DIEHandler.
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET.
dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_,
file_context.section_map(),
dwarf2reader::CompilationUnit dwarf_reader(file_context.section_map(),
offset,
&byte_reader,
&die_dispatcher);
@ -485,7 +424,7 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
}
// Find the call frame information and its size.
const uint8_t *cfi = section.contents.start;
const char *cfi = reinterpret_cast<const char *>(section.contents.start);
size_t cfi_size = section.contents.Size();
// Plug together the parser, handler, and their entourages.
@ -595,9 +534,61 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
}
bool DumpSymbols::ReadSymbolData(Module** out_module) {
scoped_ptr<Module> module;
if (!CreateEmptyModule(module))
// Select an object file, if SetArchitecture hasn't been called to set one
// explicitly.
if (!selected_object_file_) {
// If there's only one architecture, that's the one.
if (object_files_.size() == 1)
selected_object_file_ = &object_files_[0];
else {
// Look for an object file whose architecture matches our own.
const NXArchInfo *local_arch = NXGetLocalArchInfo();
if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
fprintf(stderr, "%s: object file contains more than one"
" architecture, none of which match the current"
" architecture; specify an architecture explicitly"
" with '-a ARCH' to resolve the ambiguity\n",
object_filename_.c_str());
return false;
}
}
}
assert(selected_object_file_);
// Find the name of the selected file's architecture, to appear in
// the MODULE record and in error messages.
const NXArchInfo *selected_arch_info =
google_breakpad::BreakpadGetArchInfoFromCpuType(
selected_object_file_->cputype, selected_object_file_->cpusubtype);
const char *selected_arch_name = selected_arch_info->name;
if (strcmp(selected_arch_name, "i386") == 0)
selected_arch_name = "x86";
// Produce a name to use in error messages that includes the
// filename, and the architecture, if there is more than one.
selected_object_name_ = object_filename_;
if (object_files_.size() > 1) {
selected_object_name_ += ", architecture ";
selected_object_name_ + selected_arch_name;
}
// Compute a module name, to appear in the MODULE record.
string module_name = object_filename_;
module_name = basename(&module_name[0]);
// Choose an identifier string, to appear in the MODULE record.
string identifier = Identifier();
if (identifier.empty())
return false;
identifier += "0";
// Create a module to hold the debugging information.
scoped_ptr<Module> module(new Module(module_name,
"mac",
selected_arch_name,
identifier));
// Parse the selected object file.
mach_o::Reader::Reporter reporter(selected_object_name_);
@ -632,15 +623,4 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
return false;
}
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
// it and return false.
bool DumpSymbols::WriteSymbolFileHeader(std::ostream &stream) {
scoped_ptr<Module> module;
if (!CreateEmptyModule(module))
return false;
return module->Write(stream, symbol_data_);
}
} // namespace google_breakpad

Просмотреть файл

@ -112,11 +112,6 @@ class DumpSymbols {
// return false.
bool WriteSymbolFile(std::ostream &stream);
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
// it and return false.
bool WriteSymbolFileHeader(std::ostream &stream);
// As above, but simply return the debugging information in module
// instead of writing it to a stream. The caller owns the resulting
// module object and must delete it when finished.
@ -135,10 +130,6 @@ class DumpSymbols {
// Return an identifier string for the file this DumpSymbols is dumping.
std::string Identifier();
// Creates an empty module object.
bool CreateEmptyModule(scoped_ptr<Module>& module);
// Read debugging information from |dwarf_sections|, which was taken from
// |macho_reader|, and add it to |module|. On success, return true;
// on failure, report the problem and return false.

Просмотреть файл

@ -181,15 +181,15 @@ void Reader::Reporter::LoadCommandRegionTruncated() {
void Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i,
LoadCommandType type) {
fprintf(stderr, "%s: file's header claims there are %zu"
" load commands, but load command #%zu",
fprintf(stderr, "%s: file's header claims there are %ld"
" load commands, but load command #%ld",
filename_.c_str(), claimed, i);
if (type) fprintf(stderr, ", of type %d,", type);
fprintf(stderr, " extends beyond the end of the load command region\n");
}
void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) {
fprintf(stderr, "%s: the contents of load command #%zu, of type %d,"
fprintf(stderr, "%s: the contents of load command #%ld, of type %d,"
" extend beyond the size given in the load command's header\n",
filename_.c_str(), i, type);
}

Просмотреть файл

@ -29,7 +29,6 @@ if CONFIG['MOZ_CRASHREPORTER']:
HOST_CXXFLAGS += [
'-O2',
'-g',
'-stdlib=libc++',
]
HostLibrary('host_breakpad_mac_common_s')

Просмотреть файл

@ -26,6 +26,10 @@
#import "GTMObjC2Runtime.h"
#import "GTMUnitTestDevLog.h"
#if !GTM_IPHONE_SDK
#import "GTMGarbageCollection.h"
#endif // !GTM_IPHONE_SDK
#if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST
#import <stdarg.h>
@ -426,3 +430,71 @@ static int MethodSort(id a, id b, void *context) {
}
@end
// Leak detection
#if !GTM_IPHONE_DEVICE && !GTM_SUPPRESS_RUN_LEAKS_HOOK
// Don't want to get leaks on the iPhone Device as the device doesn't
// have 'leaks'. The simulator does though.
// COV_NF_START
// We don't have leak checking on by default, so this won't be hit.
static void _GTMRunLeaks(void) {
// This is an atexit handler. It runs leaks for us to check if we are
// leaking anything in our tests.
const char* cExclusionsEnv = getenv("GTM_LEAKS_SYMBOLS_TO_IGNORE");
NSMutableString *exclusions = [NSMutableString string];
if (cExclusionsEnv) {
NSString *exclusionsEnv = [NSString stringWithUTF8String:cExclusionsEnv];
NSArray *exclusionsArray = [exclusionsEnv componentsSeparatedByString:@","];
NSString *exclusion;
NSCharacterSet *wcSet = [NSCharacterSet whitespaceCharacterSet];
GTM_FOREACH_OBJECT(exclusion, exclusionsArray) {
exclusion = [exclusion stringByTrimmingCharactersInSet:wcSet];
[exclusions appendFormat:@"-exclude \"%@\" ", exclusion];
}
}
// Clearing out DYLD_ROOT_PATH because iPhone Simulator framework libraries
// are different from regular OS X libraries and leaks will fail to run
// because of missing symbols. Also capturing the output of leaks and then
// pipe rather than a direct pipe, because otherwise if leaks failed,
// the system() call will still be successful. Bug:
// http://code.google.com/p/google-toolbox-for-mac/issues/detail?id=56
NSString *string
= [NSString stringWithFormat:
@"LeakOut=`DYLD_ROOT_PATH='' /usr/bin/leaks %@%d` &&"
@"echo \"$LeakOut\"|/usr/bin/sed -e 's/Leak: /Leaks:0: warning: Leak /'",
exclusions, getpid()];
int ret = system([string UTF8String]);
if (ret) {
fprintf(stderr,
"%s:%d: Error: Unable to run leaks. 'system' returned: %d\n",
__FILE__, __LINE__, ret);
fflush(stderr);
}
}
// COV_NF_END
static __attribute__((constructor)) void _GTMInstallLeaks(void) {
BOOL checkLeaks = YES;
#if !GTM_IPHONE_SDK
checkLeaks = GTMIsGarbageCollectionEnabled() ? NO : YES;
#endif // !GTM_IPHONE_SDK
if (checkLeaks) {
checkLeaks = getenv("GTM_ENABLE_LEAKS") ? YES : NO;
if (checkLeaks) {
// COV_NF_START
// We don't have leak checking on by default, so this won't be hit.
fprintf(stderr, "Leak Checking Enabled\n");
fflush(stderr);
int ret = atexit(&_GTMRunLeaks);
// To avoid unused variable warning when _GTMDevAssert is stripped.
(void)ret;
_GTMDevAssert(ret == 0,
@"Unable to install _GTMRunLeaks as an atexit handler (%d)",
errno);
// COV_NF_END
}
}
}
#endif // !GTM_IPHONE_DEVICE && !GTM_SUPPRESS_RUN_LEAKS_HOOK

Просмотреть файл

@ -44,6 +44,7 @@
#ifdef __APPLE__
#define sys_mmap mmap
#define sys_mmap2 mmap
#define sys_munmap munmap
#define MAP_ANONYMOUS MAP_ANON
#else
@ -63,8 +64,7 @@ class PageAllocator {
: page_size_(getpagesize()),
last_(NULL),
current_page_(NULL),
page_offset_(0),
pages_allocated_(0) {
page_offset_(0) {
}
~PageAllocator() {
@ -112,12 +112,16 @@ class PageAllocator {
return false;
}
unsigned long pages_allocated() { return pages_allocated_; }
private:
uint8_t *GetNPages(size_t num_pages) {
#if defined(__x86_64__) || defined(__aarch64__) || defined(__aarch64__) || \
((defined(__mips__) && _MIPS_SIM == _ABI64))
void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#else
void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#endif
if (a == MAP_FAILED)
return NULL;
@ -132,8 +136,6 @@ class PageAllocator {
header->num_pages = num_pages;
last_ = header;
pages_allocated_ += num_pages;
return reinterpret_cast<uint8_t*>(a);
}
@ -155,7 +157,6 @@ class PageAllocator {
PageHeader *last_;
uint8_t *current_page_;
size_t page_offset_;
unsigned long pages_allocated_;
};
// Wrapper to use with STL containers
@ -164,30 +165,12 @@ struct PageStdAllocator : public std::allocator<T> {
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;
explicit PageStdAllocator(PageAllocator& allocator) : allocator_(allocator),
stackdata_(NULL),
stackdata_size_(0)
{}
explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {}
template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other)
: allocator_(other.allocator_),
stackdata_(nullptr),
stackdata_size_(0)
{}
explicit PageStdAllocator(PageAllocator& allocator,
pointer stackdata,
size_type stackdata_size) : allocator_(allocator),
stackdata_(stackdata),
stackdata_size_(stackdata_size)
{}
: allocator_(other.allocator_) {}
inline pointer allocate(size_type n, const void* = 0) {
const size_type size = sizeof(T) * n;
if (size <= stackdata_size_) {
return stackdata_;
}
return static_cast<pointer>(allocator_.Alloc(size));
return static_cast<pointer>(allocator_.Alloc(sizeof(T) * n));
}
inline void deallocate(pointer, size_type) {
@ -205,8 +188,6 @@ struct PageStdAllocator : public std::allocator<T> {
template<typename Other> friend struct PageStdAllocator;
PageAllocator& allocator_;
pointer stackdata_;
size_type stackdata_size_;
};
// A wasteful vector is a std::vector, except that it allocates memory from a
@ -219,24 +200,6 @@ class wasteful_vector : public std::vector<T, PageStdAllocator<T> > {
: std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) {
std::vector<T, PageStdAllocator<T> >::reserve(size_hint);
}
protected:
wasteful_vector(PageStdAllocator<T> allocator)
: std::vector<T, PageStdAllocator<T> >(allocator) {}
};
// auto_wasteful_vector allocates space on the stack for N entries to avoid
// using the PageAllocator for small data, while still allowing for larger data.
template<class T, unsigned int N>
class auto_wasteful_vector : public wasteful_vector<T> {
T stackdata_[N];
public:
auto_wasteful_vector(PageAllocator* allocator)
: wasteful_vector<T>(
PageStdAllocator<T>(*allocator,
&stackdata_[0],
sizeof(stackdata_))) {
std::vector<T, PageStdAllocator<T> >::reserve(N);
}
};
} // namespace google_breakpad

Просмотреть файл

@ -38,13 +38,11 @@ typedef testing::Test PageAllocatorTest;
TEST(PageAllocatorTest, Setup) {
PageAllocator allocator;
EXPECT_EQ(0U, allocator.pages_allocated());
}
TEST(PageAllocatorTest, SmallObjects) {
PageAllocator allocator;
EXPECT_EQ(0U, allocator.pages_allocated());
for (unsigned i = 1; i < 1024; ++i) {
uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
ASSERT_FALSE(p == NULL);
@ -55,10 +53,8 @@ TEST(PageAllocatorTest, SmallObjects) {
TEST(PageAllocatorTest, LargeObject) {
PageAllocator allocator;
EXPECT_EQ(0U, allocator.pages_allocated());
uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000));
ASSERT_FALSE(p == NULL);
EXPECT_EQ(3U, allocator.pages_allocated());
for (unsigned i = 1; i < 10; ++i) {
uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
ASSERT_FALSE(p == NULL);
@ -79,7 +75,6 @@ TEST(WastefulVectorTest, Setup) {
TEST(WastefulVectorTest, Simple) {
PageAllocator allocator_;
EXPECT_EQ(0U, allocator_.pages_allocated());
wasteful_vector<unsigned> v(&allocator_);
for (unsigned i = 0; i < 256; ++i) {
@ -89,7 +84,6 @@ TEST(WastefulVectorTest, Simple) {
}
ASSERT_FALSE(v.empty());
ASSERT_EQ(v.size(), 256u);
EXPECT_EQ(1U, allocator_.pages_allocated());
for (unsigned i = 0; i < 256; ++i)
ASSERT_EQ(v[i], i);
}
@ -97,28 +91,7 @@ TEST(WastefulVectorTest, Simple) {
TEST(WastefulVectorTest, UsesPageAllocator) {
PageAllocator allocator_;
wasteful_vector<unsigned> v(&allocator_);
EXPECT_EQ(1U, allocator_.pages_allocated());
v.push_back(1);
ASSERT_TRUE(allocator_.OwnsPointer(&v[0]));
}
TEST(WastefulVectorTest, AutoWastefulVector) {
PageAllocator allocator_;
EXPECT_EQ(0U, allocator_.pages_allocated());
auto_wasteful_vector<unsigned, 4> v(&allocator_);
EXPECT_EQ(0U, allocator_.pages_allocated());
v.push_back(1);
EXPECT_EQ(0U, allocator_.pages_allocated());
EXPECT_FALSE(allocator_.OwnsPointer(&v[0]));
v.resize(4);
EXPECT_EQ(0U, allocator_.pages_allocated());
EXPECT_FALSE(allocator_.OwnsPointer(&v[0]));
v.resize(10);
EXPECT_EQ(1U, allocator_.pages_allocated());
EXPECT_TRUE(allocator_.OwnsPointer(&v[0]));
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -43,10 +43,6 @@ if CONFIG['OS_ARCH'] != 'WINNT':
'module.cc',
'string_conversion.cc',
]
if CONFIG['OS_ARCH'] == 'Darwin':
HOST_CXXFLAGS += [
'-stdlib=libc++',
]
HOST_CXXFLAGS += [
'-O2',
'-g',

Просмотреть файл

@ -1,43 +0,0 @@
// Copyright (c) 2016, 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 GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H
#define GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H
#include <stdio.h>
#if defined(_MSC_VER) && MSC_VER < 1900
#include <basetsd.h>
#define snprintf _snprintf
typedef SSIZE_T ssize_t;
#endif
#endif // GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H

Просмотреть файл

@ -210,7 +210,7 @@ bool FindAndLoadOmapTable(const wchar_t* name,
reinterpret_cast<BYTE*>(&table->at(0)),
&count_read))) {
fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading "
"data from stream \"%ws\"\n", name);
"data from stream \"%ws\"\n");
return false;
}

Просмотреть файл

@ -3,9 +3,6 @@
/* Define to 1 if you have the <a.out.h> header file. */
#undef HAVE_A_OUT_H
/* define if the compiler supports basic C++11 syntax */
#undef HAVE_CXX11
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H

Просмотреть файл

@ -40,12 +40,6 @@
#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && \
!defined(__STDC_FORMAT_MACROS)
#error "inttypes.h has already been included before this header file, but "
#error "without __STDC_FORMAT_MACROS defined."
#endif
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif /* __STDC_FORMAT_MACROS */

Просмотреть файл

@ -157,20 +157,4 @@ enum MDMIPSRegisterNumbers {
MD_CONTEXT_MIPS_FLOATING_POINT \
MD_CONTEXT_MIPS_DSP)
/**
* Breakpad defines for MIPS64
*/
#define MD_CONTEXT_MIPS64 0x00080000
#define MD_CONTEXT_MIPS64_INTEGER (MD_CONTEXT_MIPS64 | 0x00000002)
#define MD_CONTEXT_MIPS64_FLOATING_POINT (MD_CONTEXT_MIPS64 | 0x00000004)
#define MD_CONTEXT_MIPS64_DSP (MD_CONTEXT_MIPS64 | 0x00000008)
#define MD_CONTEXT_MIPS64_FULL (MD_CONTEXT_MIPS64_INTEGER | \
MD_CONTEXT_MIPS64_FLOATING_POINT | \
MD_CONTEXT_MIPS64_DSP)
#define MD_CONTEXT_MIPS64_ALL (MD_CONTEXT_MIPS64_INTEGER | \
MD_CONTEXT_MIPS64_FLOATING_POINT \
MD_CONTEXT_MIPS64_DSP)
#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__

Просмотреть файл

@ -100,9 +100,6 @@ typedef enum {
/* STATUS_STACK_BUFFER_OVERRUN */
MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION = 0xc0000374,
/* STATUS_HEAP_CORRUPTION */
MD_EXCEPTION_OUT_OF_MEMORY = 0xe0000008,
/* Exception thrown by Chromium allocators to indicate OOM.
See base/process/memory.h in Chromium for rationale. */
MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363
/* Per http://support.microsoft.com/kb/185294,
generated by Visual C++ compiler */

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше