Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b96b967685 | ||
![]() |
71ff627265 | ||
![]() |
e2fffff1a4 | ||
![]() |
dab50e6f6e | ||
![]() |
c41b7fc414 | ||
![]() |
561f818735 | ||
![]() |
b7aa202b54 | ||
![]() |
8703844b3c | ||
![]() |
6c57bc19a5 | ||
![]() |
d91bd8d23a | ||
![]() |
d7d532bf56 | ||
![]() |
0a5ebafdf0 | ||
![]() |
9e8ffc9fab | ||
![]() |
21384ad0e2 | ||
![]() |
f88336d4a1 | ||
![]() |
501673c86b | ||
![]() |
bf0e00374f | ||
![]() |
ada265ebbd | ||
![]() |
9d62ef9311 | ||
![]() |
a5da1e193c |
41
src/build/all.gyp
Normal file
41
src/build/all.gyp
Normal 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:*',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -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"
|
||||
|
57
src/build/filename_rules.gypi
Normal file
57
src/build/filename_rules.gypi
Normal 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
67
src/build/gyp_breakpad
Executable 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
90
src/build/testing.gypi
Normal 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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -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"
|
||||
|
@@ -258,6 +258,7 @@ void Breakpad::UncaughtExceptionHandler(NSException *exception) {
|
||||
if (current_breakpad_) {
|
||||
current_breakpad_->HandleUncaughtException(exception);
|
||||
}
|
||||
BreakpadRelease(current_breakpad_);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@@ -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
|
||||
|
@@ -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};
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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))
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
|
||||
|
@@ -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 {
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
240
src/common/common.gyp
Normal 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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
@@ -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());
|
||||
|
@@ -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);
|
||||
|
@@ -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_
|
||||
|
@@ -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**)¬e_section, ¬e_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;
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
84
src/common/mac/launch_reporter.cc
Normal file
84
src/common/mac/launch_reporter.cc
Normal 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
|
43
src/common/mac/launch_reporter.h
Normal file
43
src/common/mac/launch_reporter.h
Normal 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__
|
@@ -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;
|
||||
|
@@ -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_;
|
||||
}
|
||||
|
||||
|
@@ -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
62
src/common/unordered.h
Normal 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_
|
@@ -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";
|
||||
}
|
||||
|
@@ -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(×truct, &tt);
|
||||
#else
|
||||
gmtime_r(&tt, ×truct);
|
||||
#endif
|
||||
|
||||
char timestr[20];
|
||||
int rv = strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct);
|
||||
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(×truct,
|
||||
reinterpret_cast<time_t*>(&misc_info_.process_create_time));
|
||||
#else
|
||||
gmtime_r(reinterpret_cast<time_t*>(&misc_info_.process_create_time),
|
||||
×truct);
|
||||
#endif
|
||||
char timestr[20];
|
||||
strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct);
|
||||
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(×truct, reinterpret_cast<time_t*>(&header_.time_date_stamp));
|
||||
#else
|
||||
gmtime_r(reinterpret_cast<time_t*>(&header_.time_date_stamp), ×truct);
|
||||
#endif
|
||||
char timestr[20];
|
||||
strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct);
|
||||
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
175
src/processor/processor.gyp
Normal 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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
57
src/processor/processor_tools.gypi
Normal file
57
src/processor/processor_tools.gypi
Normal 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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -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));
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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),
|
||||
|
73
src/processor/testdata/minidump2.dump.out
vendored
73
src/processor/testdata/minidump2.dump.out
vendored
@@ -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
64
src/third_party/libdisasm/libdisasm.gyp
vendored
Normal 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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -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;
|
||||
|
83
src/tools/linux/tools_linux.gypi
Normal file
83
src/tools/linux/tools_linux.gypi
Normal 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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
116
src/tools/mac/tools_mac.gypi
Normal file
116
src/tools/mac/tools_mac.gypi
Normal 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
38
src/tools/tools.gyp
Normal 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'],
|
||||
}],
|
||||
],
|
||||
}
|
Reference in New Issue
Block a user