20 Commits

Author SHA1 Message Date
andresantoso@chromium.org
b96b967685 Merge r1375 from trunk for M38 release.
git-svn-id: http://google-breakpad.googlecode.com/svn/branches/chrome_38@1383 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-09-19 20:25:37 +00:00
andresantoso@chromium.org
71ff627265 Branching for M38 release.
git-svn-id: http://google-breakpad.googlecode.com/svn/branches/chrome_38@1382 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-09-19 20:15:16 +00:00
rsesek@chromium.org
e2fffff1a4 In Mac dump_syms, allow reading debug data out of both the Mach-O file and the dSYM.
This adds a new |-g <dSYM path>| flag to dump_syms, to specify the dSYM path for
the target Mach-O argument. The UUIDs and architectures of the two paths must
match in order to dump symbols for this "split module."

This reason for this is that for x86_64 binaries on OS X, the CFI data is stored
in the __TEXT,__eh_frame segment of the Mach-O file, and the data is not copied
into the dSYM by dsymutil.  Therefore, just dumping the dSYM doesn't yield CFI
data for x86_64 files, and both the dSYM and the Mach-O file must be dumped in
order to produce a complete Breakpad symbol file. For i386 binaries, the CFI data
is stored in the __DWARF,__debug_frame segment, which is part of the dSYM, so
this isn't necessary.

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

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1359 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-25 18:18:59 +00:00
rsesek@chromium.org
dab50e6f6e Add GYP build for the src/tools directory on Mac and Linux.
This GYP-ifies the src/processor and src/common directories on those platforms
as well. The Makefile build uses much more granular unittest executables, so
the new processor_unittests does not yet link because of multiple main() symbols,
but this will be fixed later.

Update issue 575

R=mark@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1358 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-24 15:22:51 +00:00
mark@chromium.org
c41b7fc414 Annotate PageAllocator for MSan.
PageAllocator maps memory via sys_mmap(), implemented in
linux_syscall_support.h. We need to explicitly inform MSan that this memory is
initialized.

Patch by Sergey Matveev <earthdok@chromium.org>

BUG=chromium:394028

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


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1356 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-22 14:24:21 +00:00
rmcilroy@chromium.org
561f818735 Chrome on Android now supports loading the shared library directly from the APK file.
This patch makes two changes to breakpad to enable crash reporting to work correctly when the library is inside another file (an archive):

- Do not filter mappings which map an executable at a non-zero offset.
- If such an executable is mapped look in the ELF information for the
shared object name and use that name in the minidump.

Note this change doesn't care about the archive format and isn't Android
specific (though loading the shared library this way is currently only done on Android).

BUG=390618
R=thestig@chromium.org

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

Patch from Anton Carver <anton@chromium.org>.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1355 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-22 11:34:11 +00:00
ivanpe@chromium.org
b7aa202b54 Both std::tr1::unordered_set and std::unordered_set are not allowed in
Google at this moment.  This change is implementing a workaround that
allows switching to hash_set and hash_map.

R=mark@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1354 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-21 18:27:43 +00:00
rmcilroy@chromium.org
8703844b3c [Android]: Remove __system_property_get(ro.build.fingerprint) from WriteOSInformation.
__system_property_get has been removed from the Android NDK for 'L' so Breakpad
no longer links. This CL just removes the call in WriteOSInformation because
Chrome already passes the build fingerprint as a crash key called "android_build_fp" in the crash report HTTP POST message.

BUG=394841,393903
R=mark@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1351 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-18 13:14:37 +00:00
rsesek@chromium.org
6c57bc19a5 Add frame pointer recovery to the AMD64 Stackwalker.
BUG=https://code.google.com/p/chromium/issues/detail?id=393594
R=mark@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1350 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-18 00:27:49 +00:00
thestig@chromium.org
d91bd8d23a Change some ELF utils to return the length as a size_t.
R=mark@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1349 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-17 18:34:18 +00:00
ted.mielczarek@gmail.com
d7d532bf56 Ensure C:/Dumps/ exists in crash_generation_app
A=j.turney
R=ted at https://breakpad.appspot.com/1134002/

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1348 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-11 18:48:41 +00:00
ted.mielczarek@gmail.com
0a5ebafdf0 Stringify minidump stream_type constants in minidump_dump output
R=mark at https://breakpad.appspot.com/3704002/

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1347 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-11 10:57:30 +00:00
ted.mielczarek@gmail.com
9e8ffc9fab Don't free pointer in BasicCodeModules::BasicCodeModules before possibly using it
A=Jim Chen <nchen@mozilla.com>
R=ted at https://bugzilla.mozilla.org/show_bug.cgi?id=1033006

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1346 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-10 19:16:43 +00:00
mark@chromium.org
21384ad0e2 Fix compilation error in Linux libc++ builds due to use of tr1/.
Patch by Sergey Matveev <earthdok@chromium.org>

BUG=chromium:391792

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


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1345 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-07 19:23:20 +00:00
qsr@chromium.org
f88336d4a1 Unhook current Breakpad object after handling uncaught NSException.
After handling an uncaught NSException, release the Breakpad object
so there will not be a second crash dump logged.

Prior to this change, for every uncaught NSException handled through
the Breakpad::UncaughtExceptionHandler(), a second crash without
any useful information (generally __cxa_rethrow and std::__terminate)
is recorded.

R=qsr@chromium.org

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

Patch from Peter Lee <pkl@chromium.org>.

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1344 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-07 08:13:23 +00:00
rmcilroy@chromium.org
501673c86b Make crash_handler volatile to prevent compiler optimizing it away.
This bug manifests itself on Android x64 (in ExceptionHandlerTest::ExternalDumper), but is possible on any platform.

The compiler is unaware of the code which runs in the signal handler which reads this variable. Without volatile the compiler is free to optimise away writes to this variable which it believes are never read.

BUG=381142, 346626
R=thestig@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1343 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-02 10:27:39 +00:00
ivanpe@chromium.org
bf0e00374f Cleanup: hide undefined behavior from the compiler better.
Submitting this on behalf of Paul Pluzhnikov.

R=mark@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1342 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-07-01 17:50:05 +00:00
mark@chromium.org
ada265ebbd dump_syms: use unordered_set<> instead of set<> for speed.
dump_syms spends a lot of time trying to compare strings.
This change speeds up processing of libwebviewchromium.so by 30% on my linux
machine.

Patch by Junichi Uekawa <uekawa@chromium.org>

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


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1341 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-06-26 12:37:15 +00:00
ivanpe@chromium.org
9d62ef9311 Update output for test minidump_dump_test.
R=mark@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1340 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-06-25 00:24:01 +00:00
mark@chromium.org
a5da1e193c minidump_dump: bug fixes.
- Convert time_t values to UTC correctly. It is incorrect to cast a uint32_t*
   to time_t* because the two types may have different widths. This is the
   case on many 64-bit systems, where time_t is a 64-bit signed integer.
   Conversion is unified in a single function, and additional uses of time_t
   in minidump files not previously displayed in UTC are now displayed.
 - Interpret the IMAGE_DEBUG_MISC structure correctly.
 - When printing MINIDUMP_SYSTEM_INFO structures, always show the "x86" side
   of the union, and state whether it's expected to be valid. (Existing
   Breakpad-produced non-Windows minidumps for x86_64 use the "x86" side of
   union, but Windows minidumps for x86_64 use the "other" side, so I want to
   print both.)

R=ivanpe@chromium.org

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

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1339 4c0a9323-5329-0410-9bdc-e9ce6186880e
2014-06-17 18:03:31 +00:00
49 changed files with 1889 additions and 332 deletions

41
src/build/all.gyp Normal file
View File

@@ -0,0 +1,41 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'targets': [
{
'target_name': 'All',
'type': 'none',
'dependencies': [
'../common/common.gyp:*',
'../processor/processor.gyp:*',
'../tools/tools.gyp:*',
],
},
],
}

View File

@@ -203,21 +203,6 @@
'enable_new_npdevice_api%': 0,
'conditions': [
['OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
# This will set gcc_version to XY if you are running gcc X.Y.*.
# This is used to tweak build flags for gcc 4.4.
'gcc_version%': '<!(python <(DEPTH)/build/compiler_version.py)',
# Figure out the python architecture to decide if we build pyauto.
'python_arch%': '<!(<(DEPTH)/build/linux/python_arch.sh <(sysroot)/usr/lib/libpython<(python_ver).so.1.0)',
'linux_breakpad%': 1,
'linux_dump_symbols%': 1,
}], # OS=="linux" or OS=="freebsd" or OS=="openbsd"
['OS=="mac"', {
# Mac wants Title Case strings
'use_titlecase_in_grd_files%': 1,
'mac_breakpad%': 0,
'mac_keystone%': 0,
}], # OS=="mac"
# Whether to use multiple cores to compile with visual studio. This is
# optional because it sometimes causes corruption on VS 2005.
# It is on by default on VS 2008 and off on VS 2005.
@@ -241,24 +226,6 @@
'NACL_WIN64',
],
}],
# Compute based on OS and target architecture whether the GPU
# plugin / process is supported.
[ 'OS=="win" or (OS=="linux" and target_arch!="arm") or OS=="mac"', {
# Enable a variable used elsewhere throughout the GYP files to determine
# whether to compile in the sources for the GPU plugin / process.
'enable_gpu%': 1,
}, { # GPU plugin not supported
'enable_gpu%': 0,
}],
# Compute based on OS, target architecture and device whether GLES
# is supported
[ 'OS=="linux" and target_arch=="arm"', {
# Enable a variable used elsewhere throughout the GYP files to determine
# whether to compile in the sources for the GLES support.
'enable_gles%': 1,
}, { # GLES not supported
'enable_gles%': 0,
}],
],
# NOTE: When these end up in the Mac bundle, we need to replace '-' for '_'
@@ -273,6 +240,9 @@
],
},
'target_defaults': {
'includes': [
'filename_rules.gypi',
],
'variables': {
# See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html
'mac_release_optimization%': '3', # Use -O3 unless overridden
@@ -299,16 +269,6 @@
}],
],
}],
['enable_gpu==1', {
'defines': [
'ENABLE_GPU=1',
],
}],
['enable_gles==1', {
'defines': [
'ENABLE_GLES=1',
],
}],
['coverage!=0', {
'conditions': [
['OS=="mac"', {
@@ -610,7 +570,7 @@
'-fvisibility=hidden',
],
'cflags_cc': [
'-fno-rtti',
'-frtti',
'-fno-threadsafe-statics',
# Make inline functions have hidden visiblity by default.
# Surprisingly, not covered by -fvisibility=hidden.
@@ -658,12 +618,6 @@
'$_LIBDIRFLAGS', '$LDMODULEFLAGS', '$SOURCES',
'-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']],
'IMPLICIT_COMMAND_DEPENDENCIES': 0,
# -rpath is only used when building with shared libraries.
'conditions': [
[ 'component=="shared_library"', {
'RPATH': '$LIB_DIR',
}],
],
},
'scons_import_variables': [
'AS',
@@ -847,21 +801,6 @@
'-fno-strict-aliasing',
],
}],
['linux_breakpad==1', {
'cflags': [ '-gstabs' ],
'defines': ['USE_LINUX_BREAKPAD'],
}],
['library=="shared_library"', {
# When building with shared libraries, remove the visiblity-hiding
# flag.
'cflags!': [ '-fvisibility=hidden' ],
'conditions': [
['target_arch=="x64" or target_arch=="arm"', {
# Shared libraries need -fPIC on x86-64 and arm
'cflags': ['-fPIC']
}]
],
}],
['linux_use_heapchecker==1', {
'variables': {'linux_use_tcmalloc%': 1},
}],
@@ -903,7 +842,7 @@
'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic
# (Equivalent to -fPIC)
'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions
'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti
'GCC_ENABLE_CPP_RTTI': 'YES', # -frtti
'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings
# GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
@@ -931,51 +870,6 @@
['_mac_bundle', {
'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
}],
['_type=="executable" or _type=="shared_library"', {
'target_conditions': [
['mac_real_dsym == 1', {
# To get a real .dSYM bundle produced by dsymutil, set the
# debug information format to dwarf-with-dsym. Since
# strip_from_xcode will not be used, set Xcode to do the
# stripping as well.
'configurations': {
'Release_Base': {
'xcode_settings': {
'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
'DEPLOYMENT_POSTPROCESSING': 'YES',
'STRIP_INSTALLED_PRODUCT': 'YES',
'target_conditions': [
['_type=="shared_library"', {
# The Xcode default is to strip debugging symbols
# only (-S). Local symbols should be stripped as
# well, which will be handled by -x. Xcode will
# continue to insert -S when stripping even when
# additional flags are added with STRIPFLAGS.
'STRIPFLAGS': '-x',
}], # _type=="shared_library"
], # target_conditions
}, # xcode_settings
}, # configuration "Release"
}, # configurations
}, { # mac_real_dsym != 1
# To get a fast fake .dSYM bundle, use a post-build step to
# produce the .dSYM and strip the executable. strip_from_xcode
# only operates in the Release configuration.
'postbuilds': [
{
'variables': {
# Define strip_from_xcode in a variable ending in _path
# so that gyp understands it's a path and performs proper
# relativization during dict merging.
'strip_from_xcode_path': 'mac/strip_from_xcode',
},
'postbuild_name': 'Strip If Needed',
'action': ['<(strip_from_xcode_path)'],
},
], # postbuilds
}], # mac_real_dsym
], # target_conditions
}], # _type=="executable" or _type=="shared_library"
], # target_conditions
}, # target_defaults
}], # OS=="mac"

View File

@@ -0,0 +1,57 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'target_conditions': [
['OS!="win"', {
'sources/': [
['exclude', '(^|/)windows/'],
],
}],
['OS!="linux"', {
'sources/': [
['exclude', '(^|/)linux/'],
],
}],
['OS!="mac"', {
'sources/': [
['exclude', '(^|/)mac/'],
],
}],
['OS!="android"', {
'sources/': [
['exclude', '(^|/)android/'],
],
}],
['OS!="solaris"', {
'sources/': [
['exclude', '(^|/)solaris/'],
],
}],
],
}

67
src/build/gyp_breakpad Executable file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import os
import platform
import sys
script_dir = os.path.dirname(os.path.realpath(__file__))
breakpad_root = os.path.abspath(os.path.join(script_dir, os.pardir))
sys.path.insert(0, os.path.join(breakpad_root, 'tools', 'gyp', 'pylib'))
import gyp
def run_gyp(args):
rc = gyp.main(args)
if rc != 0:
print 'Error running GYP'
sys.exit(rc)
def main():
args = sys.argv[1:]
args.append(os.path.join(script_dir, 'all.gyp'))
args.append('-I')
args.append(os.path.join(breakpad_root, 'build', 'common.gypi'))
args.extend(['-D', 'gyp_output_dir=out'])
# Set the GYP DEPTH variable to the root of the project.
args.append('--depth=' + os.path.relpath(breakpad_root))
print 'Updating projects from gyp files...'
sys.stdout.flush()
run_gyp(args)
if __name__ == '__main__':
sys.exit(main())

90
src/build/testing.gypi Normal file
View File

@@ -0,0 +1,90 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'targets': [
{
'target_name': 'gtest',
'type': 'static_library',
'sources': [
'../testing/gtest/src/gtest-all.cc',
],
'include_dirs': [
'../testing/gtest',
'../testing/gtest/include',
],
'direct_dependent_settings': {
'include_dirs': [
'../testing/gtest/include',
],
},
},
{
'target_name': 'gtest_main',
'type': 'static_library',
'dependencies': [
'gtest',
],
'sources': [
'gtest/src/gtest_main.cc',
],
},
{
'target_name': 'gmock',
'type': 'static_library',
'dependencies': [
'gtest',
],
'sources': [
'../testing/src/gmock-all.cc',
],
'include_dirs': [
'../testing',
'../testing/include',
],
'direct_dependent_settings': {
'include_dirs': [
'../testing/include',
],
},
'export_dependent_settings': [
'gtest',
],
},
{
'target_name': 'gmock_main',
'type': 'static_library',
'dependencies': [
'gmock',
],
'sources': [
'../testing/src/gmock_main.cc',
],
},
],
}

View File

@@ -62,6 +62,7 @@
#define BREAKPAD_EMAIL "BreakpadEmail"
#define BREAKPAD_SERVER_TYPE "BreakpadServerType"
#define BREAKPAD_SERVER_PARAMETER_DICT "BreakpadServerParameters"
#define BREAKPAD_IN_PROCESS "BreakpadInProcess"
// The keys below are NOT user supplied, and are used internally.
#define BREAKPAD_PROCESS_START_TIME "BreakpadProcStartTime"

View File

@@ -258,6 +258,7 @@ void Breakpad::UncaughtExceptionHandler(NSException *exception) {
if (current_breakpad_) {
current_breakpad_->HandleUncaughtException(exception);
}
BreakpadRelease(current_breakpad_);
}
//=============================================================================

View File

@@ -252,7 +252,11 @@ class ExceptionHandler {
MinidumpDescriptor minidump_descriptor_;
HandlerCallback crash_handler_;
// Must be volatile. The compiler is unaware of the code which runs in
// the signal handler which reads this variable. Without volatile the
// compiler is free to optimise away writes to this variable which it
// believes are never read.
volatile HandlerCallback crash_handler_;
// The global exception handler stack. This is need becuase there may exist
// multiple ExceptionHandler instances in a process. Each will have itself

View File

@@ -193,6 +193,20 @@ static bool DoneCallback(const MinidumpDescriptor& descriptor,
#ifndef ADDRESS_SANITIZER
// This is a replacement for "*reinterpret_cast<volatile int*>(NULL) = 0;"
// It is needed because GCC is allowed to assume that the program will
// not execute any undefined behavior (UB) operation. Further, when GCC
// observes that UB statement is reached, it can assume that all statements
// leading to the UB one are never executed either, and can completely
// optimize them out. In the case of ExceptionHandlerTest::ExternalDumper,
// GCC-4.9 optimized out the entire set up of ExceptionHandler, causing
// test failure.
volatile int *p_null; // external linkage, so GCC can't tell that it
// remains NULL. Volatile just for a good measure.
static void DoNullPointerDereference() {
*p_null = 1;
}
void ChildCrash(bool use_fd) {
AutoTempDir temp_dir;
int fds[2] = {0};
@@ -219,7 +233,7 @@ void ChildCrash(bool use_fd) {
true, -1));
}
// Crash with the exception handler in scope.
*reinterpret_cast<volatile int*>(NULL) = 0;
DoNullPointerDereference();
}
}
if (!use_fd)
@@ -295,7 +309,7 @@ static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter,
ExceptionHandler handler(
MinidumpDescriptor(path), filter, done, NULL, true, -1);
// Crash with the exception handler in scope.
*reinterpret_cast<volatile int*>(NULL) = 0;
DoNullPointerDereference();
}
TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) {
@@ -386,7 +400,7 @@ TEST(ExceptionHandlerTest, RedeliveryOnBadSignalHandlerFlag) {
reinterpret_cast<void*>(SIG_ERR));
// Crash with the exception handler in scope.
*reinterpret_cast<volatile int*>(NULL) = 0;
DoNullPointerDereference();
}
// SIGKILL means Breakpad's signal handler didn't crash.
ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
@@ -922,7 +936,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) {
ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL,
reinterpret_cast<void*>(fds[1]), true, -1);
handler.set_crash_handler(CrashHandler);
*reinterpret_cast<volatile int*>(NULL) = 0;
DoNullPointerDereference();
}
close(fds[1]);
struct msghdr msg = {0};

View File

@@ -124,7 +124,7 @@ bool LinuxCoreDumper::ThreadsResume() {
}
bool LinuxCoreDumper::EnumerateThreads() {
if (!mapped_core_file_.Map(core_path_)) {
if (!mapped_core_file_.Map(core_path_, 0)) {
fprintf(stderr, "Could not map core dump file into memory\n");
return false;
}

View File

@@ -38,12 +38,14 @@
#include "client/linux/minidump_writer/linux_dumper.h"
#include <assert.h>
#include <elf.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include "client/linux/minidump_writer/line_reader.h"
#include "common/linux/elfutils.h"
#include "common/linux/file_id.h"
#include "common/linux/linux_libc_support.h"
#include "common/linux/memory_mapped_file.h"
@@ -115,15 +117,16 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
char filename[NAME_MAX];
size_t filename_len = my_strlen(mapping.name);
assert(filename_len < NAME_MAX);
if (filename_len >= NAME_MAX)
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);
if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)?
MemoryMappedFile mapped_file(filename, mapping.offset);
if (!mapped_file.data() || mapped_file.size() < SELFMAG)
return false;
bool success =
@@ -136,6 +139,80 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
return success;
}
namespace {
bool ElfFileSoNameFromMappedFile(
const void* elf_base, char* soname, size_t soname_size) {
if (!IsValidElf(elf_base)) {
// Not ELF
return false;
}
const void* segment_start;
size_t segment_size;
int elf_class;
if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC,
&segment_start, &segment_size, &elf_class)) {
// No dynamic section
return false;
}
const void* dynstr_start;
size_t dynstr_size;
if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB,
&dynstr_start, &dynstr_size, &elf_class)) {
// No dynstr section
return false;
}
const ElfW(Dyn)* dynamic = static_cast<const ElfW(Dyn)*>(segment_start);
size_t dcount = segment_size / sizeof(ElfW(Dyn));
for (const ElfW(Dyn)* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
if (dyn->d_tag == DT_SONAME) {
const char* dynstr = static_cast<const char*>(dynstr_start);
if (dyn->d_un.d_val >= dynstr_size) {
// Beyond the end of the dynstr section
return false;
}
const char* str = dynstr + dyn->d_un.d_val;
const size_t maxsize = dynstr_size - dyn->d_un.d_val;
my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
return true;
}
}
// Did not find SONAME
return false;
}
} // namespace
// static
bool LinuxDumper::ElfFileSoName(
const MappingInfo& mapping, char* soname, size_t soname_size) {
if (IsMappedFileOpenUnsafe(mapping)) {
// Not safe
return false;
}
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) {
// mmap failed
return false;
}
return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
}
bool LinuxDumper::ReadAuxv() {
char auxv_path[NAME_MAX];
if (!BuildProcPath(auxv_path, pid_, "auxv")) {
@@ -195,6 +272,7 @@ bool LinuxDumper::EnumerateMappings() {
if (*i1 == '-') {
const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
if (*i2 == ' ') {
bool exec = (*(i2 + 3) == 'x');
const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
if (*i3 == ' ') {
const char* name = NULL;
@@ -223,6 +301,7 @@ bool LinuxDumper::EnumerateMappings() {
module->start_addr = start_addr;
module->size = end_addr - start_addr;
module->offset = offset;
module->exec = exec;
if (name != NULL) {
const unsigned l = my_strlen(name);
if (l < sizeof(module->name))

View File

@@ -107,6 +107,7 @@ struct MappingInfo {
uintptr_t start_addr;
size_t size;
size_t offset; // offset into the backed file.
bool exec; // true if the mapping has the execute bit set.
char name[NAME_MAX];
};
@@ -162,6 +163,13 @@ class LinuxDumper {
unsigned int mapping_id,
uint8_t identifier[sizeof(MDGUID)]);
// Find the shared object name (SONAME) by examining the ELF information
// 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.
static bool ElfFileSoName(
const MappingInfo& mapping, char* soname, size_t soname_size);
uintptr_t crash_address() const { return crash_address_; }
void set_crash_address(uintptr_t crash_address) {
crash_address_ = crash_address;

View File

@@ -938,7 +938,9 @@ class MinidumpWriter {
static bool ShouldIncludeMapping(const MappingInfo& mapping) {
if (mapping.name[0] == 0 || // only want modules with filenames.
mapping.offset || // only want to include one mapping per shared lib.
// Only want to include one mapping per shared lib.
// Avoid filtering executable mappings.
(mapping.offset != 0 && !mapping.exec) ||
mapping.size < 4096) { // too small to get a signature for.
return false;
}
@@ -1029,7 +1031,8 @@ class MinidumpWriter {
mod.base_of_image = mapping.start_addr;
mod.size_of_image = mapping.size;
const size_t filepath_len = my_strlen(mapping.name);
const char* filepath_ptr = mapping.name;
size_t filepath_len = my_strlen(mapping.name);
// Figure out file name from path
const char* filename_ptr = mapping.name + filepath_len - 1;
@@ -1040,7 +1043,31 @@ class MinidumpWriter {
}
filename_ptr++;
const size_t filename_len = mapping.name + filepath_len - filename_ptr;
size_t filename_len = mapping.name + filepath_len - filename_ptr;
// If an executable is mapped from a non-zero offset, this is likely
// because the executable was loaded directly from inside an archive
// file. We try to find the name of the shared object (SONAME) by
// looking in the file for ELF sections.
char soname[NAME_MAX];
char pathname[NAME_MAX];
if (mapping.exec && mapping.offset != 0 &&
LinuxDumper::ElfFileSoName(mapping, soname, sizeof(soname))) {
filename_ptr = soname;
filename_len = my_strlen(soname);
if (filepath_len + filename_len + 1 < NAME_MAX) {
// It doesn't have a real pathname, but tools such as stackwalk
// extract the basename, so simulating a pathname is helpful.
my_memcpy(pathname, filepath_ptr, filepath_len);
pathname[filepath_len] = '/';
my_memcpy(pathname + filepath_len + 1, filename_ptr, filename_len);
pathname[filepath_len + filename_len + 1] = '\0';
filepath_ptr = pathname;
filepath_len = filepath_len + filename_len + 1;
}
}
uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
uint8_t* cv_ptr = cv_buf;
@@ -1070,7 +1097,7 @@ class MinidumpWriter {
mod.cv_record = cv.location();
MDLocationDescriptor ld;
if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld))
if (!minidump_writer_.WriteString(filepath_ptr, filepath_len, &ld))
return false;
mod.module_name_rva = ld.rva;
return true;
@@ -1758,23 +1785,6 @@ class MinidumpWriter {
space_left -= info_len;
}
#ifdef __ANDROID__
// On Android, try to get the build fingerprint and append it.
// Fail gracefully because there is no guarantee that the system
// property will always be available or accessible.
char fingerprint[PROP_VALUE_MAX];
int fingerprint_len = __system_property_get("ro.build.fingerprint",
fingerprint);
// System property values shall always be zero-terminated.
// Be paranoid and don't trust the system.
if (fingerprint_len > 0 && fingerprint_len < PROP_VALUE_MAX) {
const char* separator = " ";
if (!first_item)
my_strlcat(buf, separator, sizeof(buf));
my_strlcat(buf, fingerprint, sizeof(buf));
}
#endif
MDLocationDescriptor location;
if (!minidump_writer_.WriteString(buf, 0, &location))
return false;

View File

@@ -158,6 +158,11 @@ typedef bool (*BreakpadFilterCallback)(int exception_type,
// but pass as URL parameters when
// uploading theminidump to the crash
// server.
//
// BREAKPAD_IN_PROCESS A boolean NSNumber value. If YES, Breakpad
// will write the dump file in-process and then
// launch the reporter executable as a child
// process.
//=============================================================================
// The BREAKPAD_PRODUCT, BREAKPAD_VERSION and BREAKPAD_URL are
// required to have non-NULL values. By default, the BREAKPAD_PRODUCT

View File

@@ -44,6 +44,7 @@
#import "client/mac/Framework/Breakpad.h"
#import "client/mac/Framework/OnDemandServer.h"
#import "client/mac/handler/protected_memory_allocator.h"
#include "common/mac/launch_reporter.h"
#import "common/mac/MachIPC.h"
#import "common/simple_string_dictionary.h"
@@ -173,6 +174,8 @@ class Breakpad {
}
bool Initialize(NSDictionary *parameters);
bool InitializeInProcess(NSDictionary *parameters);
bool InitializeOutOfProcess(NSDictionary *parameters);
bool ExtractParameters(NSDictionary *parameters);
@@ -188,6 +191,17 @@ class Breakpad {
int exception_subcode,
mach_port_t crashing_thread);
// Dispatches to HandleMinidump().
// This gets called instead of ExceptionHandlerDirectCallback when running
// with the BREAKPAD_IN_PROCESS option.
static bool HandleMinidumpCallback(const char *dump_dir,
const char *minidump_id,
void *context,
bool succeeded);
// This is only used when BREAKPAD_IN_PROCESS is YES.
bool HandleMinidump(const char *dump_dir, const char *minidump_id);
// Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's
// MachineExceptions.h, we have to explicitly name the handler.
google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG)
@@ -265,6 +279,21 @@ bool Breakpad::ExceptionHandlerDirectCallback(void *context,
crashing_thread);
}
//=============================================================================
bool Breakpad::HandleMinidumpCallback(const char *dump_dir,
const char *minidump_id,
void *context,
bool succeeded) {
Breakpad *breakpad = (Breakpad *)context;
// If our context is damaged or something, just return false to indicate that
// the handler should continue without us.
if (!breakpad || !succeeded)
return false;
return breakpad->HandleMinidump(dump_dir, minidump_id);
}
//=============================================================================
#pragma mark -
@@ -326,6 +355,25 @@ bool Breakpad::Initialize(NSDictionary *parameters) {
return false;
}
if ([[parameters objectForKey:@BREAKPAD_IN_PROCESS] boolValue])
return InitializeInProcess(parameters);
else
return InitializeOutOfProcess(parameters);
}
//=============================================================================
bool Breakpad::InitializeInProcess(NSDictionary* parameters) {
handler_ =
new (gBreakpadAllocator->Allocate(
sizeof(google_breakpad::ExceptionHandler)))
google_breakpad::ExceptionHandler(
config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY),
0, &HandleMinidumpCallback, this, true, 0);
return true;
}
//=============================================================================
bool Breakpad::InitializeOutOfProcess(NSDictionary* parameters) {
// Get path to Inspector executable.
NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION);
@@ -710,6 +758,16 @@ bool Breakpad::HandleException(int exception_type,
return false;
}
//=============================================================================
bool Breakpad::HandleMinidump(const char *dump_dir, const char *minidump_id) {
google_breakpad::ConfigFile config_file;
config_file.WriteFile(dump_dir, config_params_, dump_dir, minidump_id);
google_breakpad::LaunchReporter(
config_params_->GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION),
config_file.GetFilePath());
return true;
}
//=============================================================================
//=============================================================================

View File

@@ -36,7 +36,7 @@
#include <sys/time.h>
#import "client/apple/Framework/BreakpadDefines.h"
#import "GTMDefines.h"
#import "common/mac/GTMDefines.h"
namespace google_breakpad {

View File

@@ -138,7 +138,6 @@ class Inspector {
bool InspectTask();
kern_return_t SendAcknowledgement();
void LaunchReporter(const char *inConfigFilePath);
// The bootstrap port in which the inspector is registered and into which it
// must check in.

View File

@@ -43,6 +43,7 @@
#import "common/mac/MachIPC.h"
#include "common/mac/bootstrap_compat.h"
#include "common/mac/launch_reporter.h"
#import "GTMDefines.h"
@@ -76,7 +77,9 @@ void Inspector::Inspect(const char *receive_port_name) {
if (wrote_minidump) {
// Ask the user if he wants to upload the crash report to a server,
// and do so if he agrees.
LaunchReporter(config_file_.GetFilePath());
LaunchReporter(
config_params_.GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION),
config_file_.GetFilePath());
} else {
fprintf(stderr, "Inspection of crashed process failed\n");
}
@@ -355,51 +358,5 @@ kern_return_t Inspector::SendAcknowledgement() {
return KERN_INVALID_NAME;
}
//=============================================================================
void Inspector::LaunchReporter(const char *inConfigFilePath) {
// Extract the path to the reporter executable.
const char *reporterExecutablePath =
config_params_.GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION);
// Setup and launch the crash dump sender.
const char *argv[3];
argv[0] = reporterExecutablePath;
argv[1] = inConfigFilePath;
argv[2] = NULL;
// Launch the reporter
pid_t pid = fork();
// If we're in the child, load in our new executable and run.
// The parent will not wait for the child to complete.
if (pid == 0) {
execv(argv[0], (char * const *)argv);
config_file_.Unlink(); // launch failed - get rid of config file
_exit(1);
}
// Wait until the Reporter child process exits.
//
// We'll use a timeout of one minute.
int timeoutCount = 60; // 60 seconds
while (timeoutCount-- > 0) {
int status;
pid_t result = waitpid(pid, &status, WNOHANG);
if (result == 0) {
// The child has not yet finished.
sleep(1);
} else if (result == -1) {
// error occurred.
break;
} else {
// child has finished
break;
}
}
}
} // namespace google_breakpad

View File

@@ -283,6 +283,12 @@ void CrashServerStart() {
}
std::wstring dump_path = L"C:\\Dumps\\";
if (_wmkdir(dump_path.c_str()) && (errno != EEXIST)) {
MessageBoxW(NULL, L"Unable to create dump directory", L"Dumper", MB_OK);
return;
}
crash_server = new CrashGenerationServer(kPipeName,
NULL,
ShowClientConnected,

240
src/common/common.gyp Normal file
View File

@@ -0,0 +1,240 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'target_defaults': {
'target_conditions': [
['OS=="mac"', {
'defines': ['HAVE_MACH_O_NLIST_H'],
}],
['OS=="linux"', {
'defines': ['HAVE_A_OUT_H'],
}],
],
},
'targets': [
{
'target_name': 'common',
'type': 'static_library',
'sources': [
'android/breakpad_getcontext.S',
'android/include/elf.h',
'android/include/link.h',
'android/include/sgidefs.h',
'android/include/stab.h',
'android/include/sys/procfs.h',
'android/include/sys/signal.h',
'android/include/sys/ucontext.h',
'android/include/sys/user.h',
'android/include/ucontext.h',
'android/testing/include/wchar.h',
'android/testing/mkdtemp.h',
'android/testing/pthread_fixes.h',
'android/ucontext_constants.h',
'basictypes.h',
'byte_cursor.h',
'convert_UTF.c',
'convert_UTF.h',
'dwarf/bytereader-inl.h',
'dwarf/bytereader.cc',
'dwarf/bytereader.h',
'dwarf/cfi_assembler.cc',
'dwarf/cfi_assembler.h',
'dwarf/dwarf2diehandler.cc',
'dwarf/dwarf2diehandler.h',
'dwarf/dwarf2enums.h',
'dwarf/dwarf2reader.cc',
'dwarf/dwarf2reader.h',
'dwarf/dwarf2reader_test_common.h',
'dwarf/functioninfo.cc',
'dwarf/functioninfo.h',
'dwarf/line_state_machine.h',
'dwarf/types.h',
'dwarf_cfi_to_module.cc',
'dwarf_cfi_to_module.h',
'dwarf_cu_to_module.cc',
'dwarf_cu_to_module.h',
'dwarf_line_to_module.cc',
'dwarf_line_to_module.h',
'language.cc',
'language.h',
'linux/crc32.cc',
'linux/crc32.h',
'linux/dump_symbols.cc',
'linux/dump_symbols.h',
'linux/eintr_wrapper.h',
'linux/elf_core_dump.cc',
'linux/elf_core_dump.h',
'linux/elf_gnu_compat.h',
'linux/elf_symbols_to_module.cc',
'linux/elf_symbols_to_module.h',
'linux/elfutils-inl.h',
'linux/elfutils.cc',
'linux/elfutils.h',
'linux/file_id.cc',
'linux/file_id.h',
'linux/google_crashdump_uploader.cc',
'linux/google_crashdump_uploader.h',
'linux/guid_creator.cc',
'linux/guid_creator.h',
'linux/http_upload.cc',
'linux/http_upload.h',
'linux/ignore_ret.h',
'linux/libcurl_wrapper.cc',
'linux/libcurl_wrapper.h',
'linux/linux_libc_support.cc',
'linux/linux_libc_support.h',
'linux/memory_mapped_file.cc',
'linux/memory_mapped_file.h',
'linux/safe_readlink.cc',
'linux/safe_readlink.h',
'linux/synth_elf.cc',
'linux/synth_elf.h',
'mac/arch_utilities.cc',
'mac/arch_utilities.h',
'mac/bootstrap_compat.cc',
'mac/bootstrap_compat.h',
'mac/byteswap.h',
'mac/dump_syms.h',
'mac/dump_syms.mm',
'mac/file_id.cc',
'mac/file_id.h',
'mac/GTMDefines.h',
'mac/GTMLogger.h',
'mac/GTMLogger.m',
'mac/HTTPMultipartUpload.h',
'mac/HTTPMultipartUpload.m',
'mac/MachIPC.h',
'mac/MachIPC.mm',
'mac/macho_id.cc',
'mac/macho_id.h',
'mac/macho_reader.cc',
'mac/macho_reader.h',
'mac/macho_utilities.cc',
'mac/macho_utilities.h',
'mac/macho_walker.cc',
'mac/macho_walker.h',
'mac/scoped_task_suspend-inl.h',
'mac/string_utilities.cc',
'mac/string_utilities.h',
'md5.cc',
'md5.h',
'memory.h',
'memory_range.h',
'module.cc',
'module.h',
'scoped_ptr.h',
'simple_string_dictionary.cc',
'simple_string_dictionary.h',
'solaris/dump_symbols.cc',
'solaris/dump_symbols.h',
'solaris/file_id.cc',
'solaris/file_id.h',
'solaris/guid_creator.cc',
'solaris/guid_creator.h',
'solaris/message_output.h',
'stabs_reader.cc',
'stabs_reader.h',
'stabs_to_module.cc',
'stabs_to_module.h',
'string_conversion.cc',
'string_conversion.h',
'symbol_data.h',
'test_assembler.cc',
'test_assembler.h',
'unordered.h',
'using_std_string.h',
'windows/common_windows.gyp',
'windows/dia_util.cc',
'windows/dia_util.h',
'windows/guid_string.cc',
'windows/guid_string.h',
'windows/http_upload.cc',
'windows/http_upload.h',
'windows/omap.cc',
'windows/omap.h',
'windows/omap_internal.h',
'windows/pdb_source_line_writer.cc',
'windows/pdb_source_line_writer.h',
'windows/string_utils-inl.h',
'windows/string_utils.cc',
],
'include_dirs': [
'..',
],
},
{
'target_name': 'common_unittests',
'type': 'executable',
'sources': [
'android/breakpad_getcontext_unittest.cc',
'byte_cursor_unittest.cc',
'dwarf/bytereader_unittest.cc',
'dwarf/dwarf2diehandler_unittest.cc',
'dwarf/dwarf2reader_cfi_unittest.cc',
'dwarf/dwarf2reader_die_unittest.cc',
'dwarf_cfi_to_module_unittest.cc',
'dwarf_cu_to_module_unittest.cc',
'dwarf_line_to_module_unittest.cc',
'linux/dump_symbols_unittest.cc',
'linux/elf_core_dump_unittest.cc',
'linux/elf_symbols_to_module_unittest.cc',
'linux/file_id_unittest.cc',
'linux/google_crashdump_uploader_test.cc',
'linux/linux_libc_support_unittest.cc',
'linux/memory_mapped_file_unittest.cc',
'linux/safe_readlink_unittest.cc',
'linux/synth_elf_unittest.cc',
'linux/tests/auto_testfile.h',
'linux/tests/crash_generator.cc',
'linux/tests/crash_generator.h',
'mac/macho_reader_unittest.cc',
'memory_range_unittest.cc',
'memory_unittest.cc',
'module_unittest.cc',
'simple_string_dictionary_unittest.cc',
'stabs_reader_unittest.cc',
'stabs_to_module_unittest.cc',
'test_assembler_unittest.cc',
'tests/auto_tempdir.h',
'tests/file_utils.cc',
'tests/file_utils.h',
'windows/omap_unittest.cc',
],
'include_dirs': [
'..',
],
'dependencies': [
'common',
'../build/testing.gypi:gmock_main',
'../build/testing.gypi:gmock',
'../build/testing.gypi:gtest',
],
},
],
}

View File

@@ -46,16 +46,15 @@
#include <stdio.h>
#include <algorithm>
#include <set>
#include <utility>
#include "common/dwarf_line_to_module.h"
#include "common/unordered.h"
namespace google_breakpad {
using std::map;
using std::pair;
using std::set;
using std::sort;
using std::vector;
@@ -118,7 +117,7 @@ struct DwarfCUToModule::FilePrivate {
// so this set will actually hold yet another copy of the string (although
// everything will still work). To improve memory consumption portably,
// we will probably need to use pointers to strings held in this set.
set<string> common_strings;
unordered_set<string> common_strings;
// A map from offsets of DIEs within the .debug_info section to
// Specifications describing those DIEs. Specification references can
@@ -337,7 +336,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
}
string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) {
pair<set<string>::iterator, bool> result =
pair<unordered_set<string>::iterator, bool> result =
cu_context_->file_context->file_private_->common_strings.insert(str);
return *result.first;
}

View File

@@ -70,7 +70,7 @@ TEST(ElfCoreDumpTest, TestElfHeader) {
ElfCoreDump core;
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header) - 1));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_FALSE(core.IsValid());
EXPECT_EQ(NULL, core.GetHeader());
@@ -80,49 +80,49 @@ TEST(ElfCoreDumpTest, TestElfHeader) {
EXPECT_FALSE(core.GetFirstNote().IsValid());
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_FALSE(core.IsValid());
header.e_ident[0] = ELFMAG0;
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_FALSE(core.IsValid());
header.e_ident[1] = ELFMAG1;
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_FALSE(core.IsValid());
header.e_ident[2] = ELFMAG2;
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_FALSE(core.IsValid());
header.e_ident[3] = ELFMAG3;
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_FALSE(core.IsValid());
header.e_ident[4] = ElfCoreDump::kClass;
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_FALSE(core.IsValid());
header.e_version = EV_CURRENT;
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_FALSE(core.IsValid());
header.e_type = ET_CORE;
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
ASSERT_TRUE(mapped_core_file.Map(core_file));
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
core.SetContent(mapped_core_file.content());
EXPECT_TRUE(core.IsValid());
}
@@ -156,7 +156,8 @@ TEST(ElfCoreDumpTest, ValidCoreFile) {
#endif
MemoryMappedFile mapped_core_file;
ASSERT_TRUE(mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str()));
ASSERT_TRUE(
mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str(), 0));
ElfCoreDump core;
core.SetContent(mapped_core_file.content());

View File

@@ -44,7 +44,7 @@ void FindElfClassSection(const char *elf_base,
const char *section_name,
typename ElfClass::Word section_type,
const void **section_start,
int *section_size) {
size_t *section_size) {
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Shdr Shdr;
@@ -58,10 +58,10 @@ void FindElfClassSection(const char *elf_base,
assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
const Shdr* sections =
GetOffset<ElfClass,Shdr>(elf_header, elf_header->e_shoff);
GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
const Shdr* section_names = sections + elf_header->e_shstrndx;
const char* names =
GetOffset<ElfClass,char>(elf_header, section_names->sh_offset);
GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
const char *names_end = names + section_names->sh_size;
const Shdr* section =
@@ -79,7 +79,7 @@ template<typename ElfClass>
void FindElfClassSegment(const char *elf_base,
typename ElfClass::Word segment_type,
const void **segment_start,
int *segment_size) {
size_t *segment_size) {
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Phdr Phdr;
@@ -93,7 +93,7 @@ void FindElfClassSegment(const char *elf_base,
assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
const Phdr* phdrs =
GetOffset<ElfClass,Phdr>(elf_header, elf_header->e_phoff);
GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff);
for (int i = 0; i < elf_header->e_phnum; ++i) {
if (phdrs[i].p_type == segment_type) {
@@ -122,7 +122,7 @@ bool FindElfSection(const void *elf_mapped_base,
const char *section_name,
uint32_t section_type,
const void **section_start,
int *section_size,
size_t *section_size,
int *elfclass) {
assert(elf_mapped_base);
assert(section_start);
@@ -158,7 +158,7 @@ bool FindElfSection(const void *elf_mapped_base,
bool FindElfSegment(const void *elf_mapped_base,
uint32_t segment_type,
const void **segment_start,
int *segment_size,
size_t *segment_size,
int *elfclass) {
assert(elf_mapped_base);
assert(segment_start);

View File

@@ -30,8 +30,8 @@
// elfutils.h: Utilities for dealing with ELF files.
//
#ifndef COMMON_LINUX_ELFUTILS_H__
#define COMMON_LINUX_ELFUTILS_H__
#ifndef COMMON_LINUX_ELFUTILS_H_
#define COMMON_LINUX_ELFUTILS_H_
#include <elf.h>
#include <link.h>
@@ -79,7 +79,7 @@ bool FindElfSection(const void *elf_mapped_base,
const char *section_name,
uint32_t section_type,
const void **section_start,
int *section_size,
size_t *section_size,
int *elfclass);
// Internal helper method, exposed for convenience for callers
@@ -101,7 +101,7 @@ FindElfSectionByName(const char* name,
bool FindElfSegment(const void *elf_mapped_base,
uint32_t segment_type,
const void **segment_start,
int *segment_size,
size_t *segment_size,
int *elfclass);
// Convert an offset from an Elf header into a pointer to the mapped
@@ -115,4 +115,4 @@ GetOffset(const typename ElfClass::Ehdr* elf_header,
} // namespace google_breakpad
#endif // COMMON_LINUX_ELFUTILS_H__
#endif // COMMON_LINUX_ELFUTILS_H_

View File

@@ -57,7 +57,7 @@ FileID::FileID(const char* path) : path_(path) {}
// and use the syscall/libc wrappers instead of direct syscalls or libc.
template<typename ElfClass>
static bool ElfClassBuildIDNoteIdentifier(const void *section, int length,
static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
uint8_t identifier[kMDGUIDSize]) {
typedef typename ElfClass::Nhdr Nhdr;
@@ -92,7 +92,8 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, int length,
static bool FindElfBuildIDNote(const void *elf_mapped_base,
uint8_t identifier[kMDGUIDSize]) {
void* note_section;
int note_size, elfclass;
size_t note_size;
int elfclass;
if ((!FindElfSegment(elf_mapped_base, PT_NOTE,
(const void**)&note_section, &note_size, &elfclass) ||
note_size == 0) &&
@@ -118,7 +119,7 @@ static bool FindElfBuildIDNote(const void *elf_mapped_base,
static bool HashElfTextSection(const void *elf_mapped_base,
uint8_t identifier[kMDGUIDSize]) {
void* text_section;
int text_size;
size_t text_size;
if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS,
(const void**)&text_section, &text_size, NULL) ||
text_size == 0) {
@@ -127,7 +128,7 @@ static bool HashElfTextSection(const void *elf_mapped_base,
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, 4096);
const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096));
while (ptr < ptr_end) {
for (unsigned i = 0; i < kMDGUIDSize; i++)
identifier[i] ^= ptr[i];
@@ -148,7 +149,7 @@ bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
}
bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
MemoryMappedFile mapped_file(path_.c_str());
MemoryMappedFile mapped_file(path_.c_str(), 0);
if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)?
return false;

View File

@@ -46,15 +46,15 @@ namespace google_breakpad {
MemoryMappedFile::MemoryMappedFile() {}
MemoryMappedFile::MemoryMappedFile(const char* path) {
Map(path);
MemoryMappedFile::MemoryMappedFile(const char* path, size_t offset) {
Map(path, offset);
}
MemoryMappedFile::~MemoryMappedFile() {
Unmap();
}
bool MemoryMappedFile::Map(const char* path) {
bool MemoryMappedFile::Map(const char* path, size_t offset) {
Unmap();
int fd = sys_open(path, O_RDONLY, 0);
@@ -73,25 +73,33 @@ bool MemoryMappedFile::Map(const char* path) {
return false;
}
// If the file size is zero, simply use an empty MemoryRange and return
// true. Don't bother to call mmap() even though mmap() can handle an
// empty file on some platforms.
if (st.st_size == 0) {
// Strangely file size can be negative, but we check above that it is not.
size_t file_len = static_cast<size_t>(st.st_size);
// If the file does not extend beyond the offset, simply use an empty
// MemoryRange and return true. Don't bother to call mmap()
// even though mmap() can handle an empty file on some platforms.
if (offset >= file_len) {
sys_close(fd);
return true;
}
#if defined(__x86_64__) || defined(__aarch64__)
void* data = sys_mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
void* data = sys_mmap(NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset);
#else
void* data = sys_mmap2(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
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;
}
content_.Set(data, st.st_size);
content_.Set(data, file_len - offset);
return true;
}

View File

@@ -33,6 +33,7 @@
#ifndef COMMON_LINUX_MEMORY_MAPPED_FILE_H_
#define COMMON_LINUX_MEMORY_MAPPED_FILE_H_
#include <stddef.h>
#include "common/basictypes.h"
#include "common/memory_range.h"
@@ -47,7 +48,7 @@ class MemoryMappedFile {
// Constructor that calls Map() to map a file at |path| into memory.
// If Map() fails, the object behaves as if it is default constructed.
explicit MemoryMappedFile(const char* path);
MemoryMappedFile(const char* path, size_t offset);
~MemoryMappedFile();
@@ -56,7 +57,7 @@ class MemoryMappedFile {
// success. Mapping an empty file will succeed but with data() and size()
// returning NULL and 0, respectively. An existing mapping is unmapped
// before a new mapping is created.
bool Map(const char* path);
bool Map(const char* path, size_t offset);
// Unmaps the memory for the mapped file. It's a no-op if no file is
// mapped.

View File

@@ -71,12 +71,12 @@ TEST_F(MemoryMappedFileTest, UnmapWithoutMap) {
TEST_F(MemoryMappedFileTest, MapNonexistentFile) {
{
MemoryMappedFile mapped_file("nonexistent-file");
MemoryMappedFile mapped_file("nonexistent-file", 0);
ExpectNoMappedData(mapped_file);
}
{
MemoryMappedFile mapped_file;
EXPECT_FALSE(mapped_file.Map("nonexistent-file"));
EXPECT_FALSE(mapped_file.Map("nonexistent-file", 0));
ExpectNoMappedData(mapped_file);
}
}
@@ -87,12 +87,12 @@ TEST_F(MemoryMappedFileTest, MapEmptyFile) {
ASSERT_TRUE(WriteFile(test_file.c_str(), NULL, 0));
{
MemoryMappedFile mapped_file(test_file.c_str());
MemoryMappedFile mapped_file(test_file.c_str(), 0);
ExpectNoMappedData(mapped_file);
}
{
MemoryMappedFile mapped_file;
EXPECT_TRUE(mapped_file.Map(test_file.c_str()));
EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0));
ExpectNoMappedData(mapped_file);
}
}
@@ -109,7 +109,7 @@ TEST_F(MemoryMappedFileTest, MapNonEmptyFile) {
ASSERT_TRUE(WriteFile(test_file.c_str(), data, data_size));
{
MemoryMappedFile mapped_file(test_file.c_str());
MemoryMappedFile mapped_file(test_file.c_str(), 0);
EXPECT_FALSE(mapped_file.content().IsEmpty());
EXPECT_TRUE(mapped_file.data() != NULL);
EXPECT_EQ(data_size, mapped_file.size());
@@ -117,7 +117,7 @@ TEST_F(MemoryMappedFileTest, MapNonEmptyFile) {
}
{
MemoryMappedFile mapped_file;
EXPECT_TRUE(mapped_file.Map(test_file.c_str()));
EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0));
EXPECT_FALSE(mapped_file.content().IsEmpty());
EXPECT_TRUE(mapped_file.data() != NULL);
EXPECT_EQ(data_size, mapped_file.size());
@@ -145,13 +145,13 @@ TEST_F(MemoryMappedFileTest, RemapAfterMap) {
ASSERT_TRUE(WriteFile(test_file2.c_str(), data2, data2_size));
{
MemoryMappedFile mapped_file(test_file1.c_str());
MemoryMappedFile mapped_file(test_file1.c_str(), 0);
EXPECT_FALSE(mapped_file.content().IsEmpty());
EXPECT_TRUE(mapped_file.data() != NULL);
EXPECT_EQ(data1_size, mapped_file.size());
EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size));
mapped_file.Map(test_file2.c_str());
mapped_file.Map(test_file2.c_str(), 0);
EXPECT_FALSE(mapped_file.content().IsEmpty());
EXPECT_TRUE(mapped_file.data() != NULL);
EXPECT_EQ(data2_size, mapped_file.size());
@@ -159,16 +159,50 @@ TEST_F(MemoryMappedFileTest, RemapAfterMap) {
}
{
MemoryMappedFile mapped_file;
EXPECT_TRUE(mapped_file.Map(test_file1.c_str()));
EXPECT_TRUE(mapped_file.Map(test_file1.c_str(), 0));
EXPECT_FALSE(mapped_file.content().IsEmpty());
EXPECT_TRUE(mapped_file.data() != NULL);
EXPECT_EQ(data1_size, mapped_file.size());
EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size));
mapped_file.Map(test_file2.c_str());
mapped_file.Map(test_file2.c_str(), 0);
EXPECT_FALSE(mapped_file.content().IsEmpty());
EXPECT_TRUE(mapped_file.data() != NULL);
EXPECT_EQ(data2_size, mapped_file.size());
EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size));
}
}
TEST_F(MemoryMappedFileTest, MapWithOffset) {
// Put more data in the test file this time. Offsets can only be
// done on page boundaries, so we need a two page file to test this.
const int page_size = 4096;
char data1[2 * page_size];
size_t data1_size = sizeof(data1);
for (size_t i = 0; i < data1_size; ++i) {
data1[i] = i & 0x7f;
}
AutoTempDir temp_dir;
string test_file1 = temp_dir.path() + "/test_file1";
ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size));
{
MemoryMappedFile mapped_file(test_file1.c_str(), page_size);
EXPECT_FALSE(mapped_file.content().IsEmpty());
EXPECT_TRUE(mapped_file.data() != NULL);
EXPECT_EQ(data1_size - page_size, mapped_file.size());
EXPECT_EQ(
0,
memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size));
}
{
MemoryMappedFile mapped_file;
mapped_file.Map(test_file1.c_str(), page_size);
EXPECT_FALSE(mapped_file.content().IsEmpty());
EXPECT_TRUE(mapped_file.data() != NULL);
EXPECT_EQ(data1_size - page_size, mapped_file.size());
EXPECT_EQ(
0,
memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size));
}
}

View File

@@ -0,0 +1,84 @@
// Copyright (c) 2014, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
namespace google_breakpad {
void LaunchReporter(const char *reporter_executable_path,
const char *config_file_path) {
const char* argv[] = { reporter_executable_path, config_file_path, NULL };
// Launch the reporter
pid_t pid = fork();
if (pid == -1) {
perror("fork");
fprintf(stderr, "Failed to fork reporter process\n");
return;
}
// If we're in the child, load in our new executable and run.
// The parent will not wait for the child to complete.
if (pid == 0) {
execv(argv[0], (char* const*)argv);
perror("exec");
fprintf(stderr,
"Failed to launch reporter process from path %s\n",
reporter_executable_path);
unlink(config_file_path); // launch failed - get rid of config file
_exit(1);
}
// Wait until the Reporter child process exits.
//
// We'll use a timeout of one minute.
int timeout_count = 60; // 60 seconds
while (timeout_count-- > 0) {
int status;
pid_t result = waitpid(pid, &status, WNOHANG);
if (result == 0) {
// The child has not yet finished.
sleep(1);
} else if (result == -1) {
// error occurred.
break;
} else {
// child has finished
break;
}
}
}
} // namespace google_breakpad

View File

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

View File

@@ -38,6 +38,10 @@
#include <memory>
#include <vector>
#if defined(MEMORY_SANITIZER)
#include <sanitizer/msan_interface.h>
#endif
#ifdef __APPLE__
#define sys_mmap mmap
#define sys_mmap2 mmap
@@ -120,6 +124,12 @@ class PageAllocator {
if (a == MAP_FAILED)
return NULL;
#if defined(MEMORY_SANITIZER)
// We need to indicate to MSan that memory allocated through sys_mmap is
// initialized, since linux_syscall_support.h doesn't have MSan hooks.
__msan_unpoison(a, page_size_ * num_pages);
#endif
struct PageHeader *header = reinterpret_cast<PageHeader*>(a);
header->next = last_;
header->num_pages = num_pages;

View File

@@ -155,7 +155,7 @@ void Module::GetFiles(vector<File *> *vec) {
vec->push_back(it->second);
}
void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) {
void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const {
*vec = stack_frame_entries_;
}

View File

@@ -247,7 +247,7 @@ class Module {
// effectively a copy of the stack frame entry list, this is mostly
// useful for testing; other uses should probably get
// a more appropriate interface.)
void GetStackFrameEntries(vector<StackFrameEntry *> *vec);
void GetStackFrameEntries(vector<StackFrameEntry *> *vec) const;
// Find those files in this module that are actually referred to by
// functions' line number data, and assign them source id numbers.
@@ -270,6 +270,11 @@ class Module {
// established by SetLoadAddress.
bool Write(std::ostream &stream, SymbolData symbol_data);
string name() const { return name_; }
string os() const { return os_; }
string architecture() const { return architecture_; }
string identifier() const { return id_; }
private:
// Report an error that has occurred writing the symbol file, using
// errno to find the appropriate cause. Return false.

62
src/common/unordered.h Normal file
View File

@@ -0,0 +1,62 @@
// Copyright (c) 2010 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Include this file to use unordered_map and unordered_set. If tr1
// or C++11 is not available, you can switch to using hash_set and
// hash_map by defining BP_USE_HASH_SET.
#ifndef COMMON_UNORDERED_H_
#define COMMON_UNORDERED_H_
#if defined(BP_USE_HASH_SET)
#include <hash_map>
#include <hash_set>
// For hash<string>.
#include "util/hash/hash.h"
template <class T, class U, class H = __gnu_cxx::hash<T> >
struct unordered_map : public hash_map<T, U, H> {};
template <class T, class H = __gnu_cxx::hash<T> >
struct unordered_set : public hash_set<T, H> {};
#elif defined(_LIBCPP_VERSION) // c++11
#include <unordered_map>
#include <unordered_set>
using std::unordered_map;
using std::unordered_set;
#else // Fallback to tr1::unordered
#include <tr1/unordered_map>
#include <tr1/unordered_set>
using std::tr1::unordered_map;
using std::tr1::unordered_set;
#endif
#endif // COMMON_UNORDERED_H_

View File

@@ -64,9 +64,9 @@ BasicCodeModules::BasicCodeModules(const CodeModules *that)
// GetModuleAtIndex because ordering is unimportant when slurping the
// entire list, and GetModuleAtIndex may be faster than
// GetModuleAtSequence.
const CodeModule *module = that->GetModuleAtIndex(module_sequence)->Copy();
if (!map_->StoreRange(module->base_address(), module->size(),
linked_ptr<const CodeModule>(module))) {
linked_ptr<const CodeModule> module(
that->GetModuleAtIndex(module_sequence)->Copy());
if (!map_->StoreRange(module->base_address(), module->size(), module)) {
BPLOG(ERROR) << "Module " << module->code_file() <<
" could not be stored";
}

View File

@@ -366,6 +366,24 @@ static void PrintValueOrInvalid(bool valid,
}
}
// Converts a time_t to a string showing the time in UTC.
string TimeTToUTCString(time_t tt) {
struct tm timestruct;
#ifdef _WIN32
gmtime_s(&timestruct, &tt);
#else
gmtime_r(&tt, &timestruct);
#endif
char timestr[20];
int rv = strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
if (rv == 0) {
return string();
}
return string(timestr);
}
//
// MinidumpObject
@@ -2797,8 +2815,9 @@ void MinidumpModule::Print() {
module_.size_of_image);
printf(" checksum = 0x%x\n",
module_.checksum);
printf(" time_date_stamp = 0x%x\n",
module_.time_date_stamp);
printf(" time_date_stamp = 0x%x %s\n",
module_.time_date_stamp,
TimeTToUTCString(module_.time_date_stamp).c_str());
printf(" module_name_rva = 0x%x\n",
module_.module_name_rva);
printf(" version_info.signature = 0x%x\n",
@@ -2872,8 +2891,9 @@ void MinidumpModule::Print() {
cv_record_20->cv_header.signature);
printf(" (cv_record).cv_header.offset = 0x%x\n",
cv_record_20->cv_header.offset);
printf(" (cv_record).signature = 0x%x\n",
cv_record_20->signature);
printf(" (cv_record).signature = 0x%x %s\n",
cv_record_20->signature,
TimeTToUTCString(cv_record_20->signature).c_str());
printf(" (cv_record).age = %d\n",
cv_record_20->age);
printf(" (cv_record).pdb_file_name = \"%s\"\n",
@@ -2899,13 +2919,19 @@ void MinidumpModule::Print() {
misc_record->length);
printf(" (misc_record).unicode = %d\n",
misc_record->unicode);
// Don't bother printing the UTF-16, we don't really even expect to ever
// see this misc_record anyway.
if (misc_record->unicode)
if (misc_record->unicode) {
string misc_record_data_utf8;
ConvertUTF16BufferToUTF8String(
reinterpret_cast<const uint16_t*>(misc_record->data),
misc_record->length - offsetof(MDImageDebugMisc, data),
&misc_record_data_utf8,
false); // already swapped
printf(" (misc_record).data = \"%s\"\n",
misc_record_data_utf8.c_str());
} else {
printf(" (misc_record).data = \"%s\"\n",
misc_record->data);
else
printf(" (misc_record).data = (UTF-16)\n");
}
} else {
printf(" (misc_record) = (null)\n");
}
@@ -3830,6 +3856,12 @@ void MinidumpSystemInfo::Print() {
system_info_.csd_version_rva);
printf(" suite_mask = 0x%x\n",
system_info_.suite_mask);
if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
printf(" cpu.x86_cpu_info (valid):\n");
} else {
printf(" cpu.x86_cpu_info (invalid):\n");
}
for (unsigned int i = 0; i < 3; ++i) {
printf(" cpu.x86_cpu_info.vendor_id[%d] = 0x%x\n",
i, system_info_.cpu.x86_cpu_info.vendor_id[i]);
@@ -3840,6 +3872,14 @@ void MinidumpSystemInfo::Print() {
system_info_.cpu.x86_cpu_info.feature_information);
printf(" cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
if (system_info_.processor_architecture != MD_CPU_ARCHITECTURE_X86 &&
system_info_.processor_architecture != MD_CPU_ARCHITECTURE_X86_WIN64) {
printf(" cpu.other_cpu_info (valid):\n");
for (unsigned int i = 0; i < 2; ++i) {
printf(" cpu.other_cpu_info.processor_features[%d] = 0x%" PRIx64 "\n",
i, system_info_.cpu.other_cpu_info.processor_features[i]);
}
}
const string* csd_version = GetCSDVersion();
if (csd_version) {
printf(" (csd_version) = \"%s\"\n",
@@ -3964,19 +4004,9 @@ void MinidumpMiscInfo::Print() {
PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_ID,
kNumberFormatDecimal, misc_info_.process_id);
if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES) {
struct tm timestruct;
#ifdef _WIN32
gmtime_s(&timestruct,
reinterpret_cast<time_t*>(&misc_info_.process_create_time));
#else
gmtime_r(reinterpret_cast<time_t*>(&misc_info_.process_create_time),
&timestruct);
#endif
char timestr[20];
strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
printf(" process_create_time = 0x%x %s\n",
misc_info_.process_create_time,
timestr);
TimeTToUTCString(misc_info_.process_create_time).c_str());
} else {
printf(" process_create_time = (invalid)\n");
}
@@ -4773,6 +4803,72 @@ MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() {
return GetStream(&memory_info_list);
}
static const char* get_stream_name(uint32_t stream_type) {
switch (stream_type) {
case MD_UNUSED_STREAM:
return "MD_UNUSED_STREAM";
case MD_RESERVED_STREAM_0:
return "MD_RESERVED_STREAM_0";
case MD_RESERVED_STREAM_1:
return "MD_RESERVED_STREAM_1";
case MD_THREAD_LIST_STREAM:
return "MD_THREAD_LIST_STREAM";
case MD_MODULE_LIST_STREAM:
return "MD_MODULE_LIST_STREAM";
case MD_MEMORY_LIST_STREAM:
return "MD_MEMORY_LIST_STREAM";
case MD_EXCEPTION_STREAM:
return "MD_EXCEPTION_STREAM";
case MD_SYSTEM_INFO_STREAM:
return "MD_SYSTEM_INFO_STREAM";
case MD_THREAD_EX_LIST_STREAM:
return "MD_THREAD_EX_LIST_STREAM";
case MD_MEMORY_64_LIST_STREAM:
return "MD_MEMORY_64_LIST_STREAM";
case MD_COMMENT_STREAM_A:
return "MD_COMMENT_STREAM_A";
case MD_COMMENT_STREAM_W:
return "MD_COMMENT_STREAM_W";
case MD_HANDLE_DATA_STREAM:
return "MD_HANDLE_DATA_STREAM";
case MD_FUNCTION_TABLE_STREAM:
return "MD_FUNCTION_TABLE_STREAM";
case MD_UNLOADED_MODULE_LIST_STREAM:
return "MD_UNLOADED_MODULE_LIST_STREAM";
case MD_MISC_INFO_STREAM:
return "MD_MISC_INFO_STREAM";
case MD_MEMORY_INFO_LIST_STREAM:
return "MD_MEMORY_INFO_LIST_STREAM";
case MD_THREAD_INFO_LIST_STREAM:
return "MD_THREAD_INFO_LIST_STREAM";
case MD_HANDLE_OPERATION_LIST_STREAM:
return "MD_HANDLE_OPERATION_LIST_STREAM";
case MD_LAST_RESERVED_STREAM:
return "MD_LAST_RESERVED_STREAM";
case MD_BREAKPAD_INFO_STREAM:
return "MD_BREAKPAD_INFO_STREAM";
case MD_ASSERTION_INFO_STREAM:
return "MD_ASSERTION_INFO_STREAM";
case MD_LINUX_CPU_INFO:
return "MD_LINUX_CPU_INFO";
case MD_LINUX_PROC_STATUS:
return "MD_LINUX_PROC_STATUS";
case MD_LINUX_LSB_RELEASE:
return "MD_LINUX_LSB_RELEASE";
case MD_LINUX_CMD_LINE:
return "MD_LINUX_CMD_LINE";
case MD_LINUX_ENVIRON:
return "MD_LINUX_ENVIRON";
case MD_LINUX_AUXV:
return "MD_LINUX_AUXV";
case MD_LINUX_MAPS:
return "MD_LINUX_MAPS";
case MD_LINUX_DSO_DEBUG:
return "MD_LINUX_DSO_DEBUG";
default:
return "unknown";
}
}
void Minidump::Print() {
if (!valid_) {
@@ -4786,16 +4882,9 @@ void Minidump::Print() {
printf(" stream_count = %d\n", header_.stream_count);
printf(" stream_directory_rva = 0x%x\n", header_.stream_directory_rva);
printf(" checksum = 0x%x\n", header_.checksum);
struct tm timestruct;
#ifdef _WIN32
gmtime_s(&timestruct, reinterpret_cast<time_t*>(&header_.time_date_stamp));
#else
gmtime_r(reinterpret_cast<time_t*>(&header_.time_date_stamp), &timestruct);
#endif
char timestr[20];
strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
printf(" time_date_stamp = 0x%x %s\n", header_.time_date_stamp,
timestr);
printf(" time_date_stamp = 0x%x %s\n",
header_.time_date_stamp,
TimeTToUTCString(header_.time_date_stamp).c_str());
printf(" flags = 0x%" PRIx64 "\n", header_.flags);
printf("\n");
@@ -4806,7 +4895,8 @@ void Minidump::Print() {
printf("mDirectory[%d]\n", stream_index);
printf("MDRawDirectory\n");
printf(" stream_type = %d\n", directory_entry->stream_type);
printf(" stream_type = 0x%x (%s)\n", directory_entry->stream_type,
get_stream_name(directory_entry->stream_type));
printf(" location.data_size = %d\n",
directory_entry->location.data_size);
printf(" location.rva = 0x%x\n", directory_entry->location.rva);
@@ -4819,7 +4909,9 @@ void Minidump::Print() {
++iterator) {
uint32_t stream_type = iterator->first;
MinidumpStreamInfo info = iterator->second;
printf(" stream type 0x%x at index %d\n", stream_type, info.stream_index);
printf(" stream type 0x%x (%s) at index %d\n", stream_type,
get_stream_name(stream_type),
info.stream_index);
}
printf("\n");
}

175
src/processor/processor.gyp Normal file
View File

@@ -0,0 +1,175 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'includes': [
'processor_tools.gypi',
],
'targets': [
{
'target_name': 'processor',
'type': 'static_library',
'sources': [
'address_map-inl.h',
'address_map.h',
'basic_code_module.h',
'basic_code_modules.cc',
'basic_code_modules.h',
'basic_source_line_resolver.cc',
'basic_source_line_resolver_types.h',
'binarystream.cc',
'binarystream.h',
'call_stack.cc',
'cfi_frame_info-inl.h',
'cfi_frame_info.cc',
'cfi_frame_info.h',
'contained_range_map-inl.h',
'contained_range_map.h',
'disassembler_x86.cc',
'disassembler_x86.h',
'exploitability.cc',
'exploitability_linux.cc',
'exploitability_linux.h',
'exploitability_win.cc',
'exploitability_win.h',
'fast_source_line_resolver.cc',
'fast_source_line_resolver_types.h',
'linked_ptr.h',
'logging.cc',
'logging.h',
'map_serializers-inl.h',
'map_serializers.h',
'minidump.cc',
'minidump_processor.cc',
'module_comparer.cc',
'module_comparer.h',
'module_factory.h',
'module_serializer.cc',
'module_serializer.h',
'pathname_stripper.cc',
'pathname_stripper.h',
'postfix_evaluator-inl.h',
'postfix_evaluator.h',
'process_state.cc',
'range_map-inl.h',
'range_map.h',
'simple_serializer-inl.h',
'simple_serializer.h',
'simple_symbol_supplier.cc',
'simple_symbol_supplier.h',
'source_line_resolver_base.cc',
'source_line_resolver_base_types.h',
'stack_frame_cpu.cc',
'stack_frame_symbolizer.cc',
'stackwalker.cc',
'stackwalker_address_list.cc',
'stackwalker_address_list.h',
'stackwalker_amd64.cc',
'stackwalker_amd64.h',
'stackwalker_arm.cc',
'stackwalker_arm.h',
'stackwalker_arm64.cc',
'stackwalker_arm64.h',
'stackwalker_mips.cc',
'stackwalker_mips.h',
'stackwalker_ppc.cc',
'stackwalker_ppc.h',
'stackwalker_ppc64.cc',
'stackwalker_ppc64.h',
'stackwalker_selftest.cc',
'stackwalker_sparc.cc',
'stackwalker_sparc.h',
'stackwalker_x86.cc',
'stackwalker_x86.h',
'static_address_map-inl.h',
'static_address_map.h',
'static_contained_range_map-inl.h',
'static_contained_range_map.h',
'static_map-inl.h',
'static_map.h',
'static_map_iterator-inl.h',
'static_map_iterator.h',
'static_range_map-inl.h',
'static_range_map.h',
'synth_minidump.cc',
'synth_minidump.h',
'tokenize.cc',
'tokenize.h',
'windows_frame_info.h',
],
'include_dirs': [
'..',
],
'dependencies': [
'../common/common.gyp:common',
'../third_party/libdisasm/libdisasm.gyp:libdisasm',
],
},
{
'target_name': 'processor_unittests',
'type': 'executable',
'sources': [
'address_map_unittest.cc',
'basic_source_line_resolver_unittest.cc',
'binarystream_unittest.cc',
'cfi_frame_info_unittest.cc',
'contained_range_map_unittest.cc',
'disassembler_x86_unittest.cc',
'exploitability_unittest.cc',
'fast_source_line_resolver_unittest.cc',
'map_serializers_unittest.cc',
'minidump_processor_unittest.cc',
'minidump_unittest.cc',
'pathname_stripper_unittest.cc',
'postfix_evaluator_unittest.cc',
'range_map_unittest.cc',
'stackwalker_address_list_unittest.cc',
'stackwalker_amd64_unittest.cc',
'stackwalker_arm64_unittest.cc',
'stackwalker_arm_unittest.cc',
'stackwalker_mips_unittest.cc',
'stackwalker_unittest_utils.h',
'stackwalker_x86_unittest.cc',
'static_address_map_unittest.cc',
'static_contained_range_map_unittest.cc',
'static_map_unittest.cc',
'static_range_map_unittest.cc',
'synth_minidump_unittest.cc',
'synth_minidump_unittest_data.h',
],
'include_dirs': [
'..',
],
'dependencies': [
'processor',
'../build/testing.gypi:gmock',
'../build/testing.gypi:gtest',
],
},
],
}

View File

@@ -0,0 +1,57 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'target_defaults': {
'include_dirs': [
'..',
],
},
'targets': [
{
'target_name': 'minidump_dump',
'type': 'executable',
'sources': [
'minidump_dump.cc',
],
'dependencies': [
'processor',
],
},
{
'target_name': 'minidump_stackwalk',
'type': 'executable',
'sources': [
'minidump_stackwalk.cc',
],
'dependencies': [
'processor',
],
},
],
}

View File

@@ -147,6 +147,52 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByCFIFrameInfo(
return frame.release();
}
StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery(
const vector<StackFrame*>& frames) {
StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
uint64_t last_rsp = last_frame->context.rsp;
uint64_t last_rbp = last_frame->context.rbp;
// Assume the presence of a frame pointer. This is not mandated by the
// AMD64 ABI, c.f. section 3.2.2 footnote 7, though it is typical for
// compilers to still preserve the frame pointer and not treat %rbp as a
// general purpose register.
//
// With this assumption, the CALL instruction pushes the return address
// onto the stack and sets %rip to the procedure to enter. The procedure
// then establishes the stack frame with a prologue that PUSHes the current
// %rbp onto the stack, MOVes the current %rsp to %rbp, and then allocates
// space for any local variables. Using this procedure linking information,
// it is possible to locate frame information for the callee:
//
// %caller_rsp = *(%callee_rbp + 16)
// %caller_rip = *(%callee_rbp + 8)
// %caller_rbp = *(%callee_rbp)
uint64_t caller_rip, caller_rbp;
if (memory_->GetMemoryAtAddress(last_rbp + 8, &caller_rip) &&
memory_->GetMemoryAtAddress(last_rbp, &caller_rbp)) {
uint64_t caller_rsp = last_rbp + 16;
// Simple sanity check that the stack is growing downwards as expected.
if (caller_rbp < last_rbp || caller_rsp < last_rsp)
return NULL;
StackFrameAMD64* frame = new StackFrameAMD64();
frame->trust = StackFrame::FRAME_TRUST_FP;
frame->context = last_frame->context;
frame->context.rip = caller_rip;
frame->context.rsp = caller_rsp;
frame->context.rbp = caller_rbp;
frame->context_validity = StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP |
StackFrameAMD64::CONTEXT_VALID_RBP;
return frame;
}
return NULL;
}
StackFrameAMD64* StackwalkerAMD64::GetCallerByStackScan(
const vector<StackFrame*> &frames) {
StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
@@ -214,8 +260,12 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack,
if (cfi_frame_info.get())
new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
// If CFI failed, or there wasn't CFI available, fall back
// to stack scanning.
// If CFI was not available or failed, try using frame pointer recovery.
if (!new_frame.get()) {
new_frame.reset(GetCallerByFramePointerRecovery(frames));
}
// If all else fails, fall back to stack scanning.
if (stack_scan_allowed && !new_frame.get()) {
new_frame.reset(GetCallerByStackScan(frames));
}

View File

@@ -78,6 +78,14 @@ class StackwalkerAMD64 : public Stackwalker {
StackFrameAMD64* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames,
CFIFrameInfo* cfi_frame_info);
// Assumes a traditional frame layout where the frame pointer has not been
// omitted. The expectation is that caller's %rbp is pushed to the stack
// after the return address of the callee, and that the callee's %rsp can
// be used to find the pushed %rbp.
// Caller owns the returned frame object. Returns NULL on failure.
StackFrameAMD64* GetCallerByFramePointerRecovery(
const vector<StackFrame*>& frames);
// Scan the stack for plausible return addresses. The caller takes ownership
// of the returned frame. Return NULL on failure.
StackFrameAMD64* GetCallerByStackScan(const vector<StackFrame*> &frames);

View File

@@ -491,7 +491,7 @@ TEST_F(GetCallerFrame, CallerPushedRBP) {
EXPECT_EQ(0x40000000c0000100ULL, frame0->function_base);
StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP |
StackFrameAMD64::CONTEXT_VALID_RBP),

View File

@@ -9,67 +9,67 @@ MDRawHeader
mDirectory[0]
MDRawDirectory
stream_type = 3
stream_type = 0x3 (MD_THREAD_LIST_STREAM)
location.data_size = 100
location.rva = 0x184
mDirectory[1]
MDRawDirectory
stream_type = 4
stream_type = 0x4 (MD_MODULE_LIST_STREAM)
location.data_size = 1408
location.rva = 0x1e8
mDirectory[2]
MDRawDirectory
stream_type = 5
stream_type = 0x5 (MD_MEMORY_LIST_STREAM)
location.data_size = 52
location.rva = 0x1505
mDirectory[3]
MDRawDirectory
stream_type = 6
stream_type = 0x6 (MD_EXCEPTION_STREAM)
location.data_size = 168
location.rva = 0xdc
mDirectory[4]
MDRawDirectory
stream_type = 7
stream_type = 0x7 (MD_SYSTEM_INFO_STREAM)
location.data_size = 56
location.rva = 0x8c
mDirectory[5]
MDRawDirectory
stream_type = 15
stream_type = 0xf (MD_MISC_INFO_STREAM)
location.data_size = 24
location.rva = 0xc4
mDirectory[6]
MDRawDirectory
stream_type = 1197932545
stream_type = 0x47670001 (MD_BREAKPAD_INFO_STREAM)
location.data_size = 12
location.rva = 0x14f9
mDirectory[7]
MDRawDirectory
stream_type = 0
stream_type = 0x0 (MD_UNUSED_STREAM)
location.data_size = 0
location.rva = 0x0
mDirectory[8]
MDRawDirectory
stream_type = 0
stream_type = 0x0 (MD_UNUSED_STREAM)
location.data_size = 0
location.rva = 0x0
Streams:
stream type 0x0 at index 8
stream type 0x3 at index 0
stream type 0x4 at index 1
stream type 0x5 at index 2
stream type 0x6 at index 3
stream type 0x7 at index 4
stream type 0xf at index 5
stream type 0x47670001 at index 6
stream type 0x0 (MD_UNUSED_STREAM) at index 8
stream type 0x3 (MD_THREAD_LIST_STREAM) at index 0
stream type 0x4 (MD_MODULE_LIST_STREAM) at index 1
stream type 0x5 (MD_MEMORY_LIST_STREAM) at index 2
stream type 0x6 (MD_EXCEPTION_STREAM) at index 3
stream type 0x7 (MD_SYSTEM_INFO_STREAM) at index 4
stream type 0xf (MD_MISC_INFO_STREAM) at index 5
stream type 0x47670001 (MD_BREAKPAD_INFO_STREAM) at index 6
MinidumpThreadList
thread_count = 2
@@ -184,7 +184,7 @@ MDRawModule
base_of_image = 0x400000
size_of_image = 0x2d000
checksum = 0x0
time_date_stamp = 0x45d35f6c
time_date_stamp = 0x45d35f6c 2007-02-14 19:13:48
module_name_rva = 0x78a
version_info.signature = 0x0
version_info.struct_version = 0x0
@@ -216,7 +216,7 @@ MDRawModule
base_of_image = 0x7c900000
size_of_image = 0xb0000
checksum = 0xaf2f7
time_date_stamp = 0x411096b4
time_date_stamp = 0x411096b4 2004-08-04 07:56:36
module_name_rva = 0x7ae
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -248,7 +248,7 @@ MDRawModule
base_of_image = 0x7c800000
size_of_image = 0xf4000
checksum = 0xf724d
time_date_stamp = 0x44ab9a84
time_date_stamp = 0x44ab9a84 2006-07-05 10:55:00
module_name_rva = 0x7ee
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -280,7 +280,7 @@ MDRawModule
base_of_image = 0x774e0000
size_of_image = 0x13d000
checksum = 0x13dc6b
time_date_stamp = 0x42e5be93
time_date_stamp = 0x42e5be93 2005-07-26 04:39:47
module_name_rva = 0x834
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -312,7 +312,7 @@ MDRawModule
base_of_image = 0x77dd0000
size_of_image = 0x9b000
checksum = 0xa0de4
time_date_stamp = 0x411096a7
time_date_stamp = 0x411096a7 2004-08-04 07:56:23
module_name_rva = 0x874
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -344,7 +344,7 @@ MDRawModule
base_of_image = 0x77e70000
size_of_image = 0x91000
checksum = 0x9c482
time_date_stamp = 0x411096ae
time_date_stamp = 0x411096ae 2004-08-04 07:56:30
module_name_rva = 0x8ba
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -376,7 +376,7 @@ MDRawModule
base_of_image = 0x77f10000
size_of_image = 0x47000
checksum = 0x4d0d0
time_date_stamp = 0x43b34feb
time_date_stamp = 0x43b34feb 2005-12-29 02:54:35
module_name_rva = 0x8fc
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -408,7 +408,7 @@ MDRawModule
base_of_image = 0x77d40000
size_of_image = 0x90000
checksum = 0x9505c
time_date_stamp = 0x42260159
time_date_stamp = 0x42260159 2005-03-02 18:09:29
module_name_rva = 0x93c
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -440,7 +440,7 @@ MDRawModule
base_of_image = 0x77c10000
size_of_image = 0x58000
checksum = 0x57cd3
time_date_stamp = 0x41109752
time_date_stamp = 0x41109752 2004-08-04 07:59:14
module_name_rva = 0x97e
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -472,7 +472,7 @@ MDRawModule
base_of_image = 0x76390000
size_of_image = 0x1d000
checksum = 0x2a024
time_date_stamp = 0x411096ae
time_date_stamp = 0x411096ae 2004-08-04 07:56:30
module_name_rva = 0x9c0
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -504,7 +504,7 @@ MDRawModule
base_of_image = 0x59a60000
size_of_image = 0xa1000
checksum = 0xa8824
time_date_stamp = 0x4110969a
time_date_stamp = 0x4110969a 2004-08-04 07:56:10
module_name_rva = 0xa00
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -536,7 +536,7 @@ MDRawModule
base_of_image = 0x77c00000
size_of_image = 0x8000
checksum = 0x11d78
time_date_stamp = 0x411096b7
time_date_stamp = 0x411096b7 2004-08-04 07:56:39
module_name_rva = 0xa44
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -568,7 +568,7 @@ MDRawModule
base_of_image = 0x76bf0000
size_of_image = 0xb000
checksum = 0xa29b
time_date_stamp = 0x411096ca
time_date_stamp = 0x411096ca 2004-08-04 07:56:58
module_name_rva = 0xa88
version_info.signature = 0xfeef04bd
version_info.struct_version = 0x10000
@@ -670,7 +670,7 @@ MDRawContextX86
extended_registers[512] = 0x7f0200000000220000000000000000000000000000000000801f0000ffff00000000000018b72200000100000000000018b72200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004509917c4e09917c38b622002400020024b42200020000009041917c0070fd7f0510907cccb22200000000009cb3220018ee907c7009917cc0e4977c6f3e917c623e917c08020000dcb62200b4b622001e000000000000000000000000000000000000002eb42200000000000f000000020000001e00200000fcfd7f2f63796764726976652f632f444f43554d457e312f4d4d454e544f7e312f4c4f43414c537e312f54656d7000000000000000000130b422000000004300000000000000001efcfd7f4509917c4e09917c5ad9000008b32200b4b62200
MDRawSystemInfo
processor_architecture = 0
processor_architecture = 0x0
processor_level = 6
processor_revision = 0xd08
number_of_processors = 1
@@ -678,9 +678,10 @@ MDRawSystemInfo
major_version = 5
minor_version = 1
build_number = 2600
platform_id = 2
platform_id = 0x2
csd_version_rva = 0x768
suite_mask = 0x100
cpu.x86_cpu_info (valid):
cpu.x86_cpu_info.vendor_id[0] = 0x756e6547
cpu.x86_cpu_info.vendor_id[1] = 0x49656e69
cpu.x86_cpu_info.vendor_id[2] = 0x6c65746e
@@ -693,10 +694,10 @@ MDRawSystemInfo
MDRawMiscInfo
size_of_info = 24
flags1 = 0x3
process_id = 0xf5c
process_create_time = 0x45d35f73
process_user_time = 0x0
process_kernel_time = 0x0
process_id = 3932
process_create_time = 0x45d35f73 2007-02-14 19:13:55
process_user_time = 0
process_kernel_time = 0
MDRawBreakpadInfo
validity = 0x3

64
src/third_party/libdisasm/libdisasm.gyp vendored Normal file
View File

@@ -0,0 +1,64 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'targets': [
{
'target_name': 'libdisasm',
'type': 'static_library',
'sources': [
'ia32_implicit.c',
'ia32_implicit.h',
'ia32_insn.c',
'ia32_insn.h',
'ia32_invariant.c',
'ia32_invariant.h',
'ia32_modrm.c',
'ia32_modrm.h',
'ia32_opcode_tables.c',
'ia32_opcode_tables.h',
'ia32_operand.c',
'ia32_operand.h',
'ia32_reg.c',
'ia32_reg.h',
'ia32_settings.c',
'ia32_settings.h',
'libdis.h',
'qword.h',
'x86_disasm.c',
'x86_format.c',
'x86_imm.c',
'x86_imm.h',
'x86_insn.c',
'x86_misc.c',
'x86_operand_list.c',
'x86_operand_list.h',
],
},
],
}

View File

@@ -997,7 +997,7 @@ main(int argc, char** argv) {
if (argc != argi + 1)
return usage(argv[0]);
MemoryMappedFile mapped_file(argv[argi]);
MemoryMappedFile mapped_file(argv[argi], 0);
if (!mapped_file.data()) {
fprintf(stderr, "Failed to mmap dump file\n");
return 1;

View File

@@ -0,0 +1,83 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'target_defaults': {
'include_dirs': [
'../..',
],
},
'targets': [
{
'target_name': 'dump_syms',
'type': 'executable',
'sources': [
'dump_syms/dump_syms.cc',
],
'dependencies': [
'../common/common.gyp:common',
],
},
{
'target_name': 'md2core',
'type': 'executable',
'sources': [
'md2core/minidump-2-core.cc',
'md2core/minidump_memory_range.h',
],
'dependencies': [
'../common/common.gyp:common',
],
},
{
'target_name': 'minidump_upload',
'type': 'executable',
'sources': [
'symupload/minidump_upload.m',
],
'dependencies': [
'../common/common.gyp:common',
],
},
{
'target_name': 'symupload',
'type': 'executable',
'sources': [
'symupload/sym_upload.cc',
],
'link_settings': {
'libraries': [
'-ldl',
],
},
'dependencies': [
'../common/common.gyp:common',
],
},
],
}

View File

@@ -40,7 +40,7 @@
#include "processor/pathname_stripper.h"
#include "on_demand_symbol_supplier.h"
#include "dump_syms.h"
#include "common/mac/dump_syms.h"
using std::map;
using std::string;

View File

@@ -41,31 +41,89 @@
#include "common/mac/dump_syms.h"
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_utilities.h"
#include "common/scoped_ptr.h"
using google_breakpad::DumpSymbols;
using google_breakpad::Module;
using google_breakpad::scoped_ptr;
using std::vector;
struct Options {
Options() : srcPath(), arch(), cfi(true), handle_inter_cu_refs(true) { }
NSString *srcPath;
NSString *dsymPath;
const NXArchInfo *arch;
bool cfi;
bool handle_inter_cu_refs;
};
//=============================================================================
static bool Start(const Options &options) {
DumpSymbols dump_symbols(options.cfi ? ALL_SYMBOL_DATA : NO_CFI,
options.handle_inter_cu_refs);
static bool StackFrameEntryComparator(const Module::StackFrameEntry* a,
const Module::StackFrameEntry* b) {
return a->address < b->address;
}
if (!dump_symbols.Read(options.srcPath))
// Copy the CFI data from |from_module| into |to_module|, for any non-
// overlapping ranges.
static void CopyCFIDataBetweenModules(Module* to_module,
const Module* from_module) {
typedef vector<Module::StackFrameEntry*>::const_iterator Iterator;
// Get the CFI data from both the source and destination modules and ensure
// it is sorted by start address.
vector<Module::StackFrameEntry*> from_data;
from_module->GetStackFrameEntries(&from_data);
std::sort(from_data.begin(), from_data.end(), &StackFrameEntryComparator);
vector<Module::StackFrameEntry*> to_data;
to_module->GetStackFrameEntries(&to_data);
std::sort(to_data.begin(), to_data.end(), &StackFrameEntryComparator);
Iterator to_it = to_data.begin();
for (Iterator it = from_data.begin(); it != from_data.end(); ++it) {
Module::StackFrameEntry* from_entry = *it;
Module::Address from_entry_end = from_entry->address + from_entry->size;
// Find the first CFI record in the |to_module| that does not have an
// address less than the entry to be copied.
while (to_it != to_data.end()) {
if (from_entry->address > (*to_it)->address)
++to_it;
else
break;
}
// If the entry does not overlap, then it is safe to copy to |to_module|.
if (to_it == to_data.end() || (from_entry->address < (*to_it)->address &&
from_entry_end < (*to_it)->address)) {
to_module->AddStackFrameEntry(new Module::StackFrameEntry(*from_entry));
}
}
}
static bool Start(const Options &options) {
SymbolData symbol_data = options.cfi ? ALL_SYMBOL_DATA : NO_CFI;
DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs);
// For x86_64 binaries, the CFI data is in the __TEXT,__eh_frame of the
// Mach-O file, which is not copied into the dSYM. Whereas in i386, the CFI
// data is in the __DWARF,__debug_frame section, which is moved into the
// dSYM. Therefore, to get x86_64 CFI data, dump_syms needs to look at both
// the dSYM and the Mach-O file. If both paths are present and CFI was
// requested, then consider the Module as "split" and dump all the debug data
// from the primary debug info file, the dSYM, and then dump additional CFI
// data from the source Mach-O file.
bool split_module = options.dsymPath && options.srcPath && options.cfi;
NSString* primary_file = split_module ? options.dsymPath : options.srcPath;
if (!dump_symbols.Read(primary_file))
return false;
if (options.arch) {
if (!dump_symbols.SetArchitecture(options.arch->cputype,
options.arch->cpusubtype)) {
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
[options.srcPath fileSystemRepresentation], options.arch->name);
[primary_file fileSystemRepresentation], options.arch->name);
size_t available_size;
const struct fat_arch *available =
dump_symbols.AvailableArchitectures(&available_size);
@@ -88,16 +146,48 @@ static bool Start(const Options &options) {
}
}
return dump_symbols.WriteSymbolFile(std::cout);
// Read the primary file into a Breakpad Module.
Module* module = NULL;
if (!dump_symbols.ReadSymbolData(&module))
return false;
scoped_ptr<Module> scoped_module(module);
// If this is a split module, read the secondary Mach-O file, from which the
// CFI data will be extracted.
if (split_module && primary_file == options.dsymPath) {
if (!dump_symbols.Read(options.srcPath))
return false;
Module* cfi_module = NULL;
if (!dump_symbols.ReadSymbolData(&cfi_module))
return false;
scoped_ptr<Module> scoped_cfi_module(cfi_module);
// Ensure that the modules are for the same debug code file.
if (cfi_module->name() != module->name() ||
cfi_module->os() != module->os() ||
cfi_module->architecture() != module->architecture() ||
cfi_module->identifier() != module->identifier()) {
fprintf(stderr, "Cannot generate a symbol file from split sources that do"
" not match.\n");
return false;
}
CopyCFIDataBetweenModules(module, cfi_module);
}
return module->Write(std::cout, symbol_data);
}
//=============================================================================
static void Usage(int argc, const char *argv[]) {
fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n");
fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] <Mach-o file>\n",
argv[0]);
fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] "
"<Mach-o file>\n", argv[0]);
fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n");
fprintf(stderr, "\t in the file, if it contains only one architecture]\n");
fprintf(stderr, "\t-g: Debug symbol file (dSYM) to dump in addition to the "
"Mach-o file\n");
fprintf(stderr, "\t-c: Do not generate CFI section\n");
fprintf(stderr, "\t-r: Do not handle inter-compilation unit references\n");
fprintf(stderr, "\t-h: Usage\n");
@@ -109,7 +199,7 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
extern int optind;
signed char ch;
while ((ch = getopt(argc, (char * const *)argv, "a:chr?")) != -1) {
while ((ch = getopt(argc, (char * const *)argv, "a:g:chr?")) != -1) {
switch (ch) {
case 'a': {
const NXArchInfo *arch_info =
@@ -122,6 +212,10 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
options->arch = arch_info;
break;
}
case 'g':
options->dsymPath = [[NSFileManager defaultManager]
stringWithFileSystemRepresentation:optarg length:strlen(optarg)];
break;
case 'c':
options->cfi = false;
break;

View File

@@ -0,0 +1,116 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'target_defaults': {
'include_dirs': [
'../..',
],
},
'targets': [
{
'target_name': 'crash_report',
'type': 'executable',
'sources': [
'crash_report/crash_report.mm',
'crash_report/on_demand_symbol_supplier.h',
'crash_report/on_demand_symbol_supplier.mm',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
],
},
'dependencies': [
'../common/common.gyp:common',
'../processor/processor.gyp:processor',
],
},
{
'target_name': 'dump_syms',
'type': 'executable',
'sources': [
'dump_syms/dump_syms_tool.mm',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
],
},
'dependencies': [
'../common/common.gyp:common',
],
},
{
'target_name': 'macho_dump',
'type': 'executable',
'sources': [
'dump_syms/macho_dump.cc',
],
'dependencies': [
'../common/common.gyp:common',
],
},
{
'target_name': 'minidump_upload',
'type': 'executable',
'sources': [
'symupload/minidump_upload.m',
],
'include_dirs': [
'../../common/mac',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
],
},
'dependencies': [
'../common/common.gyp:common',
],
},
{
'target_name': 'symupload',
'type': 'executable',
'sources': [
'symupload/symupload.m',
],
'include_dirs': [
'../../common/mac',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
],
},
'dependencies': [
'../common/common.gyp:common',
],
},
],
}

38
src/tools/tools.gyp Normal file
View File

@@ -0,0 +1,38 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
'conditions': [
['OS=="mac"', {
'includes': ['mac/tools_mac.gypi'],
}],
['OS=="linux"', {
'includes': ['linux/tools_linux.gypi'],
}],
],
}