diff options
author | Elliott Hughes <enh@google.com> | 2023-08-10 22:58:49 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-08-10 22:58:49 +0000 |
commit | c3c25b3748e23f22d7eb5c0cf6ed671259a25aa0 (patch) | |
tree | f98d11d6a158167e19fc9141c79d877280a616a6 /src | |
parent | 8d0176459cfc11e28e9427a7eadcf7a42f654f62 (diff) | |
parent | 332a4371eda197cfcbcd01bf197482aecde23a1a (diff) | |
download | google-breakpad-c3c25b3748e23f22d7eb5c0cf6ed671259a25aa0.tar.gz |
Upgrade google-breakpad to v2023.01.27 am: 332a4371ed
Original change: https://android-review.googlesource.com/c/platform/external/google-breakpad/+/2704174
Change-Id: I2b9d3aeb0d60cce168eaa83dbf2e3225f26fe34e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'src')
643 files changed, 27769 insertions, 17897 deletions
diff --git a/src/breakpad_googletest_includes.h b/src/breakpad_googletest_includes.h index 19a3e980..4bc44a83 100644 --- a/src/breakpad_googletest_includes.h +++ b/src/breakpad_googletest_includes.h @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/build/all.gyp b/src/build/all.gyp deleted file mode 100644 index 4b59d917..00000000 --- a/src/build/all.gyp +++ /dev/null @@ -1,41 +0,0 @@ -# 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:*', - ], - }, - ], -} diff --git a/src/build/common.gypi b/src/build/common.gypi deleted file mode 100644 index 29990c65..00000000 --- a/src/build/common.gypi +++ /dev/null @@ -1,1045 +0,0 @@ -# Copyright 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. - -# IMPORTANT: -# Please don't directly include this file if you are building via gyp_chromium, -# since gyp_chromium is automatically forcing its inclusion. -{ - 'variables': { - # Variables expected to be overriden on the GYP command line (-D) or by - # ~/.gyp/include.gypi. - - # Putting a variables dict inside another variables dict looks kind of - # weird. This is necessary to get these variables defined for the conditions - # within this variables dict that operate on these variables. - 'variables': { - 'variables': { - # Compute the architecture that we're building on. - 'conditions': [ - [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { - # This handles the Linux platforms we generally deal with. Anything - # else gets passed through, which probably won't work very well; such - # hosts should pass an explicit target_arch to gyp. - 'host_arch%': - '<!(uname -m | sed -e "s/i.86/ia32/;s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/")', - }, { # OS!="linux" - 'host_arch%': 'ia32', - }], - ], - }, - - 'host_arch%': '<(host_arch)', - - # Default architecture we're building for is the architecture we're - # building on. - 'target_arch%': '<(host_arch)', - - # This variable tells WebCore.gyp and JavaScriptCore.gyp whether they are - # are built under a chromium full build (1) or a webkit.org chromium - # build (0). - 'inside_chromium_build%': 1, - - # Set to 1 compile with -fPIC cflag on linux. This is a must for shared - # libraries on linux x86-64 and arm. - 'linux_fpic%': 0, - - # Python version. - 'python_ver%': '2.5', - - # Determine ARM compilation flags. - 'arm_version%': 7, - - # Set Neon compilation flags (only meaningful if arm_version==7). - 'arm_neon%': 1, - - # The system root for cross-compiles. Default: none. - 'sysroot%': '', - - # On Linux, we build with sse2 for Chromium builds. - 'disable_sse2%': 0, - }, - - 'target_arch%': '<(target_arch)', - 'host_arch%': '<(host_arch)', - 'inside_chromium_build%': '<(inside_chromium_build)', - 'linux_fpic%': '<(linux_fpic)', - 'python_ver%': '<(python_ver)', - 'arm_version%': '<(arm_version)', - 'arm_neon%': '<(arm_neon)', - 'sysroot%': '<(sysroot)', - 'disable_sse2%': '<(disable_sse2)', - - # The release channel that this build targets. This is used to restrict - # channel-specific build options, like which installer packages to create. - # The default is 'all', which does no channel-specific filtering. - 'channel%': 'all', - - # Override chromium_mac_pch and set it to 0 to suppress the use of - # precompiled headers on the Mac. Prefix header injection may still be - # used, but prefix headers will not be precompiled. This is useful when - # using distcc to distribute a build to compile slaves that don't - # share the same compiler executable as the system driving the compilation, - # because precompiled headers rely on pointers into a specific compiler - # executable's image. Setting this to 0 is needed to use an experimental - # Linux-Mac cross compiler distcc farm. - 'chromium_mac_pch%': 1, - - # Mac OS X SDK and deployment target support. - # The SDK identifies the version of the system headers that will be used, - # and corresponds to the MAC_OS_X_VERSION_MAX_ALLOWED compile-time macro. - # "Maximum allowed" refers to the operating system version whose APIs are - # available in the headers. - # The deployment target identifies the minimum system version that the - # built products are expected to function on. It corresponds to the - # MAC_OS_X_VERSION_MIN_REQUIRED compile-time macro. - # To ensure these macros are available, #include <AvailabilityMacros.h>. - # Additional documentation on these macros is available at - # http://developer.apple.com/mac/library/technotes/tn2002/tn2064.html#SECTION3 - # Chrome normally builds with the Mac OS X 10.5 SDK and sets the - # deployment target to 10.5. Other projects, such as O3D, may override - # these defaults. - 'mac_sdk%': '10.5', - 'mac_deployment_target%': '10.5', - - # Set to 1 to enable code coverage. In addition to build changes - # (e.g. extra CFLAGS), also creates a new target in the src/chrome - # project file called "coverage". - # Currently ignored on Windows. - 'coverage%': 0, - - # Although base/allocator lets you select a heap library via an - # environment variable, the libcmt shim it uses sometimes gets in - # the way. To disable it entirely, and switch to normal msvcrt, do e.g. - # 'win_use_allocator_shim': 0, - # 'win_release_RuntimeLibrary': 2 - # to ~/.gyp/include.gypi, gclient runhooks --force, and do a release build. - 'win_use_allocator_shim%': 1, # 0 = shim allocator via libcmt; 1 = msvcrt - - # Whether usage of OpenMAX is enabled. - 'enable_openmax%': 0, - - # TODO(bradnelson): eliminate this when possible. - # To allow local gyp files to prevent release.vsprops from being included. - # Yes(1) means include release.vsprops. - # Once all vsprops settings are migrated into gyp, this can go away. - 'msvs_use_common_release%': 1, - - # TODO(bradnelson): eliminate this when possible. - # To allow local gyp files to override additional linker options for msvs. - # Yes(1) means set use the common linker options. - 'msvs_use_common_linker_extras%': 1, - - # TODO(sgk): eliminate this if possible. - # It would be nicer to support this via a setting in 'target_defaults' - # in chrome/app/locales/locales.gypi overriding the setting in the - # 'Debug' configuration in the 'target_defaults' dict below, - # but that doesn't work as we'd like. - 'msvs_debug_link_incremental%': '2', - - # This is the location of the sandbox binary. Chrome looks for this before - # running the zygote process. If found, and SUID, it will be used to - # sandbox the zygote process and, thus, all renderer processes. - 'linux_sandbox_path%': '', - - # Set this to true to enable SELinux support. - 'selinux%': 0, - - # Strip the binary after dumping symbols. - 'linux_strip_binary%': 0, - - # Enable TCMalloc. - 'linux_use_tcmalloc%': 1, - - # Disable TCMalloc's debugallocation. - 'linux_use_debugallocation%': 0, - - # Disable TCMalloc's heapchecker. - 'linux_use_heapchecker%': 0, - - # Set to 1 to turn on seccomp sandbox by default. - # (Note: this is ignored for official builds.) - 'linux_use_seccomp_sandbox%': 0, - - # Set to select the Title Case versions of strings in GRD files. - 'use_titlecase_in_grd%': 0, - - # Used to disable Native Client at compile time, for platforms where it - # isn't supported - 'disable_nacl%': 0, - - # Set Thumb compilation flags. - 'arm_thumb%': 0, - - # Set ARM fpu compilation flags (only meaningful if arm_version==7 and - # arm_neon==0). - 'arm_fpu%': 'vfpv3', - - # Enable new NPDevice API. - 'enable_new_npdevice_api%': 0, - - 'conditions': [ - # 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. - ['OS=="win"', { - 'conditions': [ - ['MSVS_VERSION=="2005"', { - 'msvs_multi_core_compile%': 0, - },{ - 'msvs_multi_core_compile%': 1, - }], - # Don't do incremental linking for large modules on 32-bit. - ['MSVS_OS_BITS==32', { - 'msvs_large_module_debug_link_mode%': '1', # No - },{ - 'msvs_large_module_debug_link_mode%': '2', # Yes - }], - ], - 'nacl_win64_defines': [ - # This flag is used to minimize dependencies when building - # Native Client loader for 64-bit Windows. - 'NACL_WIN64', - ], - }], - ], - - # NOTE: When these end up in the Mac bundle, we need to replace '-' for '_' - # so Cocoa is happy (http://crbug.com/20441). - 'locales': [ - 'am', 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en-GB', - 'en-US', 'es-419', 'es', 'et', 'fi', 'fil', 'fr', 'gu', 'he', - 'hi', 'hr', 'hu', 'id', 'it', 'ja', 'kn', 'ko', 'lt', 'lv', - 'ml', 'mr', 'nb', 'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', - 'sk', 'sl', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tr', 'uk', - 'vi', 'zh-CN', 'zh-TW', - ], - }, - '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 - 'mac_debug_optimization%': '0', # Use -O0 unless overridden - # See http://msdn.microsoft.com/en-us/library/aa652360(VS.71).aspx - 'win_release_Optimization%': '2', # 2 = /Os - 'win_debug_Optimization%': '0', # 0 = /Od - # See http://msdn.microsoft.com/en-us/library/aa652367(VS.71).aspx - 'win_release_RuntimeLibrary%': '0', # 0 = /MT (nondebug static) - 'win_debug_RuntimeLibrary%': '1', # 1 = /MTd (debug static) - - 'release_extra_cflags%': '', - 'debug_extra_cflags%': '', - 'release_valgrind_build%': 0, - }, - 'conditions': [ - ['selinux==1', { - 'defines': ['CHROMIUM_SELINUX=1'], - }], - ['win_use_allocator_shim==0', { - 'conditions': [ - ['OS=="win"', { - 'defines': ['NO_TCMALLOC'], - }], - ], - }], - ['coverage!=0', { - 'conditions': [ - ['OS=="mac"', { - 'xcode_settings': { - 'GCC_INSTRUMENT_PROGRAM_FLOW_ARCS': 'YES', # -fprofile-arcs - 'GCC_GENERATE_TEST_COVERAGE_FILES': 'YES', # -ftest-coverage - }, - # Add -lgcov for types executable, shared_library, and - # loadable_module; not for static_library. - # This is a delayed conditional. - 'target_conditions': [ - ['_type!="static_library"', { - 'xcode_settings': { 'OTHER_LDFLAGS': [ '-lgcov' ] }, - }], - ], - }], - # Linux gyp (into scons) doesn't like target_conditions? - # TODO(???): track down why 'target_conditions' doesn't work - # on Linux gyp into scons like it does on Mac gyp into xcodeproj. - ['OS=="linux"', { - 'cflags': [ '-ftest-coverage', - '-fprofile-arcs' ], - 'link_settings': { 'libraries': [ '-lgcov' ] }, - }], - # Finally, for Windows, we simply turn on profiling. - ['OS=="win"', { - 'msvs_settings': { - 'VCLinkerTool': { - 'Profile': 'true', - }, - 'VCCLCompilerTool': { - # /Z7, not /Zi, so coverage is happyb - 'DebugInformationFormat': '1', - 'AdditionalOptions': ['/Yd'], - } - } - }], # OS==win - ], # conditions for coverage - }], # coverage!=0 - ], # conditions for 'target_defaults' - 'target_conditions': [ - [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { - 'cflags!': [ - '-Wall', - '-Wextra', - '-Werror', - ], - }], - [ 'OS=="win"', { - 'defines': [ - '_CRT_SECURE_NO_DEPRECATE', - '_CRT_NONSTDC_NO_WARNINGS', - '_CRT_NONSTDC_NO_DEPRECATE', - # This is required for ATL to use XP-safe versions of its functions. - '_USING_V110_SDK71_', - ], - 'msvs_disabled_warnings': [4800], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'WarnAsError': 'true', - 'Detect64BitPortabilityProblems': 'false', - }, - }, - }], - [ 'OS=="mac"', { - 'xcode_settings': { - 'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO', - 'WARNING_CFLAGS!': ['-Wall'], - }, - }], - ], # target_conditions for 'target_defaults' - 'default_configuration': 'Debug', - 'configurations': { - # VCLinkerTool LinkIncremental values below: - # 0 == default - # 1 == /INCREMENTAL:NO - # 2 == /INCREMENTAL - # Debug links incremental, Release does not. - # - # Abstract base configurations to cover common - # attributes. - # - 'Common_Base': { - 'abstract': 1, - 'msvs_configuration_attributes': { - 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)', - 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)', - 'CharacterSet': '1', - }, - }, - 'x86_Base': { - 'abstract': 1, - 'msvs_settings': { - 'VCLinkerTool': { - 'MinimumRequiredVersion': '5.01', # XP. - 'TargetMachine': '1', - }, - }, - 'msvs_configuration_platform': 'Win32', - }, - 'x64_Base': { - 'abstract': 1, - 'msvs_configuration_platform': 'x64', - 'msvs_settings': { - 'VCLinkerTool': { - 'TargetMachine': '17', # x86 - 64 - 'AdditionalLibraryDirectories!': - ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'], - 'AdditionalLibraryDirectories': - ['<(DEPTH)/third_party/platformsdk_win7/files/Lib/x64'], - }, - 'VCLibrarianTool': { - 'AdditionalLibraryDirectories!': - ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'], - 'AdditionalLibraryDirectories': - ['<(DEPTH)/third_party/platformsdk_win7/files/Lib/x64'], - }, - }, - 'defines': [ - # Not sure if tcmalloc works on 64-bit Windows. - 'NO_TCMALLOC', - ], - }, - 'Debug_Base': { - 'abstract': 1, - 'xcode_settings': { - 'COPY_PHASE_STRIP': 'NO', - 'GCC_OPTIMIZATION_LEVEL': '<(mac_debug_optimization)', - 'OTHER_CFLAGS': [ '<@(debug_extra_cflags)', ], - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '<(win_debug_Optimization)', - 'PreprocessorDefinitions': ['_DEBUG'], - 'BasicRuntimeChecks': '3', - 'RuntimeLibrary': '<(win_debug_RuntimeLibrary)', - }, - 'VCLinkerTool': { - 'LinkIncremental': '<(msvs_debug_link_incremental)', - }, - 'VCResourceCompilerTool': { - 'PreprocessorDefinitions': ['_DEBUG'], - }, - }, - 'conditions': [ - ['OS=="linux"', { - 'cflags': [ - '<@(debug_extra_cflags)', - ], - }], - ], - }, - 'Release_Base': { - 'abstract': 1, - 'defines': [ - 'NDEBUG', - ], - 'xcode_settings': { - 'DEAD_CODE_STRIPPING': 'YES', # -Wl,-dead_strip - 'GCC_OPTIMIZATION_LEVEL': '<(mac_release_optimization)', - 'OTHER_CFLAGS': [ '<@(release_extra_cflags)', ], - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '<(win_release_Optimization)', - 'RuntimeLibrary': '<(win_release_RuntimeLibrary)', - }, - 'VCLinkerTool': { - 'LinkIncremental': '1', - }, - }, - 'conditions': [ - ['release_valgrind_build==0', { - 'defines': ['NVALGRIND'], - }], - ['win_use_allocator_shim==0', { - 'defines': ['NO_TCMALLOC'], - }], - ['win_release_RuntimeLibrary==2', { - # Visual C++ 2008 barfs when building anything with /MD (msvcrt): - # VC\include\typeinfo(139) : warning C4275: non dll-interface - # class 'stdext::exception' used as base for dll-interface - # class 'std::bad_cast' - 'msvs_disabled_warnings': [4275], - }], - ['OS=="linux"', { - 'cflags': [ - '<@(release_extra_cflags)', - ], - }], - ], - }, - 'Purify_Base': { - 'abstract': 1, - 'defines': [ - 'PURIFY', - 'NO_TCMALLOC', - ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '0', - 'RuntimeLibrary': '0', - 'BufferSecurityCheck': 'false', - }, - 'VCLinkerTool': { - 'EnableCOMDATFolding': '1', - 'LinkIncremental': '1', - }, - }, - }, - # - # Concrete configurations - # - 'Debug': { - 'inherit_from': ['Common_Base', 'x86_Base', 'Debug_Base'], - }, - 'Release': { - 'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base'], - 'conditions': [ - ['msvs_use_common_release', { - 'defines': ['OFFICIAL_BUILD'], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '3', - 'StringPooling': 'true', - 'OmitFramePointers': 'true', - 'InlineFunctionExpansion': '2', - 'EnableIntrinsicFunctions': 'true', - 'FavorSizeOrSpeed': '2', - 'OmitFramePointers': 'true', - 'EnableFiberSafeOptimizations': 'true', - 'WholeProgramOptimization': 'true', - }, - 'VCLibrarianTool': { - 'AdditionalOptions': ['/ltcg', '/expectedoutputsize:120000000'], - }, - 'VCLinkerTool': { - 'LinkIncremental': '1', - 'OptimizeReferences': '2', - 'EnableCOMDATFolding': '2', - 'OptimizeForWindows98': '1', - 'LinkTimeCodeGeneration': '1', - }, - }, - }], - ] - }, - 'conditions': [ - [ 'OS=="win"', { - # TODO(bradnelson): add a gyp mechanism to make this more graceful. - 'Purify': { - 'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base', 'Purify'], - }, - 'Debug_x64': { - 'inherit_from': ['Common_Base', 'x64_Base', 'Debug_Base'], - }, - 'Release_x64': { - 'inherit_from': ['Common_Base', 'x64_Base', 'Release_Base'], - }, - 'Purify_x64': { - 'inherit_from': ['Common_Base', 'x64_Base', 'Release_Base', 'Purify_Base'], - }, - }], - ], - }, - }, - 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { - 'target_defaults': { - # Enable -Werror by default, but put it in a variable so it can - # be disabled in ~/.gyp/include.gypi on the valgrind builders. - 'variables': { - # Use -fno-strict-aliasing by default since gcc 4.4 has periodic - # issues that slip through the cracks. We could do this just for - # gcc 4.4 but it makes more sense to be consistent on all - # compilers in use. TODO(Craig): turn this off again when - # there is some 4.4 test infrastructure in place and existing - # aliasing issues have been fixed. - 'no_strict_aliasing%': 1, - 'conditions': [['OS=="linux"', {'werror%': '-Werror',}], - ['OS=="freebsd"', {'werror%': '',}], - ['OS=="openbsd"', {'werror%': '',}], - ], - }, - 'cflags': [ - '<(werror)', # See note above about the werror variable. - '-pthread', - '-fno-exceptions', - '-Wall', - # TODO(evan): turn this back on once all the builds work. - # '-Wextra', - # Don't warn about unused function params. We use those everywhere. - '-Wno-unused-parameter', - # Don't warn about the "struct foo f = {0};" initialization pattern. - '-Wno-missing-field-initializers', - '-D_FILE_OFFSET_BITS=64', - # Don't export any symbols (for example, to plugins we dlopen()). - # Note: this is *required* to make some plugins work. - '-fvisibility=hidden', - ], - 'cflags_cc': [ - '-frtti', - '-fno-threadsafe-statics', - # Make inline functions have hidden visiblity by default. - # Surprisingly, not covered by -fvisibility=hidden. - '-fvisibility-inlines-hidden', - ], - 'ldflags': [ - '-pthread', '-Wl,-z,noexecstack', - ], - 'scons_variable_settings': { - 'LIBPATH': ['$LIB_DIR'], - # Linking of large files uses lots of RAM, so serialize links - # using the handy flock command from util-linux. - 'FLOCK_LINK': ['flock', '$TOP_BUILDDIR/linker.lock', '$LINK'], - 'FLOCK_SHLINK': ['flock', '$TOP_BUILDDIR/linker.lock', '$SHLINK'], - 'FLOCK_LDMODULE': ['flock', '$TOP_BUILDDIR/linker.lock', '$LDMODULE'], - - # We have several cases where archives depend on each other in - # a cyclic fashion. Since the GNU linker does only a single - # pass over the archives we surround the libraries with - # --start-group and --end-group (aka -( and -) ). That causes - # ld to loop over the group until no more undefined symbols - # are found. In an ideal world we would only make groups from - # those libraries which we knew to be in cycles. However, - # that's tough with SCons, so we bodge it by making all the - # archives a group by redefining the linking command here. - # - # TODO: investigate whether we still have cycles that - # require --{start,end}-group. There has been a lot of - # refactoring since this was first coded, which might have - # eliminated the circular dependencies. - # - # Note: $_LIBDIRFLAGS comes before ${LINK,SHLINK,LDMODULE}FLAGS - # so that we prefer our own built libraries (e.g. -lpng) to - # system versions of libraries that pkg-config might turn up. - # TODO(sgk): investigate handling this not by re-ordering the - # flags this way, but by adding a hook to use the SCons - # ParseFlags() option on the output from pkg-config. - 'LINKCOM': [['$FLOCK_LINK', '-o', '$TARGET', - '$_LIBDIRFLAGS', '$LINKFLAGS', '$SOURCES', - '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']], - 'SHLINKCOM': [['$FLOCK_SHLINK', '-o', '$TARGET', - '$_LIBDIRFLAGS', '$SHLINKFLAGS', '$SOURCES', - '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']], - 'LDMODULECOM': [['$FLOCK_LDMODULE', '-o', '$TARGET', - '$_LIBDIRFLAGS', '$LDMODULEFLAGS', '$SOURCES', - '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']], - 'IMPLICIT_COMMAND_DEPENDENCIES': 0, - }, - 'scons_import_variables': [ - 'AS', - 'CC', - 'CXX', - 'LINK', - ], - 'scons_propagate_variables': [ - 'AS', - 'CC', - 'CCACHE_DIR', - 'CXX', - 'DISTCC_DIR', - 'DISTCC_HOSTS', - 'HOME', - 'INCLUDE_SERVER_ARGS', - 'INCLUDE_SERVER_PORT', - 'LINK', - 'CHROME_BUILD_TYPE', - 'CHROMIUM_BUILD', - 'OFFICIAL_BUILD', - ], - 'configurations': { - 'Debug_Base': { - 'variables': { - 'debug_optimize%': '0', - }, - 'defines': [ - '_DEBUG', - ], - 'cflags': [ - '-O>(debug_optimize)', - '-g', - # One can use '-gstabs' to enable building the debugging - # information in STABS format for breakpad's dumpsyms. - ], - 'ldflags': [ - '-rdynamic', # Allows backtrace to resolve symbols. - ], - }, - 'Release_Base': { - 'variables': { - 'release_optimize%': '2', - }, - 'cflags': [ - '-O>(release_optimize)', - # Don't emit the GCC version ident directives, they just end up - # in the .comment section taking up binary size. - '-fno-ident', - # Put data and code in their own sections, so that unused symbols - # can be removed at link time with --gc-sections. - '-fdata-sections', - '-ffunction-sections', - ], - 'ldflags': [ - '-Wl,--gc-sections', - ], - }, - }, - 'variants': { - 'coverage': { - 'cflags': ['-fprofile-arcs', '-ftest-coverage'], - 'ldflags': ['-fprofile-arcs'], - }, - 'profile': { - 'cflags': ['-pg', '-g'], - 'ldflags': ['-pg'], - }, - 'symbols': { - 'cflags': ['-g'], - }, - }, - 'conditions': [ - [ 'target_arch=="ia32"', { - 'asflags': [ - # Needed so that libs with .s files (e.g. libicudata.a) - # are compatible with the general 32-bit-ness. - '-32', - ], - # All floating-point computations on x87 happens in 80-bit - # precision. Because the C and C++ language standards allow - # the compiler to keep the floating-point values in higher - # precision than what's specified in the source and doing so - # is more efficient than constantly rounding up to 64-bit or - # 32-bit precision as specified in the source, the compiler, - # especially in the optimized mode, tries very hard to keep - # values in x87 floating-point stack (in 80-bit precision) - # as long as possible. This has important side effects, that - # the real value used in computation may change depending on - # how the compiler did the optimization - that is, the value - # kept in 80-bit is different than the value rounded down to - # 64-bit or 32-bit. There are possible compiler options to make - # this behavior consistent (e.g. -ffloat-store would keep all - # floating-values in the memory, thus force them to be rounded - # to its original precision) but they have significant runtime - # performance penalty. - # - # -mfpmath=sse -msse2 makes the compiler use SSE instructions - # which keep floating-point values in SSE registers in its - # native precision (32-bit for single precision, and 64-bit for - # double precision values). This means the floating-point value - # used during computation does not change depending on how the - # compiler optimized the code, since the value is always kept - # in its specified precision. - 'conditions': [ - ['disable_sse2==0', { - 'cflags': [ - '-march=pentium4', - '-msse2', - '-mfpmath=sse', - ], - }], - ], - # -mmmx allows mmintrin.h to be used for mmx intrinsics. - # video playback is mmx and sse2 optimized. - 'cflags': [ - '-m32', - '-mmmx', - ], - 'ldflags': [ - '-m32', - ], - }], - ['target_arch=="arm"', { - 'target_conditions': [ - ['_toolset=="target"', { - 'cflags_cc': [ - # The codesourcery arm-2009q3 toolchain warns at that the ABI - # has changed whenever it encounters a varargs function. This - # silences those warnings, as they are not helpful and - # clutter legitimate warnings. - '-Wno-abi', - ], - 'conditions': [ - ['arm_thumb == 1', { - 'cflags': [ - '-mthumb', - # TODO(piman): -Wa,-mimplicit-it=thumb is needed for - # inline assembly that uses condition codes but it's - # suboptimal. Better would be to #ifdef __thumb__ at the - # right place and have a separate thumb path. - '-Wa,-mimplicit-it=thumb', - ] - }], - ['arm_version==7', { - 'cflags': [ - '-march=armv7-a', - '-mtune=cortex-a8', - '-mfloat-abi=softfp', - ], - 'conditions': [ - ['arm_neon==1', { - 'cflags': [ '-mfpu=neon', ], - }, { - 'cflags': [ '-mfpu=<(arm_fpu)', ], - }] - ], - }], - ], - }], - ], - }], - ['linux_fpic==1', { - 'cflags': [ - '-fPIC', - ], - }], - ['sysroot!=""', { - 'target_conditions': [ - ['_toolset=="target"', { - 'cflags': [ - '--sysroot=<(sysroot)', - ], - 'ldflags': [ - '--sysroot=<(sysroot)', - ], - }]] - }], - ['no_strict_aliasing==1', { - 'cflags': [ - '-fno-strict-aliasing', - ], - }], - ['linux_use_heapchecker==1', { - 'variables': {'linux_use_tcmalloc%': 1}, - }], - ['linux_use_tcmalloc==0', { - 'defines': ['NO_TCMALLOC'], - }], - ['linux_use_heapchecker==0', { - 'defines': ['NO_HEAPCHECKER'], - }], - ], - }, - }], - # FreeBSD-specific options; note that most FreeBSD options are set above, - # with Linux. - ['OS=="freebsd"', { - 'target_defaults': { - 'ldflags': [ - '-Wl,--no-keep-memory', - ], - }, - }], - ['OS=="solaris"', { - 'cflags!': ['-fvisibility=hidden'], - 'cflags_cc!': ['-fvisibility-inlines-hidden'], - }], - ['OS=="mac"', { - 'target_defaults': { - 'variables': { - # This should be 'mac_real_dsym%', but there seems to be a bug - # with % in variables that are intended to be set to different - # values in different targets, like this one. - 'mac_real_dsym': 0, # Fake .dSYMs are fine in most cases. - }, - 'mac_bundle': 0, - 'xcode_settings': { - 'ALWAYS_SEARCH_USER_PATHS': 'NO', - 'GCC_C_LANGUAGE_STANDARD': 'c99', # -std=c99 - 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks - 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic - # (Equivalent to -fPIC) - 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions - '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', - 'GCC_OBJC_CALL_CXX_CDTORS': 'YES', # -fobjc-call-cxx-cdtors - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden - 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics - 'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', # -Werror - 'GCC_VERSION': '4.2', - 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof - # MACOSX_DEPLOYMENT_TARGET maps to -mmacosx-version-min - 'MACOSX_DEPLOYMENT_TARGET': '<(mac_deployment_target)', - 'PREBINDING': 'NO', # No -Wl,-prebind - 'USE_HEADERMAP': 'NO', - 'WARNING_CFLAGS': ['-Wall', '-Wendif-labels'], - 'conditions': [ - ['chromium_mac_pch', {'GCC_PRECOMPILE_PREFIX_HEADER': 'YES'}, - {'GCC_PRECOMPILE_PREFIX_HEADER': 'NO'} - ], - ], - }, - 'target_conditions': [ - ['_type!="static_library"', { - 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']}, - }], - ['_mac_bundle', { - 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']}, - }], - ], # target_conditions - }, # target_defaults - }], # OS=="mac" - ['OS=="win"', { - 'target_defaults': { - 'defines': [ - '_WIN32_WINNT=0x0600', - 'WINVER=0x0600', - 'WIN32', - '_WINDOWS', - '_HAS_EXCEPTIONS=0', - 'NOMINMAX', - '_CRT_RAND_S', - 'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS', - 'WIN32_LEAN_AND_MEAN', - '_SECURE_ATL', - '_HAS_TR1=0', - ], - 'msvs_system_include_dirs': [ - '<(DEPTH)/third_party/platformsdk_win7/files/Include', - '$(VSInstallDir)/VC/atlmfc/include', - ], - 'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'], - 'msvs_disabled_warnings': [ - 4091, 4100, 4127, 4366, 4396, 4503, 4512, 4819, 4995, 4702 - ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'MinimalRebuild': 'false', - 'ExceptionHandling': '0', - 'BufferSecurityCheck': 'true', - 'EnableFunctionLevelLinking': 'true', - 'RuntimeTypeInfo': 'false', - 'WarningLevel': '4', - 'WarnAsError': 'true', - 'DebugInformationFormat': '3', - 'conditions': [ - [ 'msvs_multi_core_compile', { - 'AdditionalOptions': ['/MP'], - }], - ], - }, - 'VCLibrarianTool': { - 'AdditionalOptions': ['/ignore:4221'], - 'AdditionalLibraryDirectories': - ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'], - }, - 'VCLinkerTool': { - 'AdditionalDependencies': [ - 'wininet.lib', - 'version.lib', - 'msimg32.lib', - 'ws2_32.lib', - 'usp10.lib', - 'psapi.lib', - 'dbghelp.lib', - ], - 'AdditionalLibraryDirectories': - ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'], - 'GenerateDebugInformation': 'true', - 'MapFileName': '$(OutDir)\\$(TargetName).map', - 'ImportLibrary': '$(OutDir)\\lib\\$(TargetName).lib', - 'FixedBaseAddress': '1', - # SubSystem values: - # 0 == not set - # 1 == /SUBSYSTEM:CONSOLE - # 2 == /SUBSYSTEM:WINDOWS - # Most of the executables we'll ever create are tests - # and utilities with console output. - 'SubSystem': '1', - }, - 'VCMIDLTool': { - 'GenerateStublessProxies': 'true', - 'TypeLibraryName': '$(InputName).tlb', - 'OutputDirectory': '$(IntDir)', - 'HeaderFileName': '$(InputName).h', - 'DLLDataFileName': 'dlldata.c', - 'InterfaceIdentifierFileName': '$(InputName)_i.c', - 'ProxyFileName': '$(InputName)_p.c', - }, - 'VCResourceCompilerTool': { - 'Culture' : '1033', - 'AdditionalIncludeDirectories': ['<(DEPTH)'], - }, - }, - }, - }], - ['disable_nacl==1 or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { - 'target_defaults': { - 'defines': [ - 'DISABLE_NACL', - ], - }, - }], - ['OS=="win" and msvs_use_common_linker_extras', { - 'target_defaults': { - 'msvs_settings': { - 'VCLinkerTool': { - 'DelayLoadDLLs': [ - 'dbghelp.dll', - 'dwmapi.dll', - 'uxtheme.dll', - ], - }, - }, - 'configurations': { - 'x86_Base': { - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalOptions': [ - '/safeseh', - '/dynamicbase', - '/ignore:4199', - '/ignore:4221', - '/nxcompat', - ], - }, - }, - }, - 'x64_Base': { - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalOptions': [ - # safeseh is not compatible with x64 - '/dynamicbase', - '/ignore:4199', - '/ignore:4221', - '/nxcompat', - ], - }, - }, - }, - }, - }, - }], - ['enable_new_npdevice_api==1', { - 'target_defaults': { - 'defines': [ - 'ENABLE_NEW_NPDEVICE_API', - ], - }, - }], - ], - 'scons_settings': { - 'sconsbuild_dir': '<(DEPTH)/sconsbuild', - 'tools': ['ar', 'as', 'gcc', 'g++', 'gnulink', 'chromium_builders'], - }, - 'xcode_settings': { - # DON'T ADD ANYTHING NEW TO THIS BLOCK UNLESS YOU REALLY REALLY NEED IT! - # This block adds *project-wide* configuration settings to each project - # file. It's almost always wrong to put things here. Specify your - # custom xcode_settings in target_defaults to add them to targets instead. - - # In an Xcode Project Info window, the "Base SDK for All Configurations" - # setting sets the SDK on a project-wide basis. In order to get the - # configured SDK to show properly in the Xcode UI, SDKROOT must be set - # here at the project level. - 'SDKROOT': 'macosx<(mac_sdk)', # -isysroot - - # The Xcode generator will look for an xcode_settings section at the root - # of each dict and use it to apply settings on a file-wide basis. Most - # settings should not be here, they should be in target-specific - # xcode_settings sections, or better yet, should use non-Xcode-specific - # settings in target dicts. SYMROOT is a special case, because many other - # Xcode variables depend on it, including variables such as - # PROJECT_DERIVED_FILE_DIR. When a source group corresponding to something - # like PROJECT_DERIVED_FILE_DIR is added to a project, in order for the - # files to appear (when present) in the UI as actual files and not red - # red "missing file" proxies, the correct path to PROJECT_DERIVED_FILE_DIR, - # and therefore SYMROOT, needs to be set at the project level. - 'SYMROOT': '<(DEPTH)/xcodebuild', - }, -} diff --git a/src/build/filename_rules.gypi b/src/build/filename_rules.gypi deleted file mode 100644 index 78cd1808..00000000 --- a/src/build/filename_rules.gypi +++ /dev/null @@ -1,57 +0,0 @@ -# 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/'], - ], - }], - ], -} diff --git a/src/build/gyp_breakpad b/src/build/gyp_breakpad deleted file mode 100755 index 0b8077d2..00000000 --- a/src/build/gyp_breakpad +++ /dev/null @@ -1,67 +0,0 @@ -#!/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()) diff --git a/src/build/testing.gyp b/src/build/testing.gyp deleted file mode 100644 index 6a459a64..00000000 --- a/src/build/testing.gyp +++ /dev/null @@ -1,90 +0,0 @@ -# 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/googletest/src/gtest-all.cc', - ], - 'include_dirs': [ - '../testing/googletest', - '../testing/googletest/include', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '../testing/googletest/include', - ], - }, - }, - { - 'target_name': 'gtest_main', - 'type': 'static_library', - 'dependencies': [ - 'gtest', - ], - 'sources': [ - '../testing/googletest/src/gtest_main.cc', - ], - }, - { - 'target_name': 'gmock', - 'type': 'static_library', - 'dependencies': [ - 'gtest', - ], - 'sources': [ - '../testing/googlemock/src/gmock-all.cc', - ], - 'include_dirs': [ - '../testing/googlemock', - '../testing/googlemock/include', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '../testing/googlemock/include', - ], - }, - 'export_dependent_settings': [ - 'gtest', - ], - }, - { - 'target_name': 'gmock_main', - 'type': 'static_library', - 'dependencies': [ - 'gmock', - ], - 'sources': [ - '../testing/googlemock/src/gmock_main.cc', - ], - }, - ], -} diff --git a/src/client/apple/Framework/BreakpadDefines.h b/src/client/apple/Framework/BreakpadDefines.h index 410a5a6f..1946534e 100644 --- a/src/client/apple/Framework/BreakpadDefines.h +++ b/src/client/apple/Framework/BreakpadDefines.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/ios/Breakpad.h b/src/client/ios/Breakpad.h index fa790f77..950c0388 100644 --- a/src/client/ios/Breakpad.h +++ b/src/client/ios/Breakpad.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,7 +36,7 @@ // // These files can then be uploaded to a server. -typedef void *BreakpadRef; +typedef void* BreakpadRef; #ifdef __cplusplus extern "C" { @@ -60,15 +59,15 @@ extern "C" { typedef bool (*BreakpadFilterCallback)(int exception_type, int exception_code, mach_port_t crashing_thread, - void *context); + void* context); // Optional user-defined function that will be called after a network upload // of a crash report. // |report_id| will be the id returned by the server, or "ERR" if an error // occurred. // |error| will contain the error, or nil if no error occured. -typedef void (*BreakpadUploadCompletionCallback)(NSString *report_id, - NSError *error); +typedef void (*BreakpadUploadCompletionCallback)(NSString* report_id, + NSError* error); // Create a new BreakpadRef object and install it as an exception // handler. The |parameters| will typically be the contents of your @@ -163,7 +162,7 @@ typedef void (*BreakpadUploadCompletionCallback)(NSString *report_id, // internal values. // Returns a new BreakpadRef object on success, NULL otherwise. -BreakpadRef BreakpadCreate(NSDictionary *parameters); +BreakpadRef BreakpadCreate(NSDictionary* parameters); // Uninstall and release the data associated with |ref|. void BreakpadRelease(BreakpadRef ref); @@ -187,20 +186,20 @@ void BreakpadRelease(BreakpadRef ref); // TODO (nealsid): separate server parameter dictionary from the // dictionary used to configure Breakpad, and document limits for each // independently. -void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value); -NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key); -void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key); +void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value); +NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key); +void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key); // You can use this method to specify parameters that will be uploaded // to the crash server. They will be automatically encoded as // necessary. Note that as mentioned above there are limits on both // the number of keys and their length. -void BreakpadAddUploadParameter(BreakpadRef ref, NSString *key, - NSString *value); +void BreakpadAddUploadParameter(BreakpadRef ref, NSString* key, + NSString* value); // This method will remove a previously-added parameter from the // upload parameter set. -void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key); +void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString* key); // Method to handle uploading data to the server @@ -208,10 +207,10 @@ void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key); int BreakpadGetCrashReportCount(BreakpadRef ref); // Returns the next upload configuration. The report file is deleted. -NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref); +NSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref); // Returns the date of the most recent crash report. -NSDate *BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref); +NSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref); // Upload next report to the server. void BreakpadUploadNextReport(BreakpadRef ref); @@ -220,7 +219,7 @@ void BreakpadUploadNextReport(BreakpadRef ref); // |server_parameters| is additional server parameters to send. void BreakpadUploadNextReportWithParameters( BreakpadRef ref, - NSDictionary *server_parameters, + NSDictionary* server_parameters, BreakpadUploadCompletionCallback callback); // Upload a report to the server. @@ -228,8 +227,8 @@ void BreakpadUploadNextReportWithParameters( // |configuration| is the configuration of the breakpad report to send. void BreakpadUploadReportWithParametersAndConfiguration( BreakpadRef ref, - NSDictionary *server_parameters, - NSDictionary *configuration, + NSDictionary* server_parameters, + NSDictionary* configuration, BreakpadUploadCompletionCallback callback); // Handles the network response of a breakpad upload. This function is needed if @@ -239,21 +238,21 @@ void BreakpadUploadReportWithParametersAndConfiguration( // BreakpadUploadReportWithParametersAndConfiguration. // |data| and |error| contain the network response. void BreakpadHandleNetworkResponse(BreakpadRef ref, - NSDictionary *configuration, - NSData *data, - NSError *error); + NSDictionary* configuration, + NSData* data, + NSError* error); // Upload a file to the server. |data| is the content of the file to sent. // |server_parameters| is additional server parameters to send. -void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name, - NSDictionary *server_parameters); +void BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name, + NSDictionary* server_parameters); // Generate a breakpad minidump and configuration file in the dump directory. // The report will be available for uploading. The paths of the created files // are returned in the dictionary. |server_parameters| is additional server // parameters to add in the config file. -NSDictionary *BreakpadGenerateReport(BreakpadRef ref, - NSDictionary *server_parameters); +NSDictionary* BreakpadGenerateReport(BreakpadRef ref, + NSDictionary* server_parameters); #ifdef __cplusplus } diff --git a/src/client/ios/Breakpad.mm b/src/client/ios/Breakpad.mm index 2b61bbe3..e2497461 100644 --- a/src/client/ios/Breakpad.mm +++ b/src/client/ios/Breakpad.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -84,9 +83,9 @@ using google_breakpad::LongStringDictionary; // allocation of C++ objects. Note that we don't use operator delete() // but instead call the objects destructor directly: object->~ClassName(); // -ProtectedMemoryAllocator *gMasterAllocator = NULL; -ProtectedMemoryAllocator *gKeyValueAllocator = NULL; -ProtectedMemoryAllocator *gBreakpadAllocator = NULL; +ProtectedMemoryAllocator* gMasterAllocator = NULL; +ProtectedMemoryAllocator* gKeyValueAllocator = NULL; +ProtectedMemoryAllocator* gBreakpadAllocator = NULL; // Mutex for thread-safe access to the key/value dictionary used by breakpad. // It's a global instead of an instance variable of Breakpad @@ -101,8 +100,8 @@ pthread_mutex_t gDictionaryMutex; // Its destructor will first re-protect the memory then release the lock. class ProtectedMemoryLocker { public: - ProtectedMemoryLocker(pthread_mutex_t *mutex, - ProtectedMemoryAllocator *allocator) + ProtectedMemoryLocker(pthread_mutex_t* mutex, + ProtectedMemoryAllocator* allocator) : mutex_(mutex), allocator_(allocator) { // Lock the mutex @@ -127,17 +126,17 @@ class ProtectedMemoryLocker { ProtectedMemoryLocker(const ProtectedMemoryLocker&); ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&); - pthread_mutex_t *mutex_; - ProtectedMemoryAllocator *allocator_; + pthread_mutex_t* mutex_; + ProtectedMemoryAllocator* allocator_; }; //============================================================================= class Breakpad { public: // factory method - static Breakpad *Create(NSDictionary *parameters) { + static Breakpad* Create(NSDictionary* parameters) { // Allocate from our special allocation pool - Breakpad *breakpad = + Breakpad* breakpad = new (gBreakpadAllocator->Allocate(sizeof(Breakpad))) Breakpad(); @@ -155,62 +154,62 @@ class Breakpad { ~Breakpad(); - void SetKeyValue(NSString *key, NSString *value); - NSString *KeyValue(NSString *key); - void RemoveKeyValue(NSString *key); - NSArray *CrashReportsToUpload(); - NSString *NextCrashReportToUpload(); - NSDictionary *NextCrashReportConfiguration(); - NSDictionary *FixedUpCrashReportConfiguration(NSDictionary *configuration); - NSDate *DateOfMostRecentCrashReport(); - void UploadNextReport(NSDictionary *server_parameters); - void UploadReportWithConfiguration(NSDictionary *configuration, - NSDictionary *server_parameters, + void SetKeyValue(NSString* key, NSString* value); + NSString* KeyValue(NSString* key); + void RemoveKeyValue(NSString* key); + NSArray* CrashReportsToUpload(); + NSString* NextCrashReportToUpload(); + NSDictionary* NextCrashReportConfiguration(); + NSDictionary* FixedUpCrashReportConfiguration(NSDictionary* configuration); + NSDate* DateOfMostRecentCrashReport(); + void UploadNextReport(NSDictionary* server_parameters); + void UploadReportWithConfiguration(NSDictionary* configuration, + NSDictionary* server_parameters, BreakpadUploadCompletionCallback callback); - void UploadData(NSData *data, NSString *name, - NSDictionary *server_parameters); - void HandleNetworkResponse(NSDictionary *configuration, - NSData *data, - NSError *error); - NSDictionary *GenerateReport(NSDictionary *server_parameters); + void UploadData(NSData* data, NSString* name, + NSDictionary* server_parameters); + void HandleNetworkResponse(NSDictionary* configuration, + NSData* data, + NSError* error); + NSDictionary* GenerateReport(NSDictionary* server_parameters); private: Breakpad() : handler_(NULL), config_params_(NULL) {} - bool Initialize(NSDictionary *parameters); + bool Initialize(NSDictionary* parameters); - bool ExtractParameters(NSDictionary *parameters); + bool ExtractParameters(NSDictionary* parameters); // Dispatches to HandleMinidump() - static bool HandleMinidumpCallback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded); + static bool HandleMinidumpCallback(const char* dump_dir, + const char* minidump_id, + void* context, bool succeeded); - bool HandleMinidump(const char *dump_dir, - const char *minidump_id); + bool HandleMinidump(const char* dump_dir, + const char* minidump_id); // NSException handler - static void UncaughtExceptionHandler(NSException *exception); + static void UncaughtExceptionHandler(NSException* exception); // Handle an uncaught NSException. - void HandleUncaughtException(NSException *exception); + void HandleUncaughtException(NSException* exception); // Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's // MachineExceptions.h, we have to explicitly name the handler. - google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG) + google_breakpad::ExceptionHandler* handler_; // The actual handler (STRONG) - LongStringDictionary *config_params_; // Create parameters (STRONG) + LongStringDictionary* config_params_; // Create parameters (STRONG) ConfigFile config_file_; // A static reference to the current Breakpad instance. Used for handling // NSException. - static Breakpad *current_breakpad_; + static Breakpad* current_breakpad_; }; -Breakpad *Breakpad::current_breakpad_ = NULL; +Breakpad* Breakpad::current_breakpad_ = NULL; #pragma mark - #pragma mark Helper functions @@ -221,14 +220,14 @@ Breakpad *Breakpad::current_breakpad_ = NULL; //============================================================================= static BOOL IsDebuggerActive() { BOOL result = NO; - NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults]; + NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults]; // We check both defaults and the environment variable here BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER]; if (!ignoreDebugger) { - char *ignoreDebuggerStr = getenv(IGNORE_DEBUGGER); + char* ignoreDebuggerStr = getenv(IGNORE_DEBUGGER); ignoreDebugger = (ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0; } @@ -240,7 +239,7 @@ static BOOL IsDebuggerActive() { size_t actualSize; if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) { - struct kinfo_proc *info = (struct kinfo_proc *)malloc(actualSize); + struct kinfo_proc* info = (struct kinfo_proc*)malloc(actualSize); if (info) { // This comes from looking at the Darwin xnu Kernel @@ -256,10 +255,10 @@ static BOOL IsDebuggerActive() { } //============================================================================= -bool Breakpad::HandleMinidumpCallback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded) { - Breakpad *breakpad = (Breakpad *)context; +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. @@ -270,7 +269,7 @@ bool Breakpad::HandleMinidumpCallback(const char *dump_dir, } //============================================================================= -void Breakpad::UncaughtExceptionHandler(NSException *exception) { +void Breakpad::UncaughtExceptionHandler(NSException* exception) { NSSetUncaughtExceptionHandler(NULL); if (current_breakpad_) { current_breakpad_->HandleUncaughtException(exception); @@ -282,7 +281,7 @@ void Breakpad::UncaughtExceptionHandler(NSException *exception) { #pragma mark - //============================================================================= -bool Breakpad::Initialize(NSDictionary *parameters) { +bool Breakpad::Initialize(NSDictionary* parameters) { // Initialize current_breakpad_ = this; config_params_ = NULL; @@ -325,21 +324,21 @@ Breakpad::~Breakpad() { } //============================================================================= -bool Breakpad::ExtractParameters(NSDictionary *parameters) { - NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE]; - NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; - NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT]; - NSString *version = [parameters objectForKey:@BREAKPAD_VERSION]; - NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL]; - NSString *vendor = +bool Breakpad::ExtractParameters(NSDictionary* parameters) { + NSString* serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE]; + NSString* display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; + NSString* product = [parameters objectForKey:@BREAKPAD_PRODUCT]; + NSString* version = [parameters objectForKey:@BREAKPAD_VERSION]; + NSString* urlStr = [parameters objectForKey:@BREAKPAD_URL]; + NSString* vendor = [parameters objectForKey:@BREAKPAD_VENDOR]; // We check both parameters and the environment variable here. - char *envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY); - NSString *dumpSubdirectory = envVarDumpSubdirectory ? + char* envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY); + NSString* dumpSubdirectory = envVarDumpSubdirectory ? [NSString stringWithUTF8String:envVarDumpSubdirectory] : [parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY]; - NSDictionary *serverParameters = + NSDictionary* serverParameters = [parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT]; if (!product) @@ -360,7 +359,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { } if (!dumpSubdirectory) { - NSString *cachePath = + NSString* cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) @@ -388,7 +387,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { new (gKeyValueAllocator->Allocate(sizeof(LongStringDictionary))) LongStringDictionary(); - LongStringDictionary &dictionary = *config_params_; + LongStringDictionary& dictionary = *config_params_; dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]); dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]); @@ -407,8 +406,8 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { if (serverParameters) { // For each key-value pair, call BreakpadAddUploadParameter() - NSEnumerator *keyEnumerator = [serverParameters keyEnumerator]; - NSString *aParameter; + NSEnumerator* keyEnumerator = [serverParameters keyEnumerator]; + NSString* aParameter; while ((aParameter = [keyEnumerator nextObject])) { BreakpadAddUploadParameter(this, aParameter, [serverParameters objectForKey:aParameter]); @@ -418,7 +417,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { } //============================================================================= -void Breakpad::SetKeyValue(NSString *key, NSString *value) { +void Breakpad::SetKeyValue(NSString* key, NSString* value) { // We allow nil values. This is the same as removing the keyvalue. if (!config_params_ || !key) return; @@ -427,7 +426,7 @@ void Breakpad::SetKeyValue(NSString *key, NSString *value) { } //============================================================================= -NSString *Breakpad::KeyValue(NSString *key) { +NSString* Breakpad::KeyValue(NSString* key) { if (!config_params_ || !key) return nil; @@ -436,44 +435,44 @@ NSString *Breakpad::KeyValue(NSString *key) { } //============================================================================= -void Breakpad::RemoveKeyValue(NSString *key) { +void Breakpad::RemoveKeyValue(NSString* key) { if (!config_params_ || !key) return; config_params_->RemoveKey([key UTF8String]); } //============================================================================= -NSArray *Breakpad::CrashReportsToUpload() { - NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); +NSArray* Breakpad::CrashReportsToUpload() { + NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); if (!directory) return nil; - NSArray *dirContents = [[NSFileManager defaultManager] + NSArray* dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directory error:nil]; - NSArray *configs = [dirContents filteredArrayUsingPredicate:[NSPredicate + NSArray* configs = [dirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self BEGINSWITH 'Config-'"]]; return configs; } //============================================================================= -NSString *Breakpad::NextCrashReportToUpload() { - NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); +NSString* Breakpad::NextCrashReportToUpload() { + NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); if (!directory) return nil; - NSString *config = [CrashReportsToUpload() lastObject]; + NSString* config = [CrashReportsToUpload() lastObject]; if (!config) return nil; return [NSString stringWithFormat:@"%@/%@", directory, config]; } //============================================================================= -NSDictionary *Breakpad::NextCrashReportConfiguration() { - NSDictionary *configuration = [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()]; +NSDictionary* Breakpad::NextCrashReportConfiguration() { + NSDictionary* configuration = [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()]; return FixedUpCrashReportConfiguration(configuration); } //============================================================================= -NSDictionary *Breakpad::FixedUpCrashReportConfiguration(NSDictionary *configuration) { - NSMutableDictionary *fixedConfiguration = [[configuration mutableCopy] autorelease]; +NSDictionary* Breakpad::FixedUpCrashReportConfiguration(NSDictionary* configuration) { + NSMutableDictionary* fixedConfiguration = [[configuration mutableCopy] autorelease]; // kReporterMinidumpDirectoryKey can become stale because the app's data container path includes // an UUID that is not guaranteed to stay the same over time. [fixedConfiguration setObject:KeyValue(@BREAKPAD_DUMP_DIRECTORY) @@ -482,19 +481,19 @@ NSDictionary *Breakpad::FixedUpCrashReportConfiguration(NSDictionary *configurat } //============================================================================= -NSDate *Breakpad::DateOfMostRecentCrashReport() { - NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); +NSDate* Breakpad::DateOfMostRecentCrashReport() { + NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY); if (!directory) { return nil; } - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSArray *dirContents = [fileManager contentsOfDirectoryAtPath:directory error:nil]; - NSArray *dumps = [dirContents filteredArrayUsingPredicate:[NSPredicate + NSFileManager* fileManager = [NSFileManager defaultManager]; + NSArray* dirContents = [fileManager contentsOfDirectoryAtPath:directory error:nil]; + NSArray* dumps = [dirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self ENDSWITH '.dmp'"]]; - NSDate *mostRecentCrashReportDate = nil; - for (NSString *dump in dumps) { - NSString *filePath = [directory stringByAppendingPathComponent:dump]; - NSDate *crashReportDate = + NSDate* mostRecentCrashReportDate = nil; + for (NSString* dump in dumps) { + NSString* filePath = [directory stringByAppendingPathComponent:dump]; + NSDate* crashReportDate = [[fileManager attributesOfItemAtPath:filePath error:nil] fileCreationDate]; if (!mostRecentCrashReportDate) { mostRecentCrashReportDate = crashReportDate; @@ -506,29 +505,29 @@ NSDate *Breakpad::DateOfMostRecentCrashReport() { } //============================================================================= -void Breakpad::HandleNetworkResponse(NSDictionary *configuration, - NSData *data, - NSError *error) { - Uploader *uploader = [[[Uploader alloc] +void Breakpad::HandleNetworkResponse(NSDictionary* configuration, + NSData* data, + NSError* error) { + Uploader* uploader = [[[Uploader alloc] initWithConfig:configuration] autorelease]; [uploader handleNetworkResponse:data withError:error]; } //============================================================================= void Breakpad::UploadReportWithConfiguration( - NSDictionary *configuration, - NSDictionary *server_parameters, + NSDictionary* configuration, + NSDictionary* server_parameters, BreakpadUploadCompletionCallback callback) { - Uploader *uploader = [[[Uploader alloc] + Uploader* uploader = [[[Uploader alloc] initWithConfig:configuration] autorelease]; if (!uploader) return; - for (NSString *key in server_parameters) { + for (NSString* key in server_parameters) { [uploader addServerParameter:[server_parameters objectForKey:key] forKey:key]; } if (callback) { - [uploader setUploadCompletionBlock:^(NSString *report_id, NSError *error) { + [uploader setUploadCompletionBlock:^(NSString* report_id, NSError* error) { dispatch_async(dispatch_get_main_queue(), ^{ callback(report_id, error); }); @@ -538,8 +537,8 @@ void Breakpad::UploadReportWithConfiguration( } //============================================================================= -void Breakpad::UploadNextReport(NSDictionary *server_parameters) { - NSDictionary *configuration = NextCrashReportConfiguration(); +void Breakpad::UploadNextReport(NSDictionary* server_parameters) { + NSDictionary* configuration = NextCrashReportConfiguration(); if (configuration) { return UploadReportWithConfiguration(configuration, server_parameters, nullptr); @@ -547,19 +546,19 @@ void Breakpad::UploadNextReport(NSDictionary *server_parameters) { } //============================================================================= -void Breakpad::UploadData(NSData *data, NSString *name, - NSDictionary *server_parameters) { - NSMutableDictionary *config = [NSMutableDictionary dictionary]; +void Breakpad::UploadData(NSData* data, NSString* name, + NSDictionary* server_parameters) { + NSMutableDictionary* config = [NSMutableDictionary dictionary]; LongStringDictionary::Iterator it(*config_params_); - while (const LongStringDictionary::Entry *next = it.Next()) { + while (const LongStringDictionary::Entry* next = it.Next()) { [config setValue:[NSString stringWithUTF8String:next->value] forKey:[NSString stringWithUTF8String:next->key]]; } - Uploader *uploader = + Uploader* uploader = [[[Uploader alloc] initWithConfig:config] autorelease]; - for (NSString *key in server_parameters) { + for (NSString* key in server_parameters) { [uploader addServerParameter:[server_parameters objectForKey:key] forKey:key]; } @@ -567,11 +566,11 @@ void Breakpad::UploadData(NSData *data, NSString *name, } //============================================================================= -NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) { - NSString *dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY); +NSDictionary* Breakpad::GenerateReport(NSDictionary* server_parameters) { + NSString* dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY); if (!dumpDirAsNSString) return nil; - const char *dumpDir = [dumpDirAsNSString UTF8String]; + const char* dumpDir = [dumpDirAsNSString UTF8String]; google_breakpad::MinidumpGenerator generator(mach_task_self(), MACH_PORT_NULL); @@ -582,7 +581,7 @@ NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) { return nil; LongStringDictionary params = *config_params_; - for (NSString *key in server_parameters) { + for (NSString* key in server_parameters) { params.SetKeyValue([key UTF8String], [[server_parameters objectForKey:key] UTF8String]); } @@ -590,8 +589,8 @@ NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) { config_file.WriteFile(dumpDir, ¶ms, dumpDir, dumpId.c_str()); // Handle results. - NSMutableDictionary *result = [NSMutableDictionary dictionary]; - NSString *dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()]; + NSMutableDictionary* result = [NSMutableDictionary dictionary]; + NSString* dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()]; [result setValue:dumpFullPath forKey:@BREAKPAD_OUTPUT_DUMP_FILE]; [result setValue:[NSString stringWithUTF8String:config_file.GetFilePath()] @@ -600,8 +599,8 @@ NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) { } //============================================================================= -bool Breakpad::HandleMinidump(const char *dump_dir, - const char *minidump_id) { +bool Breakpad::HandleMinidump(const char* dump_dir, + const char* minidump_id) { config_file_.WriteFile(dump_dir, config_params_, dump_dir, @@ -613,7 +612,7 @@ bool Breakpad::HandleMinidump(const char *dump_dir, } //============================================================================= -void Breakpad::HandleUncaughtException(NSException *exception) { +void Breakpad::HandleUncaughtException(NSException* exception) { // Generate the minidump. google_breakpad::IosExceptionMinidumpGenerator generator(exception); const std::string minidump_path = @@ -650,7 +649,7 @@ void Breakpad::HandleUncaughtException(NSException *exception) { #pragma mark Public API //============================================================================= -BreakpadRef BreakpadCreate(NSDictionary *parameters) { +BreakpadRef BreakpadCreate(NSDictionary* parameters) { try { // This is confusing. Our two main allocators for breakpad memory are: // - gKeyValueAllocator for the key/value memory @@ -690,8 +689,8 @@ BreakpadRef BreakpadCreate(NSDictionary *parameters) { ProtectedMemoryAllocator(breakpad_pool_size); // Stack-based autorelease pool for Breakpad::Create() obj-c code. - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - Breakpad *breakpad = Breakpad::Create(parameters); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + Breakpad* breakpad = Breakpad::Create(parameters); if (breakpad) { // Make read-only to protect against memory smashers @@ -731,7 +730,7 @@ BreakpadRef BreakpadCreate(NSDictionary *parameters) { //============================================================================= void BreakpadRelease(BreakpadRef ref) { try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (gMasterAllocator) { gMasterAllocator->Unprotect(); @@ -764,10 +763,10 @@ void BreakpadRelease(BreakpadRef ref) { } //============================================================================= -void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) { +void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && key && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); @@ -780,20 +779,20 @@ void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) { } void BreakpadAddUploadParameter(BreakpadRef ref, - NSString *key, - NSString *value) { + NSString* key, + NSString* value) { // The only difference, internally, between an upload parameter and // a key value one that is set with BreakpadSetKeyValue is that we // prepend the keyname with a special prefix. This informs the // crash sender that the parameter should be sent along with the // POST of the crash dump upload. try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && key && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - NSString *prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX + NSString* prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX stringByAppendingString:key]; breakpad->SetKeyValue(prefixedKey, value); } @@ -803,15 +802,15 @@ void BreakpadAddUploadParameter(BreakpadRef ref, } void BreakpadRemoveUploadParameter(BreakpadRef ref, - NSString *key) { + NSString* key) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && key && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - NSString *prefixedKey = [NSString stringWithFormat:@"%@%@", + NSString* prefixedKey = [NSString stringWithFormat:@"%@%@", @BREAKPAD_SERVER_PARAMETER_PREFIX, key]; breakpad->RemoveKeyValue(prefixedKey); } @@ -820,12 +819,12 @@ void BreakpadRemoveUploadParameter(BreakpadRef ref, } } //============================================================================= -NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) { - NSString *value = nil; +NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key) { + NSString* value = nil; try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (!breakpad || !key || !gKeyValueAllocator) return nil; @@ -841,10 +840,10 @@ NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) { } //============================================================================= -void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) { +void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && key && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); @@ -860,7 +859,7 @@ void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) { int BreakpadGetCrashReportCount(BreakpadRef ref) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad) { return static_cast<int>([breakpad->CrashReportsToUpload() count]); @@ -877,9 +876,9 @@ void BreakpadUploadNextReport(BreakpadRef ref) { } //============================================================================= -NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref) { +NSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref) { try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad) return breakpad->NextCrashReportConfiguration(); } catch(...) { // don't let exceptions leave this C API @@ -889,9 +888,9 @@ NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref) { } //============================================================================= -NSDate *BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) { +NSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) { try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad) { return breakpad->DateOfMostRecentCrashReport(); } @@ -904,11 +903,11 @@ NSDate *BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) { //============================================================================= void BreakpadUploadReportWithParametersAndConfiguration( BreakpadRef ref, - NSDictionary *server_parameters, - NSDictionary *configuration, + NSDictionary* server_parameters, + NSDictionary* configuration, BreakpadUploadCompletionCallback callback) { try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (!breakpad || !configuration) return; breakpad->UploadReportWithConfiguration(configuration, server_parameters, @@ -922,13 +921,13 @@ void BreakpadUploadReportWithParametersAndConfiguration( //============================================================================= void BreakpadUploadNextReportWithParameters( BreakpadRef ref, - NSDictionary *server_parameters, + NSDictionary* server_parameters, BreakpadUploadCompletionCallback callback) { try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (!breakpad) return; - NSDictionary *configuration = breakpad->NextCrashReportConfiguration(); + NSDictionary* configuration = breakpad->NextCrashReportConfiguration(); if (!configuration) return; return BreakpadUploadReportWithParametersAndConfiguration( @@ -939,12 +938,12 @@ void BreakpadUploadNextReportWithParameters( } void BreakpadHandleNetworkResponse(BreakpadRef ref, - NSDictionary *configuration, - NSData *data, - NSError *error) { + NSDictionary* configuration, + NSData* data, + NSError* error) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && configuration) breakpad->HandleNetworkResponse(configuration,data, error); @@ -954,11 +953,11 @@ void BreakpadHandleNetworkResponse(BreakpadRef ref, } //============================================================================= -void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name, - NSDictionary *server_parameters) { +void BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name, + NSDictionary* server_parameters) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad) { breakpad->UploadData(data, name, server_parameters); @@ -969,11 +968,11 @@ void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name, } //============================================================================= -NSDictionary *BreakpadGenerateReport(BreakpadRef ref, - NSDictionary *server_parameters) { +NSDictionary* BreakpadGenerateReport(BreakpadRef ref, + NSDictionary* server_parameters) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad) { return breakpad->GenerateReport(server_parameters); diff --git a/src/client/ios/Breakpad.xcodeproj/project.pbxproj b/src/client/ios/Breakpad.xcodeproj/project.pbxproj index 2ed66d53..ca5f1f05 100644 --- a/src/client/ios/Breakpad.xcodeproj/project.pbxproj +++ b/src/client/ios/Breakpad.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 06D561E62700974500F9F2E8 /* encoding_util.h in Headers */ = {isa = PBXBuildFile; fileRef = 06D561E42700974500F9F2E8 /* encoding_util.h */; }; + 06D561E72700974500F9F2E8 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = 06D561E52700974500F9F2E8 /* encoding_util.m */; }; 14569321182CE29F0029C465 /* ucontext_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569320182CE29F0029C465 /* ucontext_compat.h */; }; 14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569322182CE2C10029C465 /* mach_vm_compat.h */; }; 16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */; }; @@ -59,9 +61,13 @@ AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; CF6D547D1F9E6FFE00E95174 /* long_string_dictionary.cc in Sources */ = {isa = PBXBuildFile; fileRef = CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */; }; CF706DC11F7C6EFB002C54C7 /* long_string_dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */; }; + E69213D8265202570071B04F /* HTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = E69213D6265202570071B04F /* HTTPRequest.h */; }; + E69213D9265202570071B04F /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E69213D7265202570071B04F /* HTTPRequest.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 06D561E42700974500F9F2E8 /* encoding_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = encoding_util.h; sourceTree = "<group>"; }; + 06D561E52700974500F9F2E8 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = encoding_util.m; sourceTree = "<group>"; }; 14569320182CE29F0029C465 /* ucontext_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucontext_compat.h; sourceTree = "<group>"; }; 14569322182CE2C10029C465 /* mach_vm_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_vm_compat.h; sourceTree = "<group>"; }; 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_exception_minidump_generator.h; sourceTree = "<group>"; }; @@ -116,6 +122,8 @@ CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = long_string_dictionary.cc; sourceTree = "<group>"; }; CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = long_string_dictionary.h; sourceTree = "<group>"; }; D2AAC07E0554694100DB518D /* libBreakpad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBreakpad.a; sourceTree = BUILT_PRODUCTS_DIR; }; + E69213D6265202570071B04F /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRequest.h; sourceTree = "<group>"; }; + E69213D7265202570071B04F /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPRequest.m; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -287,8 +295,12 @@ 16C7CC82147D4A4300776EAD /* mac */ = { isa = PBXGroup; children = ( + 06D561E42700974500F9F2E8 /* encoding_util.h */, + 06D561E52700974500F9F2E8 /* encoding_util.m */, 16C7CC88147D4A4300776EAD /* GTMLogger.h */, 16C7CC89147D4A4300776EAD /* GTMLogger.m */, + E69213D6265202570071B04F /* HTTPRequest.h */, + E69213D7265202570071B04F /* HTTPRequest.m */, 16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */, 16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */, 16C7CC93147D4A4300776EAD /* file_id.cc */, @@ -333,8 +345,10 @@ 16C7CE08147D4A4300776EAD /* uploader.h in Headers */, 16C7CE18147D4A4300776EAD /* minidump_file_writer-inl.h in Headers */, 16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */, + 06D561E62700974500F9F2E8 /* encoding_util.h in Headers */, 16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */, 16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */, + E69213D8265202570071B04F /* HTTPRequest.h in Headers */, 16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */, 16C7CE84147D4A4300776EAD /* file_id.h in Headers */, 16C7CE86147D4A4300776EAD /* macho_id.h in Headers */, @@ -416,6 +430,7 @@ buildActionMask = 2147483647; files = ( 16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */, + E69213D9265202570071B04F /* HTTPRequest.m in Sources */, 16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */, 16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */, 16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */, @@ -427,6 +442,7 @@ 16C7CE19147D4A4300776EAD /* minidump_file_writer.cc in Sources */, 16C7CE40147D4A4300776EAD /* convert_UTF.cc in Sources */, 16C7CE79147D4A4300776EAD /* GTMLogger.m in Sources */, + 06D561E72700974500F9F2E8 /* encoding_util.m in Sources */, 16C7CE7B147D4A4300776EAD /* HTTPMultipartUpload.m in Sources */, 16C7CE83147D4A4300776EAD /* file_id.cc in Sources */, 16C7CE85147D4A4300776EAD /* macho_id.cc in Sources */, diff --git a/src/client/ios/BreakpadController.h b/src/client/ios/BreakpadController.h index 6c70c202..40334592 100644 --- a/src/client/ios/BreakpadController.h +++ b/src/client/ios/BreakpadController.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/ios/BreakpadController.mm b/src/client/ios/BreakpadController.mm index 01fb5f13..d03833e9 100644 --- a/src/client/ios/BreakpadController.mm +++ b/src/client/ios/BreakpadController.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/ios/exception_handler_no_mach.cc b/src/client/ios/exception_handler_no_mach.cc index 7fcf2d83..6bb41021 100644 --- a/src/client/ios/exception_handler_no_mach.cc +++ b/src/client/ios/exception_handler_no_mach.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,7 +46,7 @@ // for more details. #if USE_PROTECTED_ALLOCATIONS #include "client/mac/handler/protected_memory_allocator.h" - extern ProtectedMemoryAllocator *gBreakpadAllocator; + extern ProtectedMemoryAllocator* gBreakpadAllocator; #endif namespace google_breakpad { @@ -72,10 +71,10 @@ static union { char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); #endif // defined PAGE_MAX_SIZE #endif // USE_PROTECTED_ALLOCATIONS - google_breakpad::ExceptionHandler *handler; + google_breakpad::ExceptionHandler* handler; } gProtectedData; -ExceptionHandler::ExceptionHandler(const string &dump_path, +ExceptionHandler::ExceptionHandler(const string& dump_path, FilterCallback filter, MinidumpCallback callback, void* callback_context, diff --git a/src/client/ios/exception_handler_no_mach.h b/src/client/ios/exception_handler_no_mach.h index 6d99565b..57247e61 100644 --- a/src/client/ios/exception_handler_no_mach.h +++ b/src/client/ios/exception_handler_no_mach.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -53,7 +52,7 @@ class ExceptionHandler { // attempting to write a minidump. If a FilterCallback returns false, Breakpad // will immediately report the exception as unhandled without writing a // minidump, allowing another handler the opportunity to handle it. - typedef bool (*FilterCallback)(void *context); + typedef bool (*FilterCallback)(void* context); // A callback function to run after the minidump has been written. // |minidump_id| is a unique id for the dump, so the minidump @@ -63,18 +62,18 @@ class ExceptionHandler { // Return true if the exception was fully handled and breakpad should exit. // Return false to allow any other exception handlers to process the // exception. - typedef bool (*MinidumpCallback)(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded); + typedef bool (*MinidumpCallback)(const char* dump_dir, + const char* minidump_id, + void* context, bool succeeded); // A callback function which will be called directly if an exception occurs. // This bypasses the minidump file writing and simply gives the client // the exception information. - typedef bool (*DirectCallback)( void *context, - int exception_type, - int exception_code, - int exception_subcode, - mach_port_t thread_name); + typedef bool (*DirectCallback)(void* context, + int exception_type, + int exception_code, + int exception_subcode, + mach_port_t thread_name); // Creates a new ExceptionHandler instance to handle writing minidumps. // Minidump files will be written to dump_path, and the optional callback @@ -84,22 +83,22 @@ class ExceptionHandler { // be written when WriteMinidump is called. // If port_name is non-NULL, attempt to perform out-of-process dump generation // If port_name is NULL, in-process dump generation will be used. - ExceptionHandler(const string &dump_path, + ExceptionHandler(const string& dump_path, FilterCallback filter, MinidumpCallback callback, - void *callback_context, bool install_handler, - const char *port_name); + void* callback_context, bool install_handler, + const char* port_name); // A special constructor if we want to bypass minidump writing and // simply get a callback with the exception information. ExceptionHandler(DirectCallback callback, - void *callback_context, + void* callback_context, bool install_handler); ~ExceptionHandler(); // Get and set the minidump path. string dump_path() const { return dump_path_; } - void set_dump_path(const string &dump_path) { + void set_dump_path(const string& dump_path) { dump_path_ = dump_path; dump_path_c_ = dump_path_.c_str(); UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. @@ -126,7 +125,7 @@ class ExceptionHandler { bool WriteMinidumpWithException(int exception_type, int exception_code, int exception_subcode, - breakpad_ucontext_t *task_context, + breakpad_ucontext_t* task_context, mach_port_t thread_name, bool exit_after_write, bool report_current_thread); @@ -135,8 +134,8 @@ class ExceptionHandler { static void SignalHandler(int sig, siginfo_t* info, void* uc); // disallow copy ctor and operator= - explicit ExceptionHandler(const ExceptionHandler &); - void operator=(const ExceptionHandler &); + explicit ExceptionHandler(const ExceptionHandler&); + void operator=(const ExceptionHandler&); // Generates a new ID and stores it in next_minidump_id_, and stores the // path of the next minidump to be written in next_minidump_path_. @@ -152,15 +151,15 @@ class ExceptionHandler { string next_minidump_path_; // Pointers to the UTF-8 versions of above - const char *dump_path_c_; - const char *next_minidump_id_c_; - const char *next_minidump_path_c_; + const char* dump_path_c_; + const char* next_minidump_id_c_; + const char* next_minidump_path_c_; // The callback function and pointer to be passed back after the minidump // has been written FilterCallback filter_; MinidumpCallback callback_; - void *callback_context_; + void* callback_context_; // The callback function to be passed back when we don't want a minidump // file to be written diff --git a/src/client/ios/handler/ios_exception_minidump_generator.h b/src/client/ios/handler/ios_exception_minidump_generator.h index 21133e63..cf72f00b 100644 --- a/src/client/ios/handler/ios_exception_minidump_generator.h +++ b/src/client/ios/handler/ios_exception_minidump_generator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -41,12 +40,12 @@ namespace google_breakpad { class IosExceptionMinidumpGenerator : public MinidumpGenerator { public: - explicit IosExceptionMinidumpGenerator(NSException *exception); + explicit IosExceptionMinidumpGenerator(NSException* exception); virtual ~IosExceptionMinidumpGenerator(); protected: - virtual bool WriteExceptionStream(MDRawDirectory *exception_stream); - virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread); + virtual bool WriteExceptionStream(MDRawDirectory* exception_stream); + virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread* thread); private: @@ -57,16 +56,16 @@ class IosExceptionMinidumpGenerator : public MinidumpGenerator { uintptr_t GetLRFromException(); // Write a virtual thread context for the crashing site. - bool WriteCrashingContext(MDLocationDescriptor *register_location); + bool WriteCrashingContext(MDLocationDescriptor* register_location); // Per-CPU implementations of the above method. #ifdef HAS_ARM_SUPPORT - bool WriteCrashingContextARM(MDLocationDescriptor *register_location); + bool WriteCrashingContextARM(MDLocationDescriptor* register_location); #endif #ifdef HAS_ARM64_SUPPORT - bool WriteCrashingContextARM64(MDLocationDescriptor *register_location); + bool WriteCrashingContextARM64(MDLocationDescriptor* register_location); #endif - NSArray *return_addresses_; + NSArray* return_addresses_; }; } // namespace google_breakpad diff --git a/src/client/ios/handler/ios_exception_minidump_generator.mm b/src/client/ios/handler/ios_exception_minidump_generator.mm index f57bdf21..053e3671 100644 --- a/src/client/ios/handler/ios_exception_minidump_generator.mm +++ b/src/client/ios/handler/ios_exception_minidump_generator.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,7 +51,7 @@ const uintptr_t kExpectedFinalSp = 0; // Append the given value to the sp position of the stack represented // by memory. -void AppendToMemory(uint8_t *memory, uintptr_t sp, uintptr_t data) { +void AppendToMemory(uint8_t* memory, uintptr_t sp, uintptr_t data) { memcpy(memory + sp, &data, sizeof(data)); } #endif @@ -62,7 +61,7 @@ void AppendToMemory(uint8_t *memory, uintptr_t sp, uintptr_t data) { namespace google_breakpad { IosExceptionMinidumpGenerator::IosExceptionMinidumpGenerator( - NSException *exception) + NSException* exception) : MinidumpGenerator(mach_task_self(), 0) { return_addresses_ = [[exception callStackReturnAddresses] retain]; SetExceptionInformation(kExceptionType, @@ -76,7 +75,7 @@ IosExceptionMinidumpGenerator::~IosExceptionMinidumpGenerator() { } bool IosExceptionMinidumpGenerator::WriteCrashingContext( - MDLocationDescriptor *register_location) { + MDLocationDescriptor* register_location) { #ifdef HAS_ARM_SUPPORT return WriteCrashingContextARM(register_location); #elif defined(HAS_ARM64_SUPPORT) @@ -89,12 +88,12 @@ bool IosExceptionMinidumpGenerator::WriteCrashingContext( #ifdef HAS_ARM_SUPPORT bool IosExceptionMinidumpGenerator::WriteCrashingContextARM( - MDLocationDescriptor *register_location) { + MDLocationDescriptor* register_location) { TypedMDRVA<MDRawContextARM> context(&writer_); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextARM *context_ptr = context.get(); + MDRawContextARM* context_ptr = context.get(); memset(context_ptr, 0, sizeof(MDRawContextARM)); context_ptr->context_flags = MD_CONTEXT_ARM_FULL; context_ptr->iregs[MD_CONTEXT_ARM_REG_IOS_FP] = kExpectedFinalFp; // FP @@ -107,12 +106,12 @@ bool IosExceptionMinidumpGenerator::WriteCrashingContextARM( #ifdef HAS_ARM64_SUPPORT bool IosExceptionMinidumpGenerator::WriteCrashingContextARM64( - MDLocationDescriptor *register_location) { + MDLocationDescriptor* register_location) { TypedMDRVA<MDRawContextARM64_Old> context(&writer_); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextARM64_Old *context_ptr = context.get(); + MDRawContextARM64_Old* context_ptr = context.get(); memset(context_ptr, 0, sizeof(*context_ptr)); context_ptr->context_flags = MD_CONTEXT_ARM64_FULL_OLD; context_ptr->iregs[MD_CONTEXT_ARM64_REG_FP] = kExpectedFinalFp; // FP @@ -132,7 +131,7 @@ uintptr_t IosExceptionMinidumpGenerator::GetLRFromException() { } bool IosExceptionMinidumpGenerator::WriteExceptionStream( - MDRawDirectory *exception_stream) { + MDRawDirectory* exception_stream) { #if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) TypedMDRVA<MDRawExceptionStream> exception(&writer_); @@ -141,7 +140,7 @@ bool IosExceptionMinidumpGenerator::WriteExceptionStream( exception_stream->stream_type = MD_EXCEPTION_STREAM; exception_stream->location = exception.location(); - MDRawExceptionStream *exception_ptr = exception.get(); + MDRawExceptionStream* exception_ptr = exception.get(); exception_ptr->thread_id = pthread_mach_thread_np(pthread_self()); // This naming is confusing, but it is the proper translation from @@ -160,7 +159,7 @@ bool IosExceptionMinidumpGenerator::WriteExceptionStream( } bool IosExceptionMinidumpGenerator::WriteThreadStream(mach_port_t thread_id, - MDRawThread *thread) { + MDRawThread* thread) { #if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) if (pthread_mach_thread_np(pthread_self()) != thread_id) return MinidumpGenerator::WriteThreadStream(thread_id, thread); diff --git a/src/client/linux/crash_generation/client_info.h b/src/client/linux/crash_generation/client_info.h index d0a184a6..6c4ecc3f 100644 --- a/src/client/linux/crash_generation/client_info.h +++ b/src/client/linux/crash_generation/client_info.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/crash_generation/crash_generation_client.cc b/src/client/linux/crash_generation/crash_generation_client.cc index 613baddc..5a8c6b4c 100644 --- a/src/client/linux/crash_generation/crash_generation_client.cc +++ b/src/client/linux/crash_generation/crash_generation_client.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -58,7 +57,7 @@ class CrashGenerationClientImpl : public CrashGenerationClient { iov.iov_base = const_cast<void*>(blob); iov.iov_len = blob_size; - struct kernel_msghdr msg = {}; + struct kernel_msghdr msg = { 0 }; msg.msg_iov = &iov; msg.msg_iovlen = 1; char cmsg[kControlMsgSize] = ""; diff --git a/src/client/linux/crash_generation/crash_generation_client.h b/src/client/linux/crash_generation/crash_generation_client.h index 4e68424a..915b5700 100644 --- a/src/client/linux/crash_generation/crash_generation_client.h +++ b/src/client/linux/crash_generation/crash_generation_client.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/crash_generation/crash_generation_server.cc b/src/client/linux/crash_generation/crash_generation_server.cc index 26c50a5c..56cc0cd7 100644 --- a/src/client/linux/crash_generation/crash_generation_server.cc +++ b/src/client/linux/crash_generation/crash_generation_server.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -229,7 +228,7 @@ CrashGenerationServer::ClientEvent(short revents) // Walk the control payload and extract the file descriptor and validated pid. pid_t crashing_pid = -1; int signal_fd = -1; - for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr; + for (struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { if (hdr->cmsg_level != SOL_SOCKET) continue; @@ -248,7 +247,7 @@ CrashGenerationServer::ClientEvent(short revents) signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0]; } } else if (hdr->cmsg_type == SCM_CREDENTIALS) { - const struct ucred *cred = + const struct ucred* cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); crashing_pid = cred->pid; } @@ -324,7 +323,7 @@ CrashGenerationServer::MakeMinidumpFilename(string& outFilename) // static void* -CrashGenerationServer::ThreadMain(void *arg) +CrashGenerationServer::ThreadMain(void* arg) { reinterpret_cast<CrashGenerationServer*>(arg)->Run(); return NULL; diff --git a/src/client/linux/crash_generation/crash_generation_server.h b/src/client/linux/crash_generation/crash_generation_server.h index 483fb709..5f4cb3a7 100644 --- a/src/client/linux/crash_generation/crash_generation_server.h +++ b/src/client/linux/crash_generation/crash_generation_server.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/dump_writer_common/mapping_info.h b/src/client/linux/dump_writer_common/mapping_info.h index c09e48ab..759e7338 100644 --- a/src/client/linux/dump_writer_common/mapping_info.h +++ b/src/client/linux/dump_writer_common/mapping_info.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/dump_writer_common/raw_context_cpu.h b/src/client/linux/dump_writer_common/raw_context_cpu.h index 07d9171a..ea4b6f6a 100644 --- a/src/client/linux/dump_writer_common/raw_context_cpu.h +++ b/src/client/linux/dump_writer_common/raw_context_cpu.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,6 +43,14 @@ typedef MDRawContextARM RawContextCPU; typedef MDRawContextARM64_Old RawContextCPU; #elif defined(__mips__) typedef MDRawContextMIPS RawContextCPU; +#elif defined(__riscv) +# if __riscv_xlen == 32 +typedef MDRawContextRISCV RawContextCPU; +# elif __riscv_xlen == 64 +typedef MDRawContextRISCV64 RawContextCPU; +# else +# error "Unexpected __riscv_xlen" +# endif #else #error "This code has not been ported to your platform yet." #endif diff --git a/src/client/linux/dump_writer_common/thread_info.cc b/src/client/linux/dump_writer_common/thread_info.cc index aae1dc13..d8bf80b0 100644 --- a/src/client/linux/dump_writer_common/thread_info.cc +++ b/src/client/linux/dump_writer_common/thread_info.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -270,7 +269,74 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const { out->float_save.fir = mcontext.fpc_eir; #endif } -#endif // __mips__ + +#elif defined(__riscv) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return mcontext.__gregs[0]; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { +# if __riscv__xlen == 32 + out->context_flags = MD_CONTEXT_RISCV_FULL; +# elif __riscv_xlen == 64 + out->context_flags = MD_CONTEXT_RISCV64_FULL; +# else +# error "Unexpected __riscv_xlen" +# endif + + out->pc = mcontext.__gregs[0]; + out->ra = mcontext.__gregs[1]; + out->sp = mcontext.__gregs[2]; + out->gp = mcontext.__gregs[3]; + out->tp = mcontext.__gregs[4]; + out->t0 = mcontext.__gregs[5]; + out->t1 = mcontext.__gregs[6]; + out->t2 = mcontext.__gregs[7]; + out->s0 = mcontext.__gregs[8]; + out->s1 = mcontext.__gregs[9]; + out->a0 = mcontext.__gregs[10]; + out->a1 = mcontext.__gregs[11]; + out->a2 = mcontext.__gregs[12]; + out->a3 = mcontext.__gregs[13]; + out->a4 = mcontext.__gregs[14]; + out->a5 = mcontext.__gregs[15]; + out->a6 = mcontext.__gregs[16]; + out->a7 = mcontext.__gregs[17]; + out->s2 = mcontext.__gregs[18]; + out->s3 = mcontext.__gregs[19]; + out->s4 = mcontext.__gregs[20]; + out->s5 = mcontext.__gregs[21]; + out->s6 = mcontext.__gregs[22]; + out->s7 = mcontext.__gregs[23]; + out->s8 = mcontext.__gregs[24]; + out->s9 = mcontext.__gregs[25]; + out->s10 = mcontext.__gregs[26]; + out->s11 = mcontext.__gregs[27]; + out->t3 = mcontext.__gregs[28]; + out->t4 = mcontext.__gregs[29]; + out->t5 = mcontext.__gregs[30]; + out->t6 = mcontext.__gregs[31]; + +# if __riscv_flen == 32 + for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) + out->float_save.regs[i] = mcontext.__fpregs.__f.__f[i]; + out->float_save.fpcsr = mcontext.__fpregs.__f.__fcsr; +# elif __riscv_flen == 64 + for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) + out->float_save.regs[i] = mcontext.__fpregs.__d.__f[i]; + out->float_save.fpcsr = mcontext.__fpregs.__d.__fcsr; +# elif __riscv_flen == 128 + for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) { + out->float_save.regs[i].high = mcontext.__fpregs.__q.__f[2*i]; + out->float_save.regs[i].low = mcontext.__fpregs.__q.__f[2*i+1]; + } + out->float_save.fpcsr = mcontext.__fpregs.__q.__fcsr; +# else +# error "Unexpected __riscv_flen" +# endif +} +#endif // __riscv void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) { assert(gp_regs || size); @@ -279,6 +345,11 @@ void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) { *gp_regs = mcontext.gregs; if (size) *size = sizeof(mcontext.gregs); +#elif defined(__riscv) + if (gp_regs) + *gp_regs = mcontext.__gregs; + if (size) + *size = sizeof(mcontext.__gregs); #else if (gp_regs) *gp_regs = ®s; @@ -294,6 +365,25 @@ void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) { *fp_regs = &mcontext.fpregs; if (size) *size = sizeof(mcontext.fpregs); +#elif defined(__riscv) +# if __riscv_flen == 32 + if (fp_regs) + *fp_regs = &mcontext.__fpregs.__f.__f; + if (size) + *size = sizeof(mcontext.__fpregs.__f.__f); +# elif __riscv_flen == 64 + if (fp_regs) + *fp_regs = &mcontext.__fpregs.__d.__f; + if (size) + *size = sizeof(mcontext.__fpregs.__d.__f); +# elif __riscv_flen == 128 + if (fp_regs) + *fp_regs = &mcontext.__fpregs.__q.__f; + if (size) + *size = sizeof(mcontext.__fpregs.__q.__f); +# else +# error "Unexpected __riscv_flen" +# endif #else if (fp_regs) *fp_regs = &fpregs; diff --git a/src/client/linux/dump_writer_common/thread_info.h b/src/client/linux/dump_writer_common/thread_info.h index fb216fa6..af786bcc 100644 --- a/src/client/linux/dump_writer_common/thread_info.h +++ b/src/client/linux/dump_writer_common/thread_info.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -68,7 +67,7 @@ struct ThreadInfo { // Use the structures defined in <sys/user.h> struct user_regs_struct regs; struct user_fpsimd_struct fpregs; -#elif defined(__mips__) +#elif defined(__mips__) || defined(__riscv) // Use the structure defined in <sys/ucontext.h>. mcontext_t mcontext; #endif diff --git a/src/client/linux/dump_writer_common/ucontext_reader.cc b/src/client/linux/dump_writer_common/ucontext_reader.cc index ee515c41..97ed2a9f 100644 --- a/src/client/linux/dump_writer_common/ucontext_reader.cc +++ b/src/client/linux/dump_writer_common/ucontext_reader.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -48,7 +47,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { return uc->uc_mcontext.gregs[REG_EIP]; } -void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc, +void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc, const fpstate_t* fp) { const greg_t* regs = uc->uc_mcontext.gregs; @@ -96,7 +95,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { return uc->uc_mcontext.gregs[REG_RIP]; } -void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc, +void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc, const fpstate_t* fpregs) { const greg_t* regs = uc->uc_mcontext.gregs; @@ -153,7 +152,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { return uc->uc_mcontext.arm_pc; } -void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) { +void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) { out->context_flags = MD_CONTEXT_ARM_FULL; out->iregs[0] = uc->uc_mcontext.arm_r0; @@ -192,7 +191,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { return uc->uc_mcontext.pc; } -void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc, +void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc, const struct fpsimd_context* fpregs) { out->context_flags = MD_CONTEXT_ARM64_FULL_OLD; @@ -218,7 +217,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { return uc->uc_mcontext.pc; } -void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) { +void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) { #if _MIPS_SIM == _ABI64 out->context_flags = MD_CONTEXT_MIPS64_FULL; #elif _MIPS_SIM == _ABIO32 @@ -254,6 +253,75 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) { out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused. #endif } + +#elif defined(__riscv) + +uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { + return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { + return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_PC]; +} + +void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) { +# if __riscv__xlen == 32 + out->context_flags = MD_CONTEXT_RISCV_FULL; +# elif __riscv_xlen == 64 + out->context_flags = MD_CONTEXT_RISCV64_FULL; +# else +# error "Unexpected __riscv_xlen" +# endif + + out->pc = uc->uc_mcontext.__gregs[0]; + out->ra = uc->uc_mcontext.__gregs[1]; + out->sp = uc->uc_mcontext.__gregs[2]; + out->gp = uc->uc_mcontext.__gregs[3]; + out->tp = uc->uc_mcontext.__gregs[4]; + out->t0 = uc->uc_mcontext.__gregs[5]; + out->t1 = uc->uc_mcontext.__gregs[6]; + out->t2 = uc->uc_mcontext.__gregs[7]; + out->s0 = uc->uc_mcontext.__gregs[8]; + out->s1 = uc->uc_mcontext.__gregs[9]; + out->a0 = uc->uc_mcontext.__gregs[10]; + out->a1 = uc->uc_mcontext.__gregs[11]; + out->a2 = uc->uc_mcontext.__gregs[12]; + out->a3 = uc->uc_mcontext.__gregs[13]; + out->a4 = uc->uc_mcontext.__gregs[14]; + out->a5 = uc->uc_mcontext.__gregs[15]; + out->a6 = uc->uc_mcontext.__gregs[16]; + out->a7 = uc->uc_mcontext.__gregs[17]; + out->s2 = uc->uc_mcontext.__gregs[18]; + out->s3 = uc->uc_mcontext.__gregs[19]; + out->s4 = uc->uc_mcontext.__gregs[20]; + out->s5 = uc->uc_mcontext.__gregs[21]; + out->s6 = uc->uc_mcontext.__gregs[22]; + out->s7 = uc->uc_mcontext.__gregs[23]; + out->s8 = uc->uc_mcontext.__gregs[24]; + out->s9 = uc->uc_mcontext.__gregs[25]; + out->s10 = uc->uc_mcontext.__gregs[26]; + out->s11 = uc->uc_mcontext.__gregs[27]; + out->t3 = uc->uc_mcontext.__gregs[28]; + out->t4 = uc->uc_mcontext.__gregs[29]; + out->t5 = uc->uc_mcontext.__gregs[30]; + out->t6 = uc->uc_mcontext.__gregs[31]; + +# if __riscv_flen == 32 + for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) + out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__f.__f[i]; + out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__f.__fcsr; +# elif __riscv_flen == 64 + for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) + out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__d.__f[i]; + out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__d.__fcsr; +# elif __riscv_flen == 128 + for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) { + out->float_save.regs[i].high = uc->uc_mcontext.__fpregs.__q.__f[2*i]; + out->float_save.regs[i].low = uc->uc_mcontext.__fpregs.__q.__f[2*i+1]; + } + out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__q.__fcsr; +# endif +} #endif } // namespace google_breakpad diff --git a/src/client/linux/dump_writer_common/ucontext_reader.h b/src/client/linux/dump_writer_common/ucontext_reader.h index 8e74a8a5..60cbf900 100644 --- a/src/client/linux/dump_writer_common/ucontext_reader.h +++ b/src/client/linux/dump_writer_common/ucontext_reader.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -50,13 +49,13 @@ struct UContextReader { // out: the minidump structure // info: the collection of register structures. #if defined(__i386__) || defined(__x86_64) - static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc, + static void FillCPUContext(RawContextCPU* out, const ucontext_t* uc, const fpstate_t* fp); #elif defined(__aarch64__) - static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc, + static void FillCPUContext(RawContextCPU* out, const ucontext_t* uc, const struct fpsimd_context* fpregs); #else - static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc); + static void FillCPUContext(RawContextCPU* out, const ucontext_t* uc); #endif }; diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc index c65feaa1..bbdb798b 100644 --- a/src/client/linux/handler/exception_handler.cc +++ b/src/client/linux/handler/exception_handler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -138,7 +137,7 @@ void InstallAlternateStackLocked() { // SIGSTKSZ may be too small to prevent the signal handlers from overrunning // the alternative stack. Ensure that the size of the alternative stack is // large enough. - static const unsigned kSigStackSize = std::max(16384, SIGSTKSZ); + const unsigned kSigStackSize = std::max<unsigned>(16384, SIGSTKSZ); // Only set an alternative stack if there isn't already one, or if the current // one is too small. @@ -419,8 +418,8 @@ struct ThreadArgument { // This is the entry function for the cloned process. We are in a compromised // context here: see the top of the file. // static -int ExceptionHandler::ThreadEntry(void *arg) { - const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg); +int ExceptionHandler::ThreadEntry(void* arg) { + const ThreadArgument* thread_arg = reinterpret_cast<ThreadArgument*>(arg); // Close the write end of the pipe. This allows us to fail if the parent dies // while waiting for the continue signal. @@ -461,10 +460,7 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) { memcpy(&g_crash_context_.float_state, fp_ptr, sizeof(g_crash_context_.float_state)); } -#elif !defined(__ARM_EABI__) && !defined(__mips__) - // FP state is not part of user ABI on ARM Linux. - // In case of MIPS Linux FP state is already part of ucontext_t - // and 'float_state' is not a member of CrashContext. +#elif GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE ucontext_t* uc_ptr = (ucontext_t*)uc; if (uc_ptr->uc_mcontext.fpregs) { memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fpregs, @@ -495,7 +491,7 @@ bool ExceptionHandler::SimulateSignalDelivery(int sig) { } // This function may run in a compromised context: see the top of the file. -bool ExceptionHandler::GenerateDump(CrashContext *context) { +bool ExceptionHandler::GenerateDump(CrashContext* context) { if (IsOutOfProcess()) return crash_generation_client_->RequestDump(context, sizeof(*context)); @@ -701,8 +697,7 @@ bool ExceptionHandler::WriteMinidump() { } #endif -#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) - // FPU state is not part of ARM EABI ucontext_t. +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE && !defined(__aarch64__) memcpy(&context.float_state, context.context.uc_mcontext.fpregs, sizeof(context.float_state)); #endif @@ -726,8 +721,11 @@ bool ExceptionHandler::WriteMinidump() { #elif defined(__mips__) context.siginfo.si_addr = reinterpret_cast<void*>(context.context.uc_mcontext.pc); +#elif defined(__riscv) + context.siginfo.si_addr = + reinterpret_cast<void*>(context.context.uc_mcontext.__gregs[REG_PC]); #else -#error "This code has not been ported to your platform yet." +# error "This code has not been ported to your platform yet." #endif return GenerateDump(&context); diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h index f44483ff..f8bc1ead 100644 --- a/src/client/linux/handler/exception_handler.h +++ b/src/client/linux/handler/exception_handler.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,6 +43,15 @@ #include "common/using_std_string.h" #include "google_breakpad/common/minidump_format.h" +#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv) +// FP state is not part of user ABI for Linux ARM. +// In case of MIPS and RISCV Linux FP state is already part of ucontext_t +// so 'float_state' is not required. +# define GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE 1 +#else +# define GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE 0 +#endif + namespace google_breakpad { // ExceptionHandler @@ -82,7 +90,7 @@ class ExceptionHandler { // attempting to write a minidump. If a FilterCallback returns false, // Breakpad will immediately report the exception as unhandled without // writing a minidump, allowing another handler the opportunity to handle it. - typedef bool (*FilterCallback)(void *context); + typedef bool (*FilterCallback)(void* context); // A callback function to run after the minidump has been written. // |descriptor| contains the file descriptor or file path containing the @@ -192,10 +200,7 @@ class ExceptionHandler { siginfo_t siginfo; pid_t tid; // the crashing thread. ucontext_t context; -#if !defined(__ARM_EABI__) && !defined(__mips__) - // #ifdef this out because FP state is not part of user ABI for Linux ARM. - // In case of MIPS Linux FP state is already part of ucontext_t so - // 'float_state' is not required. +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE fpstate_t float_state; #endif }; @@ -234,7 +239,7 @@ class ExceptionHandler { static void RestoreHandlersLocked(); void PreresolveSymbols(); - bool GenerateDump(CrashContext *context); + bool GenerateDump(CrashContext* context); void SendContinueSignalToChild(); void WaitForContinueSignal(); diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc index 27808aa1..691ea133 100644 --- a/src/client/linux/handler/exception_handler_unittest.cc +++ b/src/client/linux/handler/exception_handler_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -201,7 +200,7 @@ static bool DoneCallback(const MinidumpDescriptor& descriptor, // 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 +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; @@ -306,8 +305,22 @@ TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) { } } - // Wait a while until the child should have crashed. - usleep(1000000); + // Poll the child to see if it crashed. + int status, wp_pid; + for (int i = 0; i < 100; i++) { + wp_pid = HANDLE_EINTR(waitpid(child, &status, WNOHANG)); + ASSERT_NE(-1, wp_pid); + if (wp_pid > 0) { + ASSERT_TRUE(WIFSIGNALED(status)); + // If the child process terminated by itself, + // it will have returned SIGSEGV. + ASSERT_EQ(SIGSEGV, WTERMSIG(status)); + return; + } else { + usleep(100000); + } + } + // Kill the child if it is still running. kill(child, SIGKILL); @@ -649,7 +662,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { memset(prefix_bytes, 0, sizeof(prefix_bytes)); memset(suffix_bytes, 0, sizeof(suffix_bytes)); EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); - EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, + EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)) == 0); EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), suffix_bytes, sizeof(suffix_bytes)) == 0); @@ -738,7 +751,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)]; memset(suffix_bytes, 0, sizeof(suffix_bytes)); - EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, + EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)) == 0); EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), suffix_bytes, sizeof(suffix_bytes)) == 0); @@ -994,7 +1007,7 @@ CrashHandler(const void* crash_context, size_t crash_context_size, msg.msg_control = cmsg; msg.msg_controllen = sizeof(cmsg); - struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); + struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); hdr->cmsg_level = SOL_SOCKET; hdr->cmsg_type = SCM_RIGHTS; hdr->cmsg_len = CMSG_LEN(sizeof(int)); @@ -1003,7 +1016,7 @@ CrashHandler(const void* crash_context, size_t crash_context_size, hdr->cmsg_level = SOL_SOCKET; hdr->cmsg_type = SCM_CREDENTIALS; hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred)); - struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); + struct ucred* cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); cred->uid = getuid(); cred->gid = getgid(); cred->pid = getpid(); @@ -1056,7 +1069,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) { pid_t crashing_pid = -1; int signal_fd = -1; - for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr; + for (struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { if (hdr->cmsg_level != SOL_SOCKET) continue; @@ -1066,7 +1079,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) { ASSERT_EQ(sizeof(int), len); signal_fd = *(reinterpret_cast<int*>(CMSG_DATA(hdr))); } else if (hdr->cmsg_type == SCM_CREDENTIALS) { - const struct ucred *cred = + const struct ucred* cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); crashing_pid = cred->pid; } diff --git a/src/client/linux/handler/microdump_extra_info.h b/src/client/linux/handler/microdump_extra_info.h index bf01f0c7..1da69d09 100644 --- a/src/client/linux/handler/microdump_extra_info.h +++ b/src/client/linux/handler/microdump_extra_info.h @@ -1,5 +1,4 @@ -// Copyright 2015 Google Inc. -// All rights reserved. +// Copyright 2015 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/handler/minidump_descriptor.cc b/src/client/linux/handler/minidump_descriptor.cc index bd94474e..517fce97 100644 --- a/src/client/linux/handler/minidump_descriptor.cc +++ b/src/client/linux/handler/minidump_descriptor.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012 Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/handler/minidump_descriptor.h b/src/client/linux/handler/minidump_descriptor.h index c7e4f2b3..d822c9d9 100644 --- a/src/client/linux/handler/minidump_descriptor.h +++ b/src/client/linux/handler/minidump_descriptor.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012 Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -33,6 +32,7 @@ #include <assert.h> #include <sys/types.h> +#include <cstdint> #include <string> #include "client/linux/handler/microdump_extra_info.h" diff --git a/src/client/linux/log/log.cc b/src/client/linux/log/log.cc index fc23aa6d..c45de64b 100644 --- a/src/client/linux/log/log.cc +++ b/src/client/linux/log/log.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012 Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,8 +43,8 @@ namespace { // __android_log_buf_write() is not exported in the NDK and is being used by // dynamic runtime linking. Its declaration is taken from Android's // system/core/include/log/log.h. -using AndroidLogBufferWriteFunc = int (*)(int bufID, int prio, const char *tag, - const char *text); +using AndroidLogBufferWriteFunc = int (*)(int bufID, int prio, const char* tag, + const char* text); const int kAndroidCrashLogId = 4; // From LOG_ID_CRASH in log.h. const char kAndroidLogTag[] = "google-breakpad"; diff --git a/src/client/linux/log/log.h b/src/client/linux/log/log.h index f94bbd5f..93aeffcf 100644 --- a/src/client/linux/log/log.h +++ b/src/client/linux/log/log.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc index 0aa30fbf..1f19d3bb 100644 --- a/src/client/linux/microdump_writer/microdump_writer.cc +++ b/src/client/linux/microdump_writer/microdump_writer.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -49,8 +48,8 @@ namespace { using google_breakpad::auto_wasteful_vector; +using google_breakpad::elf::kDefaultBuildIdSize; using google_breakpad::ExceptionHandler; -using google_breakpad::kDefaultBuildIdSize; using google_breakpad::LinuxDumper; using google_breakpad::LinuxPtraceDumper; using google_breakpad::MappingInfo; @@ -138,7 +137,7 @@ class MicrodumpWriter { const MicrodumpExtraInfo& microdump_extra_info, LinuxDumper* dumper) : ucontext_(context ? &context->context : NULL), -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE float_state_(context ? &context->float_state : NULL), #endif dumper_(dumper), @@ -336,9 +335,17 @@ class MicrodumpWriter { const char kArch[] = "mips64"; # else # error "This mips ABI is currently not supported (n32)" -#endif +# endif +#elif defined(__riscv) +# if __riscv_xlen == 32 + const char kArch[] = "riscv32"; +# elif __riscv_xlen == 64 + const char kArch[] = "riscv64"; +# else +# error "Unexpected __riscv_xlen" +# endif #else -#error "This code has not been ported to your platform yet" +# error "This code has not been ported to your platform yet" #endif LogAppend("O "); @@ -409,7 +416,7 @@ class MicrodumpWriter { void DumpCPUState() { RawContextCPU cpu; my_memset(&cpu, 0, sizeof(RawContextCPU)); -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE UContextReader::FillCPUContext(&cpu, ucontext_, float_state_); #else UContextReader::FillCPUContext(&cpu, ucontext_); @@ -460,7 +467,7 @@ class MicrodumpWriter { } // Copy as many bytes of |identifier| as will fit into a MDGUID - MDGUID module_identifier = {}; + MDGUID module_identifier = {0}; memcpy(&module_identifier, &identifier_bytes[0], std::min(sizeof(MDGUID), identifier_bytes.size())); @@ -605,7 +612,7 @@ class MicrodumpWriter { void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } const ucontext_t* const ucontext_; -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE const google_breakpad::fpstate_t* const float_state_; #endif LinuxDumper* dumper_; diff --git a/src/client/linux/microdump_writer/microdump_writer.h b/src/client/linux/microdump_writer/microdump_writer.h index a1e53df6..47b03e8f 100644 --- a/src/client/linux/microdump_writer/microdump_writer.h +++ b/src/client/linux/microdump_writer/microdump_writer.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/microdump_writer/microdump_writer_unittest.cc b/src/client/linux/microdump_writer/microdump_writer_unittest.cc index 6339ac0c..84865664 100644 --- a/src/client/linux/microdump_writer/microdump_writer_unittest.cc +++ b/src/client/linux/microdump_writer/microdump_writer_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014 Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/cpu_set.h b/src/client/linux/minidump_writer/cpu_set.h index 1cca9aa5..70c1c758 100644 --- a/src/client/linux/minidump_writer/cpu_set.h +++ b/src/client/linux/minidump_writer/cpu_set.h @@ -1,5 +1,4 @@ -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/cpu_set_unittest.cc b/src/client/linux/minidump_writer/cpu_set_unittest.cc index e2274bd1..1db74410 100644 --- a/src/client/linux/minidump_writer/cpu_set_unittest.cc +++ b/src/client/linux/minidump_writer/cpu_set_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/directory_reader.h b/src/client/linux/minidump_writer/directory_reader.h index a4bde180..62bba877 100644 --- a/src/client/linux/minidump_writer/directory_reader.h +++ b/src/client/linux/minidump_writer/directory_reader.h @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/directory_reader_unittest.cc b/src/client/linux/minidump_writer/directory_reader_unittest.cc index 326f9e36..ffc5fbfd 100644 --- a/src/client/linux/minidump_writer/directory_reader_unittest.cc +++ b/src/client/linux/minidump_writer/directory_reader_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,7 +46,7 @@ typedef testing::Test DirectoryReaderTest; TEST(DirectoryReaderTest, CompareResults) { std::set<string> dent_set; - DIR *const dir = opendir("/proc/self"); + DIR* const dir = opendir("/proc/self"); ASSERT_TRUE(dir != NULL); struct dirent* dent; diff --git a/src/client/linux/minidump_writer/line_reader.h b/src/client/linux/minidump_writer/line_reader.h index 779cfeb6..d54a67d0 100644 --- a/src/client/linux/minidump_writer/line_reader.h +++ b/src/client/linux/minidump_writer/line_reader.h @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -61,7 +60,7 @@ class LineReader { // // One must call |PopLine| after this function, otherwise you'll continue to // get the same line over and over. - bool GetNextLine(const char **line, unsigned *len) { + bool GetNextLine(const char** line, unsigned* len) { for (;;) { if (buf_used_ == 0 && hit_eof_) return false; diff --git a/src/client/linux/minidump_writer/line_reader_unittest.cc b/src/client/linux/minidump_writer/line_reader_unittest.cc index 29686f04..3062c39f 100644 --- a/src/client/linux/minidump_writer/line_reader_unittest.cc +++ b/src/client/linux/minidump_writer/line_reader_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -59,7 +58,7 @@ TEST(LineReaderTest, EmptyFile) { ASSERT_TRUE(file.IsOk()); LineReader reader(file.GetFd()); - const char *line; + const char* line; unsigned len; ASSERT_FALSE(reader.GetNextLine(&line, &len)); } @@ -69,7 +68,7 @@ TEST(LineReaderTest, OneLineTerminated) { ASSERT_TRUE(file.IsOk()); LineReader reader(file.GetFd()); - const char *line; + const char* line; unsigned int len; ASSERT_TRUE(reader.GetNextLine(&line, &len)); ASSERT_EQ((unsigned int)1, len); @@ -85,7 +84,7 @@ TEST(LineReaderTest, OneLine) { ASSERT_TRUE(file.IsOk()); LineReader reader(file.GetFd()); - const char *line; + const char* line; unsigned len; ASSERT_TRUE(reader.GetNextLine(&line, &len)); ASSERT_EQ((unsigned)1, len); @@ -101,7 +100,7 @@ TEST(LineReaderTest, TwoLinesTerminated) { ASSERT_TRUE(file.IsOk()); LineReader reader(file.GetFd()); - const char *line; + const char* line; unsigned len; ASSERT_TRUE(reader.GetNextLine(&line, &len)); ASSERT_EQ((unsigned)1, len); @@ -123,7 +122,7 @@ TEST(LineReaderTest, TwoLines) { ASSERT_TRUE(file.IsOk()); LineReader reader(file.GetFd()); - const char *line; + const char* line; unsigned len; ASSERT_TRUE(reader.GetNextLine(&line, &len)); ASSERT_EQ((unsigned)1, len); @@ -147,7 +146,7 @@ TEST(LineReaderTest, MaxLength) { ASSERT_TRUE(file.IsOk()); LineReader reader(file.GetFd()); - const char *line; + const char* line; unsigned len; ASSERT_TRUE(reader.GetNextLine(&line, &len)); ASSERT_EQ(sizeof(l), len); @@ -163,7 +162,7 @@ TEST(LineReaderTest, TooLong) { ASSERT_TRUE(file.IsOk()); LineReader reader(file.GetFd()); - const char *line; + const char* line; unsigned len; ASSERT_FALSE(reader.GetNextLine(&line, &len)); } diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc index 41506898..2c507c1b 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper.cc +++ b/src/client/linux/minidump_writer/linux_core_dumper.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -112,8 +111,11 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { #elif defined(__mips__) stack_pointer = reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#elif defined(__riscv) + stack_pointer = reinterpret_cast<uint8_t*>( + info->mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP]); #else -#error "This code hasn't been ported to your platform yet." +# error "This code hasn't been ported to your platform yet." #endif info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer); return true; @@ -137,6 +139,16 @@ bool LinuxCoreDumper::EnumerateThreads() { return false; } + char proc_mem_path[NAME_MAX]; + if (BuildProcPath(proc_mem_path, pid_, "mem")) { + int fd = open(proc_mem_path, O_RDONLY | O_LARGEFILE | O_CLOEXEC); + if (fd != -1) { + core_.SetProcMem(fd); + } else { + fprintf(stderr, "Cannot open %s (%s)\n", proc_mem_path, strerror(errno)); + } + } + core_.SetContent(mapped_core_file_.content()); if (!core_.IsValid()) { fprintf(stderr, "Invalid core dump file\n"); @@ -198,19 +210,22 @@ bool LinuxCoreDumper::EnumerateThreads() { info.tgid = status->pr_pgrp; info.ppid = status->pr_ppid; #if defined(__mips__) -#if defined(__ANDROID__) +# if defined(__ANDROID__) for (int i = EF_R0; i <= EF_R31; i++) info.mcontext.gregs[i - EF_R0] = status->pr_reg[i]; -#else // __ANDROID__ +# else // __ANDROID__ for (int i = EF_REG0; i <= EF_REG31; i++) info.mcontext.gregs[i - EF_REG0] = status->pr_reg[i]; -#endif // __ANDROID__ +# endif // __ANDROID__ info.mcontext.mdlo = status->pr_reg[EF_LO]; info.mcontext.mdhi = status->pr_reg[EF_HI]; info.mcontext.pc = status->pr_reg[EF_CP0_EPC]; -#else // __mips__ +#elif defined(__riscv) + memcpy(&info.mcontext.__gregs, status->pr_reg, + sizeof(info.mcontext.__gregs)); +#else // __riscv memcpy(&info.regs, status->pr_reg, sizeof(info.regs)); -#endif // __mips__ +#endif if (first_thread) { crash_thread_ = pid; crash_signal_ = status->pr_info.si_signo; diff --git a/src/client/linux/minidump_writer/linux_core_dumper.h b/src/client/linux/minidump_writer/linux_core_dumper.h index 8a7c924b..3fc71223 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper.h +++ b/src/client/linux/minidump_writer/linux_core_dumper.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc index 77448031..157e4f89 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc +++ b/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc index ef75260e..01b06fac 100644 --- a/src/client/linux/minidump_writer/linux_dumper.cc +++ b/src/client/linux/minidump_writer/linux_dumper.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -53,6 +52,8 @@ #include "google_breakpad/common/minidump_exception_linux.h" #include "third_party/lss/linux_syscall_support.h" +using google_breakpad::elf::FileID; + #if defined(__ANDROID__) // Android packed relocations definitions are not yet available from the @@ -135,7 +136,7 @@ const size_t kHpageMask = (~(kHpageSize - 1)); // next is backed by some file. // curr and next are contiguous. // offset(next) == sizeof(curr) -void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) { +void TryRecoverMappings(MappingInfo* curr, MappingInfo* next) { // Merged segments are marked with size = 0. if (curr->size == 0 || next->size == 0) return; @@ -167,8 +168,8 @@ void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) { // next and prev are backed by the same file. // prev, curr and next are contiguous. // offset(next) == offset(prev) + sizeof(prev) + sizeof(curr) -void TryRecoverMappings(MappingInfo *prev, MappingInfo *curr, - MappingInfo *next) { +void TryRecoverMappings(MappingInfo* prev, MappingInfo* curr, + MappingInfo* next) { // Merged segments are marked with size = 0. if (prev->size == 0 || curr->size == 0 || next->size == 0) return; @@ -551,11 +552,11 @@ bool LinuxDumper::EnumerateMappings() { // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more // information. const void* linux_gate_loc = - reinterpret_cast<void *>(auxv_[AT_SYSINFO_EHDR]); + reinterpret_cast<void*>(auxv_[AT_SYSINFO_EHDR]); // Although the initial executable is usually the first mapping, it's not // guaranteed (see http://crosbug.com/25355); therefore, try to use the // actual entry point to find the mapping. - const void* entry_point_loc = reinterpret_cast<void *>(auxv_[AT_ENTRY]); + const void* entry_point_loc = reinterpret_cast<void*>(auxv_[AT_ENTRY]); const int fd = sys_open(maps_path, O_RDONLY, 0); if (fd < 0) @@ -943,7 +944,7 @@ bool LinuxDumper::HandleDeletedFileInMapping(char* path) const { char exe_link[NAME_MAX]; if (!BuildProcPath(exe_link, pid_, "exe")) return false; - MappingInfo new_mapping = {}; + MappingInfo new_mapping = {0}; if (!SafeReadLink(exe_link, new_mapping.name)) return false; char new_path[PATH_MAX]; diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index f4a75d90..2d5b2e52 100644 --- a/src/client/linux/minidump_writer/linux_dumper.h +++ b/src/client/linux/minidump_writer/linux_dumper.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -60,10 +59,12 @@ namespace google_breakpad { // Typedef for our parsing of the auxv variables in /proc/pid/auxv. #if defined(__i386) || defined(__ARM_EABI__) || \ - (defined(__mips__) && _MIPS_SIM == _ABIO32) + (defined(__mips__) && _MIPS_SIM == _ABIO32) || \ + (defined(__riscv) && __riscv_xlen == 32) typedef Elf32_auxv_t elf_aux_entry; #elif defined(__x86_64) || defined(__aarch64__) || \ - (defined(__mips__) && _MIPS_SIM != _ABIO32) + (defined(__mips__) && _MIPS_SIM != _ABIO32) || \ + (defined(__riscv) && __riscv_xlen == 64) typedef Elf64_auxv_t elf_aux_entry; #endif @@ -110,8 +111,8 @@ class LinuxDumper { } // These are only valid after a call to |Init|. - const wasteful_vector<pid_t> &threads() { return threads_; } - const wasteful_vector<MappingInfo*> &mappings() { return mappings_; } + const wasteful_vector<pid_t>& threads() { return threads_; } + const wasteful_vector<MappingInfo*>& mappings() { return mappings_; } const MappingInfo* FindMapping(const void* address) const; // Find the mapping which the given memory address falls in. Unlike // FindMapping, this method uses the unadjusted mapping address diff --git a/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc b/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc index 3ad48e50..bc1e4fbe 100644 --- a/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +++ b/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -51,12 +50,14 @@ #define TID_PTR_REGISTER "rcx" #elif defined(__mips__) #define TID_PTR_REGISTER "$1" +#elif defined(__riscv) +#define TID_PTR_REGISTER "x4" #else #error This test has not been ported to this platform. #endif -void *thread_function(void *data) { - int pipefd = *static_cast<int *>(data); +void* thread_function(void* data) { + int pipefd = *static_cast<int*>(data); volatile pid_t* thread_id = new pid_t; *thread_id = syscall(__NR_gettid); // Signal parent that a thread has started. @@ -65,13 +66,13 @@ void *thread_function(void *data) { perror("ERROR: parent notification failed"); return NULL; } - register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = thread_id; + register volatile pid_t* thread_id_ptr asm(TID_PTR_REGISTER) = thread_id; while (true) asm volatile ("" : : "r" (thread_id_ptr)); return NULL; } -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { if (argc < 3) { fprintf(stderr, "usage: linux_dumper_unittest_helper <pipe fd> <# of threads>\n"); diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc index e3ddb81a..718fab7c 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -298,8 +297,11 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { #elif defined(__mips__) stack_pointer = reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#elif defined(__riscv) + stack_pointer = reinterpret_cast<uint8_t*>( + info->mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP]); #else -#error "This code hasn't been ported to your platform yet." +# error "This code hasn't been ported to your platform yet." #endif info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer); diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.h b/src/client/linux/minidump_writer/linux_ptrace_dumper.h index cee58178..7828934f 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper.h +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc index ea6b9a12..a8455165 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -63,6 +62,8 @@ #endif using namespace google_breakpad; +using google_breakpad::elf::FileID; +using google_breakpad::elf::kDefaultBuildIdSize; namespace { @@ -337,7 +338,7 @@ TEST_F(LinuxPtraceDumperChildTest, MappingsIncludeLinuxGate) { ASSERT_TRUE(dumper.Init()); void* linux_gate_loc = - reinterpret_cast<void *>(dumper.auxv()[AT_SYSINFO_EHDR]); + reinterpret_cast<void*>(dumper.auxv()[AT_SYSINFO_EHDR]); ASSERT_TRUE(linux_gate_loc); bool found_linux_gate = false; @@ -462,6 +463,9 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) { #elif defined(__mips__) pid_t* process_tid_location = reinterpret_cast<pid_t*>(one_thread.mcontext.gregs[1]); +#elif defined(__riscv) + pid_t* process_tid_location = + reinterpret_cast<pid_t*>(one_thread.mcontext.__gregs[4]); #else #error This test has not been ported to this platform. #endif @@ -559,6 +563,8 @@ TEST_F(LinuxPtraceDumperTest, SanitizeStackCopy) { uintptr_t heap_addr = thread_info.regs.rcx; #elif defined(__mips__) uintptr_t heap_addr = thread_info.mcontext.gregs[1]; +#elif defined(__riscv) + uintptr_t heap_addr = thread_info.mcontext.__gregs[4]; #else #error This test has not been ported to this platform. #endif diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index f8cdf2a1..a5f9b841 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -71,6 +70,8 @@ #include "client/linux/minidump_writer/line_reader.h" #include "client/linux/minidump_writer/linux_dumper.h" #include "client/linux/minidump_writer/linux_ptrace_dumper.h" +#include "client/linux/minidump_writer/pe_file.h" +#include "client/linux/minidump_writer/pe_structs.h" #include "client/linux/minidump_writer/proc_cpuinfo_reader.h" #include "client/minidump_file_writer.h" #include "common/linux/file_id.h" @@ -83,9 +84,9 @@ namespace { using google_breakpad::AppMemoryList; using google_breakpad::auto_wasteful_vector; +using google_breakpad::elf::kDefaultBuildIdSize; using google_breakpad::ExceptionHandler; using google_breakpad::CpuSet; -using google_breakpad::kDefaultBuildIdSize; using google_breakpad::LineReader; using google_breakpad::LinuxDumper; using google_breakpad::LinuxPtraceDumper; @@ -95,8 +96,11 @@ using google_breakpad::MappingInfo; using google_breakpad::MappingList; using google_breakpad::MinidumpFileWriter; using google_breakpad::PageAllocator; +using google_breakpad::PEFile; +using google_breakpad::PEFileFormat; using google_breakpad::ProcCpuInfoReader; using google_breakpad::RawContextCPU; +using google_breakpad::RSDS_DEBUG_FORMAT; using google_breakpad::ThreadInfo; using google_breakpad::TypedMDRVA; using google_breakpad::UContextReader; @@ -136,7 +140,7 @@ class MinidumpWriter { : fd_(minidump_fd), path_(minidump_path), ucontext_(context ? &context->context : NULL), -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE float_state_(context ? &context->float_state : NULL), #endif dumper_(dumper), @@ -468,7 +472,7 @@ class MinidumpWriter { if (!cpu.Allocate()) return false; my_memset(cpu.get(), 0, sizeof(RawContextCPU)); -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_); #else UContextReader::FillCPUContext(cpu.get(), ucontext_); @@ -632,40 +636,88 @@ class MinidumpWriter { mod->base_of_image = mapping.start_addr; mod->size_of_image = mapping.size; - auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes( - dumper_->allocator()); + char file_name[NAME_MAX]; + char file_path[NAME_MAX]; - if (identifier) { - // GUID was provided by caller. - identifier_bytes.insert(identifier_bytes.end(), - identifier, - identifier + sizeof(MDGUID)); - } else { - // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|. - dumper_->ElfFileIdentifierForMapping(mapping, - member, - mapping_id, - identifier_bytes); - } + dumper_->GetMappingEffectiveNameAndPath(mapping, file_path, + sizeof(file_path), file_name, + sizeof(file_name)); - if (!identifier_bytes.empty()) { - UntypedMDRVA cv(&minidump_writer_); - if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size())) - return false; + RSDS_DEBUG_FORMAT rsds; + PEFileFormat file_format = PEFile::TryGetDebugInfo(file_path, &rsds); + + if (file_format == PEFileFormat::notPeCoff) { + // The module is not a PE/COFF file, process as an ELF. + auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes( + dumper_->allocator()); - const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE; - cv.Copy(&cv_signature, sizeof(cv_signature)); - cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0], - identifier_bytes.size()); + if (identifier) { + // GUID was provided by caller. + identifier_bytes.insert(identifier_bytes.end(), identifier, + identifier + sizeof(MDGUID)); + } else { + // Note: ElfFileIdentifierForMapping() can manipulate the + // |mapping.name|, that is why we need to call the method + // GetMappingEffectiveNameAndPath again. + dumper_->ElfFileIdentifierForMapping(mapping, member, mapping_id, + identifier_bytes); + dumper_->GetMappingEffectiveNameAndPath(mapping, file_path, + sizeof(file_path), file_name, + sizeof(file_name)); + } + + if (!identifier_bytes.empty()) { + UntypedMDRVA cv(&minidump_writer_); + if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size())) + return false; + + const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE; + cv.Copy(&cv_signature, sizeof(cv_signature)); + cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0], + identifier_bytes.size()); + + mod->cv_record = cv.location(); + } + } else { + // The module is a PE/COFF file. Create MDCVInfoPDB70 struct for it. + size_t file_name_length = strlen(file_name); + TypedMDRVA<MDCVInfoPDB70> cv(&minidump_writer_); + if (!cv.AllocateObjectAndArray(file_name_length + 1, sizeof(uint8_t))) + return false; + if (!cv.CopyIndexAfterObject(0, file_name, file_name_length)) + return false; + MDCVInfoPDB70* cv_ptr = cv.get(); + cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; + if (file_format == PEFileFormat::peWithBuildId) { + // Populate BuildId and age using RSDS instance. + cv_ptr->signature.data1 = static_cast<uint32_t>(rsds.guid[0]) << 24 | + static_cast<uint32_t>(rsds.guid[1]) << 16 | + static_cast<uint32_t>(rsds.guid[2]) << 8 | + static_cast<uint32_t>(rsds.guid[3]); + cv_ptr->signature.data2 = + static_cast<uint16_t>(rsds.guid[4]) << 8 | rsds.guid[5]; + cv_ptr->signature.data3 = + static_cast<uint16_t>(rsds.guid[6]) << 8 | rsds.guid[7]; + cv_ptr->signature.data4[0] = rsds.guid[8]; + cv_ptr->signature.data4[1] = rsds.guid[9]; + cv_ptr->signature.data4[2] = rsds.guid[10]; + cv_ptr->signature.data4[3] = rsds.guid[11]; + cv_ptr->signature.data4[4] = rsds.guid[12]; + cv_ptr->signature.data4[5] = rsds.guid[13]; + cv_ptr->signature.data4[6] = rsds.guid[14]; + cv_ptr->signature.data4[7] = rsds.guid[15]; + // The Age field should be reverted as well. + cv_ptr->age = static_cast<uint32_t>(rsds.age[0]) << 24 | + static_cast<uint32_t>(rsds.age[1]) << 16 | + static_cast<uint32_t>(rsds.age[2]) << 8 | + static_cast<uint32_t>(rsds.age[3]); + } else { + cv_ptr->age = 0; + } mod->cv_record = cv.location(); } - char file_name[NAME_MAX]; - char file_path[NAME_MAX]; - dumper_->GetMappingEffectiveNameAndPath( - mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); - MDLocationDescriptor ld; if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) return false; @@ -740,14 +792,14 @@ class MinidumpWriter { } bool WriteDSODebugStream(MDRawDirectory* dirent) { - ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_->auxv()[AT_PHDR]); + ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(dumper_->auxv()[AT_PHDR]); char* base; int phnum = dumper_->auxv()[AT_PHNUM]; if (!phnum || !phdr) return false; // Assume the program base is at the beginning of the same page as the PHDR - base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff); + base = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff); // Search for the program PT_DYNAMIC segment ElfW(Addr) dyn_addr = 0; @@ -768,7 +820,7 @@ class MinidumpWriter { if (!dyn_addr) return false; - ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base); + ElfW(Dyn)* dynamic = reinterpret_cast<ElfW(Dyn)*>(dyn_addr + base); // The dynamic linker makes information available that helps gdb find all // DSOs loaded into the program. If this information is indeed available, @@ -1085,9 +1137,7 @@ class MinidumpWriter { sys_close(fd); cpus_present.IntersectWith(cpus_possible); - int cpu_count = cpus_present.GetCount(); - if (cpu_count > 255) - cpu_count = 255; + int cpu_count = std::min(255, cpus_present.GetCount()); sys_info->number_of_processors = static_cast<uint8_t>(cpu_count); } } @@ -1205,6 +1255,59 @@ class MinidumpWriter { return true; } +#elif defined(__riscv) + bool WriteCPUInformation(MDRawSystemInfo* sys_info) { + // processor_architecture should always be set, do this first +# if __riscv_xlen == 32 + sys_info->processor_architecture = MD_CPU_ARCHITECTURE_RISCV; +# elif __riscv_xlen == 64 + sys_info->processor_architecture = MD_CPU_ARCHITECTURE_RISCV64; +# else +# error "Unexpected __riscv_xlen" +# endif + + // /proc/cpuinfo is not readable under various sandboxed environments + // (e.g. Android services with the android:isolatedProcess attribute) + // prepare for this by setting default values now, which will be + // returned when this happens. + // + // Note: Bogus values are used to distinguish between failures (to + // read /sys and /proc files) and really badly configured kernels. + sys_info->number_of_processors = 0; + sys_info->processor_level = 0U; + sys_info->processor_revision = 42; + sys_info->cpu.other_cpu_info.processor_features[0] = 0; + sys_info->cpu.other_cpu_info.processor_features[1] = 0; + + // Counting the number of CPUs involves parsing two sysfs files, + // because the content of /proc/cpuinfo will only mirror the number + // of 'online' cores, and thus will vary with time. + // See http://www.kernel.org/doc/Documentation/cputopology.txt + { + CpuSet cpus_present; + CpuSet cpus_possible; + + int fd = sys_open("/sys/devices/system/cpu/present", + O_RDONLY | O_CLOEXEC, 0); + if (fd >= 0) { + cpus_present.ParseSysFile(fd); + sys_close(fd); + + fd = sys_open("/sys/devices/system/cpu/possible", + O_RDONLY | O_CLOEXEC, 0); + if (fd >= 0) { + cpus_possible.ParseSysFile(fd); + sys_close(fd); + + cpus_present.IntersectWith(cpus_possible); + int cpu_count = std::min(255, cpus_present.GetCount()); + sys_info->number_of_processors = static_cast<uint8_t>(cpu_count); + } + } + } + + return true; + } #else # error "Unsupported CPU" #endif @@ -1222,7 +1325,7 @@ class MinidumpWriter { Buffers* next; size_t len; uint8_t data[kBufSize]; - } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers))); + }* buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers))); buffers->next = NULL; buffers->len = 0; @@ -1333,7 +1436,7 @@ class MinidumpWriter { const char* path_; // Path to the file where the minidum should be written. const ucontext_t* const ucontext_; // also from the signal handler -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE const google_breakpad::fpstate_t* const float_state_; // ditto #endif LinuxDumper* dumper_; diff --git a/src/client/linux/minidump_writer/minidump_writer.h b/src/client/linux/minidump_writer/minidump_writer.h index e3b0b16d..24e3c7bd 100644 --- a/src/client/linux/minidump_writer/minidump_writer.h +++ b/src/client/linux/minidump_writer/minidump_writer.h @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/minidump_writer_unittest.cc b/src/client/linux/minidump_writer/minidump_writer_unittest.cc index 3017a49a..2601d29b 100644 --- a/src/client/linux/minidump_writer/minidump_writer_unittest.cc +++ b/src/client/linux/minidump_writer/minidump_writer_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -54,6 +53,8 @@ #include "google_breakpad/processor/minidump.h" using namespace google_breakpad; +using google_breakpad::elf::FileID; +using google_breakpad::elf::kDefaultBuildIdSize; namespace { @@ -299,10 +300,10 @@ TEST(MinidumpWriterTest, MinidumpStacksSkippedIfRequested) { Minidump minidump(templ); ASSERT_TRUE(minidump.Read()); - MinidumpThreadList *threads = minidump.GetThreadList(); + MinidumpThreadList* threads = minidump.GetThreadList(); int threads_with_stacks = 0; for (unsigned int i = 0; i < threads->thread_count(); ++i) { - MinidumpThread *thread = threads->GetThreadAtIndex(i); + MinidumpThread* thread = threads->GetThreadAtIndex(i); if (thread->GetMemory()) { ++threads_with_stacks; } @@ -353,13 +354,13 @@ TEST(MinidumpWriterTest, StacksAreSanitizedIfRequested) { #else 0x0defaced; #endif - MinidumpThreadList *threads = minidump.GetThreadList(); + MinidumpThreadList* threads = minidump.GetThreadList(); for (unsigned int i = 0; i < threads->thread_count(); ++i) { - MinidumpThread *thread = threads->GetThreadAtIndex(i); - MinidumpMemoryRegion *mem = thread->GetMemory(); + MinidumpThread* thread = threads->GetThreadAtIndex(i); + MinidumpMemoryRegion* mem = thread->GetMemory(); ASSERT_TRUE(mem != nullptr); uint32_t sz = mem->GetSize(); - const uint8_t *data = mem->GetMemory(); + const uint8_t* data = mem->GetMemory(); ASSERT_TRUE(memmem(data, sz, &defaced, sizeof(defaced)) != nullptr); } close(fds[1]); @@ -521,7 +522,7 @@ TEST(MinidumpWriterTest, DeletedBinary) { // Copy binary to a temp file. AutoTempDir temp_dir; string binpath = temp_dir.path() + "/linux-dumper-unittest-helper"; - ASSERT_TRUE(CopyFile(helper_path.c_str(), binpath.c_str())) + ASSERT_TRUE(CopyFile(helper_path, binpath)) << "Failed to copy " << helper_path << " to " << binpath; ASSERT_EQ(0, chmod(binpath.c_str(), 0755)); @@ -715,6 +716,9 @@ TEST(MinidumpWriterTest, InvalidStackPointer) { #elif defined(__mips__) context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] = invalid_stack_pointer; +#elif defined(__riscv) + context.context.uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP] = + invalid_stack_pointer; #else # error "This code has not been ported to your platform yet." #endif diff --git a/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc b/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc index 9f46fa65..92cae92e 100644 --- a/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc +++ b/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -41,7 +40,7 @@ namespace google_breakpad { string GetHelperBinary() { string helper_path; - char *bindir = getenv("bindir"); + char* bindir = getenv("bindir"); if (bindir) { helper_path = string(bindir) + "/"; } else { diff --git a/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h b/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h index f16cc086..f93885ee 100644 --- a/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h +++ b/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/pe_file.cc b/src/client/linux/minidump_writer/pe_file.cc new file mode 100644 index 00000000..960b978b --- /dev/null +++ b/src/client/linux/minidump_writer/pe_file.cc @@ -0,0 +1,147 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <string.h> + +#include "client/linux/minidump_writer/pe_file.h" +#include "client/linux/minidump_writer/pe_structs.h" +#include "common/linux/memory_mapped_file.h" + +namespace google_breakpad { + +PEFileFormat PEFile::TryGetDebugInfo(const char* filename, + PRSDS_DEBUG_FORMAT debug_info) { + MemoryMappedFile mapped_file(filename, 0); + if (!mapped_file.data()) + return PEFileFormat::notPeCoff; + const void* base = mapped_file.data(); + const size_t file_size = mapped_file.size(); + + const IMAGE_DOS_HEADER* header = + TryReadStruct<IMAGE_DOS_HEADER>(base, 0, file_size); + if (!header || (header->e_magic != IMAGE_DOS_SIGNATURE)) { + return PEFileFormat::notPeCoff; + } + + // NTHeader is at position 'e_lfanew'. + DWORD nt_header_offset = header->e_lfanew; + // First, read a common IMAGE_NT_HEADERS structure. It should contain a + // special flag marking whether PE module is x64 (OptionalHeader.Magic) + // and so-called NT_SIGNATURE in Signature field. + const IMAGE_NT_HEADERS* nt_header = + TryReadStruct<IMAGE_NT_HEADERS>(base, nt_header_offset, file_size); + if (!nt_header || (nt_header->Signature != IMAGE_NT_SIGNATURE) + || ((nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) + && (nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC))) + return PEFileFormat::notPeCoff; + + bool x64 = nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC; + WORD sections_number = nt_header->FileHeader.NumberOfSections; + DWORD debug_offset; + DWORD debug_size; + DWORD section_offset; + if (x64) { + const IMAGE_NT_HEADERS64* header_64 = + TryReadStruct<IMAGE_NT_HEADERS64>(base, nt_header_offset, file_size); + if (!header_64) + return PEFileFormat::peWithoutBuildId; + debug_offset = + header_64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] + .VirtualAddress; + debug_size = + header_64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] + .Size; + section_offset = nt_header_offset + sizeof(IMAGE_NT_HEADERS64); + } else { + const IMAGE_NT_HEADERS32* header_32 = + TryReadStruct<IMAGE_NT_HEADERS32>(base, nt_header_offset, file_size); + if (!header_32) + return PEFileFormat::peWithoutBuildId; + debug_offset = + header_32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] + .VirtualAddress; + debug_size = + header_32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] + .Size; + section_offset = nt_header_offset + sizeof(IMAGE_NT_HEADERS32); + } + + DWORD debug_end_pos = debug_offset + debug_size; + while (debug_offset < debug_end_pos) { + for (WORD i = 0; i < sections_number; ++i) { + // Section headers are placed sequentially after the NT_HEADER (32/64). + const IMAGE_SECTION_HEADER* section = + TryReadStruct<IMAGE_SECTION_HEADER>(base, section_offset, file_size); + if (!section) + return PEFileFormat::peWithoutBuildId; + + section_offset += sizeof(IMAGE_SECTION_HEADER); + + // Current `debug_offset` should be inside a section, stop if we find + // a suitable one (we don't consider any malformed sections here). + if ((section->VirtualAddress <= debug_offset) && + (debug_offset < section->VirtualAddress + section->SizeOfRawData)) { + DWORD offset = + section->PointerToRawData + debug_offset - section->VirtualAddress; + // Go to the position of current ImageDebugDirectory (offset). + const IMAGE_DEBUG_DIRECTORY* debug_directory = + TryReadStruct<IMAGE_DEBUG_DIRECTORY>(base, offset, file_size); + if (!debug_directory) + return PEFileFormat::peWithoutBuildId; + // Process ImageDebugDirectory with CodeViewRecord type and skip + // all others. + if (debug_directory->Type == IMAGE_DEBUG_TYPE_CODEVIEW) { + DWORD debug_directory_size = debug_directory->SizeOfData; + if (debug_directory_size < sizeof(RSDS_DEBUG_FORMAT)) + // RSDS section is malformed. + return PEFileFormat::peWithoutBuildId; + // Go to the position of current ImageDebugDirectory Raw Data + // (debug_directory->PointerToRawData) and read the RSDS section. + const RSDS_DEBUG_FORMAT* rsds = + TryReadStruct<RSDS_DEBUG_FORMAT>( + base, debug_directory->PointerToRawData, file_size); + + if (!rsds) + return PEFileFormat::peWithoutBuildId; + + memcpy(debug_info->guid, rsds->guid, sizeof(rsds->guid)); + memcpy(debug_info->age, rsds->age, sizeof(rsds->age)); + return PEFileFormat::peWithBuildId; + } + + break; + } + } + + debug_offset += sizeof(IMAGE_DEBUG_DIRECTORY); + } + + return PEFileFormat::peWithoutBuildId; +} + +} // namespace google_breakpad
\ No newline at end of file diff --git a/src/client/linux/minidump_writer/pe_file.h b/src/client/linux/minidump_writer/pe_file.h new file mode 100644 index 00000000..97984ab5 --- /dev/null +++ b/src/client/linux/minidump_writer/pe_file.h @@ -0,0 +1,76 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_ + +#include "client/linux/minidump_writer/pe_structs.h" + +namespace google_breakpad { + +typedef enum { + notPeCoff = 0, + peWithoutBuildId = 1, + peWithBuildId = 2 +} PEFileFormat; + +class PEFile { + public: + /** + * Attempts to parse RSDS_DEBUG_FORMAT record from a PE (Portable + * Executable) file. To do this we check whether the loaded file is a PE + * file, and if it is - try to find IMAGE_DEBUG_DIRECTORY structure with + * its type set to IMAGE_DEBUG_TYPE_CODEVIEW. + * + * @param filename Filename for the module to parse. + * @param debug_info RSDS_DEBUG_FORMAT struct to be populated with PE debug + * info (GUID and age). + * @return + * notPeCoff: not PE/COFF file; + * peWithoutBuildId: a PE/COFF file but build-id is not set; + * peWithBuildId: a PE/COFF file and build-id is set. + */ + static PEFileFormat TryGetDebugInfo(const char* filename, + PRSDS_DEBUG_FORMAT debug_info); + + private: + template <class TStruct> + static const TStruct* TryReadStruct(const void* base, + const DWORD position, + const size_t file_size) { + if (position + sizeof(TStruct) >= file_size){ + return nullptr; + } + + const void* ptr = static_cast<const char*>(base) + position; + return reinterpret_cast<const TStruct*>(ptr); + } +}; + +} // namespace google_breakpad +#endif // CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_
\ No newline at end of file diff --git a/src/client/linux/minidump_writer/pe_structs.h b/src/client/linux/minidump_writer/pe_structs.h new file mode 100644 index 00000000..122cc295 --- /dev/null +++ b/src/client/linux/minidump_writer/pe_structs.h @@ -0,0 +1,225 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_ + +#include <cstdint> + +namespace google_breakpad { + +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef uint64_t ULONGLONG; + +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + +#define IMAGE_DEBUG_TYPE_CODEVIEW 2 + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + WORD e_magic; // Magic number + WORD e_cblp; // Bytes on last page of file + WORD e_cp; // Pages in file + WORD e_crlc; // Relocations + WORD e_cparhdr; // Size of header in paragraphs + WORD e_minalloc; // Minimum extra paragraphs needed + WORD e_maxalloc; // Maximum extra paragraphs needed + WORD e_ss; // Initial (relative) SS value + WORD e_sp; // Initial SP value + WORD e_csum; // Checksum + WORD e_ip; // Initial IP value + WORD e_cs; // Initial (relative) CS value + WORD e_lfarlc; // File address of relocation table + WORD e_ovno; // Overlay number + WORD e_res[4]; // Reserved words + WORD e_oemid; // OEM identifier (for e_oeminfo) + WORD e_oeminfo; // OEM information; e_oemid specific + WORD e_res2[10]; // Reserved words + DWORD e_lfanew; // File address of new exe header +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + + +typedef struct _IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD PointerToRawData; +} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY; + +typedef struct _IMAGE_OPTIONAL_HEADER64 { + // + // Standard fields - Magic. + // + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + // + // NT additional fields. + // + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + // + // NT additional fields. + // + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; + +typedef struct _IMAGE_NT_HEADERS32 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +typedef struct _RSDS_DEBUG_FORMAT { + DWORD signature; + BYTE guid[16]; + BYTE age[4]; + char pdbpath[1]; +} RSDS_DEBUG_FORMAT, *PRSDS_DEBUG_FORMAT; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_
\ No newline at end of file diff --git a/src/client/linux/minidump_writer/proc_cpuinfo_reader.h b/src/client/linux/minidump_writer/proc_cpuinfo_reader.h index d9461bf3..5ae16dfb 100644 --- a/src/client/linux/minidump_writer/proc_cpuinfo_reader.h +++ b/src/client/linux/minidump_writer/proc_cpuinfo_reader.h @@ -1,5 +1,4 @@ -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc b/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc index 6037c7e6..f6d3e285 100644 --- a/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc +++ b/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -65,7 +64,7 @@ TEST(ProcCpuInfoReaderTest, EmptyFile) { ASSERT_TRUE(file.IsOk()); ProcCpuInfoReader reader(file.GetFd()); - const char *field; + const char* field; ASSERT_FALSE(reader.GetNextField(&field)); } @@ -74,7 +73,7 @@ TEST(ProcCpuInfoReaderTest, OneLineTerminated) { ASSERT_TRUE(file.IsOk()); ProcCpuInfoReader reader(file.GetFd()); - const char *field; + const char* field; ASSERT_TRUE(reader.GetNextField(&field)); ASSERT_STREQ("foo", field); ASSERT_STREQ("bar", reader.GetValue()); @@ -87,7 +86,7 @@ TEST(ProcCpuInfoReaderTest, OneLine) { ASSERT_TRUE(file.IsOk()); ProcCpuInfoReader reader(file.GetFd()); - const char *field; + const char* field; size_t value_len; ASSERT_TRUE(reader.GetNextField(&field)); ASSERT_STREQ("foo", field); diff --git a/src/client/linux/sender/google_crash_report_sender.cc b/src/client/linux/sender/google_crash_report_sender.cc index f83a0e89..6f45d831 100644 --- a/src/client/linux/sender/google_crash_report_sender.cc +++ b/src/client/linux/sender/google_crash_report_sender.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -84,7 +83,7 @@ bool CheckForRequiredFlagsOrDie() { return true; } -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { google::InitGoogleLogging(argv[0]); google::ParseCommandLineFlags(&argc, &argv, true); if (!CheckForRequiredFlagsOrDie()) { diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj index 10876535..ed782c91 100644 --- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj +++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj @@ -149,6 +149,22 @@ D2F9A53F121383A1002747C1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; }; D2F9A541121383A1002747C1 /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2F9A41512131EF0002747C1 /* libgtest.a */; }; D2F9A553121383DC002747C1 /* crash_generation_server_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4CE121336F7002747C1 /* crash_generation_server_test.cc */; }; + EB9CF8B924F01E1D00F9B6D1 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */; }; + EB9CF8BA24F01E1D00F9B6D1 /* minidump_upload.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8AD24F01E1D00F9B6D1 /* minidump_upload.m */; }; + EB9CF8BB24F01E1D00F9B6D1 /* encoding_util.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8AE24F01E1D00F9B6D1 /* encoding_util.h */; }; + EB9CF8BC24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8AF24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h */; }; + EB9CF8BD24F01E1D00F9B6D1 /* HTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8B024F01E1D00F9B6D1 /* HTTPRequest.h */; }; + EB9CF8BE24F01E1D00F9B6D1 /* HTTPPutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B124F01E1D00F9B6D1 /* HTTPPutRequest.m */; }; + EB9CF8BF24F01E1D00F9B6D1 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */; }; + EB9CF8C024F01E1D00F9B6D1 /* SymbolCollectorClient.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B324F01E1D00F9B6D1 /* SymbolCollectorClient.m */; }; + EB9CF8C124F01E1D00F9B6D1 /* HTTPGetRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8B424F01E1D00F9B6D1 /* HTTPGetRequest.h */; }; + EB9CF8C224F01E1D00F9B6D1 /* HTTPGetRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B524F01E1D00F9B6D1 /* HTTPGetRequest.m */; }; + EB9CF8C324F01E1D00F9B6D1 /* HTTPSimplePostRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B624F01E1D00F9B6D1 /* HTTPSimplePostRequest.m */; }; + EB9CF8C424F01E1D00F9B6D1 /* SymbolCollectorClient.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8B724F01E1D00F9B6D1 /* SymbolCollectorClient.h */; }; + EB9CF8C524F01E1D00F9B6D1 /* HTTPPutRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8B824F01E1D00F9B6D1 /* HTTPPutRequest.h */; }; + EB9CF8C624F01F1100F9B6D1 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */; }; + EB9CF8C724F01F7600F9B6D1 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */; }; + EB9CF8C824F01FB900F9B6D1 /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C53770ECCE635009BE4BA /* HTTPMultipartUpload.m */; }; F4DAB1DD19F1027100A5A838 /* launch_reporter.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4DAB1DB19F1027100A5A838 /* launch_reporter.cc */; }; F4DAB1DE19F1027100A5A838 /* launch_reporter.h in Headers */ = {isa = PBXBuildFile; fileRef = F4DAB1DC19F1027100A5A838 /* launch_reporter.h */; }; F4F916B619F10FFC00B83BE4 /* launch_reporter.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4DAB1DB19F1027100A5A838 /* launch_reporter.cc */; }; @@ -634,6 +650,19 @@ DE43468E11C72971004F095F /* sl */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = sl; path = sender/sl.lproj/InfoPlist.strings; sourceTree = "<group>"; }; DE43468F11C72973004F095F /* sv */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = sv; path = sender/sv.lproj/InfoPlist.strings; sourceTree = "<group>"; }; DE43469011C72976004F095F /* tr */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = tr; path = sender/tr.lproj/InfoPlist.strings; sourceTree = "<group>"; }; + EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = encoding_util.m; path = ../../common/mac/encoding_util.m; sourceTree = "<group>"; }; + EB9CF8AD24F01E1D00F9B6D1 /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = minidump_upload.m; path = ../../common/mac/minidump_upload.m; sourceTree = "<group>"; }; + EB9CF8AE24F01E1D00F9B6D1 /* encoding_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = encoding_util.h; path = ../../common/mac/encoding_util.h; sourceTree = "<group>"; }; + EB9CF8AF24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSimplePostRequest.h; path = ../../common/mac/HTTPSimplePostRequest.h; sourceTree = "<group>"; }; + EB9CF8B024F01E1D00F9B6D1 /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPRequest.h; path = ../../common/mac/HTTPRequest.h; sourceTree = "<group>"; }; + EB9CF8B124F01E1D00F9B6D1 /* HTTPPutRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPPutRequest.m; path = ../../common/mac/HTTPPutRequest.m; sourceTree = "<group>"; }; + EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPRequest.m; path = ../../common/mac/HTTPRequest.m; sourceTree = "<group>"; }; + EB9CF8B324F01E1D00F9B6D1 /* SymbolCollectorClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SymbolCollectorClient.m; path = ../../common/mac/SymbolCollectorClient.m; sourceTree = "<group>"; }; + EB9CF8B424F01E1D00F9B6D1 /* HTTPGetRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPGetRequest.h; path = ../../common/mac/HTTPGetRequest.h; sourceTree = "<group>"; }; + EB9CF8B524F01E1D00F9B6D1 /* HTTPGetRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPGetRequest.m; path = ../../common/mac/HTTPGetRequest.m; sourceTree = "<group>"; }; + EB9CF8B624F01E1D00F9B6D1 /* HTTPSimplePostRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPSimplePostRequest.m; path = ../../common/mac/HTTPSimplePostRequest.m; sourceTree = "<group>"; }; + EB9CF8B724F01E1D00F9B6D1 /* SymbolCollectorClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolCollectorClient.h; path = ../../common/mac/SymbolCollectorClient.h; sourceTree = "<group>"; }; + EB9CF8B824F01E1D00F9B6D1 /* HTTPPutRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPPutRequest.h; path = ../../common/mac/HTTPPutRequest.h; sourceTree = "<group>"; }; F4DAB1DB19F1027100A5A838 /* launch_reporter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = launch_reporter.cc; path = ../../common/mac/launch_reporter.cc; sourceTree = SOURCE_ROOT; }; F4DAB1DC19F1027100A5A838 /* launch_reporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launch_reporter.h; path = ../../common/mac/launch_reporter.h; sourceTree = SOURCE_ROOT; }; F91AF5CF0FD60393009D8BE2 /* BreakpadFramework_Test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BreakpadFramework_Test.mm; path = tests/BreakpadFramework_Test.mm; sourceTree = "<group>"; }; @@ -959,6 +988,19 @@ F92C53840ECCE68D009BE4BA /* mac */ = { isa = PBXGroup; children = ( + EB9CF8AE24F01E1D00F9B6D1 /* encoding_util.h */, + EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */, + EB9CF8B424F01E1D00F9B6D1 /* HTTPGetRequest.h */, + EB9CF8B524F01E1D00F9B6D1 /* HTTPGetRequest.m */, + EB9CF8B824F01E1D00F9B6D1 /* HTTPPutRequest.h */, + EB9CF8B124F01E1D00F9B6D1 /* HTTPPutRequest.m */, + EB9CF8B024F01E1D00F9B6D1 /* HTTPRequest.h */, + EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */, + EB9CF8AF24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h */, + EB9CF8B624F01E1D00F9B6D1 /* HTTPSimplePostRequest.m */, + EB9CF8AD24F01E1D00F9B6D1 /* minidump_upload.m */, + EB9CF8B724F01E1D00F9B6D1 /* SymbolCollectorClient.h */, + EB9CF8B324F01E1D00F9B6D1 /* SymbolCollectorClient.m */, 162F64F0161C577500CD68D5 /* arch_utilities.cc */, 162F64F1161C577500CD68D5 /* arch_utilities.h */, 8B31007011F0CD3C00FCF3E4 /* GTMDefines.h */, @@ -1155,13 +1197,19 @@ buildActionMask = 2147483647; files = ( F92C55D00ECD0064009BE4BA /* Breakpad.h in Headers */, + EB9CF8BC24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h in Headers */, + EB9CF8BB24F01E1D00F9B6D1 /* encoding_util.h in Headers */, F92C56330ECD0DF1009BE4BA /* OnDemandServer.h in Headers */, + EB9CF8BD24F01E1D00F9B6D1 /* HTTPRequest.h in Headers */, D2F9A4C9121336C7002747C1 /* client_info.h in Headers */, + EB9CF8C524F01E1D00F9B6D1 /* HTTPPutRequest.h in Headers */, D2F9A4CA121336C7002747C1 /* crash_generation_client.h in Headers */, D2F9A4CC121336C7002747C1 /* crash_generation_server.h in Headers */, 163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */, + EB9CF8C424F01E1D00F9B6D1 /* SymbolCollectorClient.h in Headers */, 16C7C918147D45AE00776EAD /* BreakpadDefines.h in Headers */, 421BC5BD21110C0300B8042E /* convert_old_arm64_context.h in Headers */, + EB9CF8C124F01E1D00F9B6D1 /* HTTPGetRequest.h in Headers */, 162F64F3161C577500CD68D5 /* arch_utilities.h in Headers */, F4DAB1DE19F1027100A5A838 /* launch_reporter.h in Headers */, 1EEEB6241720829E00F7E689 /* simple_string_dictionary.h in Headers */, @@ -1684,8 +1732,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EB9CF8C824F01FB900F9B6D1 /* HTTPMultipartUpload.m in Sources */, + EB9CF8C224F01E1D00F9B6D1 /* HTTPGetRequest.m in Sources */, F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */, + EB9CF8BA24F01E1D00F9B6D1 /* minidump_upload.m in Sources */, F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */, + EB9CF8BE24F01E1D00F9B6D1 /* HTTPPutRequest.m in Sources */, F92C55D10ECD0064009BE4BA /* Breakpad.mm in Sources */, F4DAB1DD19F1027100A5A838 /* launch_reporter.cc in Sources */, F92C56340ECD0DF1009BE4BA /* OnDemandServer.mm in Sources */, @@ -1694,6 +1746,10 @@ 163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */, 162F64F2161C577500CD68D5 /* arch_utilities.cc in Sources */, 1EEEB6231720829E00F7E689 /* simple_string_dictionary.cc in Sources */, + EB9CF8C324F01E1D00F9B6D1 /* HTTPSimplePostRequest.m in Sources */, + EB9CF8B924F01E1D00F9B6D1 /* encoding_util.m in Sources */, + EB9CF8BF24F01E1D00F9B6D1 /* HTTPRequest.m in Sources */, + EB9CF8C024F01E1D00F9B6D1 /* SymbolCollectorClient.m in Sources */, 421BC5BC21110C0300B8042E /* convert_old_arm64_context.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1800,6 +1856,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EB9CF8C724F01F7600F9B6D1 /* encoding_util.m in Sources */, + EB9CF8C624F01F1100F9B6D1 /* HTTPRequest.m in Sources */, F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */, F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */, F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */, @@ -2794,4 +2852,4 @@ /* End XCConfigurationList section */ }; rootObject = 0867D690FE84028FC02AAC07 /* Project object */; -} +}
\ No newline at end of file diff --git a/src/client/mac/Framework/Breakpad.h b/src/client/mac/Framework/Breakpad.h index dc7e45d1..e2b48aa1 100644 --- a/src/client/mac/Framework/Breakpad.h +++ b/src/client/mac/Framework/Breakpad.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,7 +44,7 @@ // OnDemandServer and restored in Inspector. #define BREAKPAD_BOOTSTRAP_PARENT_PORT "com.Breakpad.BootstrapParent" -typedef void *BreakpadRef; +typedef void* BreakpadRef; #ifdef __cplusplus extern "C" { @@ -65,7 +64,7 @@ extern "C" { typedef bool (*BreakpadFilterCallback)(int exception_type, int exception_code, mach_port_t crashing_thread, - void *context); + void* context); // Create a new BreakpadRef object and install it as an exception // handler. The |parameters| will typically be the contents of your @@ -226,7 +225,7 @@ typedef bool (*BreakpadFilterCallback)(int exception_type, // Only used in crash_report_sender. // Returns a new BreakpadRef object on success, NULL otherwise. -BreakpadRef BreakpadCreate(NSDictionary *parameters); +BreakpadRef BreakpadCreate(NSDictionary* parameters); // Uninstall and release the data associated with |ref|. void BreakpadRelease(BreakpadRef ref); @@ -238,7 +237,7 @@ void BreakpadRelease(BreakpadRef ref); // Context is a pointer to arbitrary data to make the callback with. void BreakpadSetFilterCallback(BreakpadRef ref, BreakpadFilterCallback callback, - void *context); + void* context); // User defined key and value string storage. Generally this is used // to configure Breakpad's internal operation, such as whether the @@ -259,23 +258,23 @@ void BreakpadSetFilterCallback(BreakpadRef ref, // TODO (nealsid): separate server parameter dictionary from the // dictionary used to configure Breakpad, and document limits for each // independently. -void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value); -NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key); -void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key); +void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value); +NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key); +void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key); // You can use this method to specify parameters that will be uploaded // to the crash server. They will be automatically encoded as // necessary. Note that as mentioned above there are limits on both // the number of keys and their length. -void BreakpadAddUploadParameter(BreakpadRef ref, NSString *key, - NSString *value); +void BreakpadAddUploadParameter(BreakpadRef ref, NSString* key, + NSString* value); // This method will remove a previously-added parameter from the // upload parameter set. -void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key); +void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString* key); // Add a log file for Breakpad to read and send upon crash dump -void BreakpadAddLogFile(BreakpadRef ref, NSString *logPathname); +void BreakpadAddLogFile(BreakpadRef ref, NSString* logPathname); // Generate a minidump and send void BreakpadGenerateAndSendReport(BreakpadRef ref); diff --git a/src/client/mac/Framework/Breakpad.mm b/src/client/mac/Framework/Breakpad.mm index b2140549..def43b7d 100644 --- a/src/client/mac/Framework/Breakpad.mm +++ b/src/client/mac/Framework/Breakpad.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -81,9 +80,9 @@ using google_breakpad::SimpleStringDictionary; // allocation of C++ objects. Note that we don't use operator delete() // but instead call the objects destructor directly: object->~ClassName(); // -ProtectedMemoryAllocator *gMasterAllocator = NULL; -ProtectedMemoryAllocator *gKeyValueAllocator = NULL; -ProtectedMemoryAllocator *gBreakpadAllocator = NULL; +ProtectedMemoryAllocator* gMasterAllocator = NULL; +ProtectedMemoryAllocator* gKeyValueAllocator = NULL; +ProtectedMemoryAllocator* gBreakpadAllocator = NULL; // Mutex for thread-safe access to the key/value dictionary used by breakpad. // It's a global instead of an instance variable of Breakpad @@ -98,8 +97,8 @@ pthread_mutex_t gDictionaryMutex; // Its destructor will first re-protect the memory then release the lock. class ProtectedMemoryLocker { public: - ProtectedMemoryLocker(pthread_mutex_t *mutex, - ProtectedMemoryAllocator *allocator) + ProtectedMemoryLocker(pthread_mutex_t* mutex, + ProtectedMemoryAllocator* allocator) : mutex_(mutex), allocator_(allocator) { // Lock the mutex @@ -124,17 +123,17 @@ class ProtectedMemoryLocker { ProtectedMemoryLocker(const ProtectedMemoryLocker&); ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&); - pthread_mutex_t *mutex_; - ProtectedMemoryAllocator *allocator_; + pthread_mutex_t* mutex_; + ProtectedMemoryAllocator* allocator_; }; //============================================================================= class Breakpad { public: // factory method - static Breakpad *Create(NSDictionary *parameters) { + static Breakpad* Create(NSDictionary* parameters) { // Allocate from our special allocation pool - Breakpad *breakpad = + Breakpad* breakpad = new (gBreakpadAllocator->Allocate(sizeof(Breakpad))) Breakpad(); @@ -152,13 +151,13 @@ class Breakpad { ~Breakpad(); - void SetKeyValue(NSString *key, NSString *value); - NSString *KeyValue(NSString *key); - void RemoveKeyValue(NSString *key); + void SetKeyValue(NSString* key, NSString* value); + NSString* KeyValue(NSString* key); + void RemoveKeyValue(NSString* key); void GenerateAndSendReport(); - void SetFilterCallback(BreakpadFilterCallback callback, void *context) { + void SetFilterCallback(BreakpadFilterCallback callback, void* context) { filter_callback_ = callback; filter_callback_context_ = context; } @@ -173,14 +172,14 @@ class Breakpad { inspector_path_[0] = 0; } - bool Initialize(NSDictionary *parameters); - bool InitializeInProcess(NSDictionary *parameters); - bool InitializeOutOfProcess(NSDictionary *parameters); + bool Initialize(NSDictionary* parameters); + bool InitializeInProcess(NSDictionary* parameters); + bool InitializeOutOfProcess(NSDictionary* parameters); - bool ExtractParameters(NSDictionary *parameters); + bool ExtractParameters(NSDictionary* parameters); // Dispatches to HandleException() - static bool ExceptionHandlerDirectCallback(void *context, + static bool ExceptionHandlerDirectCallback(void* context, int exception_type, int exception_code, int exception_subcode, @@ -194,28 +193,28 @@ class Breakpad { // 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, + 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); + 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) + google_breakpad::ExceptionHandler* handler_; // The actual handler (STRONG) char inspector_path_[PATH_MAX]; // Path to inspector tool - SimpleStringDictionary *config_params_; // Create parameters (STRONG) + SimpleStringDictionary* config_params_; // Create parameters (STRONG) OnDemandServer inspector_; bool send_and_exit_; // Exit after sending, if true BreakpadFilterCallback filter_callback_; - void *filter_callback_context_; + void* filter_callback_context_; }; #pragma mark - @@ -227,14 +226,14 @@ class Breakpad { //============================================================================= static BOOL IsDebuggerActive() { BOOL result = NO; - NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults]; + NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults]; // We check both defaults and the environment variable here BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER]; if (!ignoreDebugger) { - char *ignoreDebuggerStr = getenv(IGNORE_DEBUGGER); + char* ignoreDebuggerStr = getenv(IGNORE_DEBUGGER); ignoreDebugger = (ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0; } @@ -245,7 +244,7 @@ static BOOL IsDebuggerActive() { size_t actualSize; if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) { - struct kinfo_proc *info = (struct kinfo_proc *)malloc(actualSize); + struct kinfo_proc* info = (struct kinfo_proc*)malloc(actualSize); if (info) { // This comes from looking at the Darwin xnu Kernel @@ -261,12 +260,12 @@ static BOOL IsDebuggerActive() { } //============================================================================= -bool Breakpad::ExceptionHandlerDirectCallback(void *context, - int exception_type, - int exception_code, - int exception_subcode, - mach_port_t crashing_thread) { - Breakpad *breakpad = (Breakpad *)context; +bool Breakpad::ExceptionHandlerDirectCallback(void* context, + int exception_type, + int exception_code, + int exception_subcode, + mach_port_t crashing_thread) { + Breakpad* breakpad = (Breakpad*)context; // If our context is damaged or something, just return false to indicate that // the handler should continue without us. @@ -280,11 +279,11 @@ bool Breakpad::ExceptionHandlerDirectCallback(void *context, } //============================================================================= -bool Breakpad::HandleMinidumpCallback(const char *dump_dir, - const char *minidump_id, - void *context, +bool Breakpad::HandleMinidumpCallback(const char* dump_dir, + const char* minidump_id, + void* context, bool succeeded) { - Breakpad *breakpad = (Breakpad *)context; + Breakpad* breakpad = (Breakpad*)context; // If our context is damaged or something, just return false to indicate that // the handler should continue without us. @@ -307,9 +306,9 @@ bool Breakpad::HandleMinidumpCallback(const char *dump_dir, // simple non-static C name // extern "C" { -NSString * GetResourcePath(); -NSString * GetResourcePath() { - NSString *resourcePath = nil; +NSString* GetResourcePath(); +NSString* GetResourcePath() { + NSString* resourcePath = nil; // If there are multiple breakpads installed then calling bundleWithIdentifier // will not work properly, so only use that as a backup plan. @@ -320,17 +319,17 @@ NSString * GetResourcePath() { // Get the pathname to the code which contains this function Dl_info info; if (dladdr((const void*)GetResourcePath, &info) != 0) { - NSFileManager *filemgr = [NSFileManager defaultManager]; - NSString *filePath = + NSFileManager* filemgr = [NSFileManager defaultManager]; + NSString* filePath = [filemgr stringWithFileSystemRepresentation:info.dli_fname length:strlen(info.dli_fname)]; - NSString *bundlePath = [filePath stringByDeletingLastPathComponent]; + NSString* bundlePath = [filePath stringByDeletingLastPathComponent]; // The "Resources" directory should be in the same directory as the // executable code, since that's how the Breakpad framework is built. resourcePath = [bundlePath stringByAppendingPathComponent:@"Resources/"]; } else { // fallback plan - NSBundle *bundle = + NSBundle* bundle = [NSBundle bundleWithIdentifier:@"com.Google.BreakpadFramework"]; resourcePath = [bundle resourcePath]; } @@ -340,7 +339,7 @@ NSString * GetResourcePath() { } // extern "C" //============================================================================= -bool Breakpad::Initialize(NSDictionary *parameters) { +bool Breakpad::Initialize(NSDictionary* parameters) { // Initialize config_params_ = NULL; handler_ = NULL; @@ -375,7 +374,7 @@ bool Breakpad::InitializeInProcess(NSDictionary* parameters) { //============================================================================= bool Breakpad::InitializeOutOfProcess(NSDictionary* parameters) { // Get path to Inspector executable. - NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION); + NSString* inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION); // Standardize path (resolve symlinkes, etc.) and escape spaces inspectorPathString = [inspectorPathString stringByStandardizingPath]; @@ -434,34 +433,34 @@ Breakpad::~Breakpad() { } //============================================================================= -bool Breakpad::ExtractParameters(NSDictionary *parameters) { - NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults]; - NSString *skipConfirm = [stdDefaults stringForKey:@BREAKPAD_SKIP_CONFIRM]; - NSString *sendAndExit = [stdDefaults stringForKey:@BREAKPAD_SEND_AND_EXIT]; - - NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE]; - NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; - NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT]; - NSString *version = [parameters objectForKey:@BREAKPAD_VERSION]; - NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL]; - NSString *interval = [parameters objectForKey:@BREAKPAD_REPORT_INTERVAL]; - NSString *inspectorPathString = +bool Breakpad::ExtractParameters(NSDictionary* parameters) { + NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults]; + NSString* skipConfirm = [stdDefaults stringForKey:@BREAKPAD_SKIP_CONFIRM]; + NSString* sendAndExit = [stdDefaults stringForKey:@BREAKPAD_SEND_AND_EXIT]; + + NSString* serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE]; + NSString* display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY]; + NSString* product = [parameters objectForKey:@BREAKPAD_PRODUCT]; + NSString* version = [parameters objectForKey:@BREAKPAD_VERSION]; + NSString* urlStr = [parameters objectForKey:@BREAKPAD_URL]; + NSString* interval = [parameters objectForKey:@BREAKPAD_REPORT_INTERVAL]; + NSString* inspectorPathString = [parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION]; - NSString *reporterPathString = + NSString* reporterPathString = [parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION]; - NSString *timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT]; - NSArray *logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES]; - NSString *logFileTailSize = + NSString* timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT]; + NSArray* logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES]; + NSString* logFileTailSize = [parameters objectForKey:@BREAKPAD_LOGFILE_UPLOAD_SIZE]; - NSString *requestUserText = + NSString* requestUserText = [parameters objectForKey:@BREAKPAD_REQUEST_COMMENTS]; - NSString *requestEmail = [parameters objectForKey:@BREAKPAD_REQUEST_EMAIL]; - NSString *vendor = + NSString* requestEmail = [parameters objectForKey:@BREAKPAD_REQUEST_EMAIL]; + NSString* vendor = [parameters objectForKey:@BREAKPAD_VENDOR]; - NSString *dumpSubdirectory = + NSString* dumpSubdirectory = [parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY]; - NSDictionary *serverParameters = + NSDictionary* serverParameters = [parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT]; // These may have been set above as user prefs, which take priority. @@ -536,7 +535,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { } // Find the helper applications if not specified in user config. - NSString *resourcePath = nil; + NSString* resourcePath = nil; if (!inspectorPathString || !reporterPathString) { resourcePath = GetResourcePath(); if (!resourcePath) { @@ -591,7 +590,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { new (gKeyValueAllocator->Allocate(sizeof(SimpleStringDictionary)) ) SimpleStringDictionary(); - SimpleStringDictionary &dictionary = *config_params_; + SimpleStringDictionary& dictionary = *config_params_; dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]); dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]); @@ -633,8 +632,8 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { if (serverParameters) { // For each key-value pair, call BreakpadAddUploadParameter() - NSEnumerator *keyEnumerator = [serverParameters keyEnumerator]; - NSString *aParameter; + NSEnumerator* keyEnumerator = [serverParameters keyEnumerator]; + NSString* aParameter; while ((aParameter = [keyEnumerator nextObject])) { BreakpadAddUploadParameter(this, aParameter, [serverParameters objectForKey:aParameter]); @@ -644,7 +643,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) { } //============================================================================= -void Breakpad::SetKeyValue(NSString *key, NSString *value) { +void Breakpad::SetKeyValue(NSString* key, NSString* value) { // We allow nil values. This is the same as removing the keyvalue. if (!config_params_ || !key) return; @@ -653,16 +652,16 @@ void Breakpad::SetKeyValue(NSString *key, NSString *value) { } //============================================================================= -NSString *Breakpad::KeyValue(NSString *key) { +NSString* Breakpad::KeyValue(NSString* key) { if (!config_params_ || !key) return nil; - const char *value = config_params_->GetValueForKey([key UTF8String]); + const char* value = config_params_->GetValueForKey([key UTF8String]); return value ? [NSString stringWithUTF8String:value] : nil; } //============================================================================= -void Breakpad::RemoveKeyValue(NSString *key) { +void Breakpad::RemoveKeyValue(NSString* key) { if (!config_params_ || !key) return; config_params_->RemoveKey([key UTF8String]); @@ -722,7 +721,7 @@ bool Breakpad::HandleException(int exception_type, if (result == KERN_SUCCESS) { // Now, send a series of key-value pairs to the Inspector. - const SimpleStringDictionary::Entry *entry = NULL; + const SimpleStringDictionary::Entry* entry = NULL; SimpleStringDictionary::Iterator iter(*config_params_); while ( (entry = iter.Next()) ) { @@ -759,7 +758,7 @@ bool Breakpad::HandleException(int exception_type, } //============================================================================= -bool Breakpad::HandleMinidump(const char *dump_dir, const char *minidump_id) { +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( @@ -775,7 +774,7 @@ bool Breakpad::HandleMinidump(const char *dump_dir, const char *minidump_id) { #pragma mark Public API //============================================================================= -BreakpadRef BreakpadCreate(NSDictionary *parameters) { +BreakpadRef BreakpadCreate(NSDictionary* parameters) { try { // This is confusing. Our two main allocators for breakpad memory are: // - gKeyValueAllocator for the key/value memory @@ -815,8 +814,8 @@ BreakpadRef BreakpadCreate(NSDictionary *parameters) { ProtectedMemoryAllocator(breakpad_pool_size); // Stack-based autorelease pool for Breakpad::Create() obj-c code. - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - Breakpad *breakpad = Breakpad::Create(parameters); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + Breakpad* breakpad = Breakpad::Create(parameters); if (breakpad) { // Make read-only to protect against memory smashers @@ -856,7 +855,7 @@ BreakpadRef BreakpadCreate(NSDictionary *parameters) { //============================================================================= void BreakpadRelease(BreakpadRef ref) { try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (gMasterAllocator) { gMasterAllocator->Unprotect(); @@ -889,10 +888,10 @@ void BreakpadRelease(BreakpadRef ref) { } //============================================================================= -void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) { +void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && key && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); @@ -905,20 +904,20 @@ void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) { } void BreakpadAddUploadParameter(BreakpadRef ref, - NSString *key, - NSString *value) { + NSString* key, + NSString* value) { // The only difference, internally, between an upload parameter and // a key value one that is set with BreakpadSetKeyValue is that we // prepend the keyname with a special prefix. This informs the // crash sender that the parameter should be sent along with the // POST of the crash dump upload. try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && key && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - NSString *prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX + NSString* prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX stringByAppendingString:key]; breakpad->SetKeyValue(prefixedKey, value); } @@ -928,15 +927,15 @@ void BreakpadAddUploadParameter(BreakpadRef ref, } void BreakpadRemoveUploadParameter(BreakpadRef ref, - NSString *key) { + NSString* key) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && key && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); - NSString *prefixedKey = [NSString stringWithFormat:@"%@%@", + NSString* prefixedKey = [NSString stringWithFormat:@"%@%@", @BREAKPAD_SERVER_PARAMETER_PREFIX, key]; breakpad->RemoveKeyValue(prefixedKey); } @@ -945,12 +944,12 @@ void BreakpadRemoveUploadParameter(BreakpadRef ref, } } //============================================================================= -NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) { - NSString *value = nil; +NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key) { + NSString* value = nil; try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (!breakpad || !key || !gKeyValueAllocator) return nil; @@ -966,10 +965,10 @@ NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) { } //============================================================================= -void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) { +void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key) { try { // Not called at exception time - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && key && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); @@ -984,7 +983,7 @@ void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) { //============================================================================= void BreakpadGenerateAndSendReport(BreakpadRef ref) { try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && gKeyValueAllocator) { ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator); @@ -1001,10 +1000,10 @@ void BreakpadGenerateAndSendReport(BreakpadRef ref) { //============================================================================= void BreakpadSetFilterCallback(BreakpadRef ref, BreakpadFilterCallback callback, - void *context) { + void* context) { try { - Breakpad *breakpad = (Breakpad *)ref; + Breakpad* breakpad = (Breakpad*)ref; if (breakpad && gBreakpadAllocator) { // share the dictionary mutex here (we really don't need a mutex) @@ -1018,14 +1017,14 @@ void BreakpadSetFilterCallback(BreakpadRef ref, } //============================================================================ -void BreakpadAddLogFile(BreakpadRef ref, NSString *logPathname) { +void BreakpadAddLogFile(BreakpadRef ref, NSString* logPathname) { int logFileCounter = 0; - NSString *logFileKey = [NSString stringWithFormat:@"%@%d", + NSString* logFileKey = [NSString stringWithFormat:@"%@%d", @BREAKPAD_LOGFILE_KEY_PREFIX, logFileCounter]; - NSString *existingLogFilename = nil; + NSString* existingLogFilename = nil; existingLogFilename = BreakpadKeyValue(ref, logFileKey); // Find the first log file key that we can use by testing for existence while (existingLogFilename) { diff --git a/src/client/mac/Framework/OnDemandServer.h b/src/client/mac/Framework/OnDemandServer.h index d4db5d3a..e7a52e7d 100644 --- a/src/client/mac/Framework/OnDemandServer.h +++ b/src/client/mac/Framework/OnDemandServer.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -41,7 +40,7 @@ // Example Usage : // // kern_return_t result; -// OnDemandServer *server = OnDemandServer::Create("/tmp/myserver", +// OnDemandServer* server = OnDemandServer::Create("/tmp/myserver", // "com.MyCompany.MyServiceName", // true, // &result); @@ -88,8 +87,8 @@ class OnDemandServer { } // Creates the bootstrap server and service - kern_return_t Initialize(const char *server_command, - const char *service_name, + kern_return_t Initialize(const char* server_command, + const char* service_name, bool unregister_on_cleanup); // Returns an OnDemandServer object if successful, or NULL if there's @@ -110,10 +109,10 @@ class OnDemandServer { // out_result : if non-NULL, returns the result // this value will be KERN_SUCCESS if Create() returns non-NULL // - static OnDemandServer *Create(const char *server_command, - const char *service_name, + static OnDemandServer* Create(const char *server_command, + const char* service_name, bool unregister_on_cleanup, - kern_return_t *out_result); + kern_return_t* out_result); // Cleans up and if LaunchOnDemand() has not yet been called then // the bootstrap service will be unregistered. diff --git a/src/client/mac/Framework/OnDemandServer.mm b/src/client/mac/Framework/OnDemandServer.mm index a2ffa434..d2f3a283 100644 --- a/src/client/mac/Framework/OnDemandServer.mm +++ b/src/client/mac/Framework/OnDemandServer.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -49,11 +48,11 @@ #endif //============================================================================== -OnDemandServer *OnDemandServer::Create(const char *server_command, - const char *service_name, +OnDemandServer* OnDemandServer::Create(const char* server_command, + const char* service_name, bool unregister_on_cleanup, - kern_return_t *out_result) { - OnDemandServer *server = new OnDemandServer(); + kern_return_t* out_result) { + OnDemandServer* server = new OnDemandServer(); if (!server) return NULL; @@ -74,22 +73,22 @@ OnDemandServer *OnDemandServer::Create(const char *server_command, } //============================================================================== -kern_return_t OnDemandServer::Initialize(const char *server_command, - const char *service_name, +kern_return_t OnDemandServer::Initialize(const char* server_command, + const char* service_name, bool unregister_on_cleanup) { unregister_on_cleanup_ = unregister_on_cleanup; mach_port_t self_task = mach_task_self(); - mach_port_t bootstrap_port; - kern_return_t kr = task_get_bootstrap_port(self_task, &bootstrap_port); + mach_port_t self_bootstrap_port; + kern_return_t kr = task_get_bootstrap_port(self_task, &self_bootstrap_port); if (kr != KERN_SUCCESS) { PRINT_MACH_RESULT(kr, "task_get_bootstrap_port(): "); return kr; } mach_port_t bootstrap_subset_port; - kr = bootstrap_subset(bootstrap_port, self_task, &bootstrap_subset_port); + kr = bootstrap_subset(self_bootstrap_port, self_task, &bootstrap_subset_port); if (kr != BOOTSTRAP_SUCCESS) { PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_subset(): "); return kr; @@ -105,7 +104,7 @@ kern_return_t OnDemandServer::Initialize(const char *server_command, kr = breakpad::BootstrapRegister( bootstrap_subset_port, const_cast<char*>(BREAKPAD_BOOTSTRAP_PARENT_PORT), - bootstrap_port); + self_bootstrap_port); if (kr != BOOTSTRAP_SUCCESS) { PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_register(): "); return kr; @@ -135,7 +134,8 @@ kern_return_t OnDemandServer::Initialize(const char *server_command, PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_create_service(): "); // perhaps the service has already been created - try to look it up - kr = bootstrap_look_up(bootstrap_port, (char*)service_name, &service_port_); + kr = bootstrap_look_up(self_bootstrap_port, (char*)service_name, + &service_port_); if (kr != BOOTSTRAP_SUCCESS) { PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_look_up(): "); diff --git a/src/client/mac/crash_generation/ConfigFile.h b/src/client/mac/crash_generation/ConfigFile.h index f2da7c24..4a4ed984 100644 --- a/src/client/mac/crash_generation/ConfigFile.h +++ b/src/client/mac/crash_generation/ConfigFile.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -35,7 +34,7 @@ namespace google_breakpad { -BOOL EnsureDirectoryPathExists(NSString *dirPath); +BOOL EnsureDirectoryPathExists(NSString* dirPath); //============================================================================= class ConfigFile { @@ -50,11 +49,11 @@ class ConfigFile { } void WriteFile(const char* directory, - const SimpleStringDictionary *configurationParameters, - const char *dump_dir, - const char *minidump_id); + const SimpleStringDictionary* configurationParameters, + const char* dump_dir, + const char* minidump_id); - const char *GetFilePath() { return config_file_path_; } + const char* GetFilePath() { return config_file_path_; } void Unlink() { if (config_file_ != -1) @@ -64,16 +63,16 @@ class ConfigFile { } private: - BOOL WriteData(const void *data, size_t length); + BOOL WriteData(const void* data, size_t length); - BOOL AppendConfigData(const char *key, - const void *data, + BOOL AppendConfigData(const char* key, + const void* data, size_t length); - BOOL AppendConfigString(const char *key, - const char *value); + BOOL AppendConfigString(const char* key, + const char* value); - BOOL AppendCrashTimeParameters(const char *processStartTimeString); + BOOL AppendCrashTimeParameters(const char* processStartTimeString); int config_file_; // descriptor for config file char config_file_path_[PATH_MAX]; // Path to configuration file diff --git a/src/client/mac/crash_generation/ConfigFile.mm b/src/client/mac/crash_generation/ConfigFile.mm index acab7de8..fe89e858 100644 --- a/src/client/mac/crash_generation/ConfigFile.mm +++ b/src/client/mac/crash_generation/ConfigFile.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,10 +41,10 @@ namespace google_breakpad { //============================================================================= -BOOL EnsureDirectoryPathExists(NSString *dirPath) { - NSFileManager *mgr = [NSFileManager defaultManager]; +BOOL EnsureDirectoryPathExists(NSString* dirPath) { + NSFileManager* mgr = [NSFileManager defaultManager]; - NSDictionary *attrs = + NSDictionary* attrs = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0750] forKey:NSFilePosixPermissions]; @@ -56,15 +55,15 @@ BOOL EnsureDirectoryPathExists(NSString *dirPath) { } //============================================================================= -BOOL ConfigFile::WriteData(const void *data, size_t length) { +BOOL ConfigFile::WriteData(const void* data, size_t length) { size_t result = write(config_file_, data, length); return result == length; } //============================================================================= -BOOL ConfigFile::AppendConfigData(const char *key, - const void *data, size_t length) { +BOOL ConfigFile::AppendConfigData(const char* key, + const void* data, size_t length) { assert(config_file_ != -1); if (!key) { @@ -88,13 +87,13 @@ BOOL ConfigFile::AppendConfigData(const char *key, } //============================================================================= -BOOL ConfigFile::AppendConfigString(const char *key, - const char *value) { +BOOL ConfigFile::AppendConfigString(const char* key, + const char* value) { return AppendConfigData(key, value, strlen(value)); } //============================================================================= -BOOL ConfigFile::AppendCrashTimeParameters(const char *processStartTimeString) { +BOOL ConfigFile::AppendCrashTimeParameters(const char* processStartTimeString) { // Set process uptime parameter struct timeval tv; gettimeofday(&tv, NULL); @@ -105,22 +104,23 @@ BOOL ConfigFile::AppendCrashTimeParameters(const char *processStartTimeString) { time_t processStartTime = strtol(processStartTimeString, NULL, 10); time_t processUptime = tv.tv_sec - processStartTime; // Store the uptime in milliseconds. - sprintf(processUptimeString, "%llu", - static_cast<unsigned long long int>(processUptime) * 1000); + snprintf(processUptimeString, sizeof(processUptimeString), "%llu", + static_cast<unsigned long long int>(processUptime) * 1000); if (!AppendConfigString(BREAKPAD_PROCESS_UP_TIME, processUptimeString)) return false; } - sprintf(processCrashtimeString, "%zd", tv.tv_sec); + snprintf(processCrashtimeString, sizeof(processCrashtimeString), "%llu", + static_cast<unsigned long long int>(tv.tv_sec)); return AppendConfigString(BREAKPAD_PROCESS_CRASH_TIME, processCrashtimeString); } //============================================================================= void ConfigFile::WriteFile(const char* directory, - const SimpleStringDictionary *configurationParameters, - const char *dump_dir, - const char *minidump_id) { + const SimpleStringDictionary* configurationParameters, + const char* dump_dir, + const char* minidump_id) { assert(config_file_ == -1); @@ -146,9 +146,9 @@ void ConfigFile::WriteFile(const char* directory, // Write out the configuration parameters BOOL result = YES; - const SimpleStringDictionary &dictionary = *configurationParameters; + const SimpleStringDictionary& dictionary = *configurationParameters; - const SimpleStringDictionary::Entry *entry = NULL; + const SimpleStringDictionary::Entry* entry = NULL; SimpleStringDictionary::Iterator iter(dictionary); while ((entry = iter.Next())) { diff --git a/src/client/mac/crash_generation/Inspector.h b/src/client/mac/crash_generation/Inspector.h index 7f923ed6..fb9240c2 100644 --- a/src/client/mac/crash_generation/Inspector.h +++ b/src/client/mac/crash_generation/Inspector.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -63,7 +62,7 @@ struct KeyValueMessageData { public: KeyValueMessageData() {} explicit KeyValueMessageData( - const google_breakpad::SimpleStringDictionary::Entry &inEntry) { + const google_breakpad::SimpleStringDictionary::Entry& inEntry) { strlcpy(key, inEntry.key, sizeof(key) ); strlcpy(value, inEntry.value, sizeof(value) ); } @@ -80,7 +79,7 @@ namespace google_breakpad { //============================================================================= class MinidumpLocation { public: - MinidumpLocation(NSString *minidumpDir) { + MinidumpLocation(NSString* minidumpDir) { // Ensure that the path exists. Fallback to /tmp if unable to locate path. assert(minidumpDir); if (!EnsureDirectoryPathExists(minidumpDir)) { @@ -100,8 +99,8 @@ class MinidumpLocation { strlcpy(minidump_id_, next_minidump_id.c_str(), sizeof(minidump_id_)); } - const char *GetPath() { return minidump_dir_path_; } - const char *GetID() { return minidump_id_; } + const char* GetPath() { return minidump_dir_path_; } + const char* GetID() { return minidump_id_; } private: char minidump_dir_path_[PATH_MAX]; // Path to minidump directory @@ -116,7 +115,7 @@ class Inspector { // given a bootstrap service name, receives mach messages // from a crashed process, then inspects it, creates a minidump file // and asks the user if he wants to upload it to a server. - void Inspect(const char *receive_port_name); + void Inspect(const char* receive_port_name); private: // The Inspector is invoked with its bootstrap port set to the bootstrap @@ -131,8 +130,8 @@ class Inspector { // ServiceCheckOut. kern_return_t ResetBootstrapPort(); - kern_return_t ServiceCheckIn(const char *receive_port_name); - kern_return_t ServiceCheckOut(const char *receive_port_name); + kern_return_t ServiceCheckIn(const char* receive_port_name); + kern_return_t ServiceCheckOut(const char* receive_port_name); kern_return_t ReadMessages(); diff --git a/src/client/mac/crash_generation/Inspector.mm b/src/client/mac/crash_generation/Inspector.mm index dc6f4808..8d4e3e98 100644 --- a/src/client/mac/crash_generation/Inspector.mm +++ b/src/client/mac/crash_generation/Inspector.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,7 +51,7 @@ namespace google_breakpad { //============================================================================= -void Inspector::Inspect(const char *receive_port_name) { +void Inspector::Inspect(const char* receive_port_name) { kern_return_t result = ResetBootstrapPort(); if (result != KERN_SUCCESS) { return; @@ -143,7 +142,7 @@ kern_return_t Inspector::ResetBootstrapPort() { } //============================================================================= -kern_return_t Inspector::ServiceCheckIn(const char *receive_port_name) { +kern_return_t Inspector::ServiceCheckIn(const char* receive_port_name) { // We need to get the mach port representing this service, so we can // get information from the crashed process. kern_return_t kr = bootstrap_check_in(bootstrap_subset_port_, @@ -160,7 +159,7 @@ kern_return_t Inspector::ServiceCheckIn(const char *receive_port_name) { } //============================================================================= -kern_return_t Inspector::ServiceCheckOut(const char *receive_port_name) { +kern_return_t Inspector::ServiceCheckOut(const char* receive_port_name) { // We're done receiving mach messages from the crashed process, // so clean up a bit. kern_return_t kr; @@ -198,7 +197,7 @@ kern_return_t Inspector::ReadMessages() { kern_return_t result = receive_port.WaitForMessage(&message, 1000); if (result == KERN_SUCCESS) { - InspectorInfo &info = (InspectorInfo &)*message.GetData(); + InspectorInfo& info = (InspectorInfo&)*message.GetData(); exception_type_ = info.exception_type; exception_code_ = info.exception_code; exception_subcode_ = info.exception_subcode; @@ -237,7 +236,7 @@ kern_return_t Inspector::ReadMessages() { result = receive_port.WaitForMessage(¶meter_message, 1000); if(result == KERN_SUCCESS) { - KeyValueMessageData &key_value_data = + KeyValueMessageData& key_value_data = (KeyValueMessageData&)*parameter_message.GetData(); // If we get a blank key, make sure we don't increment the // parameter count; in some cases (notably on-demand generation @@ -267,27 +266,27 @@ bool Inspector::InspectTask() { // keep the task quiet while we're looking at it task_suspend(remote_task_); - NSString *minidumpDir; + NSString* minidumpDir; - const char *minidumpDirectory = + const char* minidumpDirectory = config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY); // If the client app has not specified a minidump directory, // use a default of Library/<kDefaultLibrarySubdirectory>/<Product Name> if (!minidumpDirectory || 0 == strlen(minidumpDirectory)) { - NSArray *libraryDirectories = + NSArray* libraryDirectories = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); - NSString *applicationSupportDirectory = + NSString* applicationSupportDirectory = [libraryDirectories objectAtIndex:0]; - NSString *library_subdirectory = [NSString + NSString* library_subdirectory = [NSString stringWithUTF8String:kDefaultLibrarySubdirectory]; - NSString *breakpad_product = [NSString + NSString* breakpad_product = [NSString stringWithUTF8String:config_params_.GetValueForKey(BREAKPAD_PRODUCT)]; - NSArray *path_components = [NSArray + NSArray* path_components = [NSArray arrayWithObjects:applicationSupportDirectory, library_subdirectory, breakpad_product, @@ -306,11 +305,11 @@ bool Inspector::InspectTask() { // assumes system encoding and in RTL locales will prepend an LTR override // character for paths beginning with '/' which fileSystemRepresentation does // not remove. Filed as rdar://6889706 . - NSString *path_ns = [NSString + NSString* path_ns = [NSString stringWithUTF8String:minidumpLocation.GetPath()]; - NSString *pathid_ns = [NSString + NSString* pathid_ns = [NSString stringWithUTF8String:minidumpLocation.GetID()]; - NSString *minidumpPath = [path_ns stringByAppendingPathComponent:pathid_ns]; + NSString* minidumpPath = [path_ns stringByAppendingPathComponent:pathid_ns]; minidumpPath = [minidumpPath stringByAppendingPathExtension:@"dmp"]; diff --git a/src/client/mac/crash_generation/InspectorMain.mm b/src/client/mac/crash_generation/InspectorMain.mm index 137c6a1e..fb3199d3 100644 --- a/src/client/mac/crash_generation/InspectorMain.mm +++ b/src/client/mac/crash_generation/InspectorMain.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/crash_generation/client_info.h b/src/client/mac/crash_generation/client_info.h index a3a95dca..30870f17 100644 --- a/src/client/mac/crash_generation/client_info.h +++ b/src/client/mac/crash_generation/client_info.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/crash_generation/crash_generation_client.cc b/src/client/mac/crash_generation/crash_generation_client.cc index ceeb3b32..32f1c827 100644 --- a/src/client/mac/crash_generation/crash_generation_client.cc +++ b/src/client/mac/crash_generation/crash_generation_client.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/crash_generation/crash_generation_client.h b/src/client/mac/crash_generation/crash_generation_client.h index 527f577a..06cc0a31 100644 --- a/src/client/mac/crash_generation/crash_generation_client.h +++ b/src/client/mac/crash_generation/crash_generation_client.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/crash_generation/crash_generation_server.cc b/src/client/mac/crash_generation/crash_generation_server.cc index 451e8d9c..6bbd4bb5 100644 --- a/src/client/mac/crash_generation/crash_generation_server.cc +++ b/src/client/mac/crash_generation/crash_generation_server.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,15 +37,15 @@ namespace google_breakpad { CrashGenerationServer::CrashGenerationServer( - const char *mach_port_name, + const char* mach_port_name, FilterCallback filter, - void *filter_context, + void* filter_context, OnClientDumpRequestCallback dump_callback, - void *dump_context, + void* dump_context, OnClientExitingCallback exit_callback, - void *exit_context, + void* exit_context, bool generate_dumps, - const std::string &dump_path) + const std::string& dump_path) : filter_(filter), filter_context_(filter_context), dump_callback_(dump_callback), @@ -90,8 +89,8 @@ bool CrashGenerationServer::Stop() { } // static -void *CrashGenerationServer::WaitForMessages(void *server) { - CrashGenerationServer *self = +void* CrashGenerationServer::WaitForMessages(void* server) { + CrashGenerationServer* self = reinterpret_cast<CrashGenerationServer*>(server); while (self->WaitForOneMessage()) {} return NULL; @@ -104,7 +103,7 @@ bool CrashGenerationServer::WaitForOneMessage() { if (result == KERN_SUCCESS) { switch (message.GetMessageID()) { case kDumpRequestMessage: { - ExceptionInfo &info = (ExceptionInfo &)*message.GetData(); + ExceptionInfo& info = (ExceptionInfo&)*message.GetData(); mach_port_t remote_task = message.GetTranslatedPort(0); mach_port_t crashing_thread = message.GetTranslatedPort(1); diff --git a/src/client/mac/crash_generation/crash_generation_server.h b/src/client/mac/crash_generation/crash_generation_server.h index 85bd5b5e..2c4b56cf 100644 --- a/src/client/mac/crash_generation/crash_generation_server.h +++ b/src/client/mac/crash_generation/crash_generation_server.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -59,14 +58,14 @@ class CrashGenerationServer { // WARNING: callbacks may be invoked on a different thread // than that which creates the CrashGenerationServer. They must // be thread safe. - typedef void (*OnClientDumpRequestCallback)(void *context, - const ClientInfo &client_info, - const std::string &file_path); + typedef void (*OnClientDumpRequestCallback)(void* context, + const ClientInfo& client_info, + const std::string& file_path); - typedef void (*OnClientExitingCallback)(void *context, - const ClientInfo &client_info); + typedef void (*OnClientExitingCallback)(void* context, + const ClientInfo& client_info); // If a FilterCallback returns false, the dump will not be written. - typedef bool (*FilterCallback)(void *context); + typedef bool (*FilterCallback)(void* context); // Create an instance with the given parameters. // @@ -83,15 +82,15 @@ class CrashGenerationServer { // passed for this parameter. // dump_path: Path for generating dumps; required only if true is // passed for generateDumps parameter; NULL can be passed otherwise. - CrashGenerationServer(const char *mach_port_name, + CrashGenerationServer(const char* mach_port_name, FilterCallback filter, - void *filter_context, + void* filter_context, OnClientDumpRequestCallback dump_callback, - void *dump_context, + void* dump_context, OnClientExitingCallback exit_callback, - void *exit_context, + void* exit_context, bool generate_dumps, - const std::string &dump_path); + const std::string& dump_path); ~CrashGenerationServer(); @@ -105,24 +104,24 @@ class CrashGenerationServer { private: // Return a unique filename at which a minidump can be written. - bool MakeMinidumpFilename(std::string &outFilename); + bool MakeMinidumpFilename(std::string& outFilename); // Loop reading client messages and responding to them until // a quit message is received. - static void *WaitForMessages(void *server); + static void* WaitForMessages(void* server); // Wait for a single client message and respond to it. Returns false // if a quit message was received or if an error occurred. bool WaitForOneMessage(); FilterCallback filter_; - void *filter_context_; + void* filter_context_; OnClientDumpRequestCallback dump_callback_; - void *dump_context_; + void* dump_context_; OnClientExitingCallback exit_callback_; - void *exit_context_; + void* exit_context_; bool generate_dumps_; diff --git a/src/client/mac/handler/breakpad_nlist_64.cc b/src/client/mac/handler/breakpad_nlist_64.cc index 3492b823..b4f04c91 100644 --- a/src/client/mac/handler/breakpad_nlist_64.cc +++ b/src/client/mac/handler/breakpad_nlist_64.cc @@ -131,7 +131,7 @@ struct MachBits<nlist64> { template<typename nlist_type> int -__breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, +__breakpad_fdnlist(int fd, nlist_type* list, const char** symbolNames, cpu_type_t cpu_type); /* @@ -139,9 +139,9 @@ __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, */ template <typename nlist_type> -int breakpad_nlist_common(const char *name, - nlist_type *list, - const char **symbolNames, +int breakpad_nlist_common(const char* name, + nlist_type* list, + const char** symbolNames, cpu_type_t cpu_type) { int fd = open(name, O_RDONLY, 0); if (fd < 0) @@ -151,16 +151,16 @@ int breakpad_nlist_common(const char *name, return n; } -int breakpad_nlist(const char *name, - struct nlist *list, - const char **symbolNames, +int breakpad_nlist(const char* name, + struct nlist* list, + const char** symbolNames, cpu_type_t cpu_type) { return breakpad_nlist_common(name, list, symbolNames, cpu_type); } -int breakpad_nlist(const char *name, - struct nlist_64 *list, - const char **symbolNames, +int breakpad_nlist(const char* name, + struct nlist_64* list, + const char** symbolNames, cpu_type_t cpu_type) { return breakpad_nlist_common(name, list, symbolNames, cpu_type); } @@ -168,7 +168,7 @@ int breakpad_nlist(const char *name, /* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */ template<typename nlist_type> -int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, +int __breakpad_fdnlist(int fd, nlist_type* list, const char** symbolNames, cpu_type_t cpu_type) { typedef typename MachBits<nlist_type>::mach_header_type mach_header_type; typedef typename MachBits<nlist_type>::word_type word_type; @@ -189,9 +189,9 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, } struct exec buf; - if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) || - (N_BADMAG(buf) && *((uint32_t *)&buf) != magic && - CFSwapInt32BigToHost(*((uint32_t *)&buf)) != FAT_MAGIC && + if (read(fd, (char*)&buf, sizeof(buf)) != sizeof(buf) || + (N_BADMAG(buf) && *((uint32_t*)&buf) != magic && + CFSwapInt32BigToHost(*((uint32_t*)&buf)) != FAT_MAGIC && /* The following is the big-endian ppc64 check */ (*((uint32_t*)&buf)) != FAT_MAGIC)) { return -1; @@ -199,15 +199,15 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, /* Deal with fat file if necessary */ unsigned arch_offset = 0; - if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC || + if (CFSwapInt32BigToHost(*((uint32_t*)&buf)) == FAT_MAGIC || /* The following is the big-endian ppc64 check */ - *((unsigned int *)&buf) == FAT_MAGIC) { + *((unsigned int*)&buf) == FAT_MAGIC) { /* Read in the fat header */ struct fat_header fh; if (lseek(fd, 0, SEEK_SET) == -1) { return -1; } - if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) { + if (read(fd, (char*)&fh, sizeof(fh)) != sizeof(fh)) { return -1; } @@ -215,12 +215,12 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, fh.nfat_arch = CFSwapInt32BigToHost(fh.nfat_arch); /* Read in the fat archs */ - struct fat_arch *fat_archs = - (struct fat_arch *)malloc(fh.nfat_arch * sizeof(struct fat_arch)); + struct fat_arch* fat_archs = + (struct fat_arch*)malloc(fh.nfat_arch * sizeof(struct fat_arch)); if (fat_archs == NULL) { return -1; } - if (read(fd, (char *)fat_archs, + if (read(fd, (char*)fat_archs, sizeof(struct fat_arch) * fh.nfat_arch) != (ssize_t)(sizeof(struct fat_arch) * fh.nfat_arch)) { free(fat_archs); @@ -244,7 +244,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, CFSwapInt32BigToHost(fat_archs[i].align); } - struct fat_arch *fap = NULL; + struct fat_arch* fap = NULL; for (unsigned i = 0; i < fh.nfat_arch; i++) { if (fat_archs[i].cputype == cpu_type) { fap = &fat_archs[i]; @@ -263,7 +263,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, if (lseek(fd, arch_offset, SEEK_SET) == -1) { return -1; } - if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) { + if (read(fd, (char*)&buf, sizeof(buf)) != sizeof(buf)) { return -1; } } @@ -271,48 +271,45 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, off_t sa; /* symbol address */ off_t ss; /* start of strings */ register_t n; - if (*((unsigned int *)&buf) == magic) { + if (*((unsigned int*)&buf) == magic) { if (lseek(fd, arch_offset, SEEK_SET) == -1) { return -1; } mach_header_type mh; - if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) { + if (read(fd, (char*)&mh, sizeof(mh)) != sizeof(mh)) { return -1; } - struct load_command *load_commands = - (struct load_command *)malloc(mh.sizeofcmds); + struct load_command* load_commands = + (struct load_command*)malloc(mh.sizeofcmds); if (load_commands == NULL) { return -1; } - if (read(fd, (char *)load_commands, mh.sizeofcmds) != + if (read(fd, (char*)load_commands, mh.sizeofcmds) != (ssize_t)mh.sizeofcmds) { free(load_commands); return -1; } - struct symtab_command *stp = NULL; - struct load_command *lcp = load_commands; + struct symtab_command* stp = NULL; + struct load_command* lcp = load_commands; // iterate through all load commands, looking for // LC_SYMTAB load command for (uint32_t i = 0; i < mh.ncmds; i++) { if (lcp->cmdsize % sizeof(word_type) != 0 || lcp->cmdsize <= 0 || - (char *)lcp + lcp->cmdsize > - (char *)load_commands + mh.sizeofcmds) { + (char*)lcp + lcp->cmdsize > (char*)load_commands + mh.sizeofcmds) { free(load_commands); return -1; } if (lcp->cmd == LC_SYMTAB) { - if (lcp->cmdsize != - sizeof(struct symtab_command)) { + if (lcp->cmdsize != sizeof(struct symtab_command)) { free(load_commands); return -1; } - stp = (struct symtab_command *)lcp; + stp = (struct symtab_command*)lcp; break; } - lcp = (struct load_command *) - ((char *)lcp + lcp->cmdsize); + lcp = (struct load_command*)((char*)lcp + lcp->cmdsize); } if (stp == NULL) { free(load_commands); @@ -347,7 +344,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, if (n < m) m = n; - if (read(fd, (char *)space, m) != m) + if (read(fd, (char*)space, m) != m) break; n -= m; off_t savpos = lseek(fd, 0, SEEK_CUR); @@ -368,13 +365,13 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, if (read(fd, nambuf, maxlen+1) == -1) { return -1; } - const char *s2 = nambuf; - for (nlist_type *p = list; + const char* s2 = nambuf; + for (nlist_type* p = list; symbolNames[p-list] && symbolNames[p-list][0]; p++) { // get the symbol name the user has passed in that // corresponds to the nlist entry that we're looking at - const char *s1 = symbolNames[p - list]; + const char* s1 = symbolNames[p - list]; while (*s1) { if (*s1++ != *s2++) goto cont; diff --git a/src/client/mac/handler/breakpad_nlist_64.h b/src/client/mac/handler/breakpad_nlist_64.h index e8e2e083..7093d284 100644 --- a/src/client/mac/handler/breakpad_nlist_64.h +++ b/src/client/mac/handler/breakpad_nlist_64.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved +// Copyright 2008 Google LLC // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -10,7 +9,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -36,13 +35,13 @@ #include <mach/machine.h> -int breakpad_nlist(const char *name, - struct nlist *list, - const char **symbolNames, +int breakpad_nlist(const char* name, + struct nlist* list, + const char** symbolNames, cpu_type_t cpu_type); -int breakpad_nlist(const char *name, - struct nlist_64 *list, - const char **symbolNames, +int breakpad_nlist(const char* name, + struct nlist_64* list, + const char** symbolNames, cpu_type_t cpu_type); #endif /* CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ */ diff --git a/src/client/mac/handler/dynamic_images.cc b/src/client/mac/handler/dynamic_images.cc index cdba6df4..b1d2c464 100644 --- a/src/client/mac/handler/dynamic_images.cc +++ b/src/client/mac/handler/dynamic_images.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -66,7 +65,7 @@ struct task_dyld_info { mach_vm_size_t all_image_info_size; }; typedef struct task_dyld_info task_dyld_info_data_t; -typedef struct task_dyld_info *task_dyld_info_t; +typedef struct task_dyld_info* task_dyld_info_t; #define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t)) #endif @@ -88,7 +87,7 @@ using std::vector; // static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task, const uint64_t address, - mach_vm_size_t *size_to_end) { + mach_vm_size_t* size_to_end) { mach_vm_address_t region_base = (mach_vm_address_t)address; mach_vm_size_t region_size; natural_t nesting_level = 0; @@ -182,7 +181,7 @@ static string ReadTaskString(task_port_t target_task, kern_return_t ReadTaskMemory(task_port_t target_task, const uint64_t address, size_t length, - vector<uint8_t> &bytes) { + vector<uint8_t>& bytes) { int systemPageSize = getpagesize(); // use the negative of the page size for the mask to find the page address @@ -250,16 +249,16 @@ bool FindTextSection(DynamicImage& image) { return false; } - const struct load_command *cmd = - reinterpret_cast<const struct load_command *>(header + 1); + const struct load_command* cmd = + reinterpret_cast<const struct load_command*>(header + 1); bool found_text_section = false; bool found_dylib_id_command = false; for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) { if (!found_text_section) { if (cmd->cmd == MachBits::segment_load_command) { - const mach_segment_command_type *seg = - reinterpret_cast<const mach_segment_command_type *>(cmd); + const mach_segment_command_type* seg = + reinterpret_cast<const mach_segment_command_type*>(cmd); if (!strcmp(seg->segname, "__TEXT")) { image.vmaddr_ = static_cast<mach_vm_address_t>(seg->vmaddr); @@ -277,8 +276,8 @@ bool FindTextSection(DynamicImage& image) { if (!found_dylib_id_command) { if (cmd->cmd == LC_ID_DYLIB) { - const struct dylib_command *dc = - reinterpret_cast<const struct dylib_command *>(cmd); + const struct dylib_command* dc = + reinterpret_cast<const struct dylib_command*>(cmd); image.version_ = dc->dylib.current_version; found_dylib_id_command = true; @@ -289,8 +288,8 @@ bool FindTextSection(DynamicImage& image) { return true; } - cmd = reinterpret_cast<const struct load_command *> - (reinterpret_cast<const char *>(cmd) + cmd->cmdsize); + cmd = reinterpret_cast<const struct load_command*> + (reinterpret_cast<const char*>(cmd) + cmd->cmdsize); } return false; @@ -349,8 +348,8 @@ static uint64_t LookupSymbol(const char* symbol_name, typedef typename MachBits::nlist_type nlist_type; nlist_type symbol_info[8] = {}; - const char *symbolNames[2] = { symbol_name, "\0" }; - nlist_type &list = symbol_info[0]; + const char* symbolNames[2] = { symbol_name, "\0" }; + nlist_type& list = symbol_info[0]; int invalidEntriesCount = breakpad_nlist(filename, &list, symbolNames, @@ -396,8 +395,8 @@ uint64_t DynamicImages::GetDyldAllImageInfosPointer() { return (uint64_t)task_dyld_info.all_image_info_addr; } else { - const char *imageSymbolName = "_dyld_all_image_infos"; - const char *dyldPath = "/usr/lib/dyld"; + const char* imageSymbolName = "_dyld_all_image_infos"; + const char* dyldPath = "/usr/lib/dyld"; if (Is64Bit()) return LookupSymbol<MachO64>(imageSymbolName, dyldPath, cpu_type_); @@ -428,7 +427,7 @@ void ReadImageInfo(DynamicImages& images, dyld_all_info_bytes) != KERN_SUCCESS) return; - dyld_all_image_infos *dyldInfo = + dyld_all_image_infos* dyldInfo = reinterpret_cast<dyld_all_image_infos*>(&dyld_all_info_bytes[0]); // number of loaded images @@ -443,12 +442,12 @@ void ReadImageInfo(DynamicImages& images, dyld_info_array_bytes) != KERN_SUCCESS) return; - dyld_image_info *infoArray = + dyld_image_info* infoArray = reinterpret_cast<dyld_image_info*>(&dyld_info_array_bytes[0]); images.image_list_.reserve(count); for (int i = 0; i < count; ++i) { - dyld_image_info &info = infoArray[i]; + dyld_image_info& info = infoArray[i]; // First read just the mach_header from the image in the task. vector<uint8_t> mach_header_bytes; @@ -458,7 +457,7 @@ void ReadImageInfo(DynamicImages& images, mach_header_bytes) != KERN_SUCCESS) continue; // bail on this dynamic image - mach_header_type *header = + mach_header_type* header = reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]); // Now determine the total amount necessary to read the header @@ -482,7 +481,7 @@ void ReadImageInfo(DynamicImages& images, } // Create an object representing this image and add it to our list. - DynamicImage *new_image; + DynamicImage* new_image; new_image = new DynamicImage(&mach_header_bytes[0], header_size, info.load_address_, @@ -522,7 +521,7 @@ void DynamicImages::ReadImageInfoForTask() { } //============================================================================== -DynamicImage *DynamicImages::GetExecutableImage() { +DynamicImage* DynamicImages::GetExecutableImage() { int executable_index = GetExecutableImageIndex(); if (executable_index >= 0) { @@ -538,7 +537,7 @@ int DynamicImages::GetExecutableImageIndex() { int image_count = GetImageCount(); for (int i = 0; i < image_count; ++i) { - DynamicImage *image = GetImage(i); + DynamicImage* image = GetImage(i); if (image->GetFileType() == MH_EXECUTE) { return i; } diff --git a/src/client/mac/handler/dynamic_images.h b/src/client/mac/handler/dynamic_images.h index 65147900..b5af7584 100644 --- a/src/client/mac/handler/dynamic_images.h +++ b/src/client/mac/handler/dynamic_images.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -108,7 +107,7 @@ uint32_t GetFileTypeFromHeader(DynamicImage& image); // Represents a single dynamically loaded mach-o image class DynamicImage { public: - DynamicImage(uint8_t *header, // data is copied + DynamicImage(uint8_t* header, // data is copied size_t header_size, // includes load commands uint64_t load_address, string file_path, @@ -163,7 +162,7 @@ class DynamicImage { uint32_t GetVersion() {return version_;} // For sorting - bool operator<(const DynamicImage &inInfo) { + bool operator<(const DynamicImage& inInfo) { return GetLoadAddress() < inInfo.GetLoadAddress(); } @@ -171,8 +170,8 @@ class DynamicImage { bool IsValid() {return GetVMSize() != 0;} private: - DynamicImage(const DynamicImage &); - DynamicImage &operator=(const DynamicImage &); + DynamicImage(const DynamicImage&); + DynamicImage& operator=(const DynamicImage&); friend class DynamicImages; template<typename MachBits> @@ -205,26 +204,27 @@ class DynamicImage { // class DynamicImageRef { public: - explicit DynamicImageRef(DynamicImage *inP) : p(inP) {} + explicit DynamicImageRef(DynamicImage* inP) : p(inP) {} // The copy constructor is required by STL - DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} + DynamicImageRef(const DynamicImageRef& inRef) = default; + DynamicImageRef& operator=(const DynamicImageRef& inRef) = default; - bool operator<(const DynamicImageRef &inRef) const { + bool operator<(const DynamicImageRef& inRef) const { return (*const_cast<DynamicImageRef*>(this)->p) < (*const_cast<DynamicImageRef&>(inRef).p); } - bool operator==(const DynamicImageRef &inInfo) const { + bool operator==(const DynamicImageRef& inInfo) const { return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() == (*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress(); } // Be just like DynamicImage* - DynamicImage *operator->() {return p;} + DynamicImage* operator->() {return p;} operator DynamicImage*() {return p;} private: - DynamicImage *p; + DynamicImage* p; }; // Helper function to deal with 32-bit/64-bit Mach-O differences. @@ -250,7 +250,7 @@ class DynamicImages { int GetImageCount() const {return static_cast<int>(image_list_.size());} // Returns an individual image. - DynamicImage *GetImage(int i) { + DynamicImage* GetImage(int i) { if (i < (int)image_list_.size()) { return image_list_[i]; } @@ -258,7 +258,7 @@ class DynamicImages { } // Returns the image corresponding to the main executable. - DynamicImage *GetExecutableImage(); + DynamicImage* GetExecutableImage(); int GetExecutableImageIndex(); // Returns the task which we're looking at. @@ -312,7 +312,7 @@ class DynamicImages { kern_return_t ReadTaskMemory(task_port_t target_task, const uint64_t address, size_t length, - vector<uint8_t> &bytes); + vector<uint8_t>& bytes); } // namespace google_breakpad diff --git a/src/client/mac/handler/exception_handler.cc b/src/client/mac/handler/exception_handler.cc index 2a19d46a..c091209f 100644 --- a/src/client/mac/handler/exception_handler.cc +++ b/src/client/mac/handler/exception_handler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -220,7 +219,7 @@ kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread, } #endif -ExceptionHandler::ExceptionHandler(const string &dump_path, +ExceptionHandler::ExceptionHandler(const string& dump_path, FilterCallback filter, MinidumpCallback callback, void* callback_context, @@ -304,7 +303,7 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) { } // static -bool ExceptionHandler::WriteMinidump(const string &dump_path, +bool ExceptionHandler::WriteMinidump(const string& dump_path, bool write_exception_stream, MinidumpCallback callback, void* callback_context) { @@ -316,7 +315,7 @@ bool ExceptionHandler::WriteMinidump(const string &dump_path, // static bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, mach_port_t child_blamed_thread, - const string &dump_path, + const string& dump_path, MinidumpCallback callback, void* callback_context) { ScopedTaskSuspend suspend(child); diff --git a/src/client/mac/handler/exception_handler.h b/src/client/mac/handler/exception_handler.h index f1d9ae92..ec7ffe7e 100644 --- a/src/client/mac/handler/exception_handler.h +++ b/src/client/mac/handler/exception_handler.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -75,7 +74,7 @@ class ExceptionHandler { // attempting to write a minidump. If a FilterCallback returns false, Breakpad // will immediately report the exception as unhandled without writing a // minidump, allowing another handler the opportunity to handle it. - typedef bool (*FilterCallback)(void *context); + typedef bool (*FilterCallback)(void* context); // A callback function to run after the minidump has been written. // |minidump_id| is a unique id for the dump, so the minidump @@ -85,18 +84,18 @@ class ExceptionHandler { // Return true if the exception was fully handled and breakpad should exit. // Return false to allow any other exception handlers to process the // exception. - typedef bool (*MinidumpCallback)(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded); + typedef bool (*MinidumpCallback)(const char* dump_dir, + const char* minidump_id, + void* context, bool succeeded); // A callback function which will be called directly if an exception occurs. // This bypasses the minidump file writing and simply gives the client // the exception information. - typedef bool (*DirectCallback)( void *context, - int exception_type, - int exception_code, - int exception_subcode, - mach_port_t thread_name); + typedef bool (*DirectCallback)(void* context, + int exception_type, + int exception_code, + int exception_subcode, + mach_port_t thread_name); // Creates a new ExceptionHandler instance to handle writing minidumps. // Minidump files will be written to dump_path, and the optional callback @@ -106,22 +105,22 @@ class ExceptionHandler { // be written when WriteMinidump is called. // If port_name is non-NULL, attempt to perform out-of-process dump generation // If port_name is NULL, in-process dump generation will be used. - ExceptionHandler(const string &dump_path, + ExceptionHandler(const string& dump_path, FilterCallback filter, MinidumpCallback callback, - void *callback_context, bool install_handler, - const char *port_name); + void* callback_context, bool install_handler, + const char* port_name); // A special constructor if we want to bypass minidump writing and // simply get a callback with the exception information. ExceptionHandler(DirectCallback callback, - void *callback_context, + void* callback_context, bool install_handler); ~ExceptionHandler(); // Get and set the minidump path. string dump_path() const { return dump_path_; } - void set_dump_path(const string &dump_path) { + void set_dump_path(const string& dump_path) { dump_path_ = dump_path; dump_path_c_ = dump_path_.c_str(); UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. @@ -137,23 +136,23 @@ class ExceptionHandler { // Convenience form of WriteMinidump which does not require an // ExceptionHandler instance. - static bool WriteMinidump(const string &dump_path, MinidumpCallback callback, - void *callback_context) { + static bool WriteMinidump(const string& dump_path, MinidumpCallback callback, + void* callback_context) { return WriteMinidump(dump_path, false, callback, callback_context); } - static bool WriteMinidump(const string &dump_path, + static bool WriteMinidump(const string& dump_path, bool write_exception_stream, MinidumpCallback callback, - void *callback_context); + void* callback_context); // Write a minidump of child immediately. This can be used to capture // the execution state of a child process independently of a crash. static bool WriteMinidumpForChild(mach_port_t child, - mach_port_t child_blamed_thread, - const std::string &dump_path, - MinidumpCallback callback, - void *callback_context); + mach_port_t child_blamed_thread, + const std::string& dump_path, + MinidumpCallback callback, + void* callback_context); // Returns whether out-of-process dump generation is used or not. bool IsOutOfProcess() const { @@ -189,21 +188,21 @@ class ExceptionHandler { bool WriteMinidumpWithException(int exception_type, int exception_code, int exception_subcode, - breakpad_ucontext_t *task_context, + breakpad_ucontext_t* task_context, mach_port_t thread_name, bool exit_after_write, bool report_current_thread); // When installed, this static function will be call from a newly created // pthread with |this| as the argument - static void *WaitForMessage(void *exception_handler_class); + static void* WaitForMessage(void* exception_handler_class); // Signal handler for SIGABRT. static void SignalHandler(int sig, siginfo_t* info, void* uc); // disallow copy ctor and operator= - explicit ExceptionHandler(const ExceptionHandler &); - void operator=(const ExceptionHandler &); + explicit ExceptionHandler(const ExceptionHandler&); + void operator=(const ExceptionHandler&); // Generates a new ID and stores it in next_minidump_id_, and stores the // path of the next minidump to be written in next_minidump_path_. @@ -224,15 +223,15 @@ class ExceptionHandler { string next_minidump_path_; // Pointers to the UTF-8 versions of above - const char *dump_path_c_; - const char *next_minidump_id_c_; - const char *next_minidump_path_c_; + const char* dump_path_c_; + const char* next_minidump_id_c_; + const char* next_minidump_path_c_; // The callback function and pointer to be passed back after the minidump // has been written FilterCallback filter_; MinidumpCallback callback_; - void *callback_context_; + void* callback_context_; // The callback function to be passed back when we don't want a minidump // file to be written @@ -247,7 +246,7 @@ class ExceptionHandler { // These variables save the previous exception handler's data so that it // can be re-installed when this handler is uninstalled - ExceptionParameters *previous_; + ExceptionParameters* previous_; // True, if we've installed the exception handler bool installed_exception_handler_; diff --git a/src/client/mac/handler/mach_vm_compat.h b/src/client/mac/handler/mach_vm_compat.h index 9e9028b9..b7dc159b 100644 --- a/src/client/mac/handler/mach_vm_compat.h +++ b/src/client/mac/handler/mach_vm_compat.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc index 50df9002..3738416e 100644 --- a/src/client/mac/handler/minidump_generator.cc +++ b/src/client/mac/handler/minidump_generator.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -62,6 +61,8 @@ using MacStringUtils::IntegerValueAtIndex; namespace google_breakpad { +using mach_o::FileID; + #if defined(__LP64__) && __LP64__ #define LC_SEGMENT_ARCH LC_SEGMENT_64 #else @@ -191,12 +192,12 @@ void MinidumpGenerator::GatherSystemInformation() { os_build_number_ = IntegerValueAtIndex(product_str, 2); } -void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) { +void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t* task_context) { task_context_ = task_context; } -string MinidumpGenerator::UniqueNameInDirectory(const string &dir, - string *unique_name) { +string MinidumpGenerator::UniqueNameInDirectory(const string& dir, + string* unique_name) { CFUUIDRef uuid = CFUUIDCreate(NULL); CFStringRef uuid_cfstr = CFUUIDCreateString(NULL, uuid); CFRelease(uuid); @@ -220,7 +221,7 @@ string MinidumpGenerator::UniqueNameInDirectory(const string &dir, return path; } -bool MinidumpGenerator::Write(const char *path) { +bool MinidumpGenerator::Write(const char* path) { WriteStreamFN writers[] = { &MinidumpGenerator::WriteThreadListStream, &MinidumpGenerator::WriteMemoryListStream, @@ -256,10 +257,10 @@ bool MinidumpGenerator::Write(const char *path) { if (!dir.AllocateArray(writer_count)) return false; - MDRawHeader *header_ptr = header.get(); + MDRawHeader* header_ptr = header.get(); header_ptr->signature = MD_HEADER_SIGNATURE; header_ptr->version = MD_HEADER_VERSION; - time(reinterpret_cast<time_t *>(&(header_ptr->time_date_stamp))); + time(reinterpret_cast<time_t*>(&(header_ptr->time_date_stamp))); header_ptr->stream_count = writer_count; header_ptr->stream_directory_rva = dir.position(); @@ -335,7 +336,7 @@ size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) { bool MinidumpGenerator::WriteStackFromStartAddress( mach_vm_address_t start_addr, - MDMemoryDescriptor *stack_location) { + MDMemoryDescriptor* stack_location) { UntypedMDRVA memory(&writer_); bool result = false; @@ -372,7 +373,7 @@ bool MinidumpGenerator::WriteStackFromStartAddress( result = memory.Copy(&stack_memory[0], size); } else { - result = memory.Copy(reinterpret_cast<const void *>(start_addr), size); + result = memory.Copy(reinterpret_cast<const void*>(start_addr), size); } } @@ -383,7 +384,7 @@ bool MinidumpGenerator::WriteStackFromStartAddress( } bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location) { + MDMemoryDescriptor* stack_location) { switch (cpu_type_) { #ifdef HAS_ARM_SUPPORT case CPU_TYPE_ARM: @@ -411,7 +412,7 @@ bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, } bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) { + MDLocationDescriptor* register_location) { switch (cpu_type_) { #ifdef HAS_ARM_SUPPORT case CPU_TYPE_ARM: @@ -469,33 +470,33 @@ uint64_t MinidumpGenerator::CurrentPCForStack( #ifdef HAS_ARM_SUPPORT bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location) { - arm_thread_state_t *machine_state = - reinterpret_cast<arm_thread_state_t *>(state); + MDMemoryDescriptor* stack_location) { + arm_thread_state_t* machine_state = + reinterpret_cast<arm_thread_state_t*>(state); mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); return WriteStackFromStartAddress(start_addr, stack_location); } uint64_t MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) { - arm_thread_state_t *machine_state = - reinterpret_cast<arm_thread_state_t *>(state); + arm_thread_state_t* machine_state = + reinterpret_cast<arm_thread_state_t*>(state); return REGISTER_FROM_THREADSTATE(machine_state, pc); } bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) + MDLocationDescriptor* register_location) { TypedMDRVA<MDRawContextARM> context(&writer_); - arm_thread_state_t *machine_state = - reinterpret_cast<arm_thread_state_t *>(state); + arm_thread_state_t* machine_state = + reinterpret_cast<arm_thread_state_t*>(state); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextARM *context_ptr = context.get(); + MDRawContextARM* context_ptr = context.get(); context_ptr->context_flags = MD_CONTEXT_ARM_FULL; #define AddGPR(a) context_ptr->iregs[a] = REGISTER_FROM_THREADSTATE(machine_state, r[a]) @@ -526,34 +527,34 @@ bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state, #ifdef HAS_ARM64_SUPPORT bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location) { - arm_thread_state64_t *machine_state = - reinterpret_cast<arm_thread_state64_t *>(state); + MDMemoryDescriptor* stack_location) { + arm_thread_state64_t* machine_state = + reinterpret_cast<arm_thread_state64_t*>(state); mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); return WriteStackFromStartAddress(start_addr, stack_location); } uint64_t MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) { - arm_thread_state64_t *machine_state = - reinterpret_cast<arm_thread_state64_t *>(state); + arm_thread_state64_t* machine_state = + reinterpret_cast<arm_thread_state64_t*>(state); return REGISTER_FROM_THREADSTATE(machine_state, pc); } bool MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) + MDLocationDescriptor* register_location) { TypedMDRVA<MDRawContextARM64_Old> context(&writer_); - arm_thread_state64_t *machine_state = - reinterpret_cast<arm_thread_state64_t *>(state); + arm_thread_state64_t* machine_state = + reinterpret_cast<arm_thread_state64_t*>(state); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextARM64_Old *context_ptr = context.get(); + MDRawContextARM64_Old* context_ptr = context.get(); context_ptr->context_flags = MD_CONTEXT_ARM64_FULL_OLD; #define AddGPR(a) \ @@ -602,49 +603,49 @@ MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, #ifdef HAS_PCC_SUPPORT bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location) { - ppc_thread_state_t *machine_state = - reinterpret_cast<ppc_thread_state_t *>(state); + MDMemoryDescriptor* stack_location) { + ppc_thread_state_t* machine_state = + reinterpret_cast<ppc_thread_state_t*>(state); mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1); return WriteStackFromStartAddress(start_addr, stack_location); } bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location) { - ppc_thread_state64_t *machine_state = - reinterpret_cast<ppc_thread_state64_t *>(state); + MDMemoryDescriptor* stack_location) { + ppc_thread_state64_t* machine_state = + reinterpret_cast<ppc_thread_state64_t*>(state); mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1); return WriteStackFromStartAddress(start_addr, stack_location); } uint64_t MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) { - ppc_thread_state_t *machine_state = - reinterpret_cast<ppc_thread_state_t *>(state); + ppc_thread_state_t* machine_state = + reinterpret_cast<ppc_thread_state_t*>(state); return REGISTER_FROM_THREADSTATE(machine_state, srr0); } uint64_t MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) { - ppc_thread_state64_t *machine_state = - reinterpret_cast<ppc_thread_state64_t *>(state); + ppc_thread_state64_t* machine_state = + reinterpret_cast<ppc_thread_state64_t*>(state); return REGISTER_FROM_THREADSTATE(machine_state, srr0); } bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) + MDLocationDescriptor* register_location) { TypedMDRVA<MDRawContextPPC> context(&writer_); - ppc_thread_state_t *machine_state = - reinterpret_cast<ppc_thread_state_t *>(state); + ppc_thread_state_t* machine_state = + reinterpret_cast<ppc_thread_state_t*>(state); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextPPC *context_ptr = context.get(); + MDRawContextPPC* context_ptr = context.get(); context_ptr->context_flags = MD_CONTEXT_PPC_BASE; #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ @@ -701,16 +702,16 @@ bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state, bool MinidumpGenerator::WriteContextPPC64( breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) { + MDLocationDescriptor* register_location) { TypedMDRVA<MDRawContextPPC64> context(&writer_); - ppc_thread_state64_t *machine_state = - reinterpret_cast<ppc_thread_state64_t *>(state); + ppc_thread_state64_t* machine_state = + reinterpret_cast<ppc_thread_state64_t*>(state); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextPPC64 *context_ptr = context.get(); + MDRawContextPPC64* context_ptr = context.get(); context_ptr->context_flags = MD_CONTEXT_PPC_BASE; #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ @@ -768,18 +769,18 @@ bool MinidumpGenerator::WriteContextPPC64( #ifdef HAS_X86_SUPPORT bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location) { - i386_thread_state_t *machine_state = - reinterpret_cast<i386_thread_state_t *>(state); + MDMemoryDescriptor* stack_location) { + i386_thread_state_t* machine_state = + reinterpret_cast<i386_thread_state_t*>(state); mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp); return WriteStackFromStartAddress(start_addr, stack_location); } bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location) { - x86_thread_state64_t *machine_state = - reinterpret_cast<x86_thread_state64_t *>(state); + MDMemoryDescriptor* stack_location) { + x86_thread_state64_t* machine_state = + reinterpret_cast<x86_thread_state64_t*>(state); mach_vm_address_t start_addr = static_cast<mach_vm_address_t>( REGISTER_FROM_THREADSTATE(machine_state, rsp)); @@ -788,32 +789,32 @@ bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state, uint64_t MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) { - i386_thread_state_t *machine_state = - reinterpret_cast<i386_thread_state_t *>(state); + i386_thread_state_t* machine_state = + reinterpret_cast<i386_thread_state_t*>(state); return REGISTER_FROM_THREADSTATE(machine_state, eip); } uint64_t MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) { - x86_thread_state64_t *machine_state = - reinterpret_cast<x86_thread_state64_t *>(state); + x86_thread_state64_t* machine_state = + reinterpret_cast<x86_thread_state64_t*>(state); return REGISTER_FROM_THREADSTATE(machine_state, rip); } bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) + MDLocationDescriptor* register_location) { TypedMDRVA<MDRawContextX86> context(&writer_); - i386_thread_state_t *machine_state = - reinterpret_cast<i386_thread_state_t *>(state); + i386_thread_state_t* machine_state = + reinterpret_cast<i386_thread_state_t*>(state); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextX86 *context_ptr = context.get(); + MDRawContextX86* context_ptr = context.get(); #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ REGISTER_FROM_THREADSTATE(machine_state, a)) @@ -844,16 +845,16 @@ bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state, bool MinidumpGenerator::WriteContextX86_64( breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) { + MDLocationDescriptor* register_location) { TypedMDRVA<MDRawContextAMD64> context(&writer_); - x86_thread_state64_t *machine_state = - reinterpret_cast<x86_thread_state64_t *>(state); + x86_thread_state64_t* machine_state = + reinterpret_cast<x86_thread_state64_t*>(state); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextAMD64 *context_ptr = context.get(); + MDRawContextAMD64* context_ptr = context.get(); #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ REGISTER_FROM_THREADSTATE(machine_state, a)) @@ -892,7 +893,7 @@ bool MinidumpGenerator::WriteContextX86_64( bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, thread_state_t state, - mach_msg_type_number_t *count) { + mach_msg_type_number_t* count) { if (task_context_ && target_thread == mach_thread_self()) { switch (cpu_type_) { #ifdef HAS_ARM_SUPPORT @@ -963,7 +964,7 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, } bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, - MDRawThread *thread) { + MDRawThread* thread) { breakpad_thread_state_data_t state; mach_msg_type_number_t state_count = static_cast<mach_msg_type_number_t>(sizeof(state)); @@ -986,7 +987,7 @@ bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, } bool MinidumpGenerator::WriteThreadListStream( - MDRawDirectory *thread_list_stream) { + MDRawDirectory* thread_list_stream) { TypedMDRVA<MDRawThreadList> list(&writer_); thread_act_port_array_t threads_for_task; mach_msg_type_number_t thread_count; @@ -1027,7 +1028,7 @@ bool MinidumpGenerator::WriteThreadListStream( } bool MinidumpGenerator::WriteMemoryListStream( - MDRawDirectory *memory_list_stream) { + MDRawDirectory* memory_list_stream) { TypedMDRVA<MDRawMemoryList> list(&writer_); // If the dump has an exception, include some memory around the @@ -1119,7 +1120,7 @@ bool MinidumpGenerator::WriteMemoryListStream( } else { // In-process, just copy from local memory. ip_memory.Copy( - reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range), + reinterpret_cast<const void*>(ip_memory_d.start_of_memory_range), ip_memory_d.memory.data_size); } @@ -1133,7 +1134,7 @@ bool MinidumpGenerator::WriteMemoryListStream( } bool -MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { +MinidumpGenerator::WriteExceptionStream(MDRawDirectory* exception_stream) { TypedMDRVA<MDRawExceptionStream> exception(&writer_); if (!exception.Allocate()) @@ -1141,7 +1142,7 @@ MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { exception_stream->stream_type = MD_EXCEPTION_STREAM; exception_stream->location = exception.location(); - MDRawExceptionStream *exception_ptr = exception.get(); + MDRawExceptionStream* exception_ptr = exception.get(); exception_ptr->thread_id = exception_thread_; // This naming is confusing, but it is the proper translation from @@ -1168,7 +1169,7 @@ MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { } bool MinidumpGenerator::WriteSystemInfoStream( - MDRawDirectory *system_info_stream) { + MDRawDirectory* system_info_stream) { TypedMDRVA<MDRawSystemInfo> info(&writer_); if (!info.Allocate()) @@ -1181,7 +1182,7 @@ bool MinidumpGenerator::WriteSystemInfoStream( uint32_t number_of_processors; size_t len = sizeof(number_of_processors); sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0); - MDRawSystemInfo *info_ptr = info.get(); + MDRawSystemInfo* info_ptr = info.get(); switch (cpu_type_) { #ifdef HAS_ARM_SUPPORT @@ -1292,10 +1293,10 @@ bool MinidumpGenerator::WriteSystemInfoStream( } bool MinidumpGenerator::WriteModuleStream(unsigned int index, - MDRawModule *module) { + MDRawModule* module) { if (dynamic_images_) { // we're in a different process than the crashed process - DynamicImage *image = dynamic_images_->GetImage(index); + DynamicImage* image = dynamic_images_->GetImage(index); if (!image) return false; @@ -1337,7 +1338,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, } } else { // Getting module info in the crashed process - const breakpad_mach_header *header; + const breakpad_mach_header* header; header = (breakpad_mach_header*)_dyld_get_image_header(index); if (!header) return false; @@ -1357,16 +1358,16 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, int cpu_type = header->cputype; unsigned long slide = _dyld_get_image_vmaddr_slide(index); const char* name = _dyld_get_image_name(index); - const struct load_command *cmd = - reinterpret_cast<const struct load_command *>(header + 1); + const struct load_command* cmd = + reinterpret_cast<const struct load_command*>(header + 1); memset(module, 0, sizeof(MDRawModule)); for (unsigned int i = 0; cmd && (i < header->ncmds); i++) { if (cmd->cmd == LC_SEGMENT_ARCH) { - const breakpad_mach_segment_command *seg = - reinterpret_cast<const breakpad_mach_segment_command *>(cmd); + const breakpad_mach_segment_command* seg = + reinterpret_cast<const breakpad_mach_segment_command*>(cmd); if (!strcmp(seg->segname, "__TEXT")) { MDLocationDescriptor string_location; @@ -1389,7 +1390,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, } } - cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize); + cmd = reinterpret_cast<struct load_command*>((char*)cmd + cmd->cmdsize); } } @@ -1405,7 +1406,7 @@ int MinidumpGenerator::FindExecutableModule() { } } else { int image_count = _dyld_image_count(); - const struct mach_header *header; + const struct mach_header* header; for (int index = 0; index < image_count; ++index) { header = _dyld_get_image_header(index); @@ -1419,12 +1420,12 @@ int MinidumpGenerator::FindExecutableModule() { return 0; } -bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, - const char *module_path, bool in_memory) { +bool MinidumpGenerator::WriteCVRecord(MDRawModule* module, int cpu_type, + const char* module_path, bool in_memory) { TypedMDRVA<MDCVInfoPDB70> cv(&writer_); // Only return the last path component of the full module path - const char *module_name = strrchr(module_path, '/'); + const char* module_name = strrchr(module_path, '/'); // Increment past the slash if (module_name) @@ -1441,7 +1442,7 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, return false; module->cv_record = cv.location(); - MDCVInfoPDB70 *cv_ptr = cv.get(); + MDCVInfoPDB70* cv_ptr = cv.get(); cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; cv_ptr->age = 0; @@ -1449,8 +1450,8 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, unsigned char identifier[16]; bool result = false; if (in_memory) { - MacFileUtilities::MachoID macho(module_path, - reinterpret_cast<void *>(module->base_of_image), + MacFileUtilities::MachoID macho( + reinterpret_cast<void*>(module->base_of_image), static_cast<size_t>(module->size_of_image)); result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); if (!result) @@ -1487,7 +1488,7 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, } bool MinidumpGenerator::WriteModuleListStream( - MDRawDirectory *module_list_stream) { + MDRawDirectory* module_list_stream) { TypedMDRVA<MDRawModuleList> list(&writer_); uint32_t image_count = dynamic_images_ ? @@ -1525,7 +1526,7 @@ bool MinidumpGenerator::WriteModuleListStream( return true; } -bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { +bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory* misc_info_stream) { TypedMDRVA<MDRawMiscInfo> info(&writer_); if (!info.Allocate()) @@ -1534,7 +1535,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { misc_info_stream->stream_type = MD_MISC_INFO_STREAM; misc_info_stream->location = info.location(); - MDRawMiscInfo *info_ptr = info.get(); + MDRawMiscInfo* info_ptr = info.get(); info_ptr->size_of_info = static_cast<uint32_t>(sizeof(MDRawMiscInfo)); info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID | MD_MISCINFO_FLAGS1_PROCESS_TIMES | @@ -1577,7 +1578,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { } bool MinidumpGenerator::WriteBreakpadInfoStream( - MDRawDirectory *breakpad_info_stream) { + MDRawDirectory* breakpad_info_stream) { TypedMDRVA<MDRawBreakpadInfo> info(&writer_); if (!info.Allocate()) @@ -1585,7 +1586,7 @@ bool MinidumpGenerator::WriteBreakpadInfoStream( breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM; breakpad_info_stream->location = info.location(); - MDRawBreakpadInfo *info_ptr = info.get(); + MDRawBreakpadInfo* info_ptr = info.get(); if (exception_thread_ && exception_type_) { info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | diff --git a/src/client/mac/handler/minidump_generator.h b/src/client/mac/handler/minidump_generator.h index f3aa9bd3..efddfa9a 100644 --- a/src/client/mac/handler/minidump_generator.h +++ b/src/client/mac/handler/minidump_generator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -106,12 +105,12 @@ class MinidumpGenerator { // Return <dir>/<unique_name>.dmp // Sets |unique_name| (if requested) to the unique name for the minidump - static string UniqueNameInDirectory(const string &dir, string *unique_name); + static string UniqueNameInDirectory(const string& dir, string* unique_name); // Write out the minidump into |path| // All of the components of |path| must exist and be writable // Return true if successful, false otherwise - bool Write(const char *path); + bool Write(const char* path); // Specify some exception information, if applicable void SetExceptionInformation(int type, int code, int subcode, @@ -125,7 +124,7 @@ class MinidumpGenerator { // Specify the task context. If |task_context| is not NULL, it will be used // to retrieve the context of the current thread, instead of using // |thread_get_state|. - void SetTaskContext(breakpad_ucontext_t *task_context); + void SetTaskContext(breakpad_ucontext_t* task_context); // Gather system information. This should be call at least once before using // the MinidumpGenerator class. @@ -133,81 +132,81 @@ class MinidumpGenerator { protected: // Overridable Stream writers - virtual bool WriteExceptionStream(MDRawDirectory *exception_stream); + virtual bool WriteExceptionStream(MDRawDirectory* exception_stream); // Overridable Helper - virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread); + virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread* thread); private: - typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *); + typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory*); // Stream writers - bool WriteThreadListStream(MDRawDirectory *thread_list_stream); - bool WriteMemoryListStream(MDRawDirectory *memory_list_stream); - bool WriteSystemInfoStream(MDRawDirectory *system_info_stream); - bool WriteModuleListStream(MDRawDirectory *module_list_stream); - bool WriteMiscInfoStream(MDRawDirectory *misc_info_stream); - bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream); + bool WriteThreadListStream(MDRawDirectory* thread_list_stream); + bool WriteMemoryListStream(MDRawDirectory* memory_list_stream); + bool WriteSystemInfoStream(MDRawDirectory* system_info_stream); + bool WriteModuleListStream(MDRawDirectory* module_list_stream); + bool WriteMiscInfoStream(MDRawDirectory* misc_info_stream); + bool WriteBreakpadInfoStream(MDRawDirectory* breakpad_info_stream); // Helpers uint64_t CurrentPCForStack(breakpad_thread_state_data_t state); bool GetThreadState(thread_act_t target_thread, thread_state_t state, - mach_msg_type_number_t *count); + mach_msg_type_number_t* count); bool WriteStackFromStartAddress(mach_vm_address_t start_addr, - MDMemoryDescriptor *stack_location); + MDMemoryDescriptor* stack_location); bool WriteStack(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location); + MDMemoryDescriptor* stack_location); bool WriteContext(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location); - bool WriteCVRecord(MDRawModule *module, int cpu_type, - const char *module_path, bool in_memory); - bool WriteModuleStream(unsigned int index, MDRawModule *module); + MDLocationDescriptor* register_location); + bool WriteCVRecord(MDRawModule* module, int cpu_type, + const char* module_path, bool in_memory); + bool WriteModuleStream(unsigned int index, MDRawModule* module); size_t CalculateStackSize(mach_vm_address_t start_addr); int FindExecutableModule(); // Per-CPU implementations of these methods #ifdef HAS_ARM_SUPPORT bool WriteStackARM(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location); + MDMemoryDescriptor* stack_location); bool WriteContextARM(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location); + MDLocationDescriptor* register_location); uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state); #endif #ifdef HAS_ARM64_SUPPORT bool WriteStackARM64(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location); + MDMemoryDescriptor* stack_location); bool WriteContextARM64(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location); + MDLocationDescriptor* register_location); uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state); #endif #ifdef HAS_PPC_SUPPORT bool WriteStackPPC(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location); + MDMemoryDescriptor* stack_location); bool WriteContextPPC(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location); + MDLocationDescriptor* register_location); uint64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state); bool WriteStackPPC64(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location); + MDMemoryDescriptor* stack_location); bool WriteContextPPC64(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location); + MDLocationDescriptor* register_location); uint64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state); #endif #ifdef HAS_X86_SUPPORT bool WriteStackX86(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location); + MDMemoryDescriptor* stack_location); bool WriteContextX86(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location); + MDLocationDescriptor* register_location); uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state); bool WriteStackX86_64(breakpad_thread_state_data_t state, - MDMemoryDescriptor *stack_location); + MDMemoryDescriptor* stack_location); bool WriteContextX86_64(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location); + MDLocationDescriptor* register_location); uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state); #endif // disallow copy ctor and operator= - explicit MinidumpGenerator(const MinidumpGenerator &); - void operator=(const MinidumpGenerator &); + explicit MinidumpGenerator(const MinidumpGenerator&); + void operator=(const MinidumpGenerator&); protected: // Use this writer to put the data to disk @@ -232,10 +231,10 @@ class MinidumpGenerator { static int os_build_number_; // Context of the task to dump. - breakpad_ucontext_t *task_context_; + breakpad_ucontext_t* task_context_; // Information about dynamically loaded code - DynamicImages *dynamic_images_; + DynamicImages* dynamic_images_; // PageAllocator makes it possible to allocate memory // directly from the system, even while handling an exception. diff --git a/src/client/mac/handler/protected_memory_allocator.cc b/src/client/mac/handler/protected_memory_allocator.cc index 6142ad12..83383263 100644 --- a/src/client/mac/handler/protected_memory_allocator.cc +++ b/src/client/mac/handler/protected_memory_allocator.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/handler/protected_memory_allocator.h b/src/client/mac/handler/protected_memory_allocator.h index 7e188db2..86413c87 100644 --- a/src/client/mac/handler/protected_memory_allocator.h +++ b/src/client/mac/handler/protected_memory_allocator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/handler/testcases/DynamicImagesTests.cc b/src/client/mac/handler/testcases/DynamicImagesTests.cc index 0fc7825b..14ea88d2 100644 --- a/src/client/mac/handler/testcases/DynamicImagesTests.cc +++ b/src/client/mac/handler/testcases/DynamicImagesTests.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved +// Copyright 2008 Google LLC // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -10,7 +9,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +30,7 @@ // minidump_test // // Created by Neal Sidhwaney on 4/17/08. -// Copyright 2008 Google Inc. All rights reserved. +// Copyright 2008 Google LLC // #include "client/mac/handler/testcases/DynamicImagesTests.h" @@ -42,7 +41,7 @@ DynamicImagesTests test2(TEST_INVOCATION(DynamicImagesTests, DynamicImagesTests test3(TEST_INVOCATION(DynamicImagesTests, ReadLibrariesFromLocalTaskTest)); -DynamicImagesTests::DynamicImagesTests(TestInvocation *invocation) +DynamicImagesTests::DynamicImagesTests(TestInvocation* invocation) : TestCase(invocation) { } @@ -54,7 +53,7 @@ void DynamicImagesTests::ReadTaskMemoryTest() { // pick test2 as a symbol we know to be valid to read // anything will work, really - void *addr = reinterpret_cast<void*>(&test2); + void* addr = reinterpret_cast<void*>(&test2); std::vector<uint8_t> buf(getpagesize()); fprintf(stderr, "reading 0x%p\n", addr); @@ -71,7 +70,7 @@ void DynamicImagesTests::ReadTaskMemoryTest() { void DynamicImagesTests::ReadLibrariesFromLocalTaskTest() { mach_port_t me = mach_task_self(); - google_breakpad::DynamicImages *d = new google_breakpad::DynamicImages(me); + google_breakpad::DynamicImages* d = new google_breakpad::DynamicImages(me); fprintf(stderr,"Local task image count: %d\n", d->GetImageCount()); diff --git a/src/client/mac/handler/testcases/DynamicImagesTests.h b/src/client/mac/handler/testcases/DynamicImagesTests.h index e1e79993..f60ee69c 100644 --- a/src/client/mac/handler/testcases/DynamicImagesTests.h +++ b/src/client/mac/handler/testcases/DynamicImagesTests.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved +// Copyright 2008 Google LLC // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -10,7 +9,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +30,7 @@ // minidump_test // // Created by Neal Sidhwaney on 4/17/08. -// Copyright 2008 Google Inc. All rights reserved. +// Copyright 2008 Google LLC // // diff --git a/src/client/mac/handler/testcases/breakpad_nlist_test.cc b/src/client/mac/handler/testcases/breakpad_nlist_test.cc index e7332bfb..a89d8c44 100644 --- a/src/client/mac/handler/testcases/breakpad_nlist_test.cc +++ b/src/client/mac/handler/testcases/breakpad_nlist_test.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved +// Copyright 2008 Google LLC // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -10,7 +9,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +30,7 @@ // minidump_test // // Created by Neal Sidhwaney on 4/13/08. -// Copyright 2008 Google Inc. All rights reserved. +// Copyright 2008 Google LLC // #include "client/mac/handler/testcases/breakpad_nlist_test.h" @@ -40,7 +39,7 @@ BreakpadNlistTest test1(TEST_INVOCATION(BreakpadNlistTest, CompareToNM)); -BreakpadNlistTest::BreakpadNlistTest(TestInvocation *invocation) +BreakpadNlistTest::BreakpadNlistTest(TestInvocation* invocation) : TestCase(invocation) { } @@ -55,7 +54,7 @@ void BreakpadNlistTest::CompareToNM() { system("/usr/bin/nm -arch ppc64 /usr/lib/dyld > /tmp/dyld-namelist.txt"); #endif - FILE *fd = fopen("/tmp/dyld-namelist.txt", "rt"); + FILE* fd = fopen("/tmp/dyld-namelist.txt", "rt"); char oneNMAddr[30]; char symbolType; @@ -63,10 +62,10 @@ void BreakpadNlistTest::CompareToNM() { while (!feof(fd)) { fscanf(fd, "%s %c %s", oneNMAddr, &symbolType, symbolName); breakpad_nlist symbolList[2]; - breakpad_nlist &list = symbolList[0]; + breakpad_nlist& list = symbolList[0]; memset(symbolList, 0, sizeof(breakpad_nlist)*2); - const char *symbolNames[2]; + const char* symbolNames[2]; symbolNames[0] = (const char*)symbolName; symbolNames[1] = "\0"; breakpad_nlist_64("/usr/lib/dyld", &list, symbolNames); @@ -79,12 +78,12 @@ void BreakpadNlistTest::CompareToNM() { fclose(fd); } -bool BreakpadNlistTest::IsSymbolMoreThanOnceInDyld(const char *symbolName) { +bool BreakpadNlistTest::IsSymbolMoreThanOnceInDyld(const char* symbolName) { // These are the symbols that occur more than once when nm dumps // the symbol table of /usr/lib/dyld. Our nlist program returns // the first address because it's doing a search so we need to exclude // these from causing the test to fail - const char *multipleSymbols[] = { + const char* multipleSymbols[] = { "__Z41__static_initialization_and_destruction_0ii", "___tcf_0", "___tcf_1", diff --git a/src/client/mac/handler/testcases/breakpad_nlist_test.h b/src/client/mac/handler/testcases/breakpad_nlist_test.h index e93657cc..ca407ea8 100644 --- a/src/client/mac/handler/testcases/breakpad_nlist_test.h +++ b/src/client/mac/handler/testcases/breakpad_nlist_test.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved +// Copyright 2008 Google LLC // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -10,7 +9,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +30,7 @@ // minidump_test // // Created by Neal Sidhwaney on 4/13/08. -// Copyright 2008 Google Inc. All rights reserved. +// Copyright 2008 Google LLC // // @@ -47,7 +46,7 @@ class BreakpadNlistTest : public TestCase { // /usr/lib/dyld. So we track those so we don't report failures // in mismatches between what our nlist returns and what nm has // for the duplicate symbols. - bool IsSymbolMoreThanOnceInDyld(const char *symbolName); + bool IsSymbolMoreThanOnceInDyld(const char* symbolName); public: explicit BreakpadNlistTest(TestInvocation* invocation); diff --git a/src/client/mac/handler/testcases/dwarftests.h b/src/client/mac/handler/testcases/dwarftests.h index 21ff7a44..0c35374a 100644 --- a/src/client/mac/handler/testcases/dwarftests.h +++ b/src/client/mac/handler/testcases/dwarftests.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved +// Copyright 2008 Google LLC // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -10,7 +9,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +30,7 @@ // minidump_test // // Created by Neal Sidhwaney on 9/24/08. -// Copyright 2008 Google Inc. All rights reserved. +// Copyright 2008 Google LLC // #import <SenTestingKit/SenTestingKit.h> diff --git a/src/client/mac/handler/testcases/dwarftests.mm b/src/client/mac/handler/testcases/dwarftests.mm index 40c69aff..c02a2d23 100644 --- a/src/client/mac/handler/testcases/dwarftests.mm +++ b/src/client/mac/handler/testcases/dwarftests.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved +// Copyright 2008 Google LLC // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -10,7 +9,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +30,7 @@ // minidump_test // // Created by Neal Sidhwaney on 9/24/08. -// Copyright 2008 Google Inc. All rights reserved. +// Copyright 2008 Google LLC // #import "dwarftests.h" diff --git a/src/client/mac/handler/ucontext_compat.h b/src/client/mac/handler/ucontext_compat.h index 1e4b752e..853b1caa 100644 --- a/src/client/mac/handler/ucontext_compat.h +++ b/src/client/mac/handler/ucontext_compat.h @@ -1,5 +1,4 @@ -// Copyright 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/sender/crash_report_sender.h b/src/client/mac/sender/crash_report_sender.h index 6a29d48a..13379cea 100644 --- a/src/client/mac/sender/crash_report_sender.h +++ b/src/client/mac/sender/crash_report_sender.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/sender/crash_report_sender.m b/src/client/mac/sender/crash_report_sender.m index 88d26fb0..170fa07f 100644 --- a/src/client/mac/sender/crash_report_sender.m +++ b/src/client/mac/sender/crash_report_sender.m @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/sender/uploader.h b/src/client/mac/sender/uploader.h index 0897dade..4eba7163 100644 --- a/src/client/mac/sender/uploader.h +++ b/src/client/mac/sender/uploader.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/sender/uploader.mm b/src/client/mac/sender/uploader.mm index 13b6130a..f2bcd0b1 100644 --- a/src/client/mac/sender/uploader.mm +++ b/src/client/mac/sender/uploader.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/testapp/Controller.h b/src/client/mac/testapp/Controller.h index 7b3be2d6..36f9572a 100644 --- a/src/client/mac/testapp/Controller.h +++ b/src/client/mac/testapp/Controller.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/testapp/Controller.m b/src/client/mac/testapp/Controller.m index 87c43024..2de84f3f 100644 --- a/src/client/mac/testapp/Controller.m +++ b/src/client/mac/testapp/Controller.m @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/testapp/TestClass.h b/src/client/mac/testapp/TestClass.h index 0a6d736d..e20b0e87 100644 --- a/src/client/mac/testapp/TestClass.h +++ b/src/client/mac/testapp/TestClass.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/testapp/TestClass.mm b/src/client/mac/testapp/TestClass.mm index 6e6a8833..ed0a7eca 100644 --- a/src/client/mac/testapp/TestClass.mm +++ b/src/client/mac/testapp/TestClass.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/testapp/main.m b/src/client/mac/testapp/main.m index 1ed19bf9..af2cc141 100644 --- a/src/client/mac/testapp/main.m +++ b/src/client/mac/testapp/main.m @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -30,5 +29,5 @@ #import <Cocoa/Cocoa.h> int main(int argc, char *argv[]) { - return NSApplicationMain(argc, (const char **) argv); + return NSApplicationMain(argc, (const char**)argv); } diff --git a/src/client/mac/tests/BreakpadFramework_Test.mm b/src/client/mac/tests/BreakpadFramework_Test.mm index 2ea103c6..7a701330 100644 --- a/src/client/mac/tests/BreakpadFramework_Test.mm +++ b/src/client/mac/tests/BreakpadFramework_Test.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/tests/crash_generation_server_test.cc b/src/client/mac/tests/crash_generation_server_test.cc index 0164f4a2..50825a93 100644 --- a/src/client/mac/tests/crash_generation_server_test.cc +++ b/src/client/mac/tests/crash_generation_server_test.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -147,8 +146,8 @@ TEST_F(CrashGenerationServerTest, testRequestDumpNoDump) { globfree(&dirContents); } -void dumpCallback(void *context, const ClientInfo &client_info, - const std::string &file_path) { +void dumpCallback(void* context, const ClientInfo& client_info, + const std::string& file_path) { if (context) { CrashGenerationServerTest* self = reinterpret_cast<CrashGenerationServerTest*>(context); @@ -158,7 +157,7 @@ void dumpCallback(void *context, const ClientInfo &client_info, } } -void *RequestDump(void *context) { +void* RequestDump(void* context) { CrashGenerationClient client((const char*)context); bool result = client.RequestDump(); return (void*)(result ? 0 : 1); @@ -206,7 +205,7 @@ TEST_F(CrashGenerationServerTest, testRequestDump) { } static void Crasher() { - int *a = (int*)0x42; + int* a = (int*)0x42; fprintf(stdout, "Going to crash...\n"); fprintf(stdout, "A = %d", *a); diff --git a/src/client/mac/tests/exception_handler_test.cc b/src/client/mac/tests/exception_handler_test.cc index d5b505a1..eb9aa1bc 100644 --- a/src/client/mac/tests/exception_handler_test.cc +++ b/src/client/mac/tests/exception_handler_test.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -71,7 +70,7 @@ class ExceptionHandlerTest : public Test { }; static void Crasher() { - int *a = (int*)0x42; + int* a = (int*)0x42; fprintf(stdout, "Going to crash...\n"); fprintf(stdout, "A = %d", *a); @@ -86,8 +85,8 @@ static void SoonToCrash(void(*crasher)()) { crasher(); } -static bool MDCallback(const char *dump_dir, const char *file_name, - void *context, bool success) { +static bool MDCallback(const char* dump_dir, const char* file_name, + void* context, bool success) { string path(dump_dir); path.append("/"); path.append(file_name); @@ -179,9 +178,9 @@ TEST_F(ExceptionHandlerTest, InProcessAbort) { InProcessCrash(true); } -static bool DumpNameMDCallback(const char *dump_dir, const char *file_name, - void *context, bool success) { - ExceptionHandlerTest *self = reinterpret_cast<ExceptionHandlerTest*>(context); +static bool DumpNameMDCallback(const char* dump_dir, const char* file_name, + void* context, bool success) { + ExceptionHandlerTest* self = reinterpret_cast<ExceptionHandlerTest*>(context); if (dump_dir && file_name) { self->lastDumpName = dump_dir; self->lastDumpName += "/"; @@ -652,7 +651,7 @@ TEST_F(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { ASSERT_EQ((unsigned int)1, memory_list->region_count()); } -static void *Junk(void *) { +static void* Junk(void*) { sleep(1000000); return NULL; } diff --git a/src/client/mac/tests/minidump_generator_test.cc b/src/client/mac/tests/minidump_generator_test.cc index b1fa5d02..1a889dfe 100644 --- a/src/client/mac/tests/minidump_generator_test.cc +++ b/src/client/mac/tests/minidump_generator_test.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -79,7 +78,7 @@ class MinidumpGeneratorTest : public Test { AutoTempDir tempDir; }; -static void *Junk(void* data) { +static void* Junk(void* data) { bool* wait = reinterpret_cast<bool*>(data); while (!*wait) { usleep(10000); diff --git a/src/client/mac/tests/minidump_generator_test_helper.cc b/src/client/mac/tests/minidump_generator_test_helper.cc index 4e8ce3cf..93cbe1bb 100644 --- a/src/client/mac/tests/minidump_generator_test_helper.cc +++ b/src/client/mac/tests/minidump_generator_test_helper.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/mac/tests/spawn_child_process.h b/src/client/mac/tests/spawn_child_process.h index e52ff6b6..cc804511 100644 --- a/src/client/mac/tests/spawn_child_process.h +++ b/src/client/mac/tests/spawn_child_process.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/minidump_file_writer-inl.h b/src/client/minidump_file_writer-inl.h index 0e12e00b..d95f3554 100644 --- a/src/client/minidump_file_writer-inl.h +++ b/src/client/minidump_file_writer-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -69,7 +68,7 @@ inline bool TypedMDRVA<MDType>::AllocateObjectAndArray(size_t count, } template<typename MDType> -inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) { +inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType* item) { assert(allocation_state_ == ARRAY); return writer_->Copy( static_cast<MDRVA>(position_ + index * minidump_size<MDType>::size()), @@ -78,7 +77,7 @@ inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) { template<typename MDType> inline bool TypedMDRVA<MDType>::CopyIndexAfterObject(unsigned int index, - const void *src, + const void* src, size_t length) { assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY); return writer_->Copy( diff --git a/src/client/minidump_file_writer.cc b/src/client/minidump_file_writer.cc index a1957f32..d5193e2c 100644 --- a/src/client/minidump_file_writer.cc +++ b/src/client/minidump_file_writer.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -101,7 +100,7 @@ MinidumpFileWriter::~MinidumpFileWriter() { Close(); } -bool MinidumpFileWriter::Open(const char *path) { +bool MinidumpFileWriter::Open(const char* path) { assert(file_ == -1); #if defined(__linux__) && __linux__ file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); @@ -145,9 +144,9 @@ bool MinidumpFileWriter::Close() { return result; } -bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str, +bool MinidumpFileWriter::CopyStringToMDString(const wchar_t* str, unsigned int length, - TypedMDRVA<MDString> *mdstring) { + TypedMDRVA<MDString>* mdstring) { bool result = true; if (sizeof(wchar_t) == sizeof(uint16_t)) { // Shortcut if wchar_t is the same size as MDString's buffer @@ -178,9 +177,9 @@ bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str, return result; } -bool MinidumpFileWriter::CopyStringToMDString(const char *str, +bool MinidumpFileWriter::CopyStringToMDString(const char* str, unsigned int length, - TypedMDRVA<MDString> *mdstring) { + TypedMDRVA<MDString>* mdstring) { bool result = true; uint16_t out[2]; int out_idx = 0; @@ -205,9 +204,9 @@ bool MinidumpFileWriter::CopyStringToMDString(const char *str, } template <typename CharType> -bool MinidumpFileWriter::WriteStringCore(const CharType *str, +bool MinidumpFileWriter::WriteStringCore(const CharType* str, unsigned int length, - MDLocationDescriptor *location) { + MDLocationDescriptor* location) { assert(str); assert(location); // Calculate the mdstring length by either limiting to |length| as passed in @@ -240,18 +239,18 @@ bool MinidumpFileWriter::WriteStringCore(const CharType *str, return result; } -bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length, - MDLocationDescriptor *location) { +bool MinidumpFileWriter::WriteString(const wchar_t* str, unsigned int length, + MDLocationDescriptor* location) { return WriteStringCore(str, length, location); } -bool MinidumpFileWriter::WriteString(const char *str, unsigned int length, - MDLocationDescriptor *location) { +bool MinidumpFileWriter::WriteString(const char* str, unsigned int length, + MDLocationDescriptor* location) { return WriteStringCore(str, length, location); } -bool MinidumpFileWriter::WriteMemory(const void *src, size_t size, - MDMemoryDescriptor *output) { +bool MinidumpFileWriter::WriteMemory(const void* src, size_t size, + MDMemoryDescriptor* output) { assert(src); assert(output); UntypedMDRVA mem(this); @@ -307,7 +306,7 @@ MDRVA MinidumpFileWriter::Allocate(size_t size) { return current_position; } -bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) { +bool MinidumpFileWriter::Copy(MDRVA position, const void* src, ssize_t size) { assert(src); assert(size); assert(file_ != -1); @@ -340,7 +339,7 @@ bool UntypedMDRVA::Allocate(size_t size) { return position_ != MinidumpFileWriter::kInvalidMDRVA; } -bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) { +bool UntypedMDRVA::Copy(MDRVA pos, const void* src, size_t size) { assert(src); assert(size); assert(pos + size <= position_ + size_); diff --git a/src/client/minidump_file_writer.h b/src/client/minidump_file_writer.h index ce32b6d0..253a93a9 100644 --- a/src/client/minidump_file_writer.h +++ b/src/client/minidump_file_writer.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -77,7 +76,7 @@ public: // Open |path| as the destination of the minidump data. If |path| already // exists, then Open() will fail. // Return true on success, or false on failure. - bool Open(const char *path); + bool Open(const char* path); // Sets the file descriptor |file| as the destination of the minidump data. // Can be used as an alternative to Open() when a file descriptor is @@ -98,20 +97,20 @@ public: // entire NULL terminated string. Copying will stop at the first NULL. // |location| the allocated location // Return true on success, or false on failure - bool WriteString(const wchar_t *str, unsigned int length, - MDLocationDescriptor *location); + bool WriteString(const wchar_t* str, unsigned int length, + MDLocationDescriptor* location); // Same as above, except with |str| as a UTF-8 string - bool WriteString(const char *str, unsigned int length, - MDLocationDescriptor *location); + bool WriteString(const char* str, unsigned int length, + MDLocationDescriptor* location); // Write |size| bytes starting at |src| into the current position. // Return true on success and set |output| to position, or false on failure - bool WriteMemory(const void *src, size_t size, MDMemoryDescriptor *output); + bool WriteMemory(const void* src, size_t size, MDMemoryDescriptor* output); // Copies |size| bytes from |src| to |position| // Return true on success, or false on failure - bool Copy(MDRVA position, const void *src, ssize_t size); + bool Copy(MDRVA position, const void* src, ssize_t size); // Return the current position for writing to the minidump inline MDRVA position() const { return position_; } @@ -141,21 +140,21 @@ public: // variant may need to create a MDString that has more characters than the // source |str|, whereas the UTF-8 variant may coalesce characters to form // a single UTF-16 character. - bool CopyStringToMDString(const wchar_t *str, unsigned int length, - TypedMDRVA<MDString> *mdstring); - bool CopyStringToMDString(const char *str, unsigned int length, - TypedMDRVA<MDString> *mdstring); + bool CopyStringToMDString(const wchar_t* str, unsigned int length, + TypedMDRVA<MDString>* mdstring); + bool CopyStringToMDString(const char* str, unsigned int length, + TypedMDRVA<MDString>* mdstring); // The common templated code for writing a string template <typename CharType> - bool WriteStringCore(const CharType *str, unsigned int length, - MDLocationDescriptor *location); + bool WriteStringCore(const CharType* str, unsigned int length, + MDLocationDescriptor* location); }; // Represents an untyped allocated chunk class UntypedMDRVA { public: - explicit UntypedMDRVA(MinidumpFileWriter *writer) + explicit UntypedMDRVA(MinidumpFileWriter* writer) : writer_(writer), position_(writer->position()), size_(0) {} @@ -179,16 +178,16 @@ class UntypedMDRVA { // Copy |size| bytes starting at |src| into the minidump at |position| // Return true on success, or false on failure - bool Copy(MDRVA position, const void *src, size_t size); + bool Copy(MDRVA position, const void* src, size_t size); // Copy |size| bytes from |src| to the current position - inline bool Copy(const void *src, size_t size) { + inline bool Copy(const void* src, size_t size) { return Copy(position_, src, size); } protected: // Writer we associate with - MinidumpFileWriter *writer_; + MinidumpFileWriter* writer_; // Position of the start of the data MDRVA position_; @@ -206,7 +205,7 @@ template<typename MDType> class TypedMDRVA : public UntypedMDRVA { public: // Constructs an unallocated MDRVA - explicit TypedMDRVA(MinidumpFileWriter *writer) + explicit TypedMDRVA(MinidumpFileWriter* writer) : UntypedMDRVA(writer), data_(), allocation_state_(UNALLOCATED) {} @@ -220,7 +219,7 @@ class TypedMDRVA : public UntypedMDRVA { // Address of object data_ of MDType. This is not declared const as the // typical usage will be to access the underlying |data_| object as to // alter its contents. - MDType *get() { return &data_; } + MDType* get() { return &data_; } // Allocates minidump_size<MDType>::size() bytes. // Must not call more than once. @@ -245,12 +244,12 @@ class TypedMDRVA : public UntypedMDRVA { // Copy |item| to |index| // Must have been allocated using AllocateArray(). // Return true on success, or false on failure - bool CopyIndex(unsigned int index, MDType *item); + bool CopyIndex(unsigned int index, MDType* item); // Copy |size| bytes starting at |str| to |index| // Must have been allocated using AllocateObjectAndArray(). // Return true on success, or false on failure - bool CopyIndexAfterObject(unsigned int index, const void *src, size_t size); + bool CopyIndexAfterObject(unsigned int index, const void* src, size_t size); // Write data_ bool Flush(); diff --git a/src/client/minidump_file_writer_unittest.cc b/src/client/minidump_file_writer_unittest.cc index 256e3371..bb3a0269 100644 --- a/src/client/minidump_file_writer_unittest.cc +++ b/src/client/minidump_file_writer_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -70,16 +69,16 @@ typedef struct { ArrayStructure array[0]; } ObjectAndArrayStructure; -static bool WriteFile(const char *path) { +static bool WriteFile(const char* path) { MinidumpFileWriter writer; if (writer.Open(path)) { // Test a single structure google_breakpad::TypedMDRVA<StringStructure> strings(&writer); ASSERT_TRUE(strings.Allocate()); strings.get()->integer_value = 0xBEEF; - const char *first = "First String"; + const char* first = "First String"; ASSERT_TRUE(writer.WriteString(first, 0, &strings.get()->first_string)); - const wchar_t *second = L"Second String"; + const wchar_t* second = L"Second String"; ASSERT_TRUE(writer.WriteString(second, 0, &strings.get()->second_string)); // Test an array structure @@ -111,7 +110,7 @@ static bool WriteFile(const char *path) { return writer.Close(); } -static bool CompareFile(const char *path) { +static bool CompareFile(const char* path) { unsigned long expected[] = { #if defined(__BIG_ENDIAN__) 0x0000beef, 0x0000001e, 0x00000018, 0x00000020, 0x00000038, 0x00000000, @@ -146,13 +145,14 @@ static bool CompareFile(const char *path) { }; size_t expected_byte_count = sizeof(expected); int fd = open(path, O_RDONLY, 0600); - void *buffer = malloc(expected_byte_count); + void* buffer = malloc(expected_byte_count); ASSERT_NE(fd, -1); ASSERT_TRUE(buffer); ASSERT_EQ(read(fd, buffer, expected_byte_count), static_cast<ssize_t>(expected_byte_count)); - char *b1, *b2; + char* b1; + char* b2; b1 = reinterpret_cast<char*>(buffer); b2 = reinterpret_cast<char*>(expected); while (*b1 == *b2) { @@ -167,13 +167,13 @@ static bool CompareFile(const char *path) { } static bool RunTests() { - const char *path = "/tmp/minidump_file_writer_unittest.dmp"; + const char* path = "/tmp/minidump_file_writer_unittest.dmp"; ASSERT_TRUE(WriteFile(path)); ASSERT_TRUE(CompareFile(path)); unlink(path); return true; } -extern "C" int main(int argc, const char *argv[]) { +extern "C" int main(int argc, const char* argv[]) { return RunTests() ? 0 : 1; } diff --git a/src/client/solaris/handler/Makefile b/src/client/solaris/handler/Makefile index 6da9464e..b22fe561 100644 --- a/src/client/solaris/handler/Makefile +++ b/src/client/solaris/handler/Makefile @@ -1,5 +1,4 @@ -# Copyright (c) 2007, Google Inc. -# All rights reserved. +# Copyright 2007 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/client/solaris/handler/exception_handler.cc b/src/client/solaris/handler/exception_handler.cc index 7fc8d255..b7b702ac 100644 --- a/src/client/solaris/handler/exception_handler.cc +++ b/src/client/solaris/handler/exception_handler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -54,15 +53,15 @@ static const int kSigTable[] = { SIGBUS }; -std::vector<ExceptionHandler*> *ExceptionHandler::handler_stack_ = NULL; +std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL; int ExceptionHandler::handler_stack_index_ = 0; pthread_mutex_t ExceptionHandler::handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER; -ExceptionHandler::ExceptionHandler(const string &dump_path, +ExceptionHandler::ExceptionHandler(const string& dump_path, FilterCallback filter, MinidumpCallback callback, - void *callback_context, + void* callback_context, bool install_handler) : filter_(filter), callback_(callback), @@ -79,7 +78,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path, pthread_mutex_lock(&handler_stack_mutex_); if (handler_stack_ == NULL) - handler_stack_ = new std::vector<ExceptionHandler *>; + handler_stack_ = new std::vector<ExceptionHandler*>; handler_stack_->push_back(this); pthread_mutex_unlock(&handler_stack_mutex_); } @@ -92,7 +91,7 @@ ExceptionHandler::~ExceptionHandler() { handler_stack_->pop_back(); } else { print_message1(2, "warning: removing Breakpad handler out of order\n"); - for (std::vector<ExceptionHandler *>::iterator iterator = + for (std::vector<ExceptionHandler*>::iterator iterator = handler_stack_->begin(); iterator != handler_stack_->end(); ++iterator) { @@ -116,9 +115,9 @@ bool ExceptionHandler::WriteMinidump() { } // static -bool ExceptionHandler::WriteMinidump(const string &dump_path, +bool ExceptionHandler::WriteMinidump(const string& dump_path, MinidumpCallback callback, - void *callback_context) { + void* callback_context) { ExceptionHandler handler(dump_path, NULL, callback, callback_context, false); return handler.InternalWriteMinidump(0, 0, NULL); @@ -166,7 +165,7 @@ void ExceptionHandler::TeardownAllHandlers() { // static void ExceptionHandler::HandleException(int signo) { -//void ExceptionHandler::HandleException(int signo, siginfo_t *sip, ucontext_t *sig_ctx) { +//void ExceptionHandler::HandleException(int signo, siginfo_t* sip, ucontext_t* sig_ctx) { // The context information about the signal is put on the stack of // the signal handler frame as value parameter. For some reasons, the // prototype of the handler doesn't declare this information as parameter, we @@ -181,14 +180,14 @@ void ExceptionHandler::HandleException(int signo) { uintptr_t current_ebp = (uintptr_t)_getfp(); pthread_mutex_lock(&handler_stack_mutex_); - ExceptionHandler *current_handler = + ExceptionHandler* current_handler = handler_stack_->at(handler_stack_->size() - ++handler_stack_index_); pthread_mutex_unlock(&handler_stack_mutex_); // Restore original handler. current_handler->TeardownHandler(signo); - ucontext_t *sig_ctx = NULL; + ucontext_t* sig_ctx = NULL; if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) { // if (current_handler->InternalWriteMinidump(signo, &sig_ctx)) { // Fully handled this exception, safe to exit. @@ -218,7 +217,7 @@ void ExceptionHandler::HandleException(int signo) { bool ExceptionHandler::InternalWriteMinidump(int signo, uintptr_t sighandler_ebp, - ucontext_t **sig_ctx) { + ucontext_t** sig_ctx) { if (filter_ && !filter_(callback_context_)) return false; diff --git a/src/client/solaris/handler/exception_handler.h b/src/client/solaris/handler/exception_handler.h index 4d72485f..04d140f0 100644 --- a/src/client/solaris/handler/exception_handler.h +++ b/src/client/solaris/handler/exception_handler.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -79,7 +78,7 @@ class ExceptionHandler { // attempting to write a minidump. If a FilterCallback returns false, // Breakpad will immediately report the exception as unhandled without // writing a minidump, allowing another handler the opportunity to handle it. - typedef bool (*FilterCallback)(void *context); + typedef bool (*FilterCallback)(void* context); // A callback function to run after the minidump has been written. // minidump_id is a unique id for the dump, so the minidump @@ -97,9 +96,9 @@ class ExceptionHandler { // should normally return the value of |succeeded|, or when they wish to // not report an exception of handled, false. Callbacks will rarely want to // return true directly (unless |succeeded| is true). - typedef bool (*MinidumpCallback)(const char *dump_path, - const char *minidump_id, - void *context, + typedef bool (*MinidumpCallback)(const char* dump_path, + const char* minidump_id, + void* context, bool succeeded); // Creates a new ExceptionHandler instance to handle writing minidumps. @@ -110,15 +109,15 @@ class ExceptionHandler { // If install_handler is true, then a minidump will be written whenever // an unhandled exception occurs. If it is false, minidumps will only // be written when WriteMinidump is called. - ExceptionHandler(const string &dump_path, + ExceptionHandler(const string& dump_path, FilterCallback filter, MinidumpCallback callback, - void *callback_context, + void* callback_context, bool install_handler); ~ExceptionHandler(); // Get and Set the minidump path. string dump_path() const { return dump_path_; } - void set_dump_path(const string &dump_path) { + void set_dump_path(const string& dump_path) { dump_path_ = dump_path; dump_path_c_ = dump_path_.c_str(); } @@ -129,9 +128,9 @@ class ExceptionHandler { // Convenience form of WriteMinidump which does not require an // ExceptionHandler instance. - static bool WriteMinidump(const string &dump_path, + static bool WriteMinidump(const string& dump_path, MinidumpCallback callback, - void *callback_context); + void* callback_context); private: // Setup crash handler. @@ -144,7 +143,7 @@ class ExceptionHandler { void TeardownAllHandlers(); // Runs the main loop for the exception handler thread. - static void* ExceptionHandlerThreadMain(void *lpParameter); + static void* ExceptionHandlerThreadMain(void* lpParameter); // Signal handler. static void HandleException(int signo); @@ -157,20 +156,20 @@ class ExceptionHandler { // for the second and third parameters if you are not calling // this from a signal handler. bool InternalWriteMinidump(int signo, uintptr_t sighandler_ebp, - ucontext_t **sig_ctx); + ucontext_t** sig_ctx); private: // The callbacks before and after writing the dump file. FilterCallback filter_; MinidumpCallback callback_; - void *callback_context_; + void* callback_context_; // The directory in which a minidump will be written, set by the dump_path // argument to the constructor, or set_dump_path. string dump_path_; // C style dump path. Keep this when setting dump path, since calling // c_str() of std::string when crashing may not be safe. - const char *dump_path_c_; + const char* dump_path_c_; // True if the ExceptionHandler installed an unhandled exception filter // when created (with an install_handler parameter set to true). @@ -183,7 +182,7 @@ class ExceptionHandler { // The global exception handler stack. This is need becuase there may exist // multiple ExceptionHandler instances in a process. Each will have itself // registered in this stack. - static std::vector<ExceptionHandler *> *handler_stack_; + static std::vector<ExceptionHandler*>* handler_stack_; // The index of the handler that should handle the next exception. static int handler_stack_index_; static pthread_mutex_t handler_stack_mutex_; @@ -192,8 +191,8 @@ class ExceptionHandler { MinidumpGenerator minidump_generator_; // disallow copy ctor and operator= - explicit ExceptionHandler(const ExceptionHandler &); - void operator=(const ExceptionHandler &); + explicit ExceptionHandler(const ExceptionHandler&); + void operator=(const ExceptionHandler&); }; } // namespace google_breakpad diff --git a/src/client/solaris/handler/exception_handler_test.cc b/src/client/solaris/handler/exception_handler_test.cc index 6bb8e18d..a84f2df1 100644 --- a/src/client/solaris/handler/exception_handler_test.cc +++ b/src/client/solaris/handler/exception_handler_test.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -49,7 +48,7 @@ static int foo2(int arg) { // Stack variable, used for debugging stack dumps. int c = 0xcccccccc; fprintf(stderr, "Thread trying to crash: %x\n", getpid()); - c = *reinterpret_cast<int *>(0x5); + c = *reinterpret_cast<int*>(0x5); return c; } @@ -60,7 +59,7 @@ static int foo(int arg) { return b; } -static void *thread_crash(void *) { +static void* thread_crash(void*) { // Stack variable, used for debugging stack dumps. int a = 0xaaaaaaaa; sleep(3); @@ -69,7 +68,7 @@ static void *thread_crash(void *) { return NULL; } -static void *thread_main(void *) { +static void* thread_main(void*) { while (!should_exit) sleep(1); return NULL; @@ -91,9 +90,9 @@ static void CreateThread(int num) { } // Callback when minidump written. -static bool MinidumpCallback(const char *dump_path, - const char *minidump_id, - void *context, +static bool MinidumpCallback(const char* dump_path, + const char* minidump_id, + void* context, bool succeeded) { int index = reinterpret_cast<int>(context); if (index == 0) { @@ -104,7 +103,7 @@ static bool MinidumpCallback(const char *dump_path, return false; } -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { int handler_index = 1; ExceptionHandler handler_ignore(".", NULL, MinidumpCallback, (void*)handler_index, true); diff --git a/src/client/solaris/handler/minidump_generator.cc b/src/client/solaris/handler/minidump_generator.cc index 7485025f..8f2f6ee2 100644 --- a/src/client/solaris/handler/minidump_generator.cc +++ b/src/client/solaris/handler/minidump_generator.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,10 +46,11 @@ namespace { using namespace google_breakpad; +using namespace google_breakpad::elf::FileID; // Argument for the writer function. struct WriterArgument { - MinidumpFileWriter *minidump_writer; + MinidumpFileWriter* minidump_writer; // Pid of the lwp who called WriteMinidumpToFile int requester_pid; @@ -73,15 +73,15 @@ struct WriterArgument { // User context when crash happens. Can be NULL if this is a requested dump. // This is actually an out parameter, but it will be filled in at the start // of the writer LWP. - ucontext_t *sig_ctx; + ucontext_t* sig_ctx; // Used to get information about the lwps. - SolarisLwp *lwp_lister; + SolarisLwp* lwp_lister; }; // Holding context information for the callback of finding the crashing lwp. struct FindCrashLwpContext { - const SolarisLwp *lwp_lister; + const SolarisLwp* lwp_lister; uintptr_t crashing_stack_bottom; int crashing_lwpid; @@ -96,11 +96,11 @@ struct FindCrashLwpContext { // It will compare the stack bottom of the provided lwp with the stack // bottom of the crashed lwp, it they are eqaul, this lwp is the one // who crashed. -bool IsLwpCrashedCallback(lwpstatus_t *lsp, void *context) { - FindCrashLwpContext *crashing_context = - static_cast<FindCrashLwpContext *>(context); - const SolarisLwp *lwp_lister = crashing_context->lwp_lister; - const prgregset_t *gregs = &(lsp->pr_reg); +bool IsLwpCrashedCallback(lwpstatus_t* lsp, void* context) { + FindCrashLwpContext* crashing_context = + static_cast<FindCrashLwpContext*>(context); + const SolarisLwp* lwp_lister = crashing_context->lwp_lister; + const prgregset_t* gregs = &(lsp->pr_reg); #if TARGET_CPU_SPARC uintptr_t last_ebp = (*gregs)[R_FP]; #elif TARGET_CPU_X86 @@ -121,7 +121,7 @@ bool IsLwpCrashedCallback(lwpstatus_t *lsp, void *context) { // This is done based on stack bottom comparing. int FindCrashingLwp(uintptr_t crashing_stack_bottom, int requester_pid, - const SolarisLwp *lwp_lister) { + const SolarisLwp* lwp_lister) { FindCrashLwpContext context; context.lwp_lister = lwp_lister; context.crashing_stack_bottom = crashing_stack_bottom; @@ -131,17 +131,17 @@ int FindCrashingLwp(uintptr_t crashing_stack_bottom, return context.crashing_lwpid; } -bool WriteLwpStack(const SolarisLwp *lwp_lister, +bool WriteLwpStack(const SolarisLwp* lwp_lister, uintptr_t last_esp, - UntypedMDRVA *memory, - MDMemoryDescriptor *loc) { + UntypedMDRVA* memory, + MDMemoryDescriptor* loc) { uintptr_t stack_bottom = lwp_lister->GetLwpStackBottom(last_esp); if (stack_bottom >= last_esp) { int size = stack_bottom - last_esp; if (size > 0) { if (!memory->Allocate(size)) return false; - memory->Copy(reinterpret_cast<void *>(last_esp), size); + memory->Copy(reinterpret_cast<void*>(last_esp), size); loc->start_of_memory_range = last_esp; loc->memory = memory->location(); } @@ -151,7 +151,7 @@ bool WriteLwpStack(const SolarisLwp *lwp_lister, } #if TARGET_CPU_SPARC -bool WriteContext(MDRawContextSPARC *context, ucontext_t *sig_ctx) { +bool WriteContext(MDRawContextSPARC* context, ucontext_t* sig_ctx) { assert(sig_ctx != NULL); int* regs = sig_ctx->uc_mcontext.gregs; context->context_flags = MD_CONTEXT_SPARC_FULL; @@ -170,13 +170,13 @@ bool WriteContext(MDRawContextSPARC *context, ucontext_t *sig_ctx) { for ( int i = 1 ; i < 16; ++i ) { context->g_r[i] = (uintptr_t)(sig_ctx->uc_mcontext.gregs[i + 3]); } - context->g_r[30] = (uintptr_t)(((struct frame *)context->g_r[14])->fr_savfp); + context->g_r[30] = (uintptr_t)(((struct frame*)context->g_r[14])->fr_savfp); return true; } -bool WriteContext(MDRawContextSPARC *context, prgregset_t regs, - prfpregset_t *fp_regs) { +bool WriteContext(MDRawContextSPARC* context, prgregset_t regs, + prfpregset_t* fp_regs) { if (!context || !regs) return false; @@ -195,8 +195,8 @@ bool WriteContext(MDRawContextSPARC *context, prgregset_t regs, return true; } #elif TARGET_CPU_X86 -bool WriteContext(MDRawContextX86 *context, prgregset_t regs, - prfpregset_t *fp_regs) { +bool WriteContext(MDRawContextX86* context, prgregset_t regs, + prfpregset_t* fp_regs) { if (!context || !regs) return false; @@ -228,10 +228,10 @@ bool WriteContext(MDRawContextX86 *context, prgregset_t regs, // signal. This makes the current stack not reliable, and our stack walker // won't figure out the whole call stack for this. So we write the stack at the // time of the crash into the minidump file, not the current stack. -bool WriteCrashedLwpStream(MinidumpFileWriter *minidump_writer, - const WriterArgument *writer_args, - const lwpstatus_t *lsp, - MDRawThread *lwp) { +bool WriteCrashedLwpStream(MinidumpFileWriter* minidump_writer, + const WriterArgument* writer_args, + const lwpstatus_t* lsp, + MDRawThread* lwp) { assert(writer_args->sig_ctx != NULL); lwp->thread_id = lsp->pr_lwpid; @@ -264,16 +264,16 @@ bool WriteCrashedLwpStream(MinidumpFileWriter *minidump_writer, lwp->thread_context = context.location(); memset(context.get(), 0, sizeof(MDRawContextX86)); return WriteContext(context.get(), - (int *)&writer_args->sig_ctx->uc_mcontext.gregs, + (int*)&writer_args->sig_ctx->uc_mcontext.gregs, &writer_args->sig_ctx->uc_mcontext.fpregs); #endif } -bool WriteLwpStream(MinidumpFileWriter *minidump_writer, - const SolarisLwp *lwp_lister, - const lwpstatus_t *lsp, MDRawThread *lwp) { +bool WriteLwpStream(MinidumpFileWriter* minidump_writer, + const SolarisLwp* lwp_lister, + const lwpstatus_t* lsp, MDRawThread* lwp) { prfpregset_t fp_regs = lsp->pr_fpreg; - const prgregset_t *gregs = &(lsp->pr_reg); + const prgregset_t* gregs = &(lsp->pr_reg); UntypedMDRVA memory(minidump_writer); #if TARGET_CPU_SPARC if (!WriteLwpStack(lwp_lister, @@ -306,10 +306,10 @@ bool WriteLwpStream(MinidumpFileWriter *minidump_writer, lwp->thread_context = context.location(); memset(context.get(), 0, sizeof(MDRawContextX86)); #endif /* TARGET_CPU_XXX */ - return WriteContext(context.get(), (int *)gregs, &fp_regs); + return WriteContext(context.get(), (int*)gregs, &fp_regs); } -bool WriteCPUInformation(MDRawSystemInfo *sys_info) { +bool WriteCPUInformation(MDRawSystemInfo* sys_info) { struct utsname uts; char *major, *minor, *build; @@ -337,8 +337,8 @@ bool WriteCPUInformation(MDRawSystemInfo *sys_info) { return true; } -bool WriteOSInformation(MinidumpFileWriter *minidump_writer, - MDRawSystemInfo *sys_info) { +bool WriteOSInformation(MinidumpFileWriter* minidump_writer, + MDRawSystemInfo* sys_info) { sys_info->platform_id = MD_OS_SOLARIS; struct utsname uts; @@ -346,7 +346,7 @@ bool WriteOSInformation(MinidumpFileWriter *minidump_writer, char os_version[512]; size_t space_left = sizeof(os_version); memset(os_version, 0, space_left); - const char *os_info_table[] = { + const char* os_info_table[] = { uts.sysname, uts.release, uts.version, @@ -354,7 +354,7 @@ bool WriteOSInformation(MinidumpFileWriter *minidump_writer, "OpenSolaris", NULL }; - for (const char **cur_os_info = os_info_table; + for (const char** cur_os_info = os_info_table; *cur_os_info != NULL; ++cur_os_info) { if (cur_os_info != os_info_table && space_left > 1) { @@ -379,21 +379,21 @@ bool WriteOSInformation(MinidumpFileWriter *minidump_writer, // Callback context for get writting lwp information. struct LwpInfoCallbackCtx { - MinidumpFileWriter *minidump_writer; - const WriterArgument *writer_args; - TypedMDRVA<MDRawThreadList> *list; + MinidumpFileWriter* minidump_writer; + const WriterArgument* writer_args; + TypedMDRVA<MDRawThreadList>* list; int lwp_index; }; -bool LwpInformationCallback(lwpstatus_t *lsp, void *context) { +bool LwpInformationCallback(lwpstatus_t* lsp, void* context) { bool success = true; - LwpInfoCallbackCtx *callback_context = - static_cast<LwpInfoCallbackCtx *>(context); + LwpInfoCallbackCtx* callback_context = + static_cast<LwpInfoCallbackCtx*>(context); // The current lwp is the one to handle the crash. Ignore it. if (lsp->pr_lwpid != pthread_self()) { - LwpInfoCallbackCtx *callback_context = - static_cast<LwpInfoCallbackCtx *>(context); + LwpInfoCallbackCtx* callback_context = + static_cast<LwpInfoCallbackCtx*>(context); MDRawThread lwp; memset(&lwp, 0, sizeof(MDRawThread)); @@ -417,11 +417,11 @@ bool LwpInformationCallback(lwpstatus_t *lsp, void *context) { return success; } -bool WriteLwpListStream(MinidumpFileWriter *minidump_writer, - const WriterArgument *writer_args, - MDRawDirectory *dir) { +bool WriteLwpListStream(MinidumpFileWriter* minidump_writer, + const WriterArgument* writer_args, + MDRawDirectory* dir) { // Get the lwp information. - const SolarisLwp *lwp_lister = writer_args->lwp_lister; + const SolarisLwp* lwp_lister = writer_args->lwp_lister; int lwp_count = lwp_lister->GetLwpCount(); if (lwp_count < 0) return false; @@ -444,14 +444,14 @@ bool WriteLwpListStream(MinidumpFileWriter *minidump_writer, return written == lwp_count; } -bool WriteCVRecord(MinidumpFileWriter *minidump_writer, - MDRawModule *module, - const char *module_path, - char *realname) { +bool WriteCVRecord(MinidumpFileWriter* minidump_writer, + MDRawModule* module, + const char* module_path, + char* realname) { TypedMDRVA<MDCVInfoPDB70> cv(minidump_writer); char path[PATH_MAX]; - const char *module_name = module_path ? module_path : "<Unknown>"; + const char* module_name = module_path ? module_path : "<Unknown>"; snprintf(path, sizeof(path), "/proc/self/object/%s", module_name); size_t module_name_length = strlen(realname); @@ -461,7 +461,7 @@ bool WriteCVRecord(MinidumpFileWriter *minidump_writer, return false; module->cv_record = cv.location(); - MDCVInfoPDB70 *cv_ptr = cv.get(); + MDCVInfoPDB70* cv_ptr = cv.get(); memset(cv_ptr, 0, sizeof(MDCVInfoPDB70)); cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; cv_ptr->age = 0; @@ -489,15 +489,15 @@ bool WriteCVRecord(MinidumpFileWriter *minidump_writer, } struct ModuleInfoCallbackCtx { - MinidumpFileWriter *minidump_writer; - const WriterArgument *writer_args; - TypedMDRVA<MDRawModuleList> *list; + MinidumpFileWriter* minidump_writer; + const WriterArgument* writer_args; + TypedMDRVA<MDRawModuleList>* list; int module_index; }; -bool ModuleInfoCallback(const ModuleInfo &module_info, void *context) { - ModuleInfoCallbackCtx *callback_context = - static_cast<ModuleInfoCallbackCtx *>(context); +bool ModuleInfoCallback(const ModuleInfo& module_info, void* context) { + ModuleInfoCallbackCtx* callback_context = + static_cast<ModuleInfoCallbackCtx*>(context); // Skip those modules without name, or those that are not modules. if (strlen(module_info.name) == 0) return true; @@ -507,7 +507,7 @@ bool ModuleInfoCallback(const ModuleInfo &module_info, void *context) { MDLocationDescriptor loc; char path[PATH_MAX]; char buf[PATH_MAX]; - char *realname; + char* realname; int count; snprintf(path, sizeof (path), "/proc/self/path/%s", module_info.name); @@ -535,9 +535,9 @@ bool ModuleInfoCallback(const ModuleInfo &module_info, void *context) { return true; } -bool WriteModuleListStream(MinidumpFileWriter *minidump_writer, - const WriterArgument *writer_args, - MDRawDirectory *dir) { +bool WriteModuleListStream(MinidumpFileWriter* minidump_writer, + const WriterArgument* writer_args, + MDRawDirectory* dir) { TypedMDRVA<MDRawModuleList> list(minidump_writer); int module_count = writer_args->lwp_lister->GetModuleCount(); @@ -558,9 +558,9 @@ bool WriteModuleListStream(MinidumpFileWriter *minidump_writer, return writer_args->lwp_lister->ListModules(&callback) == module_count; } -bool WriteSystemInfoStream(MinidumpFileWriter *minidump_writer, - const WriterArgument *writer_args, - MDRawDirectory *dir) { +bool WriteSystemInfoStream(MinidumpFileWriter* minidump_writer, + const WriterArgument* writer_args, + MDRawDirectory* dir) { TypedMDRVA<MDRawSystemInfo> sys_info(minidump_writer); if (!sys_info.Allocate()) @@ -573,9 +573,9 @@ bool WriteSystemInfoStream(MinidumpFileWriter *minidump_writer, WriteOSInformation(minidump_writer, sys_info.get()); } -bool WriteExceptionStream(MinidumpFileWriter *minidump_writer, - const WriterArgument *writer_args, - MDRawDirectory *dir) { +bool WriteExceptionStream(MinidumpFileWriter* minidump_writer, + const WriterArgument* writer_args, + MDRawDirectory* dir) { // This happenes when this is not a crash, but a requested dump. if (writer_args->sig_ctx == NULL) return false; @@ -620,14 +620,14 @@ bool WriteExceptionStream(MinidumpFileWriter *minidump_writer, exception.get()->thread_context = context.location(); memset(context.get(), 0, sizeof(MDRawContextX86)); return WriteContext(context.get(), - (int *)&writer_args->sig_ctx->uc_mcontext.gregs, + (int*)&writer_args->sig_ctx->uc_mcontext.gregs, NULL); #endif } -bool WriteMiscInfoStream(MinidumpFileWriter *minidump_writer, - const WriterArgument *writer_args, - MDRawDirectory *dir) { +bool WriteMiscInfoStream(MinidumpFileWriter* minidump_writer, + const WriterArgument* writer_args, + MDRawDirectory* dir) { TypedMDRVA<MDRawMiscInfo> info(minidump_writer); if (!info.Allocate()) @@ -642,9 +642,9 @@ bool WriteMiscInfoStream(MinidumpFileWriter *minidump_writer, return true; } -bool WriteBreakpadInfoStream(MinidumpFileWriter *minidump_writer, - const WriterArgument *writer_args, - MDRawDirectory *dir) { +bool WriteBreakpadInfoStream(MinidumpFileWriter* minidump_writer, + const WriterArgument* writer_args, + MDRawDirectory* dir) { TypedMDRVA<MDRawBreakpadInfo> info(minidump_writer); if (!info.Allocate()) @@ -662,16 +662,16 @@ bool WriteBreakpadInfoStream(MinidumpFileWriter *minidump_writer, class AutoLwpResumer { public: - AutoLwpResumer(SolarisLwp *lwp) : lwp_(lwp) {} + AutoLwpResumer(SolarisLwp* lwp) : lwp_(lwp) {} ~AutoLwpResumer() { lwp_->ControlAllLwps(false); } private: - SolarisLwp *lwp_; + SolarisLwp* lwp_; }; // Prototype of writer functions. -typedef bool (*WriteStreamFN)(MinidumpFileWriter *, - const WriterArgument *, - MDRawDirectory *); +typedef bool (*WriteStreamFN)(MinidumpFileWriter*, + const WriterArgument*, + MDRawDirectory*); // Function table to writer a full minidump. const WriteStreamFN writers[] = { @@ -684,9 +684,9 @@ const WriteStreamFN writers[] = { }; // Will call each writer function in the writers table. -//void* MinidumpGenerator::Write(void *argument) { -void* Write(void *argument) { - WriterArgument *writer_args = static_cast<WriterArgument *>(argument); +//void* MinidumpGenerator::Write(void* argument) { +void* Write(void* argument) { + WriterArgument* writer_args = static_cast<WriterArgument*>(argument); if (!writer_args->lwp_lister->ControlAllLwps(true)) return NULL; @@ -712,7 +712,7 @@ void* Write(void *argument) { writer_args->crashed_lwpid = crashed_lwpid; } - MinidumpFileWriter *minidump_writer = writer_args->minidump_writer; + MinidumpFileWriter* minidump_writer = writer_args->minidump_writer; TypedMDRVA<MDRawHeader> header(minidump_writer); TypedMDRVA<MDRawDirectory> dir(minidump_writer); if (!header.Allocate()) @@ -750,10 +750,10 @@ MinidumpGenerator::~MinidumpGenerator() { // Write minidump into file. // It runs in a different thread from the crashing thread. -bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname, +bool MinidumpGenerator::WriteMinidumpToFile(const char* file_pathname, int signo, uintptr_t sighandler_ebp, - ucontext_t **sig_ctx) const { + ucontext_t** sig_ctx) const { // The exception handler thread. pthread_t handler_thread; @@ -775,7 +775,7 @@ bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname, argument.sighandler_ebp = sighandler_ebp; argument.sig_ctx = NULL; - pthread_create(&handler_thread, NULL, Write, (void *)&argument); + pthread_create(&handler_thread, NULL, Write, (void*)&argument); pthread_join(handler_thread, NULL); return true; } diff --git a/src/client/solaris/handler/minidump_generator.h b/src/client/solaris/handler/minidump_generator.h index 882f9e1d..7d2adbce 100644 --- a/src/client/solaris/handler/minidump_generator.h +++ b/src/client/solaris/handler/minidump_generator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -48,10 +47,10 @@ namespace google_breakpad { // class MinidumpGenerator { // Callback run for writing lwp information in the process. - friend bool LwpInformationCallback(lwpstatus_t *lsp, void *context); + friend bool LwpInformationCallback(lwpstatus_t* lsp, void* context); // Callback run for writing module information in the process. - friend bool ModuleInfoCallback(const ModuleInfo &module_info, void *context); + friend bool ModuleInfoCallback(const ModuleInfo& module_info, void* context); public: MinidumpGenerator(); @@ -59,10 +58,10 @@ class MinidumpGenerator { ~MinidumpGenerator(); // Write minidump. - bool WriteMinidumpToFile(const char *file_pathname, + bool WriteMinidumpToFile(const char* file_pathname, int signo, uintptr_t sighandler_ebp, - ucontext_t **sig_ctx) const; + ucontext_t** sig_ctx) const; }; } // namespace google_breakpad diff --git a/src/client/solaris/handler/minidump_test.cc b/src/client/solaris/handler/minidump_test.cc index 33302d86..00f8d9a5 100644 --- a/src/client/solaris/handler/minidump_test.cc +++ b/src/client/solaris/handler/minidump_test.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,7 +39,7 @@ using google_breakpad::MinidumpGenerator; static bool doneWritingReport = false; -static void *Reporter(void *) { +static void* Reporter(void*) { char buffer[PATH_MAX]; MinidumpGenerator md; diff --git a/src/client/solaris/handler/solaris_lwp.cc b/src/client/solaris/handler/solaris_lwp.cc index 0148997a..d707a5b3 100644 --- a/src/client/solaris/handler/solaris_lwp.cc +++ b/src/client/solaris/handler/solaris_lwp.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -69,10 +68,10 @@ struct AddressValidatingContext { }; // Convert from string to int. -static bool LocalAtoi(char *s, int *r) { +static bool LocalAtoi(char* s, int* r) { assert(s != NULL); assert(r != NULL); - char *endptr = NULL; + char* endptr = NULL; int ret = strtol(s, &endptr, 10); if (endptr == s) return false; @@ -82,10 +81,10 @@ static bool LocalAtoi(char *s, int *r) { // Callback invoked for each mapped module. // It uses the module's adderss range to validate the address. -static bool AddressNotInModuleCallback(const ModuleInfo &module_info, - void *context) { - AddressValidatingContext *addr = - reinterpret_cast<AddressValidatingContext *>(context); +static bool AddressNotInModuleCallback(const ModuleInfo& module_info, + void* context) { + AddressValidatingContext* addr = + reinterpret_cast<AddressValidatingContext*>(context); if (addr->is_mapped = ((module_info.start_addr > 0) && (addr->address >= module_info.start_addr) && (addr->address <= module_info.start_addr + @@ -97,16 +96,16 @@ static bool AddressNotInModuleCallback(const ModuleInfo &module_info, } static int IterateLwpAll(int pid, - CallbackParam<LwpidCallback> *callback_param) { + CallbackParam<LwpidCallback>* callback_param) { char lwp_path[40]; - DIR *dir; + DIR* dir; int count = 0; snprintf(lwp_path, sizeof (lwp_path), "/proc/%d/lwp", (int)pid); if ((dir = opendir(lwp_path)) == NULL) return -1; - struct dirent *entry = NULL; + struct dirent* entry = NULL; while ((entry = readdir(dir)) != NULL) { if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) { @@ -128,22 +127,22 @@ static int IterateLwpAll(int pid, } #if defined(__i386) && !defined(NO_FRAME_POINTER) -void *GetNextFrame(void **last_ebp) { - void *sp = *last_ebp; +void* GetNextFrame(void** last_ebp) { + void* sp = *last_ebp; if ((unsigned long)sp == (unsigned long)last_ebp) return NULL; - if ((unsigned long)sp & (sizeof(void *) - 1)) + if ((unsigned long)sp & (sizeof(void*) - 1)) return NULL; if ((unsigned long)sp - (unsigned long)last_ebp > 100000) return NULL; return sp; } #elif defined(__sparc) -void *GetNextFrame(void *last_ebp) { - return reinterpret_cast<struct frame *>(last_ebp)->fr_savfp; +void* GetNextFrame(void* last_ebp) { + return reinterpret_cast<struct frame*>(last_ebp)->fr_savfp; } #else -void *GetNextFrame(void **last_ebp) { +void* GetNextFrame(void** last_ebp) { return reinterpret_cast<void*>(last_ebp); } #endif @@ -159,12 +158,12 @@ class AutoCloser { // Control the execution of the lwp. // Suspend/Resume lwp based on the value of context. -static bool ControlLwp(int lwpid, void *context) { +static bool ControlLwp(int lwpid, void* context) { // The current thread is the one to handle the crash. Ignore it. if (lwpid != pthread_self()) { int ctlfd; char procname[PATH_MAX]; - bool suspend = *(bool *)context; + bool suspend = *(bool*)context; // Open the /proc/$pid/lwp/$lwpid/lwpctl files snprintf(procname, sizeof (procname), "/proc/self/lwp/%d/lwpctl", lwpid); @@ -193,7 +192,7 @@ static bool ControlLwp(int lwpid, void *context) { * prheader_t at the start (/proc/$pid/lstatus or /proc/$pid/lpsinfo). * Return true on success. */ -static bool read_lfile(int pid, const char *lname, prheader_t *lhp) { +static bool read_lfile(int pid, const char* lname, prheader_t* lhp) { char lpath[PATH_MAX]; struct stat statb; int fd; @@ -242,14 +241,14 @@ int SolarisLwp::GetLwpCount() const { } int SolarisLwp::Lwp_iter_all(int pid, - CallbackParam<LwpCallback> *callback_param) const { - lwpstatus_t *Lsp; - lwpstatus_t *sp; + CallbackParam<LwpCallback>* callback_param) const { + lwpstatus_t* Lsp; + lwpstatus_t* sp; prheader_t lphp[HEADER_MAX]; prheader_t lhp[HEADER_MAX]; - prheader_t *Lphp = lphp; - prheader_t *Lhp = lhp; - lwpsinfo_t *Lpsp; + prheader_t* Lphp = lphp; + prheader_t* Lhp = lhp; + lwpsinfo_t* Lpsp; long nstat; long ninfo; int rv = 0; @@ -264,13 +263,13 @@ int SolarisLwp::Lwp_iter_all(int pid, return -1; } - Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1); - Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1); + Lsp = (lwpstatus_t*)(uintptr_t)(Lhp + 1); + Lpsp = (lwpsinfo_t*)(uintptr_t)(Lphp + 1); for (ninfo = Lphp->pr_nent; ninfo != 0; --ninfo) { if (Lpsp->pr_sname != 'Z') { sp = Lsp; - Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize); + Lsp = (lwpstatus_t*)((uintptr_t)Lsp + Lhp->pr_entsize); } else { sp = NULL; } @@ -278,7 +277,7 @@ int SolarisLwp::Lwp_iter_all(int pid, !(callback_param->call_back)(sp, callback_param->context)) break; ++rv; - Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize); + Lpsp = (lwpsinfo_t*)((uintptr_t)Lpsp + Lphp->pr_entsize); } return rv; @@ -298,12 +297,12 @@ int SolarisLwp::GetModuleCount() const { } int SolarisLwp::ListModules( - CallbackParam<ModuleCallback> *callback_param) const { - const char *maps_path = "/proc/self/map"; + CallbackParam<ModuleCallback>* callback_param) const { + const char* maps_path = "/proc/self/map"; struct stat status; int fd = 0, num; prmap_t map_array[MAP_MAX]; - prmap_t *maps = map_array; + prmap_t* maps = map_array; size_t size; if ((fd = open(maps_path, O_RDONLY)) == -1) { @@ -326,12 +325,12 @@ int SolarisLwp::ListModules( return -1; } - if (read(fd, (void *)maps, size) < 0) { + if (read(fd, (void*)maps, size) < 0) { print_message2(2, "failed to read %d\n", fd); return -1; } - prmap_t *_maps; + prmap_t* _maps; int _num; int module_count = 0; @@ -345,7 +344,7 @@ int SolarisLwp::ListModules( */ for (_num = 0, _maps = maps; _num < num; ++_num, ++_maps) { ModuleInfo module; - char *name = _maps->pr_mapname; + char* name = _maps->pr_mapname; memset(&module, 0, sizeof (module)); module.start_addr = _maps->pr_vaddr; @@ -403,7 +402,7 @@ bool SolarisLwp::IsAddressMapped(uintptr_t address) const { // The Solaris stack looks like this: // http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libproc/common/Pstack.c#81 bool SolarisLwp::FindSigContext(uintptr_t sighandler_ebp, - ucontext_t **sig_ctx) { + ucontext_t** sig_ctx) { uintptr_t previous_ebp; uintptr_t sig_ebp; const int MAX_STACK_DEPTH = 50; @@ -416,7 +415,7 @@ bool SolarisLwp::FindSigContext(uintptr_t sighandler_ebp, *sig_ctx = reinterpret_cast<ucontext_t*>(sighandler_ebp + sizeof (struct frame)); uintptr_t sig_esp = (*sig_ctx)->uc_mcontext.gregs[REG_O6]; if (sig_esp < previous_ebp && sig_esp > sighandler_ebp) - sig_ebp = (uintptr_t)(((struct frame *)sig_esp)->fr_savfp); + sig_ebp = (uintptr_t)(((struct frame*)sig_esp)->fr_savfp); #elif TARGET_CPU_X86 previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame( diff --git a/src/client/solaris/handler/solaris_lwp.h b/src/client/solaris/handler/solaris_lwp.h index 0914cfcd..f27d6b74 100644 --- a/src/client/solaris/handler/solaris_lwp.h +++ b/src/client/solaris/handler/solaris_lwp.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -70,17 +69,17 @@ struct ModuleInfo { // A callback to run when getting a lwp in the process. // Return true will go on to the next lwp while return false will stop the // iteration. -typedef bool (*LwpCallback)(lwpstatus_t* lsp, void *context); +typedef bool (*LwpCallback)(lwpstatus_t* lsp, void* context); // A callback to run when a new module is found in the process. // Return true will go on to the next module while return false will stop the // iteration. -typedef bool (*ModuleCallback)(const ModuleInfo &module_info, void *context); +typedef bool (*ModuleCallback)(const ModuleInfo& module_info, void* context); // A callback to run when getting a lwpid in the process. // Return true will go on to the next lwp while return false will stop the // iteration. -typedef bool (*LwpidCallback)(int lwpid, void *context); +typedef bool (*LwpidCallback)(int lwpid, void* context); // Holding the callback information. template<class CallbackFunc> @@ -88,12 +87,12 @@ struct CallbackParam { // Callback function address. CallbackFunc call_back; // Callback context; - void *context; + void* context; CallbackParam() : call_back(NULL), context(NULL) { } - CallbackParam(CallbackFunc func, void *func_context) : + CallbackParam(CallbackFunc func, void* func_context) : call_back(func), context(func_context) { } }; @@ -129,7 +128,7 @@ class SolarisLwp { // Whenever there is a lwp found, the callback will be invoked to process // the information. // Return the callback return value or -1 on error. - int Lwp_iter_all(int pid, CallbackParam<LwpCallback> *callback_param) const; + int Lwp_iter_all(int pid, CallbackParam<LwpCallback>* callback_param) const; // Get the module count of the current process. int GetModuleCount() const; @@ -138,13 +137,13 @@ class SolarisLwp { // Whenever a module is found, the callback will be invoked to process the // information. // Return how may modules are found. - int ListModules(CallbackParam<ModuleCallback> *callback_param) const; + int ListModules(CallbackParam<ModuleCallback>* callback_param) const; // Get the bottom of the stack from esp. uintptr_t GetLwpStackBottom(uintptr_t current_esp) const; // Finds a signal context on the stack given the ebp of our signal handler. - bool FindSigContext(uintptr_t sighandler_ebp, ucontext_t **sig_ctx); + bool FindSigContext(uintptr_t sighandler_ebp, ucontext_t** sig_ctx); private: // Check if the address is a valid virtual address. diff --git a/src/client/windows/breakpad_client.gyp b/src/client/windows/breakpad_client.gyp deleted file mode 100644 index 64797534..00000000 --- a/src/client/windows/breakpad_client.gyp +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 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. - -{ - 'includes': [ - '../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'build_all', - 'type': 'none', - 'dependencies': [ - './crash_generation/crash_generation.gyp:*', - './handler/exception_handler.gyp:*', - './sender/crash_report_sender.gyp:*', - './unittests/client_tests.gyp:*', - './unittests/testing.gyp:*', - './tests/crash_generation_app/crash_generation_app.gyp:*', - ] - }, - { - 'target_name': 'common', - 'type': 'static_library', - 'include_dirs': [ - '<(DEPTH)', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(DEPTH)', - ] - }, - 'sources': [ - '<(DEPTH)/common/windows/guid_string.cc', - '<(DEPTH)/common/windows/guid_string.h', - '<(DEPTH)/common/windows/http_upload.cc', - '<(DEPTH)/common/windows/http_upload.h', - '<(DEPTH)/common/windows/string_utils.cc', - ] - } - ] -} diff --git a/src/client/windows/common/auto_critical_section.h b/src/client/windows/common/auto_critical_section.h index 3fd4b9b7..75ed4b9b 100644 --- a/src/client/windows/common/auto_critical_section.h +++ b/src/client/windows/common/auto_critical_section.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/common/ipc_protocol.h b/src/client/windows/common/ipc_protocol.h index c7486819..7e0c24e3 100644 --- a/src/client/windows/common/ipc_protocol.h +++ b/src/client/windows/common/ipc_protocol.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/crash_generation/client_info.cc b/src/client/windows/crash_generation/client_info.cc index ed312638..f0a4b911 100644 --- a/src/client/windows/crash_generation/client_info.cc +++ b/src/client/windows/crash_generation/client_info.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/crash_generation/client_info.h b/src/client/windows/crash_generation/client_info.h index 6a8fba31..1c9cd3c3 100644 --- a/src/client/windows/crash_generation/client_info.h +++ b/src/client/windows/crash_generation/client_info.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/crash_generation/crash_generation.gyp b/src/client/windows/crash_generation/crash_generation.gyp deleted file mode 100644 index ba343768..00000000 --- a/src/client/windows/crash_generation/crash_generation.gyp +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'crash_generation_server', - 'type': 'static_library', - 'sources': [ - 'client_info.cc', - 'crash_generation_server.cc', - 'minidump_generator.cc', - 'client_info.h', - 'crash_generation_client.h', - 'crash_generation_server.h', - 'minidump_generator.h', - ], - 'dependencies': [ - '../breakpad_client.gyp:common' - ], - }, - { - 'target_name': 'crash_generation_client', - 'type': 'static_library', - 'include_dirs': [ - '<(DEPTH)', - ], - 'sources': [ - 'crash_generation_client.h', - 'crash_generation_client.cc', - 'crash_generation_server.h', - ], - }, - ], -} diff --git a/src/client/windows/crash_generation/crash_generation_client.cc b/src/client/windows/crash_generation/crash_generation_client.cc index 3ba5d4e4..d6da09eb 100644 --- a/src/client/windows/crash_generation/crash_generation_client.cc +++ b/src/client/windows/crash_generation/crash_generation_client.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/crash_generation/crash_generation_client.h b/src/client/windows/crash_generation/crash_generation_client.h index 457f7319..f912bf5f 100644 --- a/src/client/windows/crash_generation/crash_generation_client.h +++ b/src/client/windows/crash_generation/crash_generation_client.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/crash_generation/crash_generation_server.cc b/src/client/windows/crash_generation/crash_generation_server.cc index 0af213ba..bf80ee9c 100644 --- a/src/client/windows/crash_generation/crash_generation_server.cc +++ b/src/client/windows/crash_generation/crash_generation_server.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/crash_generation/crash_generation_server.h b/src/client/windows/crash_generation/crash_generation_server.h index 0ea90e51..74275a74 100644 --- a/src/client/windows/crash_generation/crash_generation_server.h +++ b/src/client/windows/crash_generation/crash_generation_server.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/crash_generation/minidump_generator.cc b/src/client/windows/crash_generation/minidump_generator.cc index 573c2786..523db27a 100644 --- a/src/client/windows/crash_generation/minidump_generator.cc +++ b/src/client/windows/crash_generation/minidump_generator.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -432,7 +431,7 @@ bool MinidumpGenerator::WriteMinidump() { full_dump_file_, static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpNormal)) | MiniDumpWithHandleData), - exception_pointers_ ? &dump_exception_info : NULL, + dump_exception_pointers, &user_streams, NULL) != FALSE; } @@ -449,7 +448,7 @@ bool MinidumpGenerator::WriteMinidump() { dump_file_, static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpWithFullMemory)) | MiniDumpNormal), - exception_pointers_ ? &dump_exception_info : NULL, + dump_exception_pointers, &user_streams, callback_info_) != FALSE; diff --git a/src/client/windows/crash_generation/minidump_generator.h b/src/client/windows/crash_generation/minidump_generator.h index a707c0bb..f960c5dc 100644 --- a/src/client/windows/crash_generation/minidump_generator.h +++ b/src/client/windows/crash_generation/minidump_generator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/handler/exception_handler.cc b/src/client/windows/handler/exception_handler.cc index ad45b200..3b3938aa 100644 --- a/src/client/windows/handler/exception_handler.cc +++ b/src/client/windows/handler/exception_handler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -118,7 +117,7 @@ ExceptionHandler::ExceptionHandler( NULL); // custom_info - not used } -ExceptionHandler::ExceptionHandler(const wstring &dump_path, +ExceptionHandler::ExceptionHandler(const wstring& dump_path, FilterCallback filter, MinidumpCallback callback, void* callback_context, @@ -383,7 +382,7 @@ bool ExceptionHandler::RequestUpload(DWORD crash_id) { // static DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { - ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter); + ExceptionHandler* self = reinterpret_cast<ExceptionHandler*>(lpParameter); assert(self); assert(self->handler_start_semaphore_ != NULL); assert(self->handler_finish_semaphore_ != NULL); @@ -765,7 +764,7 @@ bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) { } // static -bool ExceptionHandler::WriteMinidump(const wstring &dump_path, +bool ExceptionHandler::WriteMinidump(const wstring& dump_path, MinidumpCallback callback, void* callback_context, MINIDUMP_TYPE dump_type) { diff --git a/src/client/windows/handler/exception_handler.gyp b/src/client/windows/handler/exception_handler.gyp deleted file mode 100644 index c5733277..00000000 --- a/src/client/windows/handler/exception_handler.gyp +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'exception_handler', - 'type': 'static_library', - 'sources': [ - "exception_handler.cc", - "exception_handler.h", - ], - 'dependencies': [ - '../breakpad_client.gyp:common', - '../crash_generation/crash_generation.gyp:crash_generation_server', - ] - }, - ], -} diff --git a/src/client/windows/handler/exception_handler.h b/src/client/windows/handler/exception_handler.h index 11babe51..963572bf 100644 --- a/src/client/windows/handler/exception_handler.h +++ b/src/client/windows/handler/exception_handler.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -218,7 +217,7 @@ class ExceptionHandler { // Get and set the minidump path. wstring dump_path() const { return dump_path_; } - void set_dump_path(const wstring &dump_path) { + void set_dump_path(const wstring& dump_path) { dump_path_ = dump_path; dump_path_c_ = dump_path_.c_str(); UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. @@ -237,7 +236,7 @@ class ExceptionHandler { // Convenience form of WriteMinidump which does not require an // ExceptionHandler instance. - static bool WriteMinidump(const wstring &dump_path, + static bool WriteMinidump(const wstring& dump_path, MinidumpCallback callback, void* callback_context, MINIDUMP_TYPE dump_type = MiniDumpNormal); @@ -513,8 +512,8 @@ class ExceptionHandler { static volatile LONG instance_count_; // disallow copy ctor and operator= - explicit ExceptionHandler(const ExceptionHandler &); - void operator=(const ExceptionHandler &); + explicit ExceptionHandler(const ExceptionHandler&); + void operator=(const ExceptionHandler&); }; } // namespace google_breakpad diff --git a/src/client/windows/sender/crash_report_sender.cc b/src/client/windows/sender/crash_report_sender.cc index eb2b422a..27a7ec39 100644 --- a/src/client/windows/sender/crash_report_sender.cc +++ b/src/client/windows/sender/crash_report_sender.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,12 +44,12 @@ namespace google_breakpad { static const char kCheckpointSignature[] = "GBP1\n"; -CrashReportSender::CrashReportSender(const wstring &checkpoint_file) +CrashReportSender::CrashReportSender(const wstring& checkpoint_file) : checkpoint_file_(checkpoint_file), max_reports_per_day_(-1), last_sent_date_(-1), reports_sent_(0) { - FILE *fd; + FILE* fd; if (OpenCheckpointFile(L"r", &fd) == 0) { ReadCheckpoint(fd); fclose(fd); @@ -58,8 +57,8 @@ CrashReportSender::CrashReportSender(const wstring &checkpoint_file) } ReportResult CrashReportSender::SendCrashReport( - const wstring &url, const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, wstring *report_code) { + const wstring& url, const map<wstring, wstring>& parameters, + const map<wstring, wstring>& files, wstring* report_code) { int today = GetCurrentDate(); if (today == last_sent_date_ && max_reports_per_day_ != -1 && @@ -82,7 +81,7 @@ ReportResult CrashReportSender::SendCrashReport( } } -void CrashReportSender::ReadCheckpoint(FILE *fd) { +void CrashReportSender::ReadCheckpoint(FILE* fd) { char buf[128]; if (!fgets(buf, sizeof(buf), fd) || strcmp(buf, kCheckpointSignature) != 0) { @@ -108,7 +107,7 @@ void CrashReportSender::ReportSent(int today) { ++reports_sent_; // Update the checkpoint file - FILE *fd; + FILE* fd; if (OpenCheckpointFile(L"w", &fd) == 0) { fputs(kCheckpointSignature, fd); fprintf(fd, "%d\n", last_sent_date_); @@ -124,7 +123,7 @@ int CrashReportSender::GetCurrentDate() const { system_time.wDay; } -int CrashReportSender::OpenCheckpointFile(const wchar_t *mode, FILE **fd) { +int CrashReportSender::OpenCheckpointFile(const wchar_t* mode, FILE** fd) { if (checkpoint_file_.empty()) { return ENOENT; } diff --git a/src/client/windows/sender/crash_report_sender.gyp b/src/client/windows/sender/crash_report_sender.gyp deleted file mode 100644 index dc8583a0..00000000 --- a/src/client/windows/sender/crash_report_sender.gyp +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'crash_report_sender', - 'type': 'static_library', - 'sources': [ - 'crash_report_sender.cc', - 'crash_report_sender.h', - ], - 'dependencies': [ - '../breakpad_client.gyp:common' - ], - }, - ], -} diff --git a/src/client/windows/sender/crash_report_sender.h b/src/client/windows/sender/crash_report_sender.h index 7786cc69..758adbb4 100644 --- a/src/client/windows/sender/crash_report_sender.h +++ b/src/client/windows/sender/crash_report_sender.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -65,7 +64,7 @@ class CrashReportSender { // If checkpoint_file is non-empty, breakpad will persist crash report // state to this file. A checkpoint file is required for // set_max_reports_per_day() to function properly. - explicit CrashReportSender(const wstring &checkpoint_file); + explicit CrashReportSender(const wstring& checkpoint_file); ~CrashReportSender() {} // Sets the maximum number of crash reports that will be sent in a 24-hour @@ -87,14 +86,14 @@ class CrashReportSender { // the return value is RESULT_SUCCEEDED), a code uniquely identifying the // report will be returned in report_code. // (Otherwise, report_code will be unchanged.) - ReportResult SendCrashReport(const wstring &url, - const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - wstring *report_code); + ReportResult SendCrashReport(const wstring& url, + const map<wstring, wstring>& parameters, + const map<wstring, wstring>& files, + wstring* report_code); private: // Reads persistent state from a checkpoint file. - void ReadCheckpoint(FILE *fd); + void ReadCheckpoint(FILE* fd); // Called when a new report has been sent, to update the checkpoint state. void ReportSent(int today); @@ -104,7 +103,7 @@ class CrashReportSender { // Opens the checkpoint file with the specified mode. // Returns zero on success, or an error code on failure. - int OpenCheckpointFile(const wchar_t *mode, FILE **fd); + int OpenCheckpointFile(const wchar_t* mode, FILE** fd); wstring checkpoint_file_; int max_reports_per_day_; @@ -114,8 +113,8 @@ class CrashReportSender { int reports_sent_; // Disallow copy constructor and operator= - explicit CrashReportSender(const CrashReportSender &); - void operator=(const CrashReportSender &); + explicit CrashReportSender(const CrashReportSender&); + void operator=(const CrashReportSender&); }; } // namespace google_breakpad diff --git a/src/client/windows/tests/crash_generation_app/abstract_class.cc b/src/client/windows/tests/crash_generation_app/abstract_class.cc index 32f78f2b..28b8ee14 100644 --- a/src/client/windows/tests/crash_generation_app/abstract_class.cc +++ b/src/client/windows/tests/crash_generation_app/abstract_class.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/tests/crash_generation_app/abstract_class.h b/src/client/windows/tests/crash_generation_app/abstract_class.h index e3f2a4f3..c996a216 100644 --- a/src/client/windows/tests/crash_generation_app/abstract_class.h +++ b/src/client/windows/tests/crash_generation_app/abstract_class.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/tests/crash_generation_app/crash_generation_app.cc b/src/client/windows/tests/crash_generation_app/crash_generation_app.cc index 0d837e52..883afcc6 100644 --- a/src/client/windows/tests/crash_generation_app/crash_generation_app.cc +++ b/src/client/windows/tests/crash_generation_app/crash_generation_app.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/tests/crash_generation_app/crash_generation_app.gyp b/src/client/windows/tests/crash_generation_app/crash_generation_app.gyp deleted file mode 100644 index 3ce307da..00000000 --- a/src/client/windows/tests/crash_generation_app/crash_generation_app.gyp +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 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. - -{ - 'includes': [ - '../../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'crash_generation_app', - 'type': 'executable', - 'sources': [ - 'abstract_class.cc', - 'abstract_class.h', - 'crash_generation_app.cc', - 'crash_generation_app.h', - 'crash_generation_app.ico', - 'crash_generation_app.rc', - 'resource.h', - 'small.ico', - ], - 'libraries': [ - 'user32.lib', - ], - 'dependencies': [ - '../../breakpad_client.gyp:common', - '../../crash_generation/crash_generation.gyp:crash_generation_server', - '../../crash_generation/crash_generation.gyp:crash_generation_client', - '../../handler/exception_handler.gyp:exception_handler', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'SubSystem': '2', # Windows Subsystem as opposed to a console app - }, - }, - } - ] -} diff --git a/src/client/windows/tests/crash_generation_app/crash_generation_app.h b/src/client/windows/tests/crash_generation_app/crash_generation_app.h index 4d3bb6eb..1d1deea4 100644 --- a/src/client/windows/tests/crash_generation_app/crash_generation_app.h +++ b/src/client/windows/tests/crash_generation_app/crash_generation_app.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/tests/crash_generation_app/resource.h b/src/client/windows/tests/crash_generation_app/resource.h index 8c7f6570..e9120826 100644 --- a/src/client/windows/tests/crash_generation_app/resource.h +++ b/src/client/windows/tests/crash_generation_app/resource.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/unittests/client_tests.gyp b/src/client/windows/unittests/client_tests.gyp deleted file mode 100644 index 768f8fd8..00000000 --- a/src/client/windows/unittests/client_tests.gyp +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'client_tests', - 'type': 'executable', - 'sources': [ - 'exception_handler_test.h', - 'exception_handler_test.cc', - 'exception_handler_death_test.cc', - 'exception_handler_nesting_test.cc', - 'minidump_test.cc', - 'dump_analysis.cc', - 'dump_analysis.h', - 'crash_generation_server_test.cc' - ], - 'dependencies': [ - 'testing.gyp:gtest', - 'testing.gyp:gmock', - '../breakpad_client.gyp:common', - '../crash_generation/crash_generation.gyp:crash_generation_server', - '../crash_generation/crash_generation.gyp:crash_generation_client', - '../handler/exception_handler.gyp:exception_handler', - 'processor_bits', - ] - }, - { - 'target_name': 'processor_bits', - 'type': 'static_library', - 'include_dirs': [ - '<(DEPTH)', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(DEPTH)', - ] - }, - 'sources': [ - '<(DEPTH)/common/string_conversion.cc', - '<(DEPTH)/processor/basic_code_modules.cc', - '<(DEPTH)/processor/convert_old_arm64_context.cc', - '<(DEPTH)/processor/dump_context.cc', - '<(DEPTH)/processor/dump_object.cc', - '<(DEPTH)/processor/logging.cc', - '<(DEPTH)/processor/minidump.cc', - '<(DEPTH)/processor/pathname_stripper.cc', - '<(DEPTH)/processor/proc_maps_linux.cc', - ] - } - ], -} diff --git a/src/client/windows/unittests/crash_generation_server_test.cc b/src/client/windows/unittests/crash_generation_server_test.cc index 09f2dd20..cd624f07 100644 --- a/src/client/windows/unittests/crash_generation_server_test.cc +++ b/src/client/windows/unittests/crash_generation_server_test.cc @@ -1,5 +1,4 @@ -// Copyright 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/unittests/dump_analysis.cc b/src/client/windows/unittests/dump_analysis.cc index 53d4ddbd..24a33769 100644 --- a/src/client/windows/unittests/dump_analysis.cc +++ b/src/client/windows/unittests/dump_analysis.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -127,8 +126,8 @@ size_t DumpAnalysis::GetStreamImpl(ULONG stream_number, void** stream) const { return ret ? memory_list_size : 0; } -bool DumpAnalysis::HasMemoryImpl(const void *addr_in, size_t structuresize, - void **structure) const { +bool DumpAnalysis::HasMemoryImpl(const void* addr_in, size_t structuresize, + void** structure) const { uintptr_t address = reinterpret_cast<uintptr_t>(addr_in); MINIDUMP_MEMORY_LIST* memory_list = NULL; size_t memory_list_size = GetStream(MemoryListStream, &memory_list); diff --git a/src/client/windows/unittests/dump_analysis.h b/src/client/windows/unittests/dump_analysis.h index 6cef48d8..f8acc268 100644 --- a/src/client/windows/unittests/dump_analysis.h +++ b/src/client/windows/unittests/dump_analysis.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/unittests/exception_handler_death_test.cc b/src/client/windows/unittests/exception_handler_death_test.cc index 5ef9e64d..a7679dd6 100644 --- a/src/client/windows/unittests/exception_handler_death_test.cc +++ b/src/client/windows/unittests/exception_handler_death_test.cc @@ -1,5 +1,4 @@ -// Copyright 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,7 +51,7 @@ const char kSuccessIndicator[] = "success"; const char kFailureIndicator[] = "failure"; // Utility function to test for a path's existence. -BOOL DoesPathExist(const TCHAR *path_name); +BOOL DoesPathExist(const TCHAR* path_name); enum OutOfProcGuarantee { OUT_OF_PROC_GUARANTEED, @@ -92,7 +91,7 @@ void ExceptionHandlerDeathTest::SetUp() { CreateDirectory(temp_path_, NULL); } -BOOL DoesPathExist(const TCHAR *path_name) { +BOOL DoesPathExist(const TCHAR* path_name) { DWORD flags = GetFileAttributes(path_name); if (flags == INVALID_FILE_ATTRIBUTES) { return FALSE; @@ -135,15 +134,15 @@ TEST_F(ExceptionHandlerDeathTest, InProcTest) { // Disable GTest SEH handler testing::DisableExceptionHandlerInScope disable_exception_handler; - int *i = NULL; + int* i = NULL; ASSERT_DEATH((*i)++, kSuccessIndicator); } static bool gDumpCallbackCalled = false; -void clientDumpCallback(void *dump_context, - const google_breakpad::ClientInfo *client_info, - const std::wstring *dump_path) { +void clientDumpCallback(void* dump_context, + const google_breakpad::ClientInfo* client_info, + const std::wstring* dump_path) { gDumpCallbackCalled = true; } @@ -152,7 +151,7 @@ void ExceptionHandlerDeathTest::DoCrashAccessViolation( scoped_ptr<google_breakpad::ExceptionHandler> exc; if (out_of_proc_guarantee == OUT_OF_PROC_GUARANTEED) { - google_breakpad::CrashGenerationClient *client = + google_breakpad::CrashGenerationClient* client = new google_breakpad::CrashGenerationClient(kPipeName, MiniDumpNormal, NULL); // custom_info @@ -184,7 +183,7 @@ void ExceptionHandlerDeathTest::DoCrashAccessViolation( // if it's not true we'll still get an error rather than the crash // being expected. ASSERT_TRUE(exc->IsOutOfProcess()); - int *i = NULL; + int* i = NULL; printf("%d\n", (*i)++); } @@ -283,7 +282,7 @@ TEST_F(ExceptionHandlerDeathTest, PureVirtualCallTest) { EXPECT_EXIT(DoCrashPureVirtualCall(), ::testing::ExitedWithCode(0), ""); } -wstring find_minidump_in_directory(const wstring &directory) { +wstring find_minidump_in_directory(const wstring& directory) { wstring search_path = directory + L"\\*"; WIN32_FIND_DATA find_data; HANDLE find_handle = FindFirstFileW(search_path.c_str(), &find_data); diff --git a/src/client/windows/unittests/exception_handler_nesting_test.cc b/src/client/windows/unittests/exception_handler_nesting_test.cc index 3ae1d7cd..81ae7dc7 100644 --- a/src/client/windows/unittests/exception_handler_nesting_test.cc +++ b/src/client/windows/unittests/exception_handler_nesting_test.cc @@ -1,5 +1,4 @@ -// Copyright 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -49,7 +48,7 @@ const char kFilterReturnsFalse[] = "filter_returns_false"; const char kCallbackReturnsTrue[] = "callback_returns_true"; const char kCallbackReturnsFalse[] = "callback_returns_false"; -bool DoesPathExist(const wchar_t *path_name) { +bool DoesPathExist(const wchar_t* path_name) { DWORD flags = GetFileAttributes(path_name); if (flags == INVALID_FILE_ATTRIBUTES) { return false; @@ -128,12 +127,12 @@ bool MinidumpWrittenCallback(const wchar_t* dump_path, } -void DoCrash(const char *message) { +void DoCrash(const char* message) { if (message) { fprintf(stderr, "%s", message); fflush(stderr); } - int *i = NULL; + int* i = NULL; (*i)++; ASSERT_TRUE(false); diff --git a/src/client/windows/unittests/exception_handler_test.cc b/src/client/windows/unittests/exception_handler_test.cc index a4ce12a8..237af29d 100644 --- a/src/client/windows/unittests/exception_handler_test.cc +++ b/src/client/windows/unittests/exception_handler_test.cc @@ -1,5 +1,4 @@ -// Copyright 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -87,13 +86,13 @@ class ExceptionHandlerTest : public ::testing::Test { void DoCrashPureVirtualCall(); // Utility function to test for a path's existence. - static BOOL DoesPathExist(const TCHAR *path_name); + static BOOL DoesPathExist(const TCHAR* path_name); // Client callback. static void ClientDumpCallback( - void *dump_context, - const google_breakpad::ClientInfo *client_info, - const std::wstring *dump_path); + void* dump_context, + const google_breakpad::ClientInfo* client_info, + const std::wstring* dump_path); static bool DumpCallback(const wchar_t* dump_path, const wchar_t* minidump_id, @@ -141,7 +140,7 @@ void ExceptionHandlerTest::TearDown() { } } -BOOL ExceptionHandlerTest::DoesPathExist(const TCHAR *path_name) { +BOOL ExceptionHandlerTest::DoesPathExist(const TCHAR* path_name) { DWORD flags = GetFileAttributes(path_name); if (flags == INVALID_FILE_ATTRIBUTES) { return FALSE; @@ -151,9 +150,9 @@ BOOL ExceptionHandlerTest::DoesPathExist(const TCHAR *path_name) { // static void ExceptionHandlerTest::ClientDumpCallback( - void *dump_context, - const google_breakpad::ClientInfo *client_info, - const wstring *dump_path) { + void* dump_context, + const google_breakpad::ClientInfo* client_info, + const wstring* dump_path) { dump_file = *dump_path; // Create the full dump file name from the dump path. full_dump_file = dump_file.substr(0, dump_file.length() - 4) + L"-full.dmp"; @@ -174,7 +173,7 @@ bool ExceptionHandlerTest::DumpCallback(const wchar_t* dump_path, } void ExceptionHandlerTest::DoCrashInvalidParameter() { - google_breakpad::ExceptionHandler *exc = + google_breakpad::ExceptionHandler* exc = new google_breakpad::ExceptionHandler( temp_path_, NULL, NULL, NULL, google_breakpad::ExceptionHandler::HANDLER_INVALID_PARAMETER, @@ -206,7 +205,7 @@ struct PureVirtualCall : public PureVirtualCallBase { }; void ExceptionHandlerTest::DoCrashPureVirtualCall() { - google_breakpad::ExceptionHandler *exc = + google_breakpad::ExceptionHandler* exc = new google_breakpad::ExceptionHandler( temp_path_, NULL, NULL, NULL, google_breakpad::ExceptionHandler::HANDLER_PURECALL, diff --git a/src/client/windows/unittests/exception_handler_test.h b/src/client/windows/unittests/exception_handler_test.h index ef973e53..9d4e44e4 100644 --- a/src/client/windows/unittests/exception_handler_test.h +++ b/src/client/windows/unittests/exception_handler_test.h @@ -1,5 +1,4 @@ -// Copyright 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/unittests/minidump_test.cc b/src/client/windows/unittests/minidump_test.cc index 82641125..7bfc8d77 100644 --- a/src/client/windows/unittests/minidump_test.cc +++ b/src/client/windows/unittests/minidump_test.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/client/windows/unittests/testing.gyp b/src/client/windows/unittests/testing.gyp deleted file mode 100644 index 0f9f944c..00000000 --- a/src/client/windows/unittests/testing.gyp +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 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. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'target_defaults': { - }, - 'targets': [ - { - 'target_name': 'gtest', - 'type': 'static_library', - 'include_dirs': [ - '<(DEPTH)/testing/include', - '<(DEPTH)/testing/googletest/include', - '<(DEPTH)/testing/googletest', - '<(DEPTH)/testing', - ], - 'sources': [ - '<(DEPTH)/testing/googletest/src/gtest-all.cc', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(DEPTH)/testing/include', - '<(DEPTH)/testing/gtest/include', - ], - # Visual C++ implements variadic templates strangely, and - # VC++2012 broke Google Test by lowering this value. See - # http://stackoverflow.com/questions/12558327/google-test-in-visual-studio-2012 - 'defines': ['_VARIADIC_MAX=10', '_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING'], - }, - 'defines': ['_VARIADIC_MAX=10', '_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING'], - }, - { - 'target_name': 'gmock', - 'type': 'static_library', - 'include_dirs': [ - '<(DEPTH)/testing/include', - '<(DEPTH)/testing/googletest/include', - '<(DEPTH)/testing/googletest', - '<(DEPTH)/testing/googlemock/include', - '<(DEPTH)/testing/googlemock', - '<(DEPTH)/testing', - ], - 'sources': [ - '<(DEPTH)/testing/googlemock/src/gmock-all.cc', - '<(DEPTH)/testing/googletest/src/gtest_main.cc', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '<(DEPTH)/testing/include', - '<(DEPTH)/testing/googletest/include', - '<(DEPTH)/testing/googletest', - '<(DEPTH)/testing/googlemock/include', - '<(DEPTH)/testing/googlemock', - '<(DEPTH)/testing', - ], - 'defines': ['_VARIADIC_MAX=10', '_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING'], - }, - 'defines': ['_VARIADIC_MAX=10', '_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING'], - }, - - ], -} diff --git a/src/common/android/include/elf.h b/src/common/android/include/elf.h index e6f0c672..80e4c835 100644 --- a/src/common/android/include/elf.h +++ b/src/common/android/include/elf.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/android/include/link.h b/src/common/android/include/link.h index 4324629d..02d2db26 100644 --- a/src/common/android/include/link.h +++ b/src/common/android/include/link.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/android/include/stab.h b/src/common/android/include/stab.h index cd929021..28882445 100644 --- a/src/common/android/include/stab.h +++ b/src/common/android/include/stab.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/android/include/sys/procfs.h b/src/common/android/include/sys/procfs.h index 18512436..f7ff9774 100644 --- a/src/common/android/include/sys/procfs.h +++ b/src/common/android/include/sys/procfs.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/android/include/sys/user.h b/src/common/android/include/sys/user.h index 9c27ef02..021ec90d 100644 --- a/src/common/android/include/sys/user.h +++ b/src/common/android/include/sys/user.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/android/testing/include/wchar.h b/src/common/android/testing/include/wchar.h index 85373fd2..aa17c731 100644 --- a/src/common/android/testing/include/wchar.h +++ b/src/common/android/testing/include/wchar.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/android/testing/mkdtemp.h b/src/common/android/testing/mkdtemp.h index b86e2cd7..f05cf653 100644 --- a/src/common/android/testing/mkdtemp.h +++ b/src/common/android/testing/mkdtemp.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/android/testing/pthread_fixes.h b/src/common/android/testing/pthread_fixes.h index 20c12084..04bf6369 100644 --- a/src/common/android/testing/pthread_fixes.h +++ b/src/common/android/testing/pthread_fixes.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -80,7 +79,7 @@ int pthread_barrier_wait(pthread_barrier_t* barrier) { return 0; } -int pthread_barrier_destroy(pthread_barrier_t *barrier) { +int pthread_barrier_destroy(pthread_barrier_t* barrier) { barrier->count = 0; pthread_cond_destroy(&barrier->cond); pthread_mutex_destroy(&barrier->mutex); diff --git a/src/common/basictypes.h b/src/common/basictypes.h index 9426c1f6..6458a893 100644 --- a/src/common/basictypes.h +++ b/src/common/basictypes.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/byte_cursor.h b/src/common/byte_cursor.h index accd54e0..fd0e45ff 100644 --- a/src/common/byte_cursor.h +++ b/src/common/byte_cursor.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,16 +51,16 @@ namespace google_breakpad { // A buffer holding a series of bytes. struct ByteBuffer { ByteBuffer() : start(0), end(0) { } - ByteBuffer(const uint8_t *set_start, size_t set_size) + ByteBuffer(const uint8_t* set_start, size_t set_size) : start(set_start), end(set_start + set_size) { } ~ByteBuffer() { }; // Equality operators. Useful in unit tests, and when we're using // ByteBuffers to refer to regions of a larger buffer. - bool operator==(const ByteBuffer &that) const { + bool operator==(const ByteBuffer& that) const { return start == that.start && end == that.end; } - bool operator!=(const ByteBuffer &that) const { + bool operator!=(const ByteBuffer& that) const { return start != that.start || end != that.end; } @@ -71,7 +70,8 @@ struct ByteBuffer { return end - start; } - const uint8_t *start, *end; + const uint8_t* start; + const uint8_t* end; }; // A cursor pointing into a ByteBuffer that can parse numbers of various @@ -82,8 +82,8 @@ class ByteCursor { public: // Create a cursor reading bytes from the start of BUFFER. By default, the // cursor reads multi-byte values in little-endian form. - ByteCursor(const ByteBuffer *buffer, bool big_endian = false) - : buffer_(buffer), here_(buffer->start), + ByteCursor(const ByteBuffer* buffer, bool big_endian = false) + : buffer_(buffer), here_(buffer->start), big_endian_(big_endian), complete_(true) { } // Accessor and setter for this cursor's endianness flag. @@ -92,8 +92,8 @@ class ByteCursor { // Accessor and setter for this cursor's current position. The setter // returns a reference to this cursor. - const uint8_t *here() const { return here_; } - ByteCursor &set_here(const uint8_t *here) { + const uint8_t* here() const { return here_; } + ByteCursor& set_here(const uint8_t* here) { assert(buffer_->start <= here && here <= buffer_->end); here_ = here; return *this; @@ -116,7 +116,7 @@ class ByteCursor { // this cursor's complete_ flag, and store a dummy value in *RESULT. // Return a reference to this cursor. template<typename T> - ByteCursor &Read(size_t size, bool is_signed, T *result) { + ByteCursor& Read(size_t size, bool is_signed, T* result) { if (CheckAvailable(size)) { T v = 0; if (big_endian_) { @@ -145,7 +145,7 @@ class ByteCursor { // read off the end of our buffer, clear this cursor's complete_ flag. // Return a reference to this cursor. template<typename T> - ByteCursor &operator>>(T &result) { + ByteCursor& operator>>(T& result) { bool T_is_signed = (T)-1 < 0; return Read(sizeof(T), T_is_signed, &result); } @@ -154,7 +154,7 @@ class ByteCursor { // cursor to the end of them. If we read off the end of our buffer, // clear this cursor's complete_ flag, and set *POINTER to NULL. // Return a reference to this cursor. - ByteCursor &Read(uint8_t *buffer, size_t size) { + ByteCursor& Read(uint8_t* buffer, size_t size) { if (CheckAvailable(size)) { memcpy(buffer, here_, size); here_ += size; @@ -166,11 +166,11 @@ class ByteCursor { // byte buffer does not contain a terminating zero, clear this cursor's // complete_ flag, and set STR to the empty string. Return a reference to // this cursor. - ByteCursor &CString(string *str) { - const uint8_t *end - = static_cast<const uint8_t *>(memchr(here_, '\0', Available())); + ByteCursor& CString(string* str) { + const uint8_t* end + = static_cast<const uint8_t*>(memchr(here_, '\0', Available())); if (end) { - str->assign(reinterpret_cast<const char *>(here_), end - here_); + str->assign(reinterpret_cast<const char*>(here_), end - here_); here_ = end + 1; } else { str->clear(); @@ -193,14 +193,14 @@ class ByteCursor { // // - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the // cursor by LIMIT bytes. - ByteCursor &CString(string *str, size_t limit) { + ByteCursor& CString(string* str, size_t limit) { if (CheckAvailable(limit)) { - const uint8_t *end - = static_cast<const uint8_t *>(memchr(here_, '\0', limit)); + const uint8_t* end + = static_cast<const uint8_t*>(memchr(here_, '\0', limit)); if (end) - str->assign(reinterpret_cast<const char *>(here_), end - here_); + str->assign(reinterpret_cast<const char*>(here_), end - here_); else - str->assign(reinterpret_cast<const char *>(here_), limit); + str->assign(reinterpret_cast<const char*>(here_), limit); here_ += limit; } else { str->clear(); @@ -213,7 +213,7 @@ class ByteCursor { // cursor. If we read off the end of our buffer, clear this cursor's // complete_ flag, and set *POINTER to NULL. Return a reference to this // cursor. - ByteCursor &PointTo(const uint8_t **pointer, size_t size = 0) { + ByteCursor& PointTo(const uint8_t** pointer, size_t size = 0) { if (CheckAvailable(size)) { *pointer = here_; here_ += size; @@ -226,7 +226,7 @@ class ByteCursor { // Skip SIZE bytes at the cursor. If doing so would advance us off // the end of our buffer, clear this cursor's complete_ flag, and // set *POINTER to NULL. Return a reference to this cursor. - ByteCursor &Skip(size_t size) { + ByteCursor& Skip(size_t size) { if (CheckAvailable(size)) here_ += size; return *this; @@ -247,10 +247,10 @@ class ByteCursor { } // The buffer we're reading bytes from. - const ByteBuffer *buffer_; + const ByteBuffer* buffer_; // The next byte within buffer_ that we'll read. - const uint8_t *here_; + const uint8_t* here_; // True if we should read numbers in big-endian form; false if we // should read in little-endian form. diff --git a/src/common/byte_cursor_unittest.cc b/src/common/byte_cursor_unittest.cc index 06bfd89d..00648f76 100644 --- a/src/common/byte_cursor_unittest.cc +++ b/src/common/byte_cursor_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -593,7 +592,7 @@ TEST(Extractor, Signed4) { int32_t a; // For some reason, G++ 4.4.1 complains: // warning: array subscript is above array bounds - // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but + // in ByteCursor::Read(size_t, bool, T*) as it inlines this call, but // I'm not able to see how such a reference would occur. EXPECT_TRUE(cursor >> a); EXPECT_EQ(-380377902, a); @@ -627,7 +626,7 @@ TEST(Extractor, Unsigned4) { uint32_t a; // For some reason, G++ 4.4.1 complains: // warning: array subscript is above array bounds - // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but + // in ByteCursor::Read(size_t, bool, T*) as it inlines this call, but // I'm not able to see how such a reference would occur. EXPECT_TRUE(cursor >> a); EXPECT_EQ(0xe953e4d2, a); @@ -718,10 +717,10 @@ TEST(Strings, PointTo) { ByteBuffer buffer(data, sizeof(data)); ByteCursor cursor(&buffer); - const uint8_t *received1; - const uint8_t *received2; - const uint8_t *received3; - const uint8_t *received4; + const uint8_t* received1; + const uint8_t* received2; + const uint8_t* received3; + const uint8_t* received4; EXPECT_FALSE(cursor .PointTo(&received1, 3) .PointTo(&received2, 3) diff --git a/src/common/common.gyp b/src/common/common.gyp deleted file mode 100644 index c1dbb0fe..00000000 --- a/src/common/common.gyp +++ /dev/null @@ -1,260 +0,0 @@ -# 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"', { - # Assume glibc. - 'defines': ['HAVE_A_OUT_H', 'HAVE_GETCONTEXT'], - 'sources!': [ - 'linux/breakpad_getcontext.S', - 'linux/breakpad_getcontext.h', - 'linux/breakpad_getcontext_unittest.cc', - ], - }], - ['OS!="android"', {'sources/': [['exclude', '(^|/)android/']]}], - ['OS!="linux"', {'sources/': [['exclude', '(^|/)linux/']]}], - ['OS!="mac"', {'sources/': [['exclude', '(^|/)mac/']]}], - ['OS!="solaris"', {'sources/': [['exclude', '(^|/)solaris/']]}], - ['OS!="win"', {'sources/': [['exclude', '(^|/)windows/']]}], - ], - }, - 'targets': [ - { - 'target_name': 'common', - 'type': 'static_library', - 'sources': [ - 'android/include/elf.h', - 'android/include/link.h', - 'android/include/stab.h', - 'android/include/sys/procfs.h', - 'android/include/sys/user.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.cc', - '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/elf_reader.cc', - 'dwarf/elf_reader.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/breakpad_getcontext.S', - 'linux/breakpad_getcontext.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/symbol_collector_client.cc', - 'linux/symbol_collector_client.h', - 'linux/synth_elf.cc', - 'linux/synth_elf.h', - 'long_string_dictionary.cc', - 'long_string_dictionary.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.cc', - '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', - 'mac/super_fat_arch.h', - 'md5.cc', - 'md5.h', - 'memory_allocator.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': [ - '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/breakpad_getcontext_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', - 'long_string_dictionary_unittest.cc', - 'mac/macho_reader_unittest.cc', - 'memory_allocator_unittest.cc', - 'memory_range_unittest.cc', - 'module_unittest.cc', - 'simple_string_dictionary_unittest.cc', - 'stabs_reader_unittest.cc', - 'stabs_to_module_unittest.cc', - 'string_conversion_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.gyp:gmock_main', - '../build/testing.gyp:gmock', - '../build/testing.gyp:gtest', - ], - 'libraries': [ - '-ldl', - ], - }, - ], -} diff --git a/src/common/dwarf/bytereader-inl.h b/src/common/dwarf/bytereader-inl.h index f4c068a2..21026484 100644 --- a/src/common/dwarf/bytereader-inl.h +++ b/src/common/dwarf/bytereader-inl.h @@ -1,4 +1,4 @@ -// Copyright 2006 Google Inc. All Rights Reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -34,13 +34,13 @@ #include <assert.h> #include <stdint.h> -namespace dwarf2reader { +namespace google_breakpad { -inline uint8_t ByteReader::ReadOneByte(const uint8_t *buffer) const { +inline uint8_t ByteReader::ReadOneByte(const uint8_t* buffer) const { return buffer[0]; } -inline uint16_t ByteReader::ReadTwoBytes(const uint8_t *buffer) const { +inline uint16_t ByteReader::ReadTwoBytes(const uint8_t* buffer) const { const uint16_t buffer0 = buffer[0]; const uint16_t buffer1 = buffer[1]; if (endian_ == ENDIANNESS_LITTLE) { @@ -50,7 +50,18 @@ inline uint16_t ByteReader::ReadTwoBytes(const uint8_t *buffer) const { } } -inline uint64_t ByteReader::ReadFourBytes(const uint8_t *buffer) const { +inline uint64_t ByteReader::ReadThreeBytes(const uint8_t* buffer) const { + const uint32_t buffer0 = buffer[0]; + const uint32_t buffer1 = buffer[1]; + const uint32_t buffer2 = buffer[2]; + if (endian_ == ENDIANNESS_LITTLE) { + return buffer0 | buffer1 << 8 | buffer2 << 16; + } else { + return buffer2 | buffer1 << 8 | buffer0 << 16; + } +} + +inline uint64_t ByteReader::ReadFourBytes(const uint8_t* buffer) const { const uint32_t buffer0 = buffer[0]; const uint32_t buffer1 = buffer[1]; const uint32_t buffer2 = buffer[2]; @@ -62,7 +73,7 @@ inline uint64_t ByteReader::ReadFourBytes(const uint8_t *buffer) const { } } -inline uint64_t ByteReader::ReadEightBytes(const uint8_t *buffer) const { +inline uint64_t ByteReader::ReadEightBytes(const uint8_t* buffer) const { const uint64_t buffer0 = buffer[0]; const uint64_t buffer1 = buffer[1]; const uint64_t buffer2 = buffer[2]; @@ -84,7 +95,7 @@ inline uint64_t ByteReader::ReadEightBytes(const uint8_t *buffer) const { // information, plus one bit saying whether the number continues or // not. -inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t *buffer, +inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t* buffer, size_t* len) const { uint64_t result = 0; size_t num_read = 0; @@ -109,7 +120,7 @@ inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t *buffer, // Read a signed LEB128 number. These are like regular LEB128 // numbers, except the last byte may have a sign bit set. -inline int64_t ByteReader::ReadSignedLEB128(const uint8_t *buffer, +inline int64_t ByteReader::ReadSignedLEB128(const uint8_t* buffer, size_t* len) const { int64_t result = 0; unsigned int shift = 0; @@ -129,18 +140,18 @@ inline int64_t ByteReader::ReadSignedLEB128(const uint8_t *buffer, return result; } -inline uint64_t ByteReader::ReadOffset(const uint8_t *buffer) const { +inline uint64_t ByteReader::ReadOffset(const uint8_t* buffer) const { assert(this->offset_reader_); return (this->*offset_reader_)(buffer); } -inline uint64_t ByteReader::ReadAddress(const uint8_t *buffer) const { +inline uint64_t ByteReader::ReadAddress(const uint8_t* buffer) const { assert(this->address_reader_); return (this->*address_reader_)(buffer); } inline void ByteReader::SetCFIDataBase(uint64_t section_base, - const uint8_t *buffer_base) { + const uint8_t* buffer_base) { section_base_ = section_base; buffer_base_ = buffer_base; have_section_base_ = true; @@ -165,6 +176,6 @@ inline void ByteReader::ClearFunctionBase() { have_function_base_ = false; } -} // namespace dwarf2reader +} // namespace google_breakpad #endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__ diff --git a/src/common/dwarf/bytereader.cc b/src/common/dwarf/bytereader.cc index 0b27dd58..46bed6d0 100644 --- a/src/common/dwarf/bytereader.cc +++ b/src/common/dwarf/bytereader.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -33,7 +33,7 @@ #include "common/dwarf/bytereader-inl.h" #include "common/dwarf/bytereader.h" -namespace dwarf2reader { +namespace google_breakpad { ByteReader::ByteReader(enum Endianness endian) :offset_reader_(NULL), address_reader_(NULL), endian_(endian), @@ -63,7 +63,7 @@ void ByteReader::SetAddressSize(uint8_t size) { } } -uint64_t ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) { +uint64_t ByteReader::ReadInitialLength(const uint8_t* start, size_t* len) { const uint64_t initial_length = ReadFourBytes(start); start += 4; @@ -101,9 +101,9 @@ bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const { } } -uint64_t ByteReader::ReadEncodedPointer(const uint8_t *buffer, +uint64_t ByteReader::ReadEncodedPointer(const uint8_t* buffer, DwarfPointerEncoding encoding, - size_t *len) const { + size_t* len) const { // UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't // see it here. assert(encoding != DW_EH_PE_omit); @@ -130,7 +130,7 @@ uint64_t ByteReader::ReadEncodedPointer(const uint8_t *buffer, // Round up to the next boundary. uint64_t aligned = (offset + AddressSize() - 1) & -AddressSize(); // Convert back to a pointer. - const uint8_t *aligned_buffer = buffer_base_ + (aligned - skew); + const uint8_t* aligned_buffer = buffer_base_ + (aligned - skew); // Finally, store the length and actually fetch the pointer. *len = aligned_buffer - buffer + AddressSize(); return ReadAddress(aligned_buffer); @@ -247,4 +247,4 @@ Endianness ByteReader::GetEndianness() const { return endian_; } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/bytereader.h b/src/common/dwarf/bytereader.h index 2b37a12d..761eaf68 100644 --- a/src/common/dwarf/bytereader.h +++ b/src/common/dwarf/bytereader.h @@ -1,6 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,7 +38,7 @@ #include "common/dwarf/types.h" #include "common/dwarf/dwarf2enums.h" -namespace dwarf2reader { +namespace google_breakpad { // We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN // because it conflicts with a macro @@ -62,22 +62,27 @@ class ByteReader { // Read a single byte from BUFFER and return it as an unsigned 8 bit // number. - uint8_t ReadOneByte(const uint8_t *buffer) const; + uint8_t ReadOneByte(const uint8_t* buffer) const; // Read two bytes from BUFFER and return them as an unsigned 16 bit // number, using this ByteReader's endianness. - uint16_t ReadTwoBytes(const uint8_t *buffer) const; + uint16_t ReadTwoBytes(const uint8_t* buffer) const; + + // Read three bytes from BUFFER and return them as an unsigned 64 bit + // number, using this ByteReader's endianness. DWARF 5 uses this encoding + // for various index-related DW_FORMs. + uint64_t ReadThreeBytes(const uint8_t* buffer) const; // Read four bytes from BUFFER and return them as an unsigned 32 bit // number, using this ByteReader's endianness. This function returns // a uint64_t so that it is compatible with ReadAddress and // ReadOffset. The number it returns will never be outside the range // of an unsigned 32 bit integer. - uint64_t ReadFourBytes(const uint8_t *buffer) const; + uint64_t ReadFourBytes(const uint8_t* buffer) const; // Read eight bytes from BUFFER and return them as an unsigned 64 // bit number, using this ByteReader's endianness. - uint64_t ReadEightBytes(const uint8_t *buffer) const; + uint64_t ReadEightBytes(const uint8_t* buffer) const; // Read an unsigned LEB128 (Little Endian Base 128) number from // BUFFER and return it as an unsigned 64 bit integer. Set LEN to @@ -96,7 +101,7 @@ class ByteReader { // In other words, we break VALUE into groups of seven bits, put // them in little-endian order, and then write them as eight-bit // bytes with the high bit on all but the last. - uint64_t ReadUnsignedLEB128(const uint8_t *buffer, size_t *len) const; + uint64_t ReadUnsignedLEB128(const uint8_t* buffer, size_t* len) const; // Read a signed LEB128 number from BUFFER and return it as an // signed 64 bit integer. Set LEN to the number of bytes read. @@ -115,7 +120,7 @@ class ByteReader { // In other words, we break VALUE into groups of seven bits, put // them in little-endian order, and then write them as eight-bit // bytes with the high bit on all but the last. - int64_t ReadSignedLEB128(const uint8_t *buffer, size_t *len) const; + int64_t ReadSignedLEB128(const uint8_t* buffer, size_t* len) const; // Indicate that addresses on this architecture are SIZE bytes long. SIZE // must be either 4 or 8. (DWARF allows addresses to be any number of @@ -138,7 +143,7 @@ class ByteReader { // Read an address from BUFFER and return it as an unsigned 64 bit // integer, respecting this ByteReader's endianness and address size. You // must call SetAddressSize before calling this function. - uint64_t ReadAddress(const uint8_t *buffer) const; + uint64_t ReadAddress(const uint8_t* buffer) const; // DWARF actually defines two slightly different formats: 32-bit DWARF // and 64-bit DWARF. This is *not* related to the size of registers or @@ -175,14 +180,14 @@ class ByteReader { // - The 32-bit value 0xffffffff, followed by a 64-bit byte count, // indicating that the data whose length is being measured uses // the 64-bit DWARF format. - uint64_t ReadInitialLength(const uint8_t *start, size_t *len); + uint64_t ReadInitialLength(const uint8_t* start, size_t* len); // Read an offset from BUFFER and return it as an unsigned 64 bit // integer, respecting the ByteReader's endianness. In 32-bit DWARF, the // offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes // long. You must call ReadInitialLength or SetOffsetSize before calling // this function; see the comments above for details. - uint64_t ReadOffset(const uint8_t *buffer) const; + uint64_t ReadOffset(const uint8_t* buffer) const; // Return the current offset size, in bytes. // A return value of 4 indicates that we are reading 32-bit DWARF. @@ -237,7 +242,7 @@ class ByteReader { // is BUFFER_BASE. This allows us to find the address that a given // byte in our buffer would have when loaded into the program the // data describes. We need this to resolve DW_EH_PE_pcrel pointers. - void SetCFIDataBase(uint64_t section_base, const uint8_t *buffer_base); + void SetCFIDataBase(uint64_t section_base, const uint8_t* buffer_base); // Indicate that the base address of the program's ".text" section // is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers. @@ -276,15 +281,15 @@ class ByteReader { // base address this reader hasn't been given, so you should check // with ValidEncoding and UsableEncoding first if you would rather // die in a more helpful way. - uint64_t ReadEncodedPointer(const uint8_t *buffer, + uint64_t ReadEncodedPointer(const uint8_t* buffer, DwarfPointerEncoding encoding, - size_t *len) const; + size_t* len) const; Endianness GetEndianness() const; private: // Function pointer type for our address and offset readers. - typedef uint64_t (ByteReader::*AddressReader)(const uint8_t *) const; + typedef uint64_t (ByteReader::*AddressReader)(const uint8_t*) const; // Read an offset from BUFFER and return it as an unsigned 64 bit // integer. DWARF2/3 define offsets as either 4 or 8 bytes, @@ -307,9 +312,9 @@ class ByteReader { bool have_section_base_, have_text_base_, have_data_base_; bool have_function_base_; uint64_t section_base_, text_base_, data_base_, function_base_; - const uint8_t *buffer_base_; + const uint8_t* buffer_base_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_BYTEREADER_H__ diff --git a/src/common/dwarf/bytereader_unittest.cc b/src/common/dwarf/bytereader_unittest.cc index e66062d1..c23c737b 100644 --- a/src/common/dwarf/bytereader_unittest.cc +++ b/src/common/dwarf/bytereader_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -29,7 +28,7 @@ // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> -// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader +// bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader #include <stdint.h> @@ -41,10 +40,10 @@ #include "common/dwarf/cfi_assembler.h" #include "common/using_std_string.h" -using dwarf2reader::ByteReader; -using dwarf2reader::DwarfPointerEncoding; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; +using google_breakpad::ByteReader; +using google_breakpad::DwarfPointerEncoding; +using google_breakpad::ENDIANNESS_BIG; +using google_breakpad::ENDIANNESS_LITTLE; using google_breakpad::CFISection; using google_breakpad::test_assembler::Label; using google_breakpad::test_assembler::kBigEndian; @@ -73,7 +72,7 @@ TEST_F(Reader, SimpleConstructor) { .LEB128(-0x4f337badf4483f83LL) .D32(0xfec319c9); ASSERT_TRUE(section.GetContents(&contents)); - const uint8_t *data = reinterpret_cast<const uint8_t *>(contents.data()); + const uint8_t* data = reinterpret_cast<const uint8_t*>(contents.data()); EXPECT_EQ(0xc0U, reader.ReadOneByte(data)); EXPECT_EQ(0xcf0dU, reader.ReadTwoBytes(data + 1)); EXPECT_EQ(0x96fdd219U, reader.ReadFourBytes(data + 3)); @@ -91,279 +90,279 @@ TEST_F(Reader, SimpleConstructor) { TEST_F(Reader, ValidEncodings) { ByteReader reader(ENDIANNESS_LITTLE); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_omit))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_omit))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_aligned))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_aligned))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_pcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_pcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_textrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_textrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_datarel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_datarel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_absptr | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_uleb128 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata2 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata4 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_udata8 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sleb128 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata2 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata4 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_funcrel))); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect | + google_breakpad::DW_EH_PE_sdata8 | + google_breakpad::DW_EH_PE_funcrel))); EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x05))); EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x07))); @@ -380,7 +379,7 @@ TEST_F(ReaderDeathTest, DW_EH_PE_omit) { static const uint8_t data[] = { 42 }; ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(4); - EXPECT_DEATH(reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_omit, + EXPECT_DEATH(reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_omit, &pointer_size), "encoding != DW_EH_PE_omit"); } @@ -390,7 +389,7 @@ TEST_F(Reader, DW_EH_PE_absptr4) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(4); EXPECT_EQ(0x40ea5727U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_absptr, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_absptr, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -402,7 +401,7 @@ TEST_F(Reader, DW_EH_PE_absptr8) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0x010598c240ea5727ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_absptr, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_absptr, &pointer_size)); EXPECT_EQ(8U, pointer_size); } @@ -412,7 +411,7 @@ TEST_F(Reader, DW_EH_PE_uleb128) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(4); EXPECT_EQ(0x130201U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_uleb128, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_uleb128, &pointer_size)); EXPECT_EQ(3U, pointer_size); } @@ -422,7 +421,7 @@ TEST_F(Reader, DW_EH_PE_udata2) { ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(4); EXPECT_EQ(0xf48dU, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_udata2, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_udata2, &pointer_size)); EXPECT_EQ(2U, pointer_size); } @@ -432,7 +431,7 @@ TEST_F(Reader, DW_EH_PE_udata4) { ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(8); EXPECT_EQ(0xa5628f8b, - reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_udata4, + reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_udata4, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -444,7 +443,7 @@ TEST_F(Reader, DW_EH_PE_udata8Addr8) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0x8fed199f69047304ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8, &pointer_size)); EXPECT_EQ(8U, pointer_size); } @@ -456,7 +455,7 @@ TEST_F(Reader, DW_EH_PE_udata8Addr4) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(4); EXPECT_EQ(0x69047304ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8, &pointer_size)); EXPECT_EQ(8U, pointer_size); } @@ -466,7 +465,7 @@ TEST_F(Reader, DW_EH_PE_sleb128) { ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(4); EXPECT_EQ(-0x030201U & 0xffffffff, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sleb128, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sleb128, &pointer_size)); EXPECT_EQ(3U, pointer_size); } @@ -476,7 +475,7 @@ TEST_F(Reader, DW_EH_PE_sdata2) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0xffffffffffffbfb9ULL, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_sdata2, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_sdata2, &pointer_size)); EXPECT_EQ(2U, pointer_size); } @@ -486,7 +485,7 @@ TEST_F(Reader, DW_EH_PE_sdata4) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0xffffffffadc2b8f2ULL, - reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_sdata4, + reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_sdata4, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -498,7 +497,7 @@ TEST_F(Reader, DW_EH_PE_sdata8) { ByteReader reader(ENDIANNESS_LITTLE); reader.SetAddressSize(8); EXPECT_EQ(0x87269b0ce0795766ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sdata8, + reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sdata8, &pointer_size)); EXPECT_EQ(8U, pointer_size); } @@ -510,8 +509,8 @@ TEST_F(Reader, DW_EH_PE_pcrel) { ByteReader reader(ENDIANNESS_BIG); reader.SetAddressSize(4); DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_pcrel - | dwarf2reader::DW_EH_PE_absptr); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_pcrel + | google_breakpad::DW_EH_PE_absptr); reader.SetCFIDataBase(0x89951377, data); EXPECT_EQ(0x89951377 + 3 + 0x14c8c402, reader.ReadEncodedPointer(data + 3, encoding, &pointer_size)); @@ -526,8 +525,8 @@ TEST_F(Reader, DW_EH_PE_textrel) { reader.SetAddressSize(4); reader.SetTextBase(0xb91beaf0); DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_sdata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel + | google_breakpad::DW_EH_PE_sdata2); EXPECT_EQ((0xb91beaf0 + 0xffffc917) & 0xffffffff, reader.ReadEncodedPointer(data + 3, encoding, &pointer_size)); EXPECT_EQ(2U, pointer_size); @@ -541,8 +540,8 @@ TEST_F(Reader, DW_EH_PE_datarel) { reader.SetAddressSize(8); reader.SetDataBase(0xbef308bd25ce74f0ULL); DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_sleb128); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_datarel + | google_breakpad::DW_EH_PE_sleb128); EXPECT_EQ(0xbef308bd25ce74f0ULL + 0xfffffffffffa013bULL, reader.ReadEncodedPointer(data + 2, encoding, &pointer_size)); EXPECT_EQ(3U, pointer_size); @@ -556,8 +555,8 @@ TEST_F(Reader, DW_EH_PE_funcrel) { reader.SetAddressSize(4); reader.SetFunctionBase(0x823c3520); DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel - | dwarf2reader::DW_EH_PE_udata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_funcrel + | google_breakpad::DW_EH_PE_udata2); EXPECT_EQ(0x823c3520 + 0xd148, reader.ReadEncodedPointer(data + 5, encoding, &pointer_size)); EXPECT_EQ(2U, pointer_size); @@ -567,48 +566,48 @@ TEST(UsableBase, CFI) { static const uint8_t data[] = { 0x42 }; ByteReader reader(ENDIANNESS_BIG); reader.SetCFIDataBase(0xb31cbd20, data); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } TEST(UsableBase, Text) { ByteReader reader(ENDIANNESS_BIG); reader.SetTextBase(0xa899ccb9); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } TEST(UsableBase, Data) { ByteReader reader(ENDIANNESS_BIG); reader.SetDataBase(0xf7b10bcd); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } TEST(UsableBase, Function) { ByteReader reader(ENDIANNESS_BIG); reader.SetFunctionBase(0xc2c0ed81); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } @@ -616,12 +615,12 @@ TEST(UsableBase, ClearFunction) { ByteReader reader(ENDIANNESS_BIG); reader.SetFunctionBase(0xc2c0ed81); reader.ClearFunctionBase(); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit)); EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); } @@ -641,7 +640,7 @@ class Aligned: public AlignedFixture, public Test { }; TEST_F(Aligned, DW_EH_PE_aligned0) { reader.SetCFIDataBase(0xb440305c, data); EXPECT_EQ(0xfe6e93d8U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -649,7 +648,7 @@ TEST_F(Aligned, DW_EH_PE_aligned0) { TEST_F(Aligned, DW_EH_PE_aligned1) { reader.SetCFIDataBase(0xb440305d, data); EXPECT_EQ(0xd834d51cU, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(7U, pointer_size); } @@ -657,7 +656,7 @@ TEST_F(Aligned, DW_EH_PE_aligned1) { TEST_F(Aligned, DW_EH_PE_aligned2) { reader.SetCFIDataBase(0xb440305e, data); EXPECT_EQ(0x93d834d5U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(6U, pointer_size); } @@ -665,7 +664,7 @@ TEST_F(Aligned, DW_EH_PE_aligned2) { TEST_F(Aligned, DW_EH_PE_aligned3) { reader.SetCFIDataBase(0xb440305f, data); EXPECT_EQ(0x6e93d834U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(5U, pointer_size); } @@ -674,7 +673,7 @@ TEST_F(Aligned, DW_EH_PE_aligned11) { reader.SetCFIDataBase(0xb4403061, data); EXPECT_EQ(0xd834d51cU, reader.ReadEncodedPointer(data + 1, - dwarf2reader::DW_EH_PE_aligned, + google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(6U, pointer_size); } @@ -683,7 +682,7 @@ TEST_F(Aligned, DW_EH_PE_aligned30) { reader.SetCFIDataBase(0xb4403063, data); EXPECT_EQ(0x6e93d834U, reader.ReadEncodedPointer(data + 1, - dwarf2reader::DW_EH_PE_aligned, + google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(4U, pointer_size); } @@ -692,7 +691,7 @@ TEST_F(Aligned, DW_EH_PE_aligned23) { reader.SetCFIDataBase(0xb4403062, data); EXPECT_EQ(0x1cd3ac2bU, reader.ReadEncodedPointer(data + 3, - dwarf2reader::DW_EH_PE_aligned, + google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(7U, pointer_size); } @@ -701,7 +700,7 @@ TEST_F(Aligned, DW_EH_PE_aligned03) { reader.SetCFIDataBase(0xb4403064, data); EXPECT_EQ(0x34d51cd3U, reader.ReadEncodedPointer(data + 3, - dwarf2reader::DW_EH_PE_aligned, + google_breakpad::DW_EH_PE_aligned, &pointer_size)); EXPECT_EQ(5U, pointer_size); } diff --git a/src/common/dwarf/cfi_assembler.cc b/src/common/dwarf/cfi_assembler.cc index 2dc22085..9ed979b4 100644 --- a/src/common/dwarf/cfi_assembler.cc +++ b/src/common/dwarf/cfi_assembler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,14 +37,12 @@ #include <stdlib.h> namespace google_breakpad { - -using dwarf2reader::DwarfPointerEncoding; -CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, +CFISection& CFISection::CIEHeader(uint64_t code_alignment_factor, int data_alignment_factor, unsigned return_address_register, uint8_t version, - const string &augmentation, + const string& augmentation, bool dwarf64, uint8_t address_size, uint8_t segment_size) { @@ -78,7 +75,7 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, return *this; } -CFISection &CFISection::FDEHeader(Label cie_pointer, +CFISection& CFISection::FDEHeader(Label cie_pointer, uint64_t initial_location, uint64_t address_range, bool dwarf64) { @@ -113,9 +110,9 @@ CFISection &CFISection::FDEHeader(Label cie_pointer, return *this; } -CFISection &CFISection::FinishEntry() { +CFISection& CFISection::FinishEntry() { assert(entry_length_); - Align(address_size_, dwarf2reader::DW_CFA_nop); + Align(address_size_, DW_CFA_nop); entry_length_->length = Here() - entry_length_->start; delete entry_length_; entry_length_ = NULL; @@ -123,28 +120,28 @@ CFISection &CFISection::FinishEntry() { return *this; } -CFISection &CFISection::EncodedPointer(uint64_t address, +CFISection& CFISection::EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, - const EncodedPointerBases &bases) { + const EncodedPointerBases& bases) { // Omitted data is extremely easy to emit. - if (encoding == dwarf2reader::DW_EH_PE_omit) + if (encoding == DW_EH_PE_omit) return *this; - // If (encoding & dwarf2reader::DW_EH_PE_indirect) != 0, then we assume + // If (encoding & DW_EH_PE_indirect) != 0, then we assume // that ADDRESS is the address at which the pointer is stored --- in // other words, that bit has no effect on how we write the pointer. - encoding = DwarfPointerEncoding(encoding & ~dwarf2reader::DW_EH_PE_indirect); + encoding = DwarfPointerEncoding(encoding & ~DW_EH_PE_indirect); // Find the base address to which this pointer is relative. The upper // nybble of the encoding specifies this. uint64_t base; switch (encoding & 0xf0) { - case dwarf2reader::DW_EH_PE_absptr: base = 0; break; - case dwarf2reader::DW_EH_PE_pcrel: base = bases.cfi + Size(); break; - case dwarf2reader::DW_EH_PE_textrel: base = bases.text; break; - case dwarf2reader::DW_EH_PE_datarel: base = bases.data; break; - case dwarf2reader::DW_EH_PE_funcrel: base = fde_start_address_; break; - case dwarf2reader::DW_EH_PE_aligned: base = 0; break; + case DW_EH_PE_absptr: base = 0; break; + case DW_EH_PE_pcrel: base = bases.cfi + Size(); break; + case DW_EH_PE_textrel: base = bases.text; break; + case DW_EH_PE_datarel: base = bases.data; break; + case DW_EH_PE_funcrel: base = fde_start_address_; break; + case DW_EH_PE_aligned: base = 0; break; default: abort(); }; @@ -153,7 +150,7 @@ CFISection &CFISection::EncodedPointer(uint64_t address, address -= base; // Align the pointer, if required. - if ((encoding & 0xf0) == dwarf2reader::DW_EH_PE_aligned) + if ((encoding & 0xf0) == DW_EH_PE_aligned) Align(AddressSize()); // Append ADDRESS to this section in the appropriate form. For the @@ -161,30 +158,30 @@ CFISection &CFISection::EncodedPointer(uint64_t address, // unsigned encodings, because ADDRESS has already been extended to 64 // bits before it was passed to us. switch (encoding & 0x0f) { - case dwarf2reader::DW_EH_PE_absptr: + case DW_EH_PE_absptr: Address(address); break; - case dwarf2reader::DW_EH_PE_uleb128: + case DW_EH_PE_uleb128: ULEB128(address); break; - case dwarf2reader::DW_EH_PE_sleb128: + case DW_EH_PE_sleb128: LEB128(address); break; - case dwarf2reader::DW_EH_PE_udata2: - case dwarf2reader::DW_EH_PE_sdata2: + case DW_EH_PE_udata2: + case DW_EH_PE_sdata2: D16(address); break; - case dwarf2reader::DW_EH_PE_udata4: - case dwarf2reader::DW_EH_PE_sdata4: + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: D32(address); break; - case dwarf2reader::DW_EH_PE_udata8: - case dwarf2reader::DW_EH_PE_sdata8: + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: D64(address); break; diff --git a/src/common/dwarf/cfi_assembler.h b/src/common/dwarf/cfi_assembler.h index bd7354d1..a33d5d84 100644 --- a/src/common/dwarf/cfi_assembler.h +++ b/src/common/dwarf/cfi_assembler.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -46,8 +45,6 @@ namespace google_breakpad { -using dwarf2reader::DwarfPointerEncoding; -using google_breakpad::test_assembler::Endianness; using google_breakpad::test_assembler::Label; using google_breakpad::test_assembler::Section; @@ -95,10 +92,10 @@ class CFISection: public Section { // true, use the .eh_frame format, as described by the Linux // Standards Base Core Specification, instead of the DWARF CFI // format. - CFISection(Endianness endianness, size_t address_size, + CFISection(google_breakpad::test_assembler::Endianness endianness, size_t address_size, bool eh_frame = false) : Section(endianness), address_size_(address_size), eh_frame_(eh_frame), - pointer_encoding_(dwarf2reader::DW_EH_PE_absptr), + pointer_encoding_(DW_EH_PE_absptr), encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) { // The 'start', 'Here', and 'Mark' members of a CFISection all refer // to section offsets. @@ -120,7 +117,7 @@ class CFISection: public Section { // Use the addresses in BASES as the base addresses for encoded // pointers in subsequent calls to FDEHeader or EncodedPointer. // This function makes a copy of BASES. - void SetEncodedPointerBases(const EncodedPointerBases &bases) { + void SetEncodedPointerBases(const EncodedPointerBases& bases) { encoded_pointer_bases_ = bases; } @@ -133,11 +130,11 @@ class CFISection: public Section { // Before calling this function, you will typically want to use Mark // or Here to make a label to pass to FDEHeader that refers to this // CIE's position in the section. - CFISection &CIEHeader(uint64_t code_alignment_factor, + CFISection& CIEHeader(uint64_t code_alignment_factor, int data_alignment_factor, unsigned return_address_register, uint8_t version = 3, - const string &augmentation = "", + const string& augmentation = "", bool dwarf64 = false, uint8_t address_size = 8, uint8_t segment_size = 0); @@ -152,7 +149,7 @@ class CFISection: public Section { // 0xffffff00 bytes. (The "initial length" is always a 32-bit // value.) Nor does it support .debug_frame sections longer than // 0xffffff00 bytes. - CFISection &FDEHeader(Label cie_pointer, + CFISection& FDEHeader(Label cie_pointer, uint64_t initial_location, uint64_t address_range, bool dwarf64 = false); @@ -161,11 +158,11 @@ class CFISection: public Section { // started, after padding with DW_CFA_nops for alignment. This // defines the label representing the entry's length, cited in the // entry's header. Return a reference to this section. - CFISection &FinishEntry(); + CFISection& FinishEntry(); // Append the contents of BLOCK as a DW_FORM_block value: an // unsigned LEB128 length, followed by that many bytes of data. - CFISection &Block(const string &block) { + CFISection& Block(const string& block) { ULEB128(block.size()); Append(block); return *this; @@ -173,11 +170,11 @@ class CFISection: public Section { // Append ADDRESS to this section, in the appropriate size and // endianness. Return a reference to this section. - CFISection &Address(uint64_t address) { + CFISection& Address(uint64_t address) { Section::Append(endianness(), address_size_, address); return *this; } - CFISection &Address(Label address) { + CFISection& Address(Label address) { Section::Append(endianness(), address_size_, address); return *this; } @@ -191,26 +188,26 @@ class CFISection: public Section { // // (C++ doesn't let me use default arguments here, because I want to // refer to members of *this in the default argument expression.) - CFISection &EncodedPointer(uint64_t address) { + CFISection& EncodedPointer(uint64_t address) { return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_); } - CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { + CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { return EncodedPointer(address, encoding, encoded_pointer_bases_); } - CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, - const EncodedPointerBases &bases); + CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, + const EncodedPointerBases& bases); // Restate some member functions, to keep chaining working nicely. - CFISection &Mark(Label *label) { Section::Mark(label); return *this; } - CFISection &D8(uint8_t v) { Section::D8(v); return *this; } - CFISection &D16(uint16_t v) { Section::D16(v); return *this; } - CFISection &D16(Label v) { Section::D16(v); return *this; } - CFISection &D32(uint32_t v) { Section::D32(v); return *this; } - CFISection &D32(const Label &v) { Section::D32(v); return *this; } - CFISection &D64(uint64_t v) { Section::D64(v); return *this; } - CFISection &D64(const Label &v) { Section::D64(v); return *this; } - CFISection &LEB128(long long v) { Section::LEB128(v); return *this; } - CFISection &ULEB128(uint64_t v) { Section::ULEB128(v); return *this; } + CFISection& Mark(Label* label) { Section::Mark(label); return *this; } + CFISection& D8(uint8_t v) { Section::D8(v); return *this; } + CFISection& D16(uint16_t v) { Section::D16(v); return *this; } + CFISection& D16(Label v) { Section::D16(v); return *this; } + CFISection& D32(uint32_t v) { Section::D32(v); return *this; } + CFISection& D32(const Label& v) { Section::D32(v); return *this; } + CFISection& D64(uint64_t v) { Section::D64(v); return *this; } + CFISection& D64(const Label& v) { Section::D64(v); return *this; } + CFISection& LEB128(long long v) { Section::LEB128(v); return *this; } + CFISection& ULEB128(uint64_t v) { Section::ULEB128(v); return *this; } private: // A length value that we've appended to the section, but is not yet diff --git a/src/common/dwarf/dwarf2diehandler.cc b/src/common/dwarf/dwarf2diehandler.cc index 63845018..ea3ac71c 100644 --- a/src/common/dwarf/dwarf2diehandler.cc +++ b/src/common/dwarf/dwarf2diehandler.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -39,11 +39,11 @@ #include "common/dwarf/dwarf2diehandler.h" #include "common/using_std_string.h" -namespace dwarf2reader { +namespace google_breakpad { DIEDispatcher::~DIEDispatcher() { while (!die_handlers_.empty()) { - HandlerStack &entry = die_handlers_.top(); + HandlerStack& entry = die_handlers_.top(); if (entry.handler_ != root_handler_) delete entry.handler_; die_handlers_.pop(); @@ -60,7 +60,7 @@ bool DIEDispatcher::StartCompilationUnit(uint64_t offset, uint8_t address_size, bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { // The stack entry for the parent of this DIE, if there is one. - HandlerStack *parent = die_handlers_.empty() ? NULL : &die_handlers_.top(); + HandlerStack* parent = die_handlers_.empty() ? NULL : &die_handlers_.top(); // Does this call indicate that we're done receiving the parent's // attributes' values? If so, call its EndAttributes member function. @@ -78,7 +78,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { } // Find a handler for this DIE. - DIEHandler *handler; + DIEHandler* handler; if (parent) { if (parent->handler_) // Ask the parent to find a handler. @@ -115,7 +115,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) { void DIEDispatcher::EndDIE(uint64_t offset) { assert(!die_handlers_.empty()); - HandlerStack *entry = &die_handlers_.top(); + HandlerStack* entry = &die_handlers_.top(); if (entry->handler_) { // This entry had better be the handler for this DIE. assert(entry->offset_ == offset); @@ -139,7 +139,7 @@ void DIEDispatcher::ProcessAttributeUnsigned(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, uint64_t data) { - HandlerStack ¤t = die_handlers_.top(); + HandlerStack& current = die_handlers_.top(); // This had better be an attribute of the DIE we were meant to handle. assert(offset == current.offset_); current.handler_->ProcessAttributeUnsigned(attr, form, data); @@ -149,7 +149,7 @@ void DIEDispatcher::ProcessAttributeSigned(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, int64_t data) { - HandlerStack ¤t = die_handlers_.top(); + HandlerStack& current = die_handlers_.top(); // This had better be an attribute of the DIE we were meant to handle. assert(offset == current.offset_); current.handler_->ProcessAttributeSigned(attr, form, data); @@ -159,7 +159,7 @@ void DIEDispatcher::ProcessAttributeReference(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, uint64_t data) { - HandlerStack ¤t = die_handlers_.top(); + HandlerStack& current = die_handlers_.top(); // This had better be an attribute of the DIE we were meant to handle. assert(offset == current.offset_); current.handler_->ProcessAttributeReference(attr, form, data); @@ -168,9 +168,9 @@ void DIEDispatcher::ProcessAttributeReference(uint64_t offset, void DIEDispatcher::ProcessAttributeBuffer(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len) { - HandlerStack ¤t = die_handlers_.top(); + HandlerStack& current = die_handlers_.top(); // This had better be an attribute of the DIE we were meant to handle. assert(offset == current.offset_); current.handler_->ProcessAttributeBuffer(attr, form, data, len); @@ -180,7 +180,7 @@ void DIEDispatcher::ProcessAttributeString(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, const string& data) { - HandlerStack ¤t = die_handlers_.top(); + HandlerStack& current = die_handlers_.top(); // This had better be an attribute of the DIE we were meant to handle. assert(offset == current.offset_); current.handler_->ProcessAttributeString(attr, form, data); @@ -190,10 +190,10 @@ void DIEDispatcher::ProcessAttributeSignature(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, uint64_t signature) { - HandlerStack ¤t = die_handlers_.top(); + HandlerStack& current = die_handlers_.top(); // This had better be an attribute of the DIE we were meant to handle. assert(offset == current.offset_); current.handler_->ProcessAttributeSignature(attr, form, signature); } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/dwarf2diehandler.h b/src/common/dwarf/dwarf2diehandler.h index 871ba436..02c22853 100644 --- a/src/common/dwarf/dwarf2diehandler.h +++ b/src/common/dwarf/dwarf2diehandler.h @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -166,7 +166,7 @@ #include "common/dwarf/dwarf2reader.h" #include "common/using_std_string.h" -namespace dwarf2reader { +namespace google_breakpad { // A base class for handlers for specific DIE types. The series of // calls made on a DIE handler is as follows: @@ -208,7 +208,7 @@ class DIEHandler { uint64_t data) { } virtual void ProcessAttributeBuffer(enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len) { } virtual void ProcessAttributeString(enum DwarfAttribute attr, enum DwarfForm form, @@ -244,7 +244,7 @@ class DIEHandler { // it is. // // The default definition skips all children. - virtual DIEHandler *FindChildHandler(uint64_t offset, enum DwarfTag tag) { + virtual DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag) { return NULL; } @@ -258,10 +258,13 @@ class DIEHandler { // A subclass of DIEHandler, with additional kludges for handling the // compilation unit's root die. -class RootDIEHandler: public DIEHandler { +class RootDIEHandler : public DIEHandler { public: - RootDIEHandler() { } - virtual ~RootDIEHandler() { } + bool handle_inline; + + explicit RootDIEHandler(bool handle_inline = false) + : handle_inline(handle_inline) {} + virtual ~RootDIEHandler() {} // We pass the values reported via Dwarf2Handler::StartCompilationUnit // to this member function, and skip the entire compilation unit if it @@ -288,7 +291,7 @@ class DIEDispatcher: public Dwarf2Handler { // Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for // the compilation unit's root die, as described for the DIEHandler // class. - DIEDispatcher(RootDIEHandler *root_handler) : root_handler_(root_handler) { } + DIEDispatcher(RootDIEHandler* root_handler) : root_handler_(root_handler) { } // Destroying a DIEDispatcher destroys all active handler objects // except the root handler. ~DIEDispatcher(); @@ -311,12 +314,12 @@ class DIEDispatcher: public Dwarf2Handler { void ProcessAttributeBuffer(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len); void ProcessAttributeString(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const string &data); + const string& data); void ProcessAttributeSignature(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, @@ -335,7 +338,7 @@ class DIEDispatcher: public Dwarf2Handler { // The handler object interested in this DIE's attributes and // children. If NULL, we're not interested in either. - DIEHandler *handler_; + DIEHandler* handler_; // Have we reported the end of this DIE's attributes to the handler? bool reported_attributes_end_; @@ -358,8 +361,8 @@ class DIEDispatcher: public Dwarf2Handler { // The root handler. We don't push it on die_handlers_ until we // actually get the StartDIE call for the root. - RootDIEHandler *root_handler_; + RootDIEHandler* root_handler_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_DWARF2DIEHANDLER_H__ diff --git a/src/common/dwarf/dwarf2diehandler_unittest.cc b/src/common/dwarf/dwarf2diehandler_unittest.cc index 01b70489..67c9489d 100644 --- a/src/common/dwarf/dwarf2diehandler_unittest.cc +++ b/src/common/dwarf/dwarf2diehandler_unittest.cc @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -53,12 +53,12 @@ using ::testing::Return; using ::testing::Sequence; using ::testing::StrEq; -using dwarf2reader::DIEDispatcher; -using dwarf2reader::DIEHandler; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfTag; -using dwarf2reader::RootDIEHandler; +using google_breakpad::DIEDispatcher; +using google_breakpad::DIEHandler; +using google_breakpad::DwarfAttribute; +using google_breakpad::DwarfForm; +using google_breakpad::DwarfTag; +using google_breakpad::RootDIEHandler; class MockDIEHandler: public DIEHandler { public: @@ -69,9 +69,9 @@ class MockDIEHandler: public DIEHandler { MOCK_METHOD3(ProcessAttributeReference, void(DwarfAttribute, DwarfForm, uint64_t)); MOCK_METHOD4(ProcessAttributeBuffer, - void(DwarfAttribute, DwarfForm, const uint8_t *, uint64_t)); + void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t)); MOCK_METHOD3(ProcessAttributeString, - void(DwarfAttribute, DwarfForm, const string &)); + void(DwarfAttribute, DwarfForm, const string&)); MOCK_METHOD3(ProcessAttributeSignature, void(DwarfAttribute, DwarfForm, uint64_t)); MOCK_METHOD0(EndAttributes, bool()); @@ -88,9 +88,9 @@ class MockRootDIEHandler: public RootDIEHandler { MOCK_METHOD3(ProcessAttributeReference, void(DwarfAttribute, DwarfForm, uint64_t)); MOCK_METHOD4(ProcessAttributeBuffer, - void(DwarfAttribute, DwarfForm, const uint8_t *, uint64_t)); + void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t)); MOCK_METHOD3(ProcessAttributeString, - void(DwarfAttribute, DwarfForm, const string &)); + void(DwarfAttribute, DwarfForm, const string&)); MOCK_METHOD3(ProcessAttributeSignature, void(DwarfAttribute, DwarfForm, uint64_t)); MOCK_METHOD0(EndAttributes, bool()); @@ -339,7 +339,7 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) { EXPECT_CALL(mock_root_handler, FindChildHandler(0x97412be24875de9dLL, (DwarfTag) 0x505a068b)) - .WillOnce(Return((DIEHandler *) NULL)); + .WillOnce(Return((DIEHandler*) NULL)); // Third child DIE. EXPECT_CALL(mock_root_handler, diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h index 4316a89c..777d9bfc 100644 --- a/src/common/dwarf/dwarf2enums.h +++ b/src/common/dwarf/dwarf2enums.h @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +31,7 @@ #ifndef COMMON_DWARF_DWARF2ENUMS_H__ #define COMMON_DWARF_DWARF2ENUMS_H__ -namespace dwarf2reader { +namespace google_breakpad { // These enums do not follow the google3 style only because they are // known universally (specs, other implementations) by the names in @@ -95,6 +95,10 @@ enum DwarfTag { DW_TAG_unspecified_type = 0x3b, DW_TAG_partial_unit = 0x3c, DW_TAG_imported_unit = 0x3d, + // DWARF 4. + DW_TAG_type_unit = 0x41, + // DWARF 5. + DW_TAG_skeleton_unit = 0x4a, // SGI/MIPS Extensions. DW_TAG_MIPS_loop = 0x4081, // HP extensions. See: @@ -115,6 +119,16 @@ enum DwarfTag { DW_TAG_PGI_interface_block = 0xA020 }; +enum DwarfUnitHeader { + DW_UT_compile = 0x01, + DW_UT_type = 0x02, + DW_UT_partial = 0x03, + DW_UT_skeleton = 0x04, + DW_UT_split_compile = 0x05, + DW_UT_split_type = 0x06, + DW_UT_lo_user = 0x80, + DW_UT_hi_user = 0xFF +}; enum DwarfHasChild { DW_children_no = 0, @@ -149,7 +163,33 @@ enum DwarfForm { DW_FORM_sec_offset = 0x17, DW_FORM_exprloc = 0x18, DW_FORM_flag_present = 0x19, + + // Added in DWARF 5: + DW_FORM_strx = 0x1a, + DW_FORM_addrx = 0x1b, + DW_FORM_ref_sup4 = 0x1c, + DW_FORM_strp_sup = 0x1d, + DW_FORM_data16 = 0x1e, + DW_FORM_line_strp = 0x1f, + + // DWARF 4, but value out of order. DW_FORM_ref_sig8 = 0x20, + + // Added in DWARF 5: + DW_FORM_implicit_const = 0x21, + DW_FORM_loclistx = 0x22, + DW_FORM_rnglistx = 0x23, + DW_FORM_ref_sup8 = 0x24, + DW_FORM_strx1 = 0x25, + DW_FORM_strx2 = 0x26, + DW_FORM_strx3 = 0x27, + DW_FORM_strx4 = 0x28, + + DW_FORM_addrx1 = 0x29, + DW_FORM_addrx2 = 0x2a, + DW_FORM_addrx3 = 0x2b, + DW_FORM_addrx4 = 0x2c, + // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. DW_FORM_GNU_addr_index = 0x1f01, DW_FORM_GNU_str_index = 0x1f02 @@ -234,6 +274,11 @@ enum DwarfAttribute { DW_AT_call_line = 0x59, // DWARF 4 DW_AT_linkage_name = 0x6e, + // DWARF 5 + DW_AT_str_offsets_base = 0x72, + DW_AT_addr_base = 0x73, + DW_AT_rnglists_base = 0x74, + DW_AT_dwo_name = 0x76, // SGI/MIPS extensions. DW_AT_MIPS_fde = 0x2001, DW_AT_MIPS_loop_begin = 0x2002, @@ -286,6 +331,26 @@ enum DwarfAttribute { DW_AT_PGI_lstride = 0x3a02 }; +// .debug_rngslist entry types +enum DwarfRngListEntry { + DW_RLE_end_of_list = 0, + DW_RLE_base_addressx = 1, + DW_RLE_startx_endx = 2, + DW_RLE_startx_length = 3, + DW_RLE_offset_pair = 4, + DW_RLE_base_address = 5, + DW_RLE_start_end = 6, + DW_RLE_start_length = 7, +}; + +// Line number content type codes (DWARF 5). +enum DwarfLineNumberContentType { + DW_LNCT_path = 1, + DW_LNCT_directory_index = 2, + DW_LNCT_timestamp = 3, + DW_LNCT_size = 4, + DW_LNCT_MD5 = 5, +}; // Line number opcodes. enum DwarfLineNumberOps { @@ -675,5 +740,5 @@ enum DwarfPointerEncoding DW_EH_PE_indirect = 0x80 }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_DWARF2ENUMS_H__ diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index 6b9ce2b4..b191d78c 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -28,16 +28,16 @@ // CFI reader author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> -// Implementation of dwarf2reader::LineInfo, dwarf2reader::CompilationUnit, -// and dwarf2reader::CallFrameInfo. See dwarf2reader.h for details. +// Implementation of LineInfo, CompilationUnit, +// and CallFrameInfo. See dwarf2reader.h for details. #include "common/dwarf/dwarf2reader.h" -#include <assert.h> #include <stdint.h> #include <stdio.h> #include <string.h> +#include <algorithm> #include <map> #include <memory> #include <stack> @@ -52,7 +52,19 @@ #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" -namespace dwarf2reader { +namespace google_breakpad { + +const SectionMap::const_iterator GetSectionByName(const SectionMap& + sections, const char *name) { + assert(name[0] == '.'); + auto iter = sections.find(name); + if (iter != sections.end()) + return iter; + std::string macho_name("__"); + macho_name += name + 1; + iter = sections.find(macho_name); + return iter; +} CompilationUnit::CompilationUnit(const string& path, const SectionMap& sections, uint64_t offset, @@ -60,11 +72,12 @@ CompilationUnit::CompilationUnit(const string& path, : path_(path), offset_from_section_start_(offset), reader_(reader), sections_(sections), handler_(handler), abbrevs_(), string_buffer_(NULL), string_buffer_length_(0), + line_string_buffer_(NULL), line_string_buffer_length_(0), str_offsets_buffer_(NULL), str_offsets_buffer_length_(0), addr_buffer_(NULL), addr_buffer_length_(0), - is_split_dwarf_(false), dwo_id_(0), dwo_name_(), + is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(), skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), - have_checked_for_dwp_(false), dwp_path_(), + str_offsets_base_(0), have_checked_for_dwp_(false), dwp_path_(), dwp_byte_reader_(), dwp_reader_() {} // Initialize a compilation unit from a .dwo or .dwp file. @@ -99,12 +112,9 @@ void CompilationUnit::ReadAbbrevs() { if (abbrevs_) return; - // First get the debug_abbrev section. ".debug_abbrev" is the name - // recommended in the DWARF spec, and used on Linux; - // "__debug_abbrev" is the name used in Mac OS X Mach-O files. - SectionMap::const_iterator iter = sections_.find(".debug_abbrev"); - if (iter == sections_.end()) - iter = sections_.find("__debug_abbrev"); + // First get the debug_abbrev section. + SectionMap::const_iterator iter = + GetSectionByName(sections_, ".debug_abbrev"); assert(iter != sections_.end()); abbrevs_ = new std::vector<Abbrev>; @@ -113,17 +123,20 @@ void CompilationUnit::ReadAbbrevs() { // The only way to check whether we are reading over the end of the // buffer would be to first compute the size of the leb128 data by // reading it, then go back and read it again. - const uint8_t *abbrev_start = iter->second.first + + const uint8_t* abbrev_start = iter->second.first + header_.abbrev_offset; - const uint8_t *abbrevptr = abbrev_start; + const uint8_t* abbrevptr = abbrev_start; #ifndef NDEBUG const uint64_t abbrev_length = iter->second.second - header_.abbrev_offset; #endif + uint64_t highest_number = 0; + while (1) { CompilationUnit::Abbrev abbrev; size_t len; const uint64_t number = reader_->ReadUnsignedLEB128(abbrevptr, &len); + highest_number = std::max(highest_number, number); if (number == 0) break; @@ -151,29 +164,42 @@ void CompilationUnit::ReadAbbrevs() { if (nametemp == 0 && formtemp == 0) break; - const enum DwarfAttribute name = - static_cast<enum DwarfAttribute>(nametemp); - const enum DwarfForm form = static_cast<enum DwarfForm>(formtemp); - abbrev.attributes.push_back(std::make_pair(name, form)); + uint64_t value = 0; + if (formtemp == DW_FORM_implicit_const) { + value = reader_->ReadUnsignedLEB128(abbrevptr, &len); + abbrevptr += len; + } + AttrForm abbrev_attr(static_cast<enum DwarfAttribute>(nametemp), + static_cast<enum DwarfForm>(formtemp), + value); + abbrev.attributes.push_back(abbrev_attr); } - assert(abbrev.number == abbrevs_->size()); abbrevs_->push_back(abbrev); } + + // Account of cases where entries are out of order. + std::sort(abbrevs_->begin(), abbrevs_->end(), + [](const CompilationUnit::Abbrev& lhs, const CompilationUnit::Abbrev& rhs) { + return lhs.number < rhs.number; + }); + + // Ensure that there are no missing sections. + assert(abbrevs_->size() == highest_number + 1); } // Skips a single DIE's attributes. -const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start, +const uint8_t* CompilationUnit::SkipDIE(const uint8_t* start, const Abbrev& abbrev) { for (AttributeList::const_iterator i = abbrev.attributes.begin(); i != abbrev.attributes.end(); i++) { - start = SkipAttribute(start, i->second); + start = SkipAttribute(start, i->form_); } return start; } // Skips a single attribute form's data. -const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, +const uint8_t* CompilationUnit::SkipAttribute(const uint8_t* start, enum DwarfForm form) { size_t len; @@ -185,27 +211,45 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, return SkipAttribute(start, form); case DW_FORM_flag_present: + case DW_FORM_implicit_const: return start; + case DW_FORM_addrx1: case DW_FORM_data1: case DW_FORM_flag: case DW_FORM_ref1: + case DW_FORM_strx1: return start + 1; + case DW_FORM_addrx2: case DW_FORM_ref2: case DW_FORM_data2: + case DW_FORM_strx2: return start + 2; + case DW_FORM_addrx3: + case DW_FORM_strx3: + return start + 3; + case DW_FORM_addrx4: case DW_FORM_ref4: case DW_FORM_data4: + case DW_FORM_strx4: + case DW_FORM_ref_sup4: return start + 4; case DW_FORM_ref8: case DW_FORM_data8: case DW_FORM_ref_sig8: + case DW_FORM_ref_sup8: return start + 8; + case DW_FORM_data16: + return start + 16; case DW_FORM_string: - return start + strlen(reinterpret_cast<const char *>(start)) + 1; + return start + strlen(reinterpret_cast<const char*>(start)) + 1; case DW_FORM_udata: case DW_FORM_ref_udata: + case DW_FORM_strx: case DW_FORM_GNU_str_index: case DW_FORM_GNU_addr_index: + case DW_FORM_addrx: + case DW_FORM_rnglistx: + case DW_FORM_loclistx: reader_->ReadUnsignedLEB128(start, &len); return start + len; @@ -237,6 +281,8 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, return start + size + len; } case DW_FORM_strp: + case DW_FORM_line_strp: + case DW_FORM_strp_sup: case DW_FORM_sec_offset: return start + reader_->OffsetSize(); } @@ -244,13 +290,52 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, return NULL; } -// Read a DWARF2/3 header. -// The header is variable length in DWARF3 (and DWARF2 as extended by -// most compilers), and consists of an length field, a version number, -// the offset in the .debug_abbrev section for our abbrevs, and an -// address size. +// Read the abbreviation offset from a compilation unit header. +size_t CompilationUnit::ReadAbbrevOffset(const uint8_t* headerptr) { + assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_); + header_.abbrev_offset = reader_->ReadOffset(headerptr); + return reader_->OffsetSize(); +} + +// Read the address size from a compilation unit header. +size_t CompilationUnit::ReadAddressSize(const uint8_t* headerptr) { + // Compare against less than or equal because this may be the last + // section in the file. + assert(headerptr + 1 <= buffer_ + buffer_length_); + header_.address_size = reader_->ReadOneByte(headerptr); + reader_->SetAddressSize(header_.address_size); + return 1; +} + +// Read the DWO id from a split or skeleton compilation unit header. +size_t CompilationUnit::ReadDwoId(const uint8_t* headerptr) { + assert(headerptr + 8 <= buffer_ + buffer_length_); + dwo_id_ = reader_->ReadEightBytes(headerptr); + return 8; +} + +// Read the type signature from a type or split type compilation unit header. +size_t CompilationUnit::ReadTypeSignature(const uint8_t* headerptr) { + assert(headerptr + 8 <= buffer_ + buffer_length_); + type_signature_ = reader_->ReadEightBytes(headerptr); + return 8; +} + +// Read the DWO id from a split or skeleton compilation unit header. +size_t CompilationUnit::ReadTypeOffset(const uint8_t* headerptr) { + assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_); + type_offset_ = reader_->ReadOffset(headerptr); + return reader_->OffsetSize(); +} + + +// Read a DWARF header. The header is variable length in DWARF3 and DWARF4 +// (and DWARF2 as extended by most compilers), and consists of an length +// field, a version number, the offset in the .debug_abbrev section for our +// abbrevs, and an address size. DWARF5 adds a unit_type to distinguish +// between partial-, full-, skeleton-, split-, and type- compilation units. void CompilationUnit::ReadHeader() { - const uint8_t *headerptr = buffer_; + const uint8_t* headerptr = buffer_; size_t initial_length_size; assert(headerptr + 4 < buffer_ + buffer_length_); @@ -263,17 +348,37 @@ void CompilationUnit::ReadHeader() { header_.version = reader_->ReadTwoBytes(headerptr); headerptr += 2; - assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_); - header_.abbrev_offset = reader_->ReadOffset(headerptr); - headerptr += reader_->OffsetSize(); - - // Compare against less than or equal because this may be the last - // section in the file. - assert(headerptr + 1 <= buffer_ + buffer_length_); - header_.address_size = reader_->ReadOneByte(headerptr); - reader_->SetAddressSize(header_.address_size); - headerptr += 1; - + if (header_.version <= 4) { + // Older versions of dwarf have a relatively simple structure. + headerptr += ReadAbbrevOffset(headerptr); + headerptr += ReadAddressSize(headerptr); + } else { + // DWARF5 adds a unit_type field, and various fields based on unit_type. + assert(headerptr + 1 < buffer_ + buffer_length_); + uint8_t unit_type = reader_->ReadOneByte(headerptr); + headerptr += 1; + headerptr += ReadAddressSize(headerptr); + headerptr += ReadAbbrevOffset(headerptr); + switch (unit_type) { + case DW_UT_compile: + case DW_UT_partial: + // nothing else to read + break; + case DW_UT_skeleton: + case DW_UT_split_compile: + headerptr += ReadDwoId(headerptr); + break; + case DW_UT_type: + case DW_UT_split_type: + is_type_unit_ = true; + headerptr += ReadTypeSignature(headerptr); + headerptr += ReadTypeOffset(headerptr); + break; + default: + fprintf(stderr, "Unhandled compilation unit type 0x%x", unit_type); + break; + } + } after_header_ = headerptr; // This check ensures that we don't have to do checking during the @@ -284,12 +389,9 @@ void CompilationUnit::ReadHeader() { } uint64_t CompilationUnit::Start() { - // First get the debug_info section. ".debug_info" is the name - // recommended in the DWARF spec, and used on Linux; "__debug_info" - // is the name used in Mac OS X Mach-O files. - SectionMap::const_iterator iter = sections_.find(".debug_info"); - if (iter == sections_.end()) - iter = sections_.find("__debug_info"); + // First get the debug_info section. + SectionMap::const_iterator iter = + GetSectionByName(sections_, ".debug_info"); assert(iter != sections_.end()); // Set up our buffer @@ -315,30 +417,35 @@ uint64_t CompilationUnit::Start() { header_.length, header_.version)) return ourlength; + else if (header_.version == 5 && is_type_unit_) + return ourlength; // Otherwise, continue by reading our abbreviation entries. ReadAbbrevs(); - // Set the string section if we have one. ".debug_str" is the name - // recommended in the DWARF spec, and used on Linux; "__debug_str" - // is the name used in Mac OS X Mach-O files. - iter = sections_.find(".debug_str"); - if (iter == sections_.end()) - iter = sections_.find("__debug_str"); + // Set the string section if we have one. + iter = GetSectionByName(sections_, ".debug_str"); if (iter != sections_.end()) { string_buffer_ = iter->second.first; string_buffer_length_ = iter->second.second; } + // Set the line string section if we have one. + iter = GetSectionByName(sections_, ".debug_line_str"); + if (iter != sections_.end()) { + line_string_buffer_ = iter->second.first; + line_string_buffer_length_ = iter->second.second; + } + // Set the string offsets section if we have one. - iter = sections_.find(".debug_str_offsets"); + iter = GetSectionByName(sections_, ".debug_str_offsets"); if (iter != sections_.end()) { str_offsets_buffer_ = iter->second.first; str_offsets_buffer_length_ = iter->second.second; } // Set the address section if we have one. - iter = sections_.find(".debug_addr"); + iter = GetSectionByName(sections_, ".debug_addr"); if (iter != sections_.end()) { addr_buffer_ = iter->second.first; addr_buffer_length_ = iter->second.second; @@ -358,12 +465,189 @@ uint64_t CompilationUnit::Start() { return ourlength; } +void CompilationUnit::ProcessFormStringIndex( + uint64_t dieoffset, enum DwarfAttribute attr, enum DwarfForm form, + uint64_t str_index) { + const size_t kStringOffsetsTableHeaderSize = + header_.version >= 5 ? (reader_->OffsetSize() == 8 ? 16 : 8) : 0; + const uint8_t* str_offsets_table_after_header = str_offsets_base_ ? + str_offsets_buffer_ + str_offsets_base_ : + str_offsets_buffer_ + kStringOffsetsTableHeaderSize; + const uint8_t* offset_ptr = + str_offsets_table_after_header + str_index * reader_->OffsetSize(); + + const uint64_t offset = reader_->ReadOffset(offset_ptr); + if (offset >= string_buffer_length_) { + return; + } + + const char* str = reinterpret_cast<const char*>(string_buffer_) + offset; + ProcessAttributeString(dieoffset, attr, form, str); +} + +// Special function for pre-processing the +// DW_AT_str_offsets_base and DW_AT_addr_base in a DW_TAG_compile_unit die (for +// DWARF v5). We must make sure to find and process the +// DW_AT_str_offsets_base and DW_AT_addr_base attributes before attempting to +// read any string and address attribute in the compile unit. +const uint8_t* CompilationUnit::ProcessOffsetBaseAttribute( + uint64_t dieoffset, const uint8_t* start, enum DwarfAttribute attr, + enum DwarfForm form, uint64_t implicit_const) { + size_t len; + + switch (form) { + // DW_FORM_indirect is never used because it is such a space + // waster. + case DW_FORM_indirect: + form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start, + &len)); + start += len; + return ProcessOffsetBaseAttribute(dieoffset, start, attr, form, + implicit_const); + + case DW_FORM_flag_present: + return start; + case DW_FORM_data1: + case DW_FORM_flag: + return start + 1; + case DW_FORM_data2: + return start + 2; + case DW_FORM_data4: + return start + 4; + case DW_FORM_data8: + return start + 8; + case DW_FORM_data16: + // This form is designed for an md5 checksum inside line tables. + return start + 16; + case DW_FORM_string: { + const char* str = reinterpret_cast<const char*>(start); + return start + strlen(str) + 1; + } + case DW_FORM_udata: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + case DW_FORM_sdata: + reader_->ReadSignedLEB128(start, &len); + return start + len; + case DW_FORM_addr: + reader_->ReadAddress(start); + return start + reader_->AddressSize(); + + // This is the important one here! + case DW_FORM_sec_offset: + if (attr == DW_AT_str_offsets_base || + attr == DW_AT_addr_base) + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadOffset(start)); + else + reader_->ReadOffset(start); + return start + reader_->OffsetSize(); + + case DW_FORM_ref1: + return start + 1; + case DW_FORM_ref2: + return start + 2; + case DW_FORM_ref4: + return start + 4; + case DW_FORM_ref8: + return start + 8; + case DW_FORM_ref_udata: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + case DW_FORM_ref_addr: + // DWARF2 and 3/4 differ on whether ref_addr is address size or + // offset size. + assert(header_.version >= 2); + if (header_.version == 2) { + reader_->ReadAddress(start); + return start + reader_->AddressSize(); + } else if (header_.version >= 3) { + reader_->ReadOffset(start); + return start + reader_->OffsetSize(); + } + break; + case DW_FORM_ref_sig8: + return start + 8; + case DW_FORM_implicit_const: + return start; + case DW_FORM_block1: { + uint64_t datalen = reader_->ReadOneByte(start); + return start + 1 + datalen; + } + case DW_FORM_block2: { + uint64_t datalen = reader_->ReadTwoBytes(start); + return start + 2 + datalen; + } + case DW_FORM_block4: { + uint64_t datalen = reader_->ReadFourBytes(start); + return start + 4 + datalen; + } + case DW_FORM_block: + case DW_FORM_exprloc: { + uint64_t datalen = reader_->ReadUnsignedLEB128(start, &len); + return start + datalen + len; + } + case DW_FORM_strp: { + reader_->ReadOffset(start); + return start + reader_->OffsetSize(); + } + case DW_FORM_line_strp: { + reader_->ReadOffset(start); + return start + reader_->OffsetSize(); + } + case DW_FORM_strp_sup: + return start + 4; + case DW_FORM_ref_sup4: + return start + 4; + case DW_FORM_ref_sup8: + return start + 8; + case DW_FORM_loclistx: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + case DW_FORM_strx: + case DW_FORM_GNU_str_index: { + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + } + case DW_FORM_strx1: { + return start + 1; + } + case DW_FORM_strx2: { + return start + 2; + } + case DW_FORM_strx3: { + return start + 3; + } + case DW_FORM_strx4: { + return start + 4; + } + + case DW_FORM_addrx: + case DW_FORM_GNU_addr_index: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + case DW_FORM_addrx1: + return start + 1; + case DW_FORM_addrx2: + return start + 2; + case DW_FORM_addrx3: + return start + 3; + case DW_FORM_addrx4: + return start + 4; + case DW_FORM_rnglistx: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + } + fprintf(stderr, "Unhandled form type\n"); + return NULL; +} + // If one really wanted, you could merge SkipAttribute and // ProcessAttribute // This is all boring data manipulation and calling of the handler. -const uint8_t *CompilationUnit::ProcessAttribute( - uint64_t dieoffset, const uint8_t *start, enum DwarfAttribute attr, - enum DwarfForm form) { +const uint8_t* CompilationUnit::ProcessAttribute( + uint64_t dieoffset, const uint8_t* start, enum DwarfAttribute attr, + enum DwarfForm form, uint64_t implicit_const) { size_t len; switch (form) { @@ -373,7 +657,7 @@ const uint8_t *CompilationUnit::ProcessAttribute( form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start, &len)); start += len; - return ProcessAttribute(dieoffset, start, attr, form); + return ProcessAttribute(dieoffset, start, attr, form, implicit_const); case DW_FORM_flag_present: ProcessAttributeUnsigned(dieoffset, attr, form, 1); @@ -395,8 +679,12 @@ const uint8_t *CompilationUnit::ProcessAttribute( ProcessAttributeUnsigned(dieoffset, attr, form, reader_->ReadEightBytes(start)); return start + 8; + case DW_FORM_data16: + // This form is designed for an md5 checksum inside line tables. + fprintf(stderr, "Unhandled form type: DW_FORM_data16\n"); + return start + 16; case DW_FORM_string: { - const char *str = reinterpret_cast<const char *>(start); + const char* str = reinterpret_cast<const char*>(start); ProcessAttributeString(dieoffset, attr, form, str); return start + strlen(str) + 1; } @@ -462,7 +750,10 @@ const uint8_t *CompilationUnit::ProcessAttribute( handler_->ProcessAttributeSignature(dieoffset, attr, form, reader_->ReadEightBytes(start)); return start + 8; - + case DW_FORM_implicit_const: + handler_->ProcessAttributeUnsigned(dieoffset, attr, form, + implicit_const); + return start; case DW_FORM_block1: { uint64_t datalen = reader_->ReadOneByte(start); handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1, @@ -494,45 +785,118 @@ const uint8_t *CompilationUnit::ProcessAttribute( const uint64_t offset = reader_->ReadOffset(start); assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_); - const char *str = reinterpret_cast<const char *>(string_buffer_ + offset); + const char* str = reinterpret_cast<const char*>(string_buffer_ + offset); ProcessAttributeString(dieoffset, attr, form, str); return start + reader_->OffsetSize(); } + case DW_FORM_line_strp: { + assert(line_string_buffer_ != NULL); - case DW_FORM_GNU_str_index: { - uint64_t str_index = reader_->ReadUnsignedLEB128(start, &len); - const uint8_t* offset_ptr = - str_offsets_buffer_ + str_index * reader_->OffsetSize(); - const uint64_t offset = reader_->ReadOffset(offset_ptr); - if (offset >= string_buffer_length_) { - return NULL; - } + const uint64_t offset = reader_->ReadOffset(start); + assert(line_string_buffer_ + offset < + line_string_buffer_ + line_string_buffer_length_); - const char* str = reinterpret_cast<const char *>(string_buffer_) + offset; + const char* str = + reinterpret_cast<const char*>(line_string_buffer_ + offset); ProcessAttributeString(dieoffset, attr, form, str); - return start + len; - break; + return start + reader_->OffsetSize(); } - case DW_FORM_GNU_addr_index: { - uint64_t addr_index = reader_->ReadUnsignedLEB128(start, &len); - const uint8_t* addr_ptr = - addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize(); + case DW_FORM_strp_sup: + // No support currently for suplementary object files. + fprintf(stderr, "Unhandled form type: DW_FORM_strp_sup\n"); + return start + 4; + case DW_FORM_ref_sup4: + // No support currently for suplementary object files. + fprintf(stderr, "Unhandled form type: DW_FORM_ref_sup4\n"); + return start + 4; + case DW_FORM_ref_sup8: + // No support currently for suplementary object files. + fprintf(stderr, "Unhandled form type: DW_FORM_ref_sup8\n"); + return start + 8; + case DW_FORM_loclistx: ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadAddress(addr_ptr)); + reader_->ReadUnsignedLEB128(start, &len)); return start + len; + case DW_FORM_strx: + case DW_FORM_GNU_str_index: { + uint64_t str_index = reader_->ReadUnsignedLEB128(start, &len); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + len; + } + case DW_FORM_strx1: { + uint64_t str_index = reader_->ReadOneByte(start); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + 1; + } + case DW_FORM_strx2: { + uint64_t str_index = reader_->ReadTwoBytes(start); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + 2; + } + case DW_FORM_strx3: { + uint64_t str_index = reader_->ReadThreeBytes(start); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + 3; + } + case DW_FORM_strx4: { + uint64_t str_index = reader_->ReadFourBytes(start); + ProcessFormStringIndex(dieoffset, attr, form, str_index); + return start + 4; } + + case DW_FORM_addrx: + case DW_FORM_GNU_addr_index: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadUnsignedLEB128(start, &len)); + return start + len; + case DW_FORM_addrx1: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadOneByte(start)); + return start + 1; + case DW_FORM_addrx2: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadTwoBytes(start)); + return start + 2; + case DW_FORM_addrx3: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadThreeBytes(start)); + return start + 3; + case DW_FORM_addrx4: + ProcessAttributeAddrIndex( + dieoffset, attr, form, reader_->ReadFourBytes(start)); + return start + 4; + case DW_FORM_rnglistx: + ProcessAttributeUnsigned( + dieoffset, attr, form, reader_->ReadUnsignedLEB128(start, &len)); + return start + len; } fprintf(stderr, "Unhandled form type\n"); return NULL; } -const uint8_t *CompilationUnit::ProcessDIE(uint64_t dieoffset, - const uint8_t *start, +const uint8_t* CompilationUnit::ProcessDIE(uint64_t dieoffset, + const uint8_t* start, const Abbrev& abbrev) { + // With DWARF v5, the compile_unit die may contain a + // DW_AT_str_offsets_base or DW_AT_addr_base. If it does, that attribute must + // be found and processed before trying to process the other attributes; + // otherwise the string or address values will all come out incorrect. + if (abbrev.tag == DW_TAG_compile_unit && header_.version == 5) { + uint64_t dieoffset_copy = dieoffset; + const uint8_t* start_copy = start; + for (AttributeList::const_iterator i = abbrev.attributes.begin(); + i != abbrev.attributes.end(); + i++) { + start_copy = ProcessOffsetBaseAttribute(dieoffset_copy, start_copy, + i->attr_, i->form_, + i->value_); + } + } + for (AttributeList::const_iterator i = abbrev.attributes.begin(); i != abbrev.attributes.end(); i++) { - start = ProcessAttribute(dieoffset, start, i->first, i->second); + start = ProcessAttribute(dieoffset, start, i->attr_, i->form_, i->value_); } // If this is a compilation unit in a split DWARF object, verify that @@ -548,12 +912,12 @@ const uint8_t *CompilationUnit::ProcessDIE(uint64_t dieoffset, } void CompilationUnit::ProcessDIEs() { - const uint8_t *dieptr = after_header_; + const uint8_t* dieptr = after_header_; size_t len; // lengthstart is the place the length field is based on. // It is the point in the header after the initial length field - const uint8_t *lengthstart = buffer_; + const uint8_t* lengthstart = buffer_; // In 64 bit dwarf, the initial length is 12 bytes, because of the // 0xffffffff at the start. @@ -563,7 +927,7 @@ void CompilationUnit::ProcessDIEs() { lengthstart += 4; std::stack<uint64_t> die_stack; - + while (dieptr < (lengthstart + header_.length)) { // We give the user the absolute offset from the beginning of // debug_info, since they need it to deal with ref_addr forms. @@ -589,8 +953,23 @@ void CompilationUnit::ProcessDIEs() { const enum DwarfTag tag = abbrev.tag; if (!handler_->StartDIE(absolute_offset, tag)) { dieptr = SkipDIE(dieptr, abbrev); + if (!dieptr) { + fprintf(stderr, + "An error happens when skipping a DIE's attributes at offset " + "0x%" PRIx64 + ". Stopped processing following DIEs in this CU.\n", + absolute_offset); + exit(1); + } } else { dieptr = ProcessDIE(absolute_offset, dieptr, abbrev); + if (!dieptr) { + fprintf(stderr, + "An error happens when processing a DIE at offset 0x%" PRIx64 + ". Stopped processing following DIEs in this CU.\n", + absolute_offset); + exit(1); + } } if (abbrev.has_children) { @@ -691,7 +1070,7 @@ void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, if (section_data != NULL) sections->insert(std::make_pair( base_name, std::make_pair( - reinterpret_cast<const uint8_t *>(section_data), + reinterpret_cast<const uint8_t*>(section_data), section_size))); } } @@ -720,11 +1099,11 @@ void DwpReader::Initialize() { &string_buffer_size_); version_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_)); + reinterpret_cast<const uint8_t*>(cu_index_)); if (version_ == 1) { nslots_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + reinterpret_cast<const uint8_t*>(cu_index_) + 3 * sizeof(uint32_t)); phash_ = cu_index_ + 4 * sizeof(uint32_t); pindex_ = phash_ + nslots_ * sizeof(uint64_t); @@ -732,13 +1111,13 @@ void DwpReader::Initialize() { if (shndx_pool_ >= cu_index_ + cu_index_size_) { version_ = 0; } - } else if (version_ == 2) { + } else if (version_ == 2 || version_ == 5) { ncolumns_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(cu_index_) + sizeof(uint32_t)); nunits_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + 2 * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(cu_index_) + 2 * sizeof(uint32_t)); nslots_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + 3 * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(cu_index_) + 3 * sizeof(uint32_t)); phash_ = cu_index_ + 4 * sizeof(uint32_t); pindex_ = phash_ + nslots_ * sizeof(uint64_t); offset_table_ = pindex_ + nslots_ * sizeof(uint32_t); @@ -766,7 +1145,7 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, // can read a list of section indexes for the debug sections // for the CU whose dwo_id we are looking for. int index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + reinterpret_cast<const uint8_t*>(pindex_) + slot * sizeof(uint32_t)); const char* shndx_list = shndx_pool_ + index * sizeof(uint32_t); for (;;) { @@ -775,7 +1154,7 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, return; } unsigned int shndx = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(shndx_list)); + reinterpret_cast<const uint8_t*>(shndx_list)); shndx_list += sizeof(uint32_t); if (shndx == 0) break; @@ -789,28 +1168,28 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); sections->insert(std::make_pair( ".debug_abbrev", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), + std::make_pair(reinterpret_cast<const uint8_t*> (section_data), section_size))); } else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) { section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); sections->insert(std::make_pair( ".debug_info", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), + std::make_pair(reinterpret_cast<const uint8_t*> (section_data), section_size))); } else if (!strncmp(section_name, ".debug_str_offsets", strlen(".debug_str_offsets"))) { section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); sections->insert(std::make_pair( ".debug_str_offsets", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), + std::make_pair(reinterpret_cast<const uint8_t*> (section_data), section_size))); } } sections->insert(std::make_pair( ".debug_str", - std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_), + std::make_pair(reinterpret_cast<const uint8_t*> (string_buffer_), string_buffer_size_))); - } else if (version_ == 2) { + } else if (version_ == 2 || version_ == 5) { uint32_t index = LookupCUv2(dwo_id); if (index == 0) { return; @@ -833,33 +1212,33 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, } for (unsigned int col = 0u; col < ncolumns_; ++col) { uint32_t section_id = - byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t *>(id_row) + byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t*>(id_row) + col * sizeof(uint32_t)); uint32_t offset = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(offset_row) + reinterpret_cast<const uint8_t*>(offset_row) + col * sizeof(uint32_t)); uint32_t size = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(size_row) + col * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(size_row) + col * sizeof(uint32_t)); if (section_id == DW_SECT_ABBREV) { sections->insert(std::make_pair( ".debug_abbrev", - std::make_pair(reinterpret_cast<const uint8_t *> (abbrev_data_) + std::make_pair(reinterpret_cast<const uint8_t*> (abbrev_data_) + offset, size))); } else if (section_id == DW_SECT_INFO) { sections->insert(std::make_pair( ".debug_info", - std::make_pair(reinterpret_cast<const uint8_t *> (info_data_) + std::make_pair(reinterpret_cast<const uint8_t*> (info_data_) + offset, size))); } else if (section_id == DW_SECT_STR_OFFSETS) { sections->insert(std::make_pair( ".debug_str_offsets", - std::make_pair(reinterpret_cast<const uint8_t *> (str_offsets_data_) + std::make_pair(reinterpret_cast<const uint8_t*> (str_offsets_data_) + offset, size))); } } sections->insert(std::make_pair( ".debug_str", - std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_), + std::make_pair(reinterpret_cast<const uint8_t*> (string_buffer_), string_buffer_size_))); } } @@ -867,14 +1246,14 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, int DwpReader::LookupCU(uint64_t dwo_id) { uint32_t slot = static_cast<uint32_t>(dwo_id) & (nslots_ - 1); uint64_t probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t)); + reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t)); if (probe != 0 && probe != dwo_id) { uint32_t secondary_hash = (static_cast<uint32_t>(dwo_id >> 32) & (nslots_ - 1)) | 1; do { slot = (slot + secondary_hash) & (nslots_ - 1); probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t)); + reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t)); } while (probe != 0 && probe != dwo_id); } if (probe == 0) @@ -885,28 +1264,35 @@ int DwpReader::LookupCU(uint64_t dwo_id) { uint32_t DwpReader::LookupCUv2(uint64_t dwo_id) { uint32_t slot = static_cast<uint32_t>(dwo_id) & (nslots_ - 1); uint64_t probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t)); + reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t)); uint32_t index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(pindex_) + slot * sizeof(uint32_t)); if (index != 0 && probe != dwo_id) { uint32_t secondary_hash = (static_cast<uint32_t>(dwo_id >> 32) & (nslots_ - 1)) | 1; do { slot = (slot + secondary_hash) & (nslots_ - 1); probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t)); + reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t)); index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32_t)); + reinterpret_cast<const uint8_t*>(pindex_) + slot * sizeof(uint32_t)); } while (index != 0 && probe != dwo_id); } return index; } -LineInfo::LineInfo(const uint8_t *buffer, uint64_t buffer_length, - ByteReader* reader, LineInfoHandler* handler): - handler_(handler), reader_(reader), buffer_(buffer) { +LineInfo::LineInfo(const uint8_t* buffer, uint64_t buffer_length, + ByteReader* reader, const uint8_t* string_buffer, + size_t string_buffer_length, + const uint8_t* line_string_buffer, + size_t line_string_buffer_length, LineInfoHandler* handler): + handler_(handler), reader_(reader), buffer_(buffer), + string_buffer_(string_buffer), + line_string_buffer_(line_string_buffer) { #ifndef NDEBUG buffer_length_ = buffer_length; + string_buffer_length_ = string_buffer_length; + line_string_buffer_length_ = line_string_buffer_length; #endif header_.std_opcode_lengths = NULL; } @@ -917,10 +1303,132 @@ uint64_t LineInfo::Start() { return after_header_ - buffer_; } +void LineInfo::ReadTypesAndForms(const uint8_t** lineptr, + uint32_t* content_types, + uint32_t* content_forms, + uint32_t max_types, + uint32_t* format_count) { + size_t len; + + uint32_t count = reader_->ReadUnsignedLEB128(*lineptr, &len); + *lineptr += len; + if (count < 1 || count > max_types) { + return; + } + for (uint32_t col = 0; col < count; ++col) { + content_types[col] = reader_->ReadUnsignedLEB128(*lineptr, &len); + *lineptr += len; + content_forms[col] = reader_->ReadUnsignedLEB128(*lineptr, &len); + *lineptr += len; + } + *format_count = count; +} + +const char* LineInfo::ReadStringForm(uint32_t form, const uint8_t** lineptr) { + const char* name = nullptr; + if (form == DW_FORM_string) { + name = reinterpret_cast<const char*>(*lineptr); + *lineptr += strlen(name) + 1; + return name; + } else if (form == DW_FORM_strp) { + uint64_t offset = reader_->ReadOffset(*lineptr); + assert(offset < string_buffer_length_); + *lineptr += reader_->OffsetSize(); + if (string_buffer_ != nullptr) { + name = reinterpret_cast<const char*>(string_buffer_) + offset; + return name; + } + } else if (form == DW_FORM_line_strp) { + uint64_t offset = reader_->ReadOffset(*lineptr); + assert(offset < line_string_buffer_length_); + *lineptr += reader_->OffsetSize(); + if (line_string_buffer_ != nullptr) { + name = reinterpret_cast<const char*>(line_string_buffer_) + offset; + return name; + } + } + // Shouldn't be called with a non-string-form, and + // if there is a string form but no string buffer, + // that is a problem too. + assert(0); + return nullptr; +} + +uint64_t LineInfo::ReadUnsignedData(uint32_t form, const uint8_t** lineptr) { + size_t len; + uint64_t value; + + switch (form) { + case DW_FORM_data1: + value = reader_->ReadOneByte(*lineptr); + *lineptr += 1; + return value; + case DW_FORM_data2: + value = reader_->ReadTwoBytes(*lineptr); + *lineptr += 2; + return value; + case DW_FORM_data4: + value = reader_->ReadFourBytes(*lineptr); + *lineptr += 4; + return value; + case DW_FORM_data8: + value = reader_->ReadEightBytes(*lineptr); + *lineptr += 8; + return value; + case DW_FORM_udata: + value = reader_->ReadUnsignedLEB128(*lineptr, &len); + *lineptr += len; + return value; + default: + fprintf(stderr, "Unrecognized data form."); + return 0; + } +} + +void LineInfo::ReadFileRow(const uint8_t** lineptr, + const uint32_t* content_types, + const uint32_t* content_forms, uint32_t row, + uint32_t format_count) { + const char* filename = nullptr; + uint64_t dirindex = 0; + uint64_t mod_time = 0; + uint64_t filelength = 0; + + for (uint32_t col = 0; col < format_count; ++col) { + switch (content_types[col]) { + case DW_LNCT_path: + filename = ReadStringForm(content_forms[col], lineptr); + break; + case DW_LNCT_directory_index: + dirindex = ReadUnsignedData(content_forms[col], lineptr); + break; + case DW_LNCT_timestamp: + mod_time = ReadUnsignedData(content_forms[col], lineptr); + break; + case DW_LNCT_size: + filelength = ReadUnsignedData(content_forms[col], lineptr); + break; + case DW_LNCT_MD5: + // MD5 entries help a debugger sort different versions of files with + // the same name. It is always paired with a DW_FORM_data16 and is + // unused in this case. + *lineptr += 16; + break; + default: + fprintf(stderr, "Unrecognized form in line table header. %d\n", + content_types[col]); + assert(false); + break; + } + } + assert(filename != nullptr); + handler_->DefineFile(filename, row, dirindex, mod_time, filelength); +} + // The header for a debug_line section is mildly complicated, because // the line info is very tightly encoded. void LineInfo::ReadHeader() { - const uint8_t *lineptr = buffer_; + const uint8_t* lineptr = buffer_; size_t initial_length_size; const uint64_t initial_length @@ -931,12 +1439,24 @@ void LineInfo::ReadHeader() { assert(buffer_ + initial_length_size + header_.total_length <= buffer_ + buffer_length_); - // Address size *must* be set by CU ahead of time. - assert(reader_->AddressSize() != 0); header_.version = reader_->ReadTwoBytes(lineptr); lineptr += 2; + if (header_.version >= 5) { + uint8_t address_size = reader_->ReadOneByte(lineptr); + reader_->SetAddressSize(address_size); + lineptr += 1; + uint8_t segment_selector_size = reader_->ReadOneByte(lineptr); + if (segment_selector_size != 0) { + fprintf(stderr,"No support for segmented memory."); + } + lineptr += 1; + } else { + // Address size *must* be set by CU ahead of time. + assert(reader_->AddressSize() != 0); + } + header_.prologue_length = reader_->ReadOffset(lineptr); lineptr += reader_->OffsetSize(); @@ -970,53 +1490,96 @@ void LineInfo::ReadHeader() { lineptr += 1; } - // It is legal for the directory entry table to be empty. - if (*lineptr) { - uint32_t dirindex = 1; - while (*lineptr) { - const char *dirname = reinterpret_cast<const char *>(lineptr); - handler_->DefineDir(dirname, dirindex); - lineptr += strlen(dirname) + 1; - dirindex++; + if (header_.version <= 4) { + // Directory zero is assumed to be the compilation directory and special + // cased where used. It is not actually stored in the dwarf data. But an + // empty entry here avoids off-by-one errors elsewhere in the code. + handler_->DefineDir("", 0); + // It is legal for the directory entry table to be empty. + if (*lineptr) { + uint32_t dirindex = 1; + while (*lineptr) { + const char* dirname = reinterpret_cast<const char*>(lineptr); + handler_->DefineDir(dirname, dirindex); + lineptr += strlen(dirname) + 1; + dirindex++; + } } - } - lineptr++; - - // It is also legal for the file entry table to be empty. - if (*lineptr) { - uint32_t fileindex = 1; + lineptr++; + // It is also legal for the file entry table to be empty. + + // Similarly for file zero. + handler_->DefineFile("", 0, 0, 0, 0); + if (*lineptr) { + uint32_t fileindex = 1; + size_t len; + while (*lineptr) { + const char* filename = ReadStringForm(DW_FORM_string, &lineptr); + + uint64_t dirindex = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + + uint64_t mod_time = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + + uint64_t filelength = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + handler_->DefineFile(filename, fileindex, + static_cast<uint32_t>(dirindex), mod_time, + filelength); + fileindex++; + } + } + lineptr++; + } else { + // Read the DWARF-5 directory table. + + // Dwarf5 supports five different types and forms per directory- and + // file-table entry. Theoretically, there could be duplicate entries + // in this table, but that would be quite unusual. + static const uint32_t kMaxTypesAndForms = 5; + uint32_t content_types[kMaxTypesAndForms]; + uint32_t content_forms[kMaxTypesAndForms]; + uint32_t format_count; size_t len; - while (*lineptr) { - const char *filename = reinterpret_cast<const char *>(lineptr); - lineptr += strlen(filename) + 1; - uint64_t dirindex = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; + ReadTypesAndForms(&lineptr, content_types, content_forms, kMaxTypesAndForms, + &format_count); + uint32_t entry_count = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + for (uint32_t row = 0; row < entry_count; ++row) { + const char* dirname = nullptr; + for (uint32_t col = 0; col < format_count; ++col) { + // The path is the only relevant content type for this implementation. + if (content_types[col] == DW_LNCT_path) { + dirname = ReadStringForm(content_forms[col], &lineptr); + } + } + handler_->DefineDir(dirname, row); + } - uint64_t mod_time = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; + // Read the DWARF-5 filename table. + ReadTypesAndForms(&lineptr, content_types, content_forms, kMaxTypesAndForms, + &format_count); + entry_count = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; - uint64_t filelength = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; - handler_->DefineFile(filename, fileindex, static_cast<uint32_t>(dirindex), - mod_time, filelength); - fileindex++; + for (uint32_t row = 0; row < entry_count; ++row) { + ReadFileRow(&lineptr, content_types, content_forms, row, format_count); } } - lineptr++; - after_header_ = lineptr; } /* static */ bool LineInfo::ProcessOneOpcode(ByteReader* reader, LineInfoHandler* handler, - const struct LineInfoHeader &header, - const uint8_t *start, + const struct LineInfoHeader& header, + const uint8_t* start, struct LineStateMachine* lsm, size_t* len, uintptr pc, - bool *lsm_passes_pc) { + bool* lsm_passes_pc) { size_t oplen = 0; size_t templen; uint8_t opcode = reader->ReadOneByte(start); @@ -1153,7 +1716,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader, } break; case DW_LNE_define_file: { - const char *filename = reinterpret_cast<const char *>(start); + const char* filename = reinterpret_cast<const char*>(start); templen = strlen(filename) + 1; start += templen; @@ -1170,7 +1733,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader, oplen += templen; if (handler) { - handler->DefineFile(filename, -1, static_cast<uint32_t>(dirindex), + handler->DefineFile(filename, -1, static_cast<uint32_t>(dirindex), mod_time, filelength); } } @@ -1200,7 +1763,7 @@ void LineInfo::ReadLines() { // lengthstart is the place the length field is based on. // It is the point in the header after the initial length field - const uint8_t *lengthstart = buffer_; + const uint8_t* lengthstart = buffer_; // In 64 bit dwarf, the initial length is 12 bytes, because of the // 0xffffffff at the start. @@ -1209,7 +1772,7 @@ void LineInfo::ReadLines() { else lengthstart += 4; - const uint8_t *lineptr = after_header_; + const uint8_t* lineptr = after_header_; lsm.Reset(header_.default_is_stmt); // The LineInfoHandler interface expects each line's length along @@ -1232,7 +1795,7 @@ void LineInfo::ReadLines() { pending_file_num, pending_line_num, pending_column_num); if (lsm.end_sequence) { - lsm.Reset(header_.default_is_stmt); + lsm.Reset(header_.default_is_stmt); have_pending_line = false; } else { pending_address = lsm.address; @@ -1248,11 +1811,25 @@ void LineInfo::ReadLines() { after_header_ = lengthstart + header_.total_length; } -RangeListReader::RangeListReader(const uint8_t *buffer, uint64_t size, - ByteReader *reader, RangeListHandler *handler) - : buffer_(buffer), size_(size), reader_(reader), handler_(handler) { } +bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) { + if (form == DW_FORM_sec_offset) { + if (cu_info_->version_ <= 4) { + return ReadDebugRanges(data); + } else { + return ReadDebugRngList(data); + } + } else if (form == DW_FORM_rnglistx) { + offset_array_ = cu_info_->ranges_base_; + uint64_t index_offset = reader_->OffsetSize() * data; + uint64_t range_list_offset = + reader_->ReadOffset(cu_info_->buffer_ + offset_array_ + index_offset); -bool RangeListReader::ReadRangeList(uint64_t offset) { + return ReadDebugRngList(offset_array_ + range_list_offset); + } + return false; +} + +bool RangeListReader::ReadDebugRanges(uint64_t offset) { const uint64_t max_address = (reader_->AddressSize() == 4) ? 0xffffffffUL : 0xffffffffffffffffULL; @@ -1260,21 +1837,22 @@ bool RangeListReader::ReadRangeList(uint64_t offset) { bool list_end = false; do { - if (offset > size_ - entry_size) { + if (offset > cu_info_->size_ - entry_size) { return false; // Invalid range detected } - uint64_t start_address = reader_->ReadAddress(buffer_ + offset); - uint64_t end_address = - reader_->ReadAddress(buffer_ + offset + reader_->AddressSize()); + uint64_t start_address = reader_->ReadAddress(cu_info_->buffer_ + offset); + uint64_t end_address = reader_->ReadAddress( + cu_info_->buffer_ + offset + reader_->AddressSize()); if (start_address == max_address) { // Base address selection - handler_->SetBaseAddress(end_address); + cu_info_->base_address_ = end_address; } else if (start_address == 0 && end_address == 0) { // End-of-list handler_->Finish(); list_end = true; } else { // Add a range entry - handler_->AddRange(start_address, end_address); + handler_->AddRange(start_address + cu_info_->base_address_, + end_address + cu_info_->base_address_); } offset += entry_size; @@ -1283,6 +1861,62 @@ bool RangeListReader::ReadRangeList(uint64_t offset) { return true; } +bool RangeListReader::ReadDebugRngList(uint64_t offset) { + uint64_t start = 0; + uint64_t end = 0; + uint64_t range_len = 0; + uint64_t index = 0; + // A uleb128's length isn't known until after it has been read, so overruns + // are only caught after an entire entry. + while (offset < cu_info_->size_) { + uint8_t entry_type = reader_->ReadOneByte(cu_info_->buffer_ + offset); + offset += 1; + // Handle each entry type per Dwarf 5 Standard, section 2.17.3. + switch (entry_type) { + case DW_RLE_end_of_list: + handler_->Finish(); + return true; + case DW_RLE_base_addressx: + offset += ReadULEB(offset, &index); + cu_info_->base_address_ = GetAddressAtIndex(index); + break; + case DW_RLE_startx_endx: + offset += ReadULEB(offset, &index); + start = GetAddressAtIndex(index); + offset += ReadULEB(offset, &index); + end = GetAddressAtIndex(index); + handler_->AddRange(start, end); + break; + case DW_RLE_startx_length: + offset += ReadULEB(offset, &index); + start = GetAddressAtIndex(index); + offset += ReadULEB(offset, &range_len); + handler_->AddRange(start, start + range_len); + break; + case DW_RLE_offset_pair: + offset += ReadULEB(offset, &start); + offset += ReadULEB(offset, &end); + handler_->AddRange(start + cu_info_->base_address_, + end + cu_info_->base_address_); + break; + case DW_RLE_base_address: + offset += ReadAddress(offset, &cu_info_->base_address_); + break; + case DW_RLE_start_end: + offset += ReadAddress(offset, &start); + offset += ReadAddress(offset, &end); + handler_->AddRange(start, end); + break; + case DW_RLE_start_length: + offset += ReadAddress(offset, &start); + offset += ReadULEB(offset, &end); + handler_->AddRange(start, start + end); + break; + } + } + return false; +} + // A DWARF rule for recovering the address or value of a register, or // computing the canonical frame address. There is one subclass of this for // each '*Rule' member function in CallFrameInfo::Handler. @@ -1305,17 +1939,17 @@ class CallFrameInfo::Rule { // this rule. If REG is kCFARegister, then this rule describes how to compute // the canonical frame address. Return what the HANDLER member function // returned. - virtual bool Handle(Handler *handler, + virtual bool Handle(Handler* handler, uint64_t address, int reg) const = 0; // Equality on rules. We use these to decide which rules we need // to report after a DW_CFA_restore_state instruction. - virtual bool operator==(const Rule &rhs) const = 0; + virtual bool operator==(const Rule& rhs) const = 0; - bool operator!=(const Rule &rhs) const { return ! (*this == rhs); } + bool operator!=(const Rule& rhs) const { return ! (*this == rhs); } // Return a pointer to a copy of this rule. - virtual Rule *Copy() const = 0; + virtual Rule* Copy() const = 0; // If this is a base+offset rule, change its base register to REG. // Otherwise, do nothing. (Ugly, but required for DW_CFA_def_cfa_register.) @@ -1331,16 +1965,16 @@ class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule { public: UndefinedRule() { } ~UndefinedRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->UndefinedRule(address, reg); } - bool operator==(const Rule &rhs) const { + bool operator==(const Rule& rhs) const { // dynamic_cast is allowed by the Google C++ Style Guide, if the use has // been carefully considered; cheap RTTI-like workarounds are forbidden. - const UndefinedRule *our_rhs = dynamic_cast<const UndefinedRule *>(&rhs); + const UndefinedRule* our_rhs = dynamic_cast<const UndefinedRule*>(&rhs); return (our_rhs != NULL); } - Rule *Copy() const { return new UndefinedRule(*this); } + Rule* Copy() const { return new UndefinedRule(*this); } }; // Rule: the register's value is the same as that it had in the caller. @@ -1348,16 +1982,16 @@ class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule { public: SameValueRule() { } ~SameValueRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->SameValueRule(address, reg); } - bool operator==(const Rule &rhs) const { + bool operator==(const Rule& rhs) const { // dynamic_cast is allowed by the Google C++ Style Guide, if the use has // been carefully considered; cheap RTTI-like workarounds are forbidden. - const SameValueRule *our_rhs = dynamic_cast<const SameValueRule *>(&rhs); + const SameValueRule* our_rhs = dynamic_cast<const SameValueRule*>(&rhs); return (our_rhs != NULL); } - Rule *Copy() const { return new SameValueRule(*this); } + Rule* Copy() const { return new SameValueRule(*this); } }; // Rule: the register is saved at OFFSET from BASE_REGISTER. BASE_REGISTER @@ -1367,18 +2001,18 @@ class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule { OffsetRule(int base_register, long offset) : base_register_(base_register), offset_(offset) { } ~OffsetRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->OffsetRule(address, reg, base_register_, offset_); } - bool operator==(const Rule &rhs) const { + bool operator==(const Rule& rhs) const { // dynamic_cast is allowed by the Google C++ Style Guide, if the use has // been carefully considered; cheap RTTI-like workarounds are forbidden. - const OffsetRule *our_rhs = dynamic_cast<const OffsetRule *>(&rhs); + const OffsetRule* our_rhs = dynamic_cast<const OffsetRule*>(&rhs); return (our_rhs && base_register_ == our_rhs->base_register_ && offset_ == our_rhs->offset_); } - Rule *Copy() const { return new OffsetRule(*this); } + Rule* Copy() const { return new OffsetRule(*this); } // We don't actually need SetBaseRegister or SetOffset here, since they // are only ever applied to CFA rules, for DW_CFA_def_cfa_offset, and it // doesn't make sense to use OffsetRule for computing the CFA: it @@ -1396,18 +2030,18 @@ class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule { ValOffsetRule(int base_register, long offset) : base_register_(base_register), offset_(offset) { } ~ValOffsetRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->ValOffsetRule(address, reg, base_register_, offset_); } - bool operator==(const Rule &rhs) const { + bool operator==(const Rule& rhs) const { // dynamic_cast is allowed by the Google C++ Style Guide, if the use has // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ValOffsetRule *our_rhs = dynamic_cast<const ValOffsetRule *>(&rhs); + const ValOffsetRule* our_rhs = dynamic_cast<const ValOffsetRule*>(&rhs); return (our_rhs && base_register_ == our_rhs->base_register_ && offset_ == our_rhs->offset_); } - Rule *Copy() const { return new ValOffsetRule(*this); } + Rule* Copy() const { return new ValOffsetRule(*this); } void SetBaseRegister(unsigned reg) { base_register_ = reg; } void SetOffset(long long offset) { offset_ = offset; } private: @@ -1421,16 +2055,16 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule { explicit RegisterRule(int register_number) : register_number_(register_number) { } ~RegisterRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->RegisterRule(address, reg, register_number_); } - bool operator==(const Rule &rhs) const { + bool operator==(const Rule& rhs) const { // dynamic_cast is allowed by the Google C++ Style Guide, if the use has // been carefully considered; cheap RTTI-like workarounds are forbidden. - const RegisterRule *our_rhs = dynamic_cast<const RegisterRule *>(&rhs); + const RegisterRule* our_rhs = dynamic_cast<const RegisterRule*>(&rhs); return (our_rhs && register_number_ == our_rhs->register_number_); } - Rule *Copy() const { return new RegisterRule(*this); } + Rule* Copy() const { return new RegisterRule(*this); } private: int register_number_; }; @@ -1438,19 +2072,19 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule { // Rule: EXPRESSION evaluates to the address at which the register is saved. class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule { public: - explicit ExpressionRule(const string &expression) + explicit ExpressionRule(const string& expression) : expression_(expression) { } ~ExpressionRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->ExpressionRule(address, reg, expression_); } - bool operator==(const Rule &rhs) const { + bool operator==(const Rule& rhs) const { // dynamic_cast is allowed by the Google C++ Style Guide, if the use has // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ExpressionRule *our_rhs = dynamic_cast<const ExpressionRule *>(&rhs); + const ExpressionRule* our_rhs = dynamic_cast<const ExpressionRule*>(&rhs); return (our_rhs && expression_ == our_rhs->expression_); } - Rule *Copy() const { return new ExpressionRule(*this); } + Rule* Copy() const { return new ExpressionRule(*this); } private: string expression_; }; @@ -1458,20 +2092,20 @@ class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule { // Rule: EXPRESSION evaluates to the address at which the register is saved. class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { public: - explicit ValExpressionRule(const string &expression) + explicit ValExpressionRule(const string& expression) : expression_(expression) { } ~ValExpressionRule() { } - bool Handle(Handler *handler, uint64_t address, int reg) const { + bool Handle(Handler* handler, uint64_t address, int reg) const { return handler->ValExpressionRule(address, reg, expression_); } - bool operator==(const Rule &rhs) const { + bool operator==(const Rule& rhs) const { // dynamic_cast is allowed by the Google C++ Style Guide, if the use has // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ValExpressionRule *our_rhs = - dynamic_cast<const ValExpressionRule *>(&rhs); + const ValExpressionRule* our_rhs = + dynamic_cast<const ValExpressionRule*>(&rhs); return (our_rhs && expression_ == our_rhs->expression_); } - Rule *Copy() const { return new ValExpressionRule(*this); } + Rule* Copy() const { return new ValExpressionRule(*this); } private: string expression_; }; @@ -1480,51 +2114,51 @@ class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { class CallFrameInfo::RuleMap { public: RuleMap() : cfa_rule_(NULL) { } - RuleMap(const RuleMap &rhs) : cfa_rule_(NULL) { *this = rhs; } + RuleMap(const RuleMap& rhs) : cfa_rule_(NULL) { *this = rhs; } ~RuleMap() { Clear(); } - RuleMap &operator=(const RuleMap &rhs); + RuleMap& operator=(const RuleMap& rhs); // Set the rule for computing the CFA to RULE. Take ownership of RULE. - void SetCFARule(Rule *rule) { delete cfa_rule_; cfa_rule_ = rule; } + void SetCFARule(Rule* rule) { delete cfa_rule_; cfa_rule_ = rule; } // Return the current CFA rule. Unlike RegisterRule, this RuleMap retains // ownership of the rule. We use this for DW_CFA_def_cfa_offset and // DW_CFA_def_cfa_register, and for detecting references to the CFA before // a rule for it has been established. - Rule *CFARule() const { return cfa_rule_; } + Rule* CFARule() const { return cfa_rule_; } // Return the rule for REG, or NULL if there is none. The caller takes // ownership of the result. - Rule *RegisterRule(int reg) const; + Rule* RegisterRule(int reg) const; // Set the rule for computing REG to RULE. Take ownership of RULE. - void SetRegisterRule(int reg, Rule *rule); + void SetRegisterRule(int reg, Rule* rule); // Make all the appropriate calls to HANDLER as if we were changing from // this RuleMap to NEW_RULES at ADDRESS. We use this to implement // DW_CFA_restore_state, where lots of rules can change simultaneously. // Return true if all handlers returned true; otherwise, return false. - bool HandleTransitionTo(Handler *handler, uint64_t address, - const RuleMap &new_rules) const; + bool HandleTransitionTo(Handler* handler, uint64_t address, + const RuleMap& new_rules) const; private: // A map from register numbers to Rules. - typedef std::map<int, Rule *> RuleByNumber; + typedef std::map<int, Rule*> RuleByNumber; // Remove all register rules and clear cfa_rule_. void Clear(); // The rule for computing the canonical frame address. This RuleMap owns // this rule. - Rule *cfa_rule_; + Rule* cfa_rule_; // A map from register numbers to postfix expressions to recover // their values. This RuleMap owns the Rules the map refers to. RuleByNumber registers_; }; -CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) { +CallFrameInfo::RuleMap& CallFrameInfo::RuleMap::operator=(const RuleMap& rhs) { Clear(); // Since each map owns the rules it refers to, assignment must copy them. if (rhs.cfa_rule_) cfa_rule_ = rhs.cfa_rule_->Copy(); @@ -1534,7 +2168,7 @@ CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) { return *this; } -CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const { +CallFrameInfo::Rule* CallFrameInfo::RuleMap::RegisterRule(int reg) const { assert(reg != Handler::kCFARegister); RuleByNumber::const_iterator it = registers_.find(reg); if (it != registers_.end()) @@ -1543,18 +2177,18 @@ CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const { return NULL; } -void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule *rule) { +void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule* rule) { assert(reg != Handler::kCFARegister); assert(rule); - Rule **slot = ®isters_[reg]; + Rule** slot = ®isters_[reg]; delete *slot; *slot = rule; } bool CallFrameInfo::RuleMap::HandleTransitionTo( - Handler *handler, + Handler* handler, uint64_t address, - const RuleMap &new_rules) const { + const RuleMap& new_rules) const { // Transition from cfa_rule_ to new_rules.cfa_rule_. if (cfa_rule_ && new_rules.cfa_rule_) { if (*cfa_rule_ != *new_rules.cfa_rule_ && @@ -1634,7 +2268,7 @@ class CallFrameInfo::State { public: // Create a call frame information interpreter state with the given // reporter, reader, handler, and initial call frame info address. - State(ByteReader *reader, Handler *handler, Reporter *reporter, + State(ByteReader* reader, Handler* handler, Reporter* reporter, uint64_t address) : reader_(reader), handler_(handler), reporter_(reporter), address_(address), entry_(NULL), cursor_(NULL) { } @@ -1642,13 +2276,13 @@ class CallFrameInfo::State { // Interpret instructions from CIE, save the resulting rule set for // DW_CFA_restore instructions, and return true. On error, report // the problem to reporter_ and return false. - bool InterpretCIE(const CIE &cie); + bool InterpretCIE(const CIE& cie); // Interpret instructions from FDE, and return true. On error, // report the problem to reporter_ and return false. - bool InterpretFDE(const FDE &fde); + bool InterpretFDE(const FDE& fde); - private: + private: // The operands of a CFI instruction, for ParseOperands. struct Operands { unsigned register_number; // A register number. @@ -1676,7 +2310,7 @@ class CallFrameInfo::State { // '8' an eight-byte offset (OPERANDS->offset) // 'e' a DW_FORM_block holding a (OPERANDS->expression) // DWARF expression - bool ParseOperands(const char *format, Operands *operands); + bool ParseOperands(const char* format, Operands* operands); // Interpret one CFI instruction from STATE's instruction stream, update // STATE, report any rule changes to handler_, and return true. On @@ -1699,7 +2333,7 @@ class CallFrameInfo::State { // Specify that REG can be recovered using RULE, and return true. On // failure, report and return false. - bool DoRule(unsigned reg, Rule *rule); + bool DoRule(unsigned reg, Rule* rule); // Specify that REG can be found at OFFSET from the CFA, and return true. // On failure, report and return false. (Subroutine for DW_CFA_offset, @@ -1727,23 +2361,23 @@ class CallFrameInfo::State { } // For reading multi-byte values with the appropriate endianness. - ByteReader *reader_; + ByteReader* reader_; // The handler to which we should report the data we find. - Handler *handler_; + Handler* handler_; // For reporting problems in the info we're parsing. - Reporter *reporter_; + Reporter* reporter_; // The code address to which the next instruction in the stream applies. uint64_t address_; // The entry whose instructions we are currently processing. This is // first a CIE, and then an FDE. - const Entry *entry_; + const Entry* entry_; // The next instruction to process. - const uint8_t *cursor_; + const uint8_t* cursor_; // The current set of rules. RuleMap rules_; @@ -1758,7 +2392,7 @@ class CallFrameInfo::State { std::stack<RuleMap> saved_rules_; }; -bool CallFrameInfo::State::InterpretCIE(const CIE &cie) { +bool CallFrameInfo::State::InterpretCIE(const CIE& cie) { entry_ = &cie; cursor_ = entry_->instructions; while (cursor_ < entry_->end) @@ -1770,7 +2404,7 @@ bool CallFrameInfo::State::InterpretCIE(const CIE &cie) { return true; } -bool CallFrameInfo::State::InterpretFDE(const FDE &fde) { +bool CallFrameInfo::State::InterpretFDE(const FDE& fde) { entry_ = &fde; cursor_ = entry_->instructions; while (cursor_ < entry_->end) @@ -1779,10 +2413,10 @@ bool CallFrameInfo::State::InterpretFDE(const FDE &fde) { return true; } -bool CallFrameInfo::State::ParseOperands(const char *format, - Operands *operands) { +bool CallFrameInfo::State::ParseOperands(const char* format, + Operands* operands) { size_t len; - const char *operand; + const char* operand; for (operand = format; *operand; operand++) { size_t bytes_left = entry_->end - cursor_; @@ -1841,7 +2475,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format, if (len > bytes_left || expression_length > bytes_left - len) return ReportIncomplete(); cursor_ += len; - operands->expression = string(reinterpret_cast<const char *>(cursor_), + operands->expression = string(reinterpret_cast<const char*>(cursor_), expression_length); cursor_ += expression_length; break; @@ -1856,7 +2490,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format, } bool CallFrameInfo::State::DoInstruction() { - CIE *cie = entry_->cie; + CIE* cie = entry_->cie; Operands ops; // Our entry's kind should have been set by now. @@ -1909,19 +2543,19 @@ bool CallFrameInfo::State::DoInstruction() { if (!ParseOperands("1", &ops)) return false; address_ += ops.offset * cie->code_alignment_factor; break; - + // Advance the address. case DW_CFA_advance_loc2: if (!ParseOperands("2", &ops)) return false; address_ += ops.offset * cie->code_alignment_factor; break; - + // Advance the address. case DW_CFA_advance_loc4: if (!ParseOperands("4", &ops)) return false; address_ += ops.offset * cie->code_alignment_factor; break; - + // Advance the address. case DW_CFA_MIPS_advance_loc8: if (!ParseOperands("8", &ops)) return false; @@ -1946,7 +2580,7 @@ bool CallFrameInfo::State::DoInstruction() { // Change the base register used to compute the CFA. case DW_CFA_def_cfa_register: { if (!ParseOperands("r", &ops)) return false; - Rule *cfa_rule = rules_.CFARule(); + Rule* cfa_rule = rules_.CFARule(); if (!cfa_rule) { if (!DoDefCFA(ops.register_number, ops.offset)) { reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); @@ -1979,7 +2613,7 @@ bool CallFrameInfo::State::DoInstruction() { case DW_CFA_def_cfa_expression: { if (!ParseOperands("e", &ops)) return false; - Rule *rule = new ValExpressionRule(ops.expression); + Rule* rule = new ValExpressionRule(ops.expression); rules_.SetCFARule(rule); if (!rule->Handle(handler_, address_, Handler::kCFARegister)) @@ -2086,7 +2720,7 @@ bool CallFrameInfo::State::DoInstruction() { CursorOffset()); return false; } - const RuleMap &new_rules = saved_rules_.top(); + const RuleMap& new_rules = saved_rules_.top(); if (rules_.CFARule() && !new_rules.CFARule()) { reporter_->ClearingCFARule(entry_->offset, entry_->kind, CursorOffset()); @@ -2102,23 +2736,32 @@ bool CallFrameInfo::State::DoInstruction() { case DW_CFA_nop: break; - // A SPARC register window save: Registers 8 through 15 (%o0-%o7) - // are saved in registers 24 through 31 (%i0-%i7), and registers - // 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets - // (0-15 * the register size). The register numbers must be - // hard-coded. A GNU extension, and not a pretty one. + // case DW_CFA_AARCH64_negate_ra_state case DW_CFA_GNU_window_save: { - // Save %o0-%o7 in %i0-%i7. - for (int i = 8; i < 16; i++) - if (!DoRule(i, new RegisterRule(i + 16))) - return false; - // Save %l0-%l7 and %i0-%i7 at the CFA. - for (int i = 16; i < 32; i++) - // Assume that the byte reader's address size is the same as - // the architecture's register size. !@#%*^ hilarious. - if (!DoRule(i, new OffsetRule(Handler::kCFARegister, - (i - 16) * reader_->AddressSize()))) - return false; + if (handler_->Architecture() == "arm64") { + // Indicates that the return address, x30 has been signed. + // Breakpad will speculatively remove pointer-authentication codes when + // interpreting return addresses, regardless of this bit. + } else if (handler_->Architecture() == "sparc" || + handler_->Architecture() == "sparcv9") { + // A SPARC register window save: Registers 8 through 15 (%o0-%o7) + // are saved in registers 24 through 31 (%i0-%i7), and registers + // 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets + // (0-15 * the register size). The register numbers must be + // hard-coded. A GNU extension, and not a pretty one. + + // Save %o0-%o7 in %i0-%i7. + for (int i = 8; i < 16; i++) + if (!DoRule(i, new RegisterRule(i + 16))) + return false; + // Save %l0-%l7 and %i0-%i7 at the CFA. + for (int i = 16; i < 32; i++) + // Assume that the byte reader's address size is the same as + // the architecture's register size. !@#%*^ hilarious. + if (!DoRule(i, new OffsetRule(Handler::kCFARegister, + (i - 16) * reader_->AddressSize()))) + return false; + } break; } @@ -2138,14 +2781,14 @@ bool CallFrameInfo::State::DoInstruction() { } bool CallFrameInfo::State::DoDefCFA(unsigned base_register, long offset) { - Rule *rule = new ValOffsetRule(base_register, offset); + Rule* rule = new ValOffsetRule(base_register, offset); rules_.SetCFARule(rule); return rule->Handle(handler_, address_, Handler::kCFARegister); } bool CallFrameInfo::State::DoDefCFAOffset(long offset) { - Rule *cfa_rule = rules_.CFARule(); + Rule* cfa_rule = rules_.CFARule(); if (!cfa_rule) { reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); return false; @@ -2155,7 +2798,7 @@ bool CallFrameInfo::State::DoDefCFAOffset(long offset) { Handler::kCFARegister); } -bool CallFrameInfo::State::DoRule(unsigned reg, Rule *rule) { +bool CallFrameInfo::State::DoRule(unsigned reg, Rule* rule) { rules_.SetRegisterRule(reg, rule); return rule->Handle(handler_, address_, reg); } @@ -2184,7 +2827,7 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) { reporter_->RestoreInCIE(entry_->offset, CursorOffset()); return false; } - Rule *rule = cie_rules_.RegisterRule(reg); + Rule* rule = cie_rules_.RegisterRule(reg); if (!rule) { // This isn't really the right thing to do, but since CFI generally // only mentions callee-saves registers, and GCC's convention for @@ -2195,8 +2838,8 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) { return DoRule(reg, rule); } -bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { - const uint8_t *buffer_end = buffer_ + buffer_length_; +bool CallFrameInfo::ReadEntryPrologue(const uint8_t* cursor, Entry* entry) { + const uint8_t* buffer_end = buffer_ + buffer_length_; // Initialize enough of ENTRY for use in error reporting. entry->offset = cursor - buffer_; @@ -2222,7 +2865,7 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { // Validate the length. if (length > size_t(buffer_end - cursor)) return ReportIncomplete(entry); - + // The length is the number of bytes after the initial length field; // we have that position handy at this point, so compute the end // now. (If we're parsing 64-bit-offset DWARF on a 32-bit machine, @@ -2264,7 +2907,7 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { // Now advance cursor past the id. cursor += offset_size; - + // The fields specific to this kind of entry start here. entry->fields = cursor; @@ -2273,8 +2916,8 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { return true; } -bool CallFrameInfo::ReadCIEFields(CIE *cie) { - const uint8_t *cursor = cie->fields; +bool CallFrameInfo::ReadCIEFields(CIE* cie) { + const uint8_t* cursor = cie->fields; size_t len; assert(cie->kind == kCIE); @@ -2305,13 +2948,13 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { return false; } - const uint8_t *augmentation_start = cursor; - const uint8_t *augmentation_end = - reinterpret_cast<const uint8_t *>(memchr(augmentation_start, '\0', + const uint8_t* augmentation_start = cursor; + const uint8_t* augmentation_end = + reinterpret_cast<const uint8_t*>(memchr(augmentation_start, '\0', cie->end - augmentation_start)); if (! augmentation_end) return ReportIncomplete(cie); cursor = augmentation_end; - cie->augmentation = string(reinterpret_cast<const char *>(augmentation_start), + cie->augmentation = string(reinterpret_cast<const char*>(augmentation_start), cursor - augmentation_start); // Skip the terminating '\0'. cursor++; @@ -2372,9 +3015,9 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { if (size_t(cie->end - cursor) < len + data_size) return ReportIncomplete(cie); cursor += len; - const uint8_t *data = cursor; + const uint8_t* data = cursor; cursor += data_size; - const uint8_t *data_end = cursor; + const uint8_t* data_end = cursor; cie->has_z_lsda = false; cie->has_z_personality = false; @@ -2465,8 +3108,8 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { return true; } -bool CallFrameInfo::ReadFDEFields(FDE *fde) { - const uint8_t *cursor = fde->fields; +bool CallFrameInfo::ReadFDEFields(FDE* fde) { + const uint8_t* cursor = fde->fields; size_t size; fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding, @@ -2492,7 +3135,7 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) { if (size_t(fde->end - cursor) < size + data_size) return ReportIncomplete(fde); cursor += size; - + // In the abstract, we should walk the augmentation string, and extract // items from the FDE's augmentation data as we encounter augmentation // string characters that specify their presence: the ordering of items @@ -2530,12 +3173,12 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) { return true; } - + bool CallFrameInfo::Start() { - const uint8_t *buffer_end = buffer_ + buffer_length_; - const uint8_t *cursor; + const uint8_t* buffer_end = buffer_ + buffer_length_; + const uint8_t* cursor; bool all_ok = true; - const uint8_t *entry_end; + const uint8_t* entry_end; bool ok; // Traverse all the entries in buffer_, skipping CIEs and offering @@ -2587,7 +3230,7 @@ bool CallFrameInfo::Start() { reporter_->CIEPointerOutOfRange(fde.offset, fde.id); continue; } - + CIE cie; // Parse this FDE's CIE header. @@ -2626,7 +3269,7 @@ bool CallFrameInfo::Start() { ok = true; continue; } - + if (cie.has_z_augmentation) { // Report the personality routine address, if we have one. if (cie.has_z_personality) { @@ -2666,7 +3309,7 @@ bool CallFrameInfo::Start() { return all_ok; } -const char *CallFrameInfo::KindName(EntryKind kind) { +const char* CallFrameInfo::KindName(EntryKind kind) { if (kind == CallFrameInfo::kUnknown) return "entry"; else if (kind == CallFrameInfo::kCIE) @@ -2679,7 +3322,7 @@ const char *CallFrameInfo::KindName(EntryKind kind) { } } -bool CallFrameInfo::ReportIncomplete(Entry *entry) { +bool CallFrameInfo::ReportIncomplete(Entry* entry) { reporter_->Incomplete(entry->offset, entry->kind); return false; } @@ -2738,7 +3381,7 @@ void CallFrameInfo::Reporter::UnrecognizedVersion(uint64_t offset, int version) } void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64_t offset, - const string &aug) { + const string& aug) { fprintf(stderr, "%s: CFI frame description entry at offset 0x%" PRIx64 " in '%s':" " CIE specifies unrecognized augmentation: '%s'\n", @@ -2813,4 +3456,4 @@ void CallFrameInfo::Reporter::ClearingCFARule(uint64_t offset, section_.c_str(), insn_offset); } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index 0b194c17..ddcdd801 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -1,6 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,6 +40,7 @@ #ifndef COMMON_DWARF_DWARF2READER_H__ #define COMMON_DWARF_DWARF2READER_H__ +#include <assert.h> #include <stdint.h> #include <list> @@ -55,7 +56,7 @@ #include "common/using_std_string.h" #include "common/dwarf/elf_reader.h" -namespace dwarf2reader { +namespace google_breakpad { struct LineStateMachine; class Dwarf2Handler; class LineInfoHandler; @@ -63,9 +64,27 @@ class DwpReader; // This maps from a string naming a section to a pair containing a // the data for the section, and the size of the section. -typedef std::map<string, std::pair<const uint8_t *, uint64_t> > SectionMap; -typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> > - AttributeList; +typedef std::map<string, std::pair<const uint8_t*, uint64_t> > SectionMap; + +// Abstract away the difference between elf and mach-o section names. +// Elf-names use ".section_name, mach-o uses "__section_name". Pass "name" in +// the elf form, ".section_name". +const SectionMap::const_iterator GetSectionByName(const SectionMap& + sections, const char* name); + +// Most of the time, this struct functions as a simple attribute and form pair. +// However, Dwarf5 DW_FORM_implicit_const means that a form may have its value +// in line in the abbrev table, and that value must be associated with the +// pair until the attr's value is needed. +struct AttrForm { + AttrForm(enum DwarfAttribute attr, enum DwarfForm form, uint64_t value) : + attr_(attr), form_(form), value_(value) { } + + enum DwarfAttribute attr_; + enum DwarfForm form_; + uint64_t value_; +}; +typedef std::list<AttrForm> AttributeList; typedef AttributeList::iterator AttributeIterator; typedef AttributeList::const_iterator ConstAttributeIterator; @@ -80,7 +99,7 @@ struct LineInfoHeader { uint8_t opcode_base; // Use a pointer so that signalsafe_addr2line is able to use this structure // without heap allocation problem. - std::vector<unsigned char> *std_opcode_lengths; + std::vector<unsigned char>* std_opcode_lengths; }; class LineInfo { @@ -90,8 +109,10 @@ class LineInfo { // to the beginning and length of the line information to read. // Reader is a ByteReader class that has the endianness set // properly. - LineInfo(const uint8_t *buffer_, uint64_t buffer_length, - ByteReader* reader, LineInfoHandler* handler); + LineInfo(const uint8_t* buffer, uint64_t buffer_length, + ByteReader* reader, const uint8_t* string_buffer, + size_t string_buffer_length, const uint8_t* line_string_buffer, + size_t line_string_buffer_length, LineInfoHandler* handler); virtual ~LineInfo() { if (header_.std_opcode_lengths) { @@ -115,12 +136,12 @@ class LineInfo { // lsm's old address < PC <= lsm's new address static bool ProcessOneOpcode(ByteReader* reader, LineInfoHandler* handler, - const struct LineInfoHeader &header, - const uint8_t *start, + const struct LineInfoHeader& header, + const uint8_t* start, struct LineStateMachine* lsm, size_t* len, uintptr pc, - bool *lsm_passes_pc); + bool* lsm_passes_pc); private: // Reads the DWARF2/3 header for this line info. @@ -129,26 +150,54 @@ class LineInfo { // Reads the DWARF2/3 line information void ReadLines(); + // Read the DWARF5 types and forms for the file and directory tables. + void ReadTypesAndForms(const uint8_t** lineptr, uint32_t* content_types, + uint32_t* content_forms, uint32_t max_types, + uint32_t* format_count); + + // Read a row from the dwarf5 LineInfo file table. + void ReadFileRow(const uint8_t** lineptr, const uint32_t* content_types, + const uint32_t* content_forms, uint32_t row, + uint32_t format_count); + + // Read and return the data at *lineptr according to form. Advance + // *lineptr appropriately. + uint64_t ReadUnsignedData(uint32_t form, const uint8_t** lineptr); + + // Read and return the data at *lineptr according to form. Advance + // *lineptr appropriately. + const char* ReadStringForm(uint32_t form, const uint8_t** lineptr); + // The associated handler to call processing functions in LineInfoHandler* handler_; // The associated ByteReader that handles endianness issues for us ByteReader* reader_; - // A DWARF2/3 line info header. This is not the same size as - // in the actual file, as the one in the file may have a 32 bit or - // 64 bit lengths + // A DWARF line info header. This is not the same size as in the actual file, + // as the one in the file may have a 32 bit or 64 bit lengths struct LineInfoHeader header_; // buffer is the buffer for our line info, starting at exactly where // the line info to read is. after_header is the place right after // the end of the line information header. - const uint8_t *buffer_; + const uint8_t* buffer_; #ifndef NDEBUG uint64_t buffer_length_; #endif - const uint8_t *after_header_; + // Convenience pointers into .debug_str and .debug_line_str. These exactly + // correspond to those in the compilation unit. + const uint8_t* string_buffer_; +#ifndef NDEBUG + uint64_t string_buffer_length_; +#endif + const uint8_t* line_string_buffer_; +#ifndef NDEBUG + uint64_t line_string_buffer_length_; +#endif + + const uint8_t* after_header_; }; // This class is the main interface between the line info reader and @@ -196,25 +245,75 @@ class RangeListHandler { // Add a range. virtual void AddRange(uint64_t begin, uint64_t end) { }; - // A new base address must be set for computing the ranges' addresses. - virtual void SetBaseAddress(uint64_t base_address) { }; - // Finish processing the range list. virtual void Finish() { }; }; class RangeListReader { public: - RangeListReader(const uint8_t *buffer, uint64_t size, ByteReader *reader, - RangeListHandler *handler); + // Reading a range list requires quite a bit of information + // from the compilation unit. Package it conveniently. + struct CURangesInfo { + CURangesInfo() : + version_(0), base_address_(0), ranges_base_(0), + buffer_(nullptr), size_(0), addr_buffer_(nullptr), + addr_buffer_size_(0), addr_base_(0) { } + + uint16_t version_; + // Ranges base address. Ordinarily the CU's low_pc. + uint64_t base_address_; + // Offset into .debug_rnglists for this CU's rangelists. + uint64_t ranges_base_; + // Contents of either .debug_ranges or .debug_rnglists. + const uint8_t* buffer_; + uint64_t size_; + // Contents of .debug_addr. This cu's contribution starts at + // addr_base_ + const uint8_t* addr_buffer_; + uint64_t addr_buffer_size_; + uint64_t addr_base_; + }; + + RangeListReader(ByteReader* reader, CURangesInfo* cu_info, + RangeListHandler* handler) : + reader_(reader), cu_info_(cu_info), handler_(handler), + offset_array_(0) { } - bool ReadRangeList(uint64_t offset); + // Read ranges from cu_info as specified by form and data. + bool ReadRanges(enum DwarfForm form, uint64_t data); private: - const uint8_t *buffer_; - uint64_t size_; + // Read dwarf4 .debug_ranges at offset. + bool ReadDebugRanges(uint64_t offset); + // Read dwarf5 .debug_rngslist at offset. + bool ReadDebugRngList(uint64_t offset); + + // Convenience functions to handle the mechanics of reading entries in the + // ranges section. + uint64_t ReadULEB(uint64_t offset, uint64_t* value) { + size_t len; + *value = reader_->ReadUnsignedLEB128(cu_info_->buffer_ + offset, &len); + return len; + } + + uint64_t ReadAddress(uint64_t offset, uint64_t* value) { + *value = reader_->ReadAddress(cu_info_->buffer_ + offset); + return reader_->AddressSize(); + } + + // Read the address at this CU's addr_index in the .debug_addr section. + uint64_t GetAddressAtIndex(uint64_t addr_index) { + assert(cu_info_->addr_buffer_ != nullptr); + uint64_t offset = + cu_info_->addr_base_ + addr_index * reader_->AddressSize(); + assert(offset < cu_info_->addr_buffer_size_); + return reader_->ReadAddress(cu_info_->addr_buffer_ + offset); + } + ByteReader* reader_; - RangeListHandler *handler_; + CURangesInfo* cu_info_; + RangeListHandler* handler_; + uint64_t offset_array_; }; // This class is the main interface between the reader and the @@ -288,7 +387,7 @@ class Dwarf2Handler { virtual void ProcessAttributeBuffer(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len) { } // Called when we have an attribute with string data to give to our handler. @@ -410,18 +509,42 @@ class CompilationUnit { // Reads the DWARF2/3 abbreviations for this compilation unit void ReadAbbrevs(); + // Read the abbreviation offset for this compilation unit + size_t ReadAbbrevOffset(const uint8_t* headerptr); + + // Read the address size for this compilation unit + size_t ReadAddressSize(const uint8_t* headerptr); + + // Read the DWO id from a split or skeleton compilation unit header + size_t ReadDwoId(const uint8_t* headerptr); + + // Read the type signature from a type or split type compilation unit header + size_t ReadTypeSignature(const uint8_t* headerptr); + + // Read the DWO id from a split or skeleton compilation unit header + size_t ReadTypeOffset(const uint8_t* headerptr); + // Processes a single DIE for this compilation unit and return a new // pointer just past the end of it - const uint8_t *ProcessDIE(uint64_t dieoffset, - const uint8_t *start, + const uint8_t* ProcessDIE(uint64_t dieoffset, + const uint8_t* start, const Abbrev& abbrev); // Processes a single attribute and return a new pointer just past the // end of it - const uint8_t *ProcessAttribute(uint64_t dieoffset, - const uint8_t *start, + const uint8_t* ProcessAttribute(uint64_t dieoffset, + const uint8_t* start, enum DwarfAttribute attr, - enum DwarfForm form); + enum DwarfForm form, + uint64_t implicit_const); + + // Special version of ProcessAttribute, for finding str_offsets_base and + // DW_AT_addr_base in DW_TAG_compile_unit, for DWARF v5. + const uint8_t* ProcessOffsetBaseAttribute(uint64_t dieoffset, + const uint8_t* start, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t implicit_const); // Called when we have an attribute with unsigned data to give to // our handler. The attribute is for the DIE at OFFSET from the @@ -436,10 +559,13 @@ class CompilationUnit { if (attr == DW_AT_GNU_dwo_id) { dwo_id_ = data; } - else if (attr == DW_AT_GNU_addr_base) { + else if (attr == DW_AT_GNU_addr_base || attr == DW_AT_addr_base) { addr_base_ = data; } - else if (attr == DW_AT_GNU_ranges_base) { + else if (attr == DW_AT_str_offsets_base) { + str_offsets_base_ = data; + } + else if (attr == DW_AT_GNU_ranges_base || attr == DW_AT_rnglists_base) { ranges_base_ = data; } // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, @@ -475,6 +601,14 @@ class CompilationUnit { handler_->ProcessAttributeBuffer(offset, attr, form, data, len); } + // Handles the common parts of DW_FORM_GNU_str_index, DW_FORM_strx, + // DW_FORM_strx1, DW_FORM_strx2, DW_FORM_strx3, and DW_FORM_strx4. + // Retrieves the data and calls through to ProcessAttributeString. + void ProcessFormStringIndex(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t str_index); + // Called when we have an attribute with string data to give to // our handler. The attribute is for the DIE at OFFSET from the // beginning of compilation unit, has a name of ATTR, a form of @@ -485,21 +619,33 @@ class CompilationUnit { enum DwarfAttribute attr, enum DwarfForm form, const char* data) { - if (attr == DW_AT_GNU_dwo_name) + if (attr == DW_AT_GNU_dwo_name || attr == DW_AT_dwo_name) dwo_name_ = data; handler_->ProcessAttributeString(offset, attr, form, data); } + // Called to handle common portions of DW_FORM_addrx and variations, as well + // as DW_FORM_GNU_addr_index. + void ProcessAttributeAddrIndex(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t addr_index) { + const uint8_t* addr_ptr = + addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize(); + ProcessAttributeUnsigned( + offset, attr, form, reader_->ReadAddress(addr_ptr)); + } + // Processes all DIEs for this compilation unit void ProcessDIEs(); // Skips the die with attributes specified in ABBREV starting at // START, and return the new place to position the stream to. - const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev); + const uint8_t* SkipDIE(const uint8_t* start, const Abbrev& abbrev); // Skips the attribute starting at START, with FORM, and return the // new place to position the stream to. - const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form); + const uint8_t* SkipAttribute(const uint8_t* start, enum DwarfForm form); // Process the actual debug information in a split DWARF file. void ProcessSplitDwarf(); @@ -518,9 +664,9 @@ class CompilationUnit { // buffer is the buffer for our CU, starting at .debug_info + offset // passed in from constructor. // after_header points to right after the compilation unit header. - const uint8_t *buffer_; + const uint8_t* buffer_; uint64_t buffer_length_; - const uint8_t *after_header_; + const uint8_t* after_header_; // The associated ByteReader that handles endianness issues for us ByteReader* reader_; @@ -539,9 +685,13 @@ class CompilationUnit { // String section buffer and length, if we have a string section. // This is here to avoid doing a section lookup for strings in // ProcessAttribute, which is in the hot path for DWARF2 reading. - const uint8_t *string_buffer_; + const uint8_t* string_buffer_; uint64_t string_buffer_length_; + // Similarly for .debug_line_string. + const uint8_t* line_string_buffer_; + uint64_t line_string_buffer_length_; + // String offsets section buffer and length, if we have a string offsets // section (.debug_str_offsets or .debug_str_offsets.dwo). const uint8_t* str_offsets_buffer_; @@ -561,9 +711,18 @@ class CompilationUnit { // associated with the skeleton compilation unit. bool is_split_dwarf_; + // Flag indicating if it's a Type Unit (only applicable to DWARF v5). + bool is_type_unit_; + // The value of the DW_AT_GNU_dwo_id attribute, if any. uint64_t dwo_id_; + // The value of the DW_AT_GNU_type_signature attribute, if any. + uint64_t type_signature_; + + // The value of the DW_AT_GNU_type_offset attribute, if any. + size_t type_offset_; + // The value of the DW_AT_GNU_dwo_name attribute, if any. const char* dwo_name_; @@ -571,12 +730,16 @@ class CompilationUnit { // from the skeleton CU. uint64_t skeleton_dwo_id_; - // The value of the DW_AT_GNU_ranges_base attribute, if any. + // The value of the DW_AT_GNU_ranges_base or DW_AT_rnglists_base attribute, + // if any. uint64_t ranges_base_; // The value of the DW_AT_GNU_addr_base attribute, if any. uint64_t addr_base_; + // The value of DW_AT_str_offsets_base attribute, if any. + uint64_t str_offsets_base_; + // True if we have already looked for a .dwp file. bool have_checked_for_dwp_; @@ -905,8 +1068,8 @@ class CallFrameInfo { // The mechanics of C++ exception handling, personality routines, // and language-specific data areas are described here, rather nicely: // http://www.codesourcery.com/public/cxx-abi/abi-eh.html - CallFrameInfo(const uint8_t *buffer, size_t buffer_length, - ByteReader *reader, Handler *handler, Reporter *reporter, + CallFrameInfo(const uint8_t* buffer, size_t buffer_length, + ByteReader* reader, Handler* handler, Reporter* reporter, bool eh_frame = false) : buffer_(buffer), buffer_length_(buffer_length), reader_(reader), handler_(handler), reporter_(reporter), @@ -920,7 +1083,7 @@ class CallFrameInfo { bool Start(); // Return the textual name of KIND. For error reporting. - static const char *KindName(EntryKind kind); + static const char* KindName(EntryKind kind); private: @@ -933,7 +1096,7 @@ class CallFrameInfo { size_t offset; // The start of this entry in the buffer. - const uint8_t *start; + const uint8_t* start; // Which kind of entry this is. // @@ -944,16 +1107,16 @@ class CallFrameInfo { // The end of this entry's common prologue (initial length and id), and // the start of this entry's kind-specific fields. - const uint8_t *fields; + const uint8_t* fields; // The start of this entry's instructions. - const uint8_t *instructions; + const uint8_t* instructions; // The address past the entry's last byte in the buffer. (Note that // since offset points to the entry's initial length field, and the // length field is the number of bytes after that field, this is not // simply buffer_ + offset + length.) - const uint8_t *end; + const uint8_t* end; // For both DWARF CFI and .eh_frame sections, this is the CIE id in a // CIE, and the offset of the associated CIE in an FDE. @@ -961,7 +1124,7 @@ class CallFrameInfo { // The CIE that applies to this entry, if we've parsed it. If this is a // CIE, then this field points to this structure. - CIE *cie; + CIE* cie; }; // A common information entry (CIE). @@ -1035,14 +1198,14 @@ class CallFrameInfo { // true. On failure, report the problem, and return false. Even if we // return false, set ENTRY->end to the first byte after the entry if we // were able to figure that out, or NULL if we weren't. - bool ReadEntryPrologue(const uint8_t *cursor, Entry *entry); + bool ReadEntryPrologue(const uint8_t* cursor, Entry* entry); // Parse the fields of a CIE after the entry prologue, including any 'z' // augmentation data. Assume that the 'Entry' fields of CIE are // populated; use CIE->fields and CIE->end as the start and limit for // parsing. On success, populate the rest of *CIE, and return true; on // failure, report the problem and return false. - bool ReadCIEFields(CIE *cie); + bool ReadCIEFields(CIE* cie); // Parse the fields of an FDE after the entry prologue, including any 'z' // augmentation data. Assume that the 'Entry' fields of *FDE are @@ -1050,12 +1213,12 @@ class CallFrameInfo { // parsing. Assume that FDE->cie is fully initialized. On success, // populate the rest of *FDE, and return true; on failure, report the // problem and return false. - bool ReadFDEFields(FDE *fde); + bool ReadFDEFields(FDE* fde); // Report that ENTRY is incomplete, and return false. This is just a // trivial wrapper for invoking reporter_->Incomplete; it provides a // little brevity. - bool ReportIncomplete(Entry *entry); + bool ReportIncomplete(Entry* entry); // Return true if ENCODING has the DW_EH_PE_indirect bit set. static bool IsIndirectEncoding(DwarfPointerEncoding encoding) { @@ -1063,17 +1226,17 @@ class CallFrameInfo { } // The contents of the DWARF .debug_info section we're parsing. - const uint8_t *buffer_; + const uint8_t* buffer_; size_t buffer_length_; // For reading multi-byte values with the appropriate endianness. - ByteReader *reader_; + ByteReader* reader_; // The handler to which we should report the data we find. - Handler *handler_; + Handler* handler_; // For reporting problems in the info we're parsing. - Reporter *reporter_; + Reporter* reporter_; // True if we are processing .eh_frame-format data. bool eh_frame_; @@ -1106,7 +1269,7 @@ class CallFrameInfo::Handler { // process a given FDE, the parser reiterates the appropriate CIE's // contents at the beginning of the FDE's rules. virtual bool Entry(size_t offset, uint64_t address, uint64_t length, - uint8_t version, const string &augmentation, + uint8_t version, const string& augmentation, unsigned return_address) = 0; // When the Entry function returns true, the parser calls these @@ -1155,13 +1318,13 @@ class CallFrameInfo::Handler { // At ADDRESS, the DWARF expression EXPRESSION yields the address at // which REG was saved. virtual bool ExpressionRule(uint64_t address, int reg, - const string &expression) = 0; + const string& expression) = 0; // At ADDRESS, the DWARF expression EXPRESSION yields the caller's // value for REG. (This rule doesn't provide an address at which the // register's value is saved.) virtual bool ValExpressionRule(uint64_t address, int reg, - const string &expression) = 0; + const string& expression) = 0; // Indicate that the rules for the address range reported by the // last call to Entry are complete. End should return true if @@ -1169,6 +1332,9 @@ class CallFrameInfo::Handler { // should stop. virtual bool End() = 0; + // The target architecture for the data. + virtual string Architecture() = 0; + // Handler functions for Linux C++ exception handling data. These are // only called if the data includes 'z' augmentation strings. @@ -1238,8 +1404,8 @@ class CallFrameInfo::Reporter { // in a Mach-O section named __debug_frame. If we support // Linux-style exception handling data, we could be reading an // .eh_frame section. - Reporter(const string &filename, - const string §ion = ".debug_frame") + Reporter(const string& filename, + const string& section = ".debug_frame") : filename_(filename), section_(section) { } virtual ~Reporter() { } @@ -1279,7 +1445,7 @@ class CallFrameInfo::Reporter { // which we don't recognize. We cannot parse DWARF CFI if it uses // augmentations we don't recognize. virtual void UnrecognizedAugmentation(uint64_t offset, - const string &augmentation); + const string& augmentation); // The pointer encoding ENCODING, specified by the CIE at OFFSET, is not // a valid encoding. @@ -1326,6 +1492,6 @@ class CallFrameInfo::Reporter { string section_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // UTIL_DEBUGINFO_DWARF2READER_H__ diff --git a/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/src/common/dwarf/dwarf2reader_cfi_unittest.cc index ebe612e1..dc4418c7 100644 --- a/src/common/dwarf/dwarf2reader_cfi_unittest.cc +++ b/src/common/dwarf/dwarf2reader_cfi_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -29,7 +28,7 @@ // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> -// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo +// dwarf2reader_cfi_unittest.cc: Unit tests for google_breakpad::CallFrameInfo #include <stdint.h> #include <stdlib.h> @@ -72,11 +71,11 @@ using google_breakpad::test_assembler::kBigEndian; using google_breakpad::test_assembler::kLittleEndian; using google_breakpad::test_assembler::Section; -using dwarf2reader::DwarfPointerEncoding; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; -using dwarf2reader::ByteReader; -using dwarf2reader::CallFrameInfo; +using google_breakpad::DwarfPointerEncoding; +using google_breakpad::ENDIANNESS_BIG; +using google_breakpad::ENDIANNESS_LITTLE; +using google_breakpad::ByteReader; +using google_breakpad::CallFrameInfo; using std::vector; using testing::InSequence; @@ -87,7 +86,7 @@ using testing::_; #ifdef WRITE_ELF void WriteELFFrameSection(const char *filename, const char *section_name, - const CFISection §ion); + const CFISection& section); #define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) \ WriteELFFrameSection("cfitest-" name, ".debug_frame", section); #define PERHAPS_WRITE_EH_FRAME_FILE(name, section) \ @@ -100,7 +99,7 @@ void WriteELFFrameSection(const char *filename, const char *section_name, class MockCallFrameInfoHandler: public CallFrameInfo::Handler { public: MOCK_METHOD6(Entry, bool(size_t offset, uint64_t address, uint64_t length, - uint8_t version, const string &augmentation, + uint8_t version, const string& augmentation, unsigned return_address)); MOCK_METHOD2(UndefinedRule, bool(uint64_t address, int reg)); MOCK_METHOD2(SameValueRule, bool(uint64_t address, int reg)); @@ -110,10 +109,11 @@ class MockCallFrameInfoHandler: public CallFrameInfo::Handler { long offset)); MOCK_METHOD3(RegisterRule, bool(uint64_t address, int reg, int base_register)); MOCK_METHOD3(ExpressionRule, bool(uint64_t address, int reg, - const string &expression)); + const string& expression)); MOCK_METHOD3(ValExpressionRule, bool(uint64_t address, int reg, - const string &expression)); + const string& expression)); MOCK_METHOD0(End, bool()); + MOCK_METHOD0(Architecture, string()); MOCK_METHOD2(PersonalityRoutine, bool(uint64_t address, bool indirect)); MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64_t address, bool indirect)); MOCK_METHOD0(SignalHandler, bool()); @@ -129,7 +129,7 @@ class MockCallFrameErrorReporter: public CallFrameInfo::Reporter { MOCK_METHOD2(UnexpectedAddressSize, void(uint64_t, uint8_t)); MOCK_METHOD2(UnexpectedSegmentSize, void(uint64_t, uint8_t)); MOCK_METHOD2(UnrecognizedVersion, void(uint64_t, int version)); - MOCK_METHOD2(UnrecognizedAugmentation, void(uint64_t, const string &)); + MOCK_METHOD2(UnrecognizedAugmentation, void(uint64_t, const string&)); MOCK_METHOD2(InvalidPointerEncoding, void(uint64_t, uint8_t)); MOCK_METHOD2(UnusablePointerEncoding, void(uint64_t, uint8_t)); MOCK_METHOD2(RestoreInCIE, void(uint64_t, uint64_t)); @@ -218,7 +218,7 @@ TEST_F(CFI, IncompleteLength32) { ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size() - 2, &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -244,7 +244,7 @@ TEST_F(CFI, IncompleteLength64) { ByteReader byte_reader(ENDIANNESS_LITTLE); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size() - 4, &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -269,7 +269,7 @@ TEST_F(CFI, IncompleteId32) { ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -296,7 +296,7 @@ TEST_F(CFI, BadId32) { ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -306,7 +306,7 @@ TEST_F(CFI, BadId32) { TEST_F(CFI, SingleCIE) { CFISection section(kLittleEndian, 4); section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, ""); - section.Append(10, dwarf2reader::DW_CFA_nop); + section.Append(10, google_breakpad::DW_CFA_nop); section.FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section); @@ -318,7 +318,7 @@ TEST_F(CFI, SingleCIE) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_LITTLE); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -349,7 +349,7 @@ TEST_F(CFI, OneFDE) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -393,7 +393,7 @@ TEST_F(CFI, TwoFDEsOneCIE) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -443,7 +443,7 @@ TEST_F(CFI, TwoFDEsTwoCIEs) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_LITTLE); byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -488,7 +488,7 @@ TEST_F(CFI, BadVersion) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -533,7 +533,7 @@ TEST_F(CFI, BadAugmentation) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -568,7 +568,7 @@ TEST_F(CFI, CIEVersion1ReturnColumn) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -603,7 +603,7 @@ TEST_F(CFI, CIEVersion3ReturnColumn) { EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -633,7 +633,7 @@ TEST_F(CFI, CIEVersion4AdditionalFields) { string contents; EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -663,7 +663,7 @@ TEST_F(CFI, CIEVersion4AdditionalFields32BitAddress) { string contents; EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_TRUE(parser.Start()); @@ -690,7 +690,7 @@ TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedAddressSize) { string contents; EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -715,7 +715,7 @@ TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedSegmentSize) { string contents; EXPECT_TRUE(section.GetContents(&contents)); ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); EXPECT_FALSE(parser.Start()); @@ -763,7 +763,7 @@ struct CFIInsnFixture: public CFIFixture { .Mark(&cie_label) .CIEHeader(code_factor, data_factor, return_register, version, "") - .D8(dwarf2reader::DW_CFA_def_cfa) + .D8(google_breakpad::DW_CFA_def_cfa) .ULEB128(cfa_base_register) .ULEB128(cfa_offset) .FinishEntry(); @@ -788,7 +788,7 @@ struct CFIInsnFixture: public CFIFixture { void ParseSection(CFISection *section, bool succeeds = true) { string contents; EXPECT_TRUE(section->GetContents(&contents)); - dwarf2reader::Endianness endianness; + google_breakpad::Endianness endianness; if (section->endianness() == kBigEndian) endianness = ENDIANNESS_BIG; else { @@ -797,7 +797,7 @@ struct CFIInsnFixture: public CFIFixture { } ByteReader byte_reader(endianness); byte_reader.SetAddressSize(section->AddressSize()); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter); if (succeeds) @@ -823,10 +823,10 @@ TEST_F(CFIInsn, DW_CFA_set_loc) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a) + .D8(google_breakpad::DW_CFA_set_loc).D32(0xb1ee3e7a) // Use DW_CFA_def_cfa to force a handler call that we can use to // check the effect of the DW_CFA_set_loc. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section); @@ -844,10 +844,10 @@ TEST_F(CFIInsn, DW_CFA_advance_loc) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a) + .D8(google_breakpad::DW_CFA_advance_loc | 0x2a) // Use DW_CFA_def_cfa to force a handler call that we can use to // check the effect of the DW_CFA_advance_loc. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section); @@ -866,8 +866,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc1) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) + .D8(google_breakpad::DW_CFA_advance_loc1).D8(0xd8) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section); @@ -886,8 +886,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc2) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) + .D8(google_breakpad::DW_CFA_advance_loc2).D16(0x3adb) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section); @@ -906,8 +906,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc4) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) + .D8(google_breakpad::DW_CFA_advance_loc4).D32(0x15813c88) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section); @@ -927,8 +927,8 @@ TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) + .D8(google_breakpad::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section); @@ -947,7 +947,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section); @@ -964,8 +964,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_sf) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) - .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) + .D8(google_breakpad::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) + .D8(google_breakpad::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) .FinishEntry(); EXPECT_CALL(handler, @@ -985,7 +985,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_register) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) + .D8(google_breakpad::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) .FinishEntry(); EXPECT_CALL(handler, @@ -1002,8 +1002,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack") - .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) + .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("needle in a haystack") + .D8(google_breakpad::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) .FinishEntry(); EXPECT_CALL(handler, @@ -1019,7 +1019,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offset) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) + .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) .FinishEntry(); EXPECT_CALL(handler, @@ -1035,8 +1035,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970) - .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) + .D8(google_breakpad::DW_CFA_def_cfa_offset_sf).LEB128(0x970) + .D8(google_breakpad::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) .FinishEntry(); EXPECT_CALL(handler, @@ -1058,8 +1058,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday") - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) + .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("six ways to Sunday") + .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) .FinishEntry(); EXPECT_CALL(handler, @@ -1074,7 +1074,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_expression) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow") + .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("eating crow") .FinishEntry(); EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister, @@ -1089,7 +1089,7 @@ TEST_F(CFIInsn, DW_CFA_undefined) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x300ce45d) .FinishEntry(); EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d)) @@ -1103,7 +1103,7 @@ TEST_F(CFIInsn, DW_CFA_same_value) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760) + .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x3865a760) .FinishEntry(); EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760)) @@ -1117,7 +1117,7 @@ TEST_F(CFIInsn, DW_CFA_offset) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6) + .D8(google_breakpad::DW_CFA_offset | 0x2c).ULEB128(0x9f6) .FinishEntry(); EXPECT_CALL(handler, @@ -1132,7 +1132,7 @@ TEST_F(CFIInsn, DW_CFA_offset_extended) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) + .D8(google_breakpad::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) .FinishEntry(); EXPECT_CALL(handler, @@ -1147,9 +1147,9 @@ TEST_F(CFIInsn, DW_CFA_offset_extended_sf) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset_extended_sf) + .D8(google_breakpad::DW_CFA_offset_extended_sf) .ULEB128(0x997c23ee).LEB128(0x2d00) - .D8(dwarf2reader::DW_CFA_offset_extended_sf) + .D8(google_breakpad::DW_CFA_offset_extended_sf) .ULEB128(0x9519eb82).LEB128(-0xa77) .FinishEntry(); @@ -1170,7 +1170,7 @@ TEST_F(CFIInsn, DW_CFA_val_offset) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) .FinishEntry(); EXPECT_CALL(handler, @@ -1186,8 +1186,8 @@ TEST_F(CFIInsn, DW_CFA_val_offset_sf) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) - .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) + .D8(google_breakpad::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) + .D8(google_breakpad::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) .FinishEntry(); EXPECT_CALL(handler, @@ -1207,7 +1207,7 @@ TEST_F(CFIInsn, DW_CFA_register) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414)) @@ -1221,7 +1221,7 @@ TEST_F(CFIInsn, DW_CFA_expression) { CFISection section(kBigEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0xa1619fb2) .Block("plus ça change, plus c'est la même chose") .FinishEntry(); @@ -1238,7 +1238,7 @@ TEST_F(CFIInsn, DW_CFA_val_expression) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) + .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) .Block("he who has the gold makes the rules") .FinishEntry(); @@ -1265,18 +1265,18 @@ TEST_F(CFIInsn, DW_CFA_restore) { .CIEHeader(code_factor, data_factor, return_register, version, "") // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8) // Provide an offset(N) rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348) + .D8(google_breakpad::DW_CFA_offset | 0x3c).ULEB128(0xb348) .FinishEntry() // In the FDE... .FDEHeader(cie, fde_start, fde_size) // At a second address, provide a new offset(N) rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x13) - .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0x9a50) + .D8(google_breakpad::DW_CFA_advance_loc | 0x13) + .D8(google_breakpad::DW_CFA_offset | 0x3c).ULEB128(0x9a50) // At a third address, restore the original rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x01) - .D8(dwarf2reader::DW_CFA_restore | 0x3c) + .D8(google_breakpad::DW_CFA_advance_loc | 0x01) + .D8(google_breakpad::DW_CFA_restore | 0x3c) .FinishEntry(); { @@ -1321,16 +1321,16 @@ TEST_F(CFIInsn, DW_CFA_restoreNoRule) { .Mark(&cie) .CIEHeader(code_factor, data_factor, return_register, version, "") // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127) .FinishEntry() // In the FDE... .FDEHeader(cie, fde_start, fde_size) // At a second address, provide an offset(N) rule for register 0x2c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x7) - .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x1f47) + .D8(google_breakpad::DW_CFA_advance_loc | 0x7) + .D8(google_breakpad::DW_CFA_offset | 0x2c).ULEB128(0x1f47) // At a third address, restore the (missing) CIE rule for register 0x2c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0xb) - .D8(dwarf2reader::DW_CFA_restore | 0x2c) + .D8(google_breakpad::DW_CFA_advance_loc | 0xb) + .D8(google_breakpad::DW_CFA_restore | 0x2c) .FinishEntry(); { @@ -1371,20 +1371,20 @@ TEST_F(CFIInsn, DW_CFA_restore_extended) { .CIEHeader(code_factor, data_factor, return_register, version, "", true /* dwarf64 */ ) // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5) // Provide an offset(N) rule for register 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_offset_extended) + .D8(google_breakpad::DW_CFA_offset_extended) .ULEB128(0x0f9b8a1c).ULEB128(0xc979) .FinishEntry() // In the FDE... .FDEHeader(cie, fde_start, fde_size) // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x3) - .D8(dwarf2reader::DW_CFA_offset_extended) + .D8(google_breakpad::DW_CFA_advance_loc | 0x3) + .D8(google_breakpad::DW_CFA_offset_extended) .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b) // At a third address, restore the original rule for register 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x04) - .D8(dwarf2reader::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c) + .D8(google_breakpad::DW_CFA_advance_loc | 0x04) + .D8(google_breakpad::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c) .FinishEntry(); { @@ -1433,21 +1433,21 @@ TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) { // 5 offset(N) no rule new "same value" rule section // Create the "incoming" state, which we will save and later restore. - .D8(dwarf2reader::DW_CFA_offset | 2).ULEB128(0x9806) - .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0x995d) - .D8(dwarf2reader::DW_CFA_offset | 4).ULEB128(0x7055) - .D8(dwarf2reader::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_offset | 2).ULEB128(0x9806) + .D8(google_breakpad::DW_CFA_offset | 3).ULEB128(0x995d) + .D8(google_breakpad::DW_CFA_offset | 4).ULEB128(0x7055) + .D8(google_breakpad::DW_CFA_remember_state) // Advance to a new instruction; an implementation could legitimately // ignore all but the final rule for a given register at a given address. - .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_advance_loc | 1) // Create the "outgoing" state, which we will discard. - .D8(dwarf2reader::DW_CFA_offset | 1).ULEB128(0xea1a) - .D8(dwarf2reader::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767) - .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0xdd29) - .D8(dwarf2reader::DW_CFA_offset | 5).ULEB128(0xf1ce) + .D8(google_breakpad::DW_CFA_offset | 1).ULEB128(0xea1a) + .D8(google_breakpad::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767) + .D8(google_breakpad::DW_CFA_offset | 3).ULEB128(0xdd29) + .D8(google_breakpad::DW_CFA_offset | 5).ULEB128(0xf1ce) // At a third address, restore the incoming state. - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); uint64_t addr = fde_start; @@ -1496,11 +1496,11 @@ TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) { StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x90481102) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister, @@ -1519,9 +1519,9 @@ TEST_F(CFIInsn, DW_CFA_nop) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_nop) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) - .D8(dwarf2reader::DW_CFA_nop) + .D8(google_breakpad::DW_CFA_nop) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) + .D8(google_breakpad::DW_CFA_nop) .FinishEntry(); EXPECT_CALL(handler, @@ -1536,9 +1536,11 @@ TEST_F(CFIInsn, DW_CFA_GNU_window_save) { CFISection section(kBigEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_GNU_window_save) + .D8(google_breakpad::DW_CFA_GNU_window_save) .FinishEntry(); + EXPECT_CALL(handler, Architecture()).WillRepeatedly(Return("sparc")); + // Don't include all the rules in any particular sequence. // The caller's %o0-%o7 have become the callee's %i0-%i7. This is @@ -1561,9 +1563,9 @@ TEST_F(CFIInsn, DW_CFA_GNU_args_size) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520) + .D8(google_breakpad::DW_CFA_GNU_args_size).ULEB128(0xeddfa520) // Verify that we see this, meaning we parsed the above properly. - .D8(dwarf2reader::DW_CFA_offset | 0x23).ULEB128(0x269) + .D8(google_breakpad::DW_CFA_offset | 0x23).ULEB128(0x269) .FinishEntry(); EXPECT_CALL(handler, @@ -1578,7 +1580,7 @@ TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended) + .D8(google_breakpad::DW_CFA_GNU_negative_offset_extended) .ULEB128(0x430cc87a).ULEB128(0x613) .FinishEntry(); @@ -1599,19 +1601,19 @@ TEST_F(CFIInsn, SkipFDE) { // CIE, used by all FDEs. .Mark(&cie) .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "") - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) .FinishEntry() // First FDE. .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf) .FinishEntry() // Second FDE. .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18) .FinishEntry() // Third FDE. .FDEHeader(cie, 0xf681cfc8, 0x7e4594e) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) .FinishEntry(); { @@ -1652,8 +1654,8 @@ TEST_F(CFIInsn, QuitMidentry) { CFISection section(kLittleEndian, 8); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") + .D8(google_breakpad::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431)) @@ -1670,10 +1672,10 @@ TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x0bac878e) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e)) @@ -1687,12 +1689,12 @@ TEST_F(CFIRestore, RestoreUndefinedRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x7dedff5f) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x7dedff5f) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f)) @@ -1710,10 +1712,10 @@ TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_same_value).ULEB128(0xadbc9b3a) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a)) @@ -1727,12 +1729,12 @@ TEST_F(CFIRestore, RestoreSameValueRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x3d90dcb5) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x3d90dcb5) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5)) @@ -1750,10 +1752,10 @@ TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_offset | 0x14).ULEB128(0xb6f) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, OffsetRule(fde_start, 0x14, @@ -1768,12 +1770,12 @@ TEST_F(CFIRestore, RestoreOffsetRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0xeb7) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x21) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, @@ -1793,12 +1795,12 @@ TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0x134) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0xf4f) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, @@ -1819,10 +1821,10 @@ TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6, @@ -1837,12 +1839,12 @@ TEST_F(CFIRestore, RestoreValOffsetRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xf17c36d6) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6, @@ -1862,12 +1864,12 @@ TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b, @@ -1888,10 +1890,10 @@ TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce)) @@ -1905,12 +1907,12 @@ TEST_F(CFIRestore, RestoreRegisterRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xe39acce5) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559)) @@ -1929,12 +1931,12 @@ TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a)) @@ -1954,10 +1956,10 @@ TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf")) @@ -1971,12 +1973,12 @@ TEST_F(CFIRestore, RestoreExpressionRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xb5ca5c46) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf")) @@ -1995,12 +1997,12 @@ TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf")) @@ -2021,11 +2023,11 @@ TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152) + .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0x666ae152) .Block("hideous") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous")) @@ -2039,13 +2041,13 @@ TEST_F(CFIRestore, RestoreValExpressionRuleChanged) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46) + .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0xb5ca5c46) .Block("revolting") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xb5ca5c46) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section); @@ -2066,14 +2068,14 @@ TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) { CFISection section(kLittleEndian, 4); StockCIEAndFDE(§ion); section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) + .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0x500f5739) .Block("repulsive") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) + .D8(google_breakpad::DW_CFA_remember_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0x500f5739) .Block("nauseous") - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) + .D8(google_breakpad::DW_CFA_advance_loc | 1) + .D8(google_breakpad::DW_CFA_restore_state) .FinishEntry(); PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression", @@ -2110,7 +2112,7 @@ struct EHFrameFixture: public CFIInsnFixture { EXPECT_TRUE(section->ContainsEHFrame()); string contents; EXPECT_TRUE(section->GetContents(&contents)); - dwarf2reader::Endianness endianness; + google_breakpad::Endianness endianness; if (section->endianness() == kBigEndian) endianness = ENDIANNESS_BIG; else { @@ -2120,10 +2122,10 @@ struct EHFrameFixture: public CFIInsnFixture { ByteReader byte_reader(endianness); byte_reader.SetAddressSize(section->AddressSize()); byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi, - reinterpret_cast<const uint8_t *>(contents.data())); + reinterpret_cast<const uint8_t*>(contents.data())); byte_reader.SetTextBase(encoded_pointer_bases.text); byte_reader.SetDataBase(encoded_pointer_bases.data); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()), contents.size(), &byte_reader, &handler, &reporter, true); if (succeeds) @@ -2142,11 +2144,11 @@ TEST_F(EHFrame, Terminator) { section .Mark(&cie) .CIEHeader(9968, 2466, 67, 1, "") - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372) .FinishEntry() .FDEHeader(cie, 0x848037a1, 0x7b30475e) - .D8(dwarf2reader::DW_CFA_set_loc).D32(0x17713850) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(5721) + .D8(google_breakpad::DW_CFA_set_loc).D32(0x17713850) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(5721) .FinishEntry() .D32(0) // Terminate the sequence. // This FDE should be ignored. @@ -2172,12 +2174,12 @@ TEST_F(EHFrame, Terminator) { // The parser should recognize the Linux Standards Base 'z' augmentations. TEST_F(EHFrame, SimpleFDE) { DwarfPointerEncoding lsda_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect - | dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_sdata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect + | google_breakpad::DW_EH_PE_datarel + | google_breakpad::DW_EH_PE_sdata2); DwarfPointerEncoding fde_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_udata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel + | google_breakpad::DW_EH_PE_udata2); section.SetPointerEncoding(fde_encoding); section.SetEncodedPointerBases(encoded_pointer_bases); @@ -2187,17 +2189,17 @@ TEST_F(EHFrame, SimpleFDE) { .CIEHeader(4873, 7012, 100, 1, "zSLPR") .ULEB128(7) // Augmentation data length .D8(lsda_encoding) // LSDA pointer format - .D8(dwarf2reader::DW_EH_PE_pcrel) // personality pointer format - .EncodedPointer(0x97baa00, dwarf2reader::DW_EH_PE_pcrel) // and value + .D8(google_breakpad::DW_EH_PE_pcrel) // personality pointer format + .EncodedPointer(0x97baa00, google_breakpad::DW_EH_PE_pcrel) // and value .D8(fde_encoding) // FDE pointer format - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31) .FinishEntry() .FDEHeader(cie, 0x540f6b56, 0xf686) .ULEB128(2) // Augmentation data length .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed - .D8(dwarf2reader::DW_CFA_set_loc) + .D8(google_breakpad::DW_CFA_set_loc) .EncodedPointer(0x540fa4ce, fde_encoding) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x675e) .FinishEntry() .D32(0); // terminator @@ -2228,12 +2230,12 @@ TEST_F(EHFrame, EmptyZ) { .Mark(&cie) .CIEHeader(5955, 5805, 228, 1, "z") .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247) .FinishEntry() .FDEHeader(cie, 0xda007738, 0xfb55c641) .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_advance_loc1).D8(11) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(3769) + .D8(google_breakpad::DW_CFA_advance_loc1).D8(11) + .D8(google_breakpad::DW_CFA_undefined).ULEB128(3769) .FinishEntry(); PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section); @@ -2257,12 +2259,12 @@ TEST_F(EHFrame, BadZ) { .Mark(&cie) .CIEHeader(6937, 1045, 142, 1, "zQ") .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725) + .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725) .FinishEntry() .FDEHeader(cie, 0x1293efa8, 0x236f53f2) .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_advance_loc | 12) - .D8(dwarf2reader::DW_CFA_register).ULEB128(5667).ULEB128(3462) + .D8(google_breakpad::DW_CFA_advance_loc | 12) + .D8(google_breakpad::DW_CFA_register).ULEB128(5667).ULEB128(3462) .FinishEntry(); PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section); @@ -2276,8 +2278,8 @@ TEST_F(EHFrame, BadZ) { TEST_F(EHFrame, zL) { Label cie; DwarfPointerEncoding lsda_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel - | dwarf2reader::DW_EH_PE_udata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_funcrel + | google_breakpad::DW_EH_PE_udata2); section .Mark(&cie) .CIEHeader(9285, 9959, 54, 1, "zL") @@ -2306,8 +2308,8 @@ TEST_F(EHFrame, zL) { TEST_F(EHFrame, zP) { Label cie; DwarfPointerEncoding personality_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_udata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_datarel + | google_breakpad::DW_EH_PE_udata2); section .Mark(&cie) .CIEHeader(1097, 6313, 17, 1, "zP") @@ -2335,8 +2337,8 @@ TEST_F(EHFrame, zP) { TEST_F(EHFrame, zR) { Label cie; DwarfPointerEncoding pointer_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_sdata2); + DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel + | google_breakpad::DW_EH_PE_sdata2); section.SetPointerEncoding(pointer_encoding); section .Mark(&cie) @@ -2468,7 +2470,7 @@ struct ELFSectionHeader { uint64_t entry_size; }; -void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) { +void AppendSectionHeader(CFISection* table, const ELFSectionHeader& header) { (*table) .D32(header.name) // name, index in string tbl .D32(header.type) // type @@ -2483,7 +2485,7 @@ void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) { } void WriteELFFrameSection(const char *filename, const char *cfi_name, - const CFISection &cfi) { + const CFISection& cfi) { int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64; int elf_data = (cfi.endianness() == kBigEndian ? ELFDATA2MSB : ELFDATA2LSB); diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index ca44cad0..fc639a64 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -29,7 +28,7 @@ // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> -// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit +// dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit #include <stdint.h> #include <stdlib.h> @@ -51,16 +50,16 @@ using google_breakpad::test_assembler::Section; using google_breakpad::test_assembler::kBigEndian; using google_breakpad::test_assembler::kLittleEndian; -using dwarf2reader::ByteReader; -using dwarf2reader::CompilationUnit; -using dwarf2reader::Dwarf2Handler; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfHasChild; -using dwarf2reader::DwarfTag; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; -using dwarf2reader::SectionMap; +using google_breakpad::ByteReader; +using google_breakpad::CompilationUnit; +using google_breakpad::Dwarf2Handler; +using google_breakpad::DwarfAttribute; +using google_breakpad::DwarfForm; +using google_breakpad::DwarfHasChild; +using google_breakpad::DwarfTag; +using google_breakpad::ENDIANNESS_BIG; +using google_breakpad::ENDIANNESS_LITTLE; +using google_breakpad::SectionMap; using std::vector; using testing::InSequence; @@ -93,7 +92,7 @@ class MockDwarf2Handler: public Dwarf2Handler { MOCK_METHOD5(ProcessAttributeBuffer, void(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len)); MOCK_METHOD4(ProcessAttributeString, void(uint64_t offset, enum DwarfAttribute attr, @@ -128,17 +127,17 @@ struct DIEFixture { // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This // function returns a reference to the same SectionMap each time; new // calls wipe out maps established by earlier calls. - const SectionMap &MakeSectionMap() { + const SectionMap& MakeSectionMap() { // Copy the sections' contents into strings that will live as long as // the map itself. assert(info.GetContents(&info_contents)); assert(abbrevs.GetContents(&abbrevs_contents)); section_map.clear(); section_map[".debug_info"].first - = reinterpret_cast<const uint8_t *>(info_contents.data()); + = reinterpret_cast<const uint8_t*>(info_contents.data()); section_map[".debug_info"].second = info_contents.size(); section_map[".debug_abbrev"].first - = reinterpret_cast<const uint8_t *>(abbrevs_contents.data()); + = reinterpret_cast<const uint8_t*>(abbrevs_contents.data()); section_map[".debug_abbrev"].second = abbrevs_contents.size(); return section_map; } @@ -152,13 +151,15 @@ struct DIEFixture { struct DwarfHeaderParams { DwarfHeaderParams(Endianness endianness, size_t format_size, - int version, size_t address_size) + int version, size_t address_size, int header_type) : endianness(endianness), format_size(format_size), - version(version), address_size(address_size) { } + version(version), address_size(address_size), header_type(header_type) + { } Endianness endianness; size_t format_size; // 4-byte or 8-byte DWARF offsets int version; size_t address_size; + int header_type; // DW_UT_{compile, type, partial, skeleton, etc} }; class DwarfHeader: public DIEFixture, @@ -166,16 +167,17 @@ class DwarfHeader: public DIEFixture, TEST_P(DwarfHeader, Header) { Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_children_yes) - .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string) + abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_children_yes) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string) .EndAbbrev() .EndTable(); info.set_format_size(GetParam().format_size); info.set_endianness(GetParam().endianness); - info.Header(GetParam().version, abbrev_table, GetParam().address_size) + info.Header(GetParam().version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_compile) .ULEB128(1) // DW_TAG_compile_unit, with children .AppendCString("sam") // DW_AT_name, DW_FORM_string .D8(0); // end of children @@ -188,10 +190,10 @@ TEST_P(DwarfHeader, Header) { GetParam().format_size, _, GetParam().version)) .WillOnce(Return(true)); - EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit)) + EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_compile_unit)) .WillOnce(Return(true)); - EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_string, + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_string, "sam")) .WillOnce(Return()); EXPECT_CALL(handler, EndDIE(_)) @@ -204,44 +206,91 @@ TEST_P(DwarfHeader, Header) { EXPECT_EQ(parser.Start(), info_contents.size()); } -INSTANTIATE_TEST_CASE_P( +TEST_P(DwarfHeader, TypeUnitHeader) { + Label abbrev_table = abbrevs.Here(); + int version = 5; + abbrevs.Abbrev(1, google_breakpad::DW_TAG_type_unit, + google_breakpad::DW_children_yes) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string) + .EndAbbrev() + .EndTable(); + + info.set_format_size(GetParam().format_size); + info.set_endianness(GetParam().endianness); + + info.Header(version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_type) + .ULEB128(0x41) // DW_TAG_type_unit, with children + .AppendCString("sam") // DW_AT_name, DW_FORM_string + .D8(0); // end of children + info.Finish(); + + { + InSequence s; + EXPECT_CALL(handler, + StartCompilationUnit(0, GetParam().address_size, + GetParam().format_size, _, + version)) + .WillOnce(Return(true)); + // If the type unit is handled properly, these calls will be skipped. + EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_type_unit)) + .Times(0); + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_string, + "sam")) + .Times(0); + EXPECT_CALL(handler, EndDIE(_)) + .Times(0); + } + + ByteReader byte_reader(GetParam().endianness == kLittleEndian ? + ENDIANNESS_LITTLE : ENDIANNESS_BIG); + CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler); + EXPECT_EQ(parser.Start(), info_contents.size()); +} + +INSTANTIATE_TEST_SUITE_P( HeaderVariants, DwarfHeader, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - DwarfHeaderParams(kLittleEndian, 4, 2, 8), - DwarfHeaderParams(kLittleEndian, 4, 3, 4), - DwarfHeaderParams(kLittleEndian, 4, 3, 8), - DwarfHeaderParams(kLittleEndian, 4, 4, 4), - DwarfHeaderParams(kLittleEndian, 4, 4, 8), - DwarfHeaderParams(kLittleEndian, 8, 2, 4), - DwarfHeaderParams(kLittleEndian, 8, 2, 8), - DwarfHeaderParams(kLittleEndian, 8, 3, 4), - DwarfHeaderParams(kLittleEndian, 8, 3, 8), - DwarfHeaderParams(kLittleEndian, 8, 4, 4), - DwarfHeaderParams(kLittleEndian, 8, 4, 8), - DwarfHeaderParams(kBigEndian, 4, 2, 4), - DwarfHeaderParams(kBigEndian, 4, 2, 8), - DwarfHeaderParams(kBigEndian, 4, 3, 4), - DwarfHeaderParams(kBigEndian, 4, 3, 8), - DwarfHeaderParams(kBigEndian, 4, 4, 4), - DwarfHeaderParams(kBigEndian, 4, 4, 8), - DwarfHeaderParams(kBigEndian, 8, 2, 4), - DwarfHeaderParams(kBigEndian, 8, 2, 8), - DwarfHeaderParams(kBigEndian, 8, 3, 4), - DwarfHeaderParams(kBigEndian, 8, 3, 8), - DwarfHeaderParams(kBigEndian, 8, 4, 4), - DwarfHeaderParams(kBigEndian, 8, 4, 8))); + ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 5, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 5, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 5, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 5, 8, 1))); struct DwarfFormsFixture: public DIEFixture { // Start a compilation unit, as directed by |params|, containing one // childless DIE of the given tag, with one attribute of the given name // and form. The 'info' fixture member is left just after the abbrev // code, waiting for the attribute value to be appended. - void StartSingleAttributeDIE(const DwarfHeaderParams ¶ms, + void StartSingleAttributeDIE(const DwarfHeaderParams& params, DwarfTag tag, DwarfAttribute name, DwarfForm form) { // Create the abbreviation table. Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no) + abbrevs.Abbrev(1, tag, google_breakpad::DW_children_no) .Attribute(name, form) .EndAbbrev() .EndTable(); @@ -249,14 +298,15 @@ struct DwarfFormsFixture: public DIEFixture { // Create the compilation unit, up to the attribute value. info.set_format_size(params.format_size); info.set_endianness(params.endianness); - info.Header(params.version, abbrev_table, params.address_size) + info.Header(params.version, abbrev_table, params.address_size, + google_breakpad::DW_UT_compile) .ULEB128(1); // abbrev code } // Set up handler to expect a compilation unit matching |params|, // containing one childless DIE of the given tag, in the sequence s. Stop // just before the expectations. - void ExpectBeginCompilationUnit(const DwarfHeaderParams ¶ms, + void ExpectBeginCompilationUnit(const DwarfHeaderParams& params, DwarfTag tag, uint64_t offset=0) { EXPECT_CALL(handler, StartCompilationUnit(offset, params.address_size, @@ -275,7 +325,7 @@ struct DwarfFormsFixture: public DIEFixture { .WillOnce(Return()); } - void ParseCompilationUnit(const DwarfHeaderParams ¶ms, + void ParseCompilationUnit(const DwarfHeaderParams& params, uint64_t offset=0) { ByteReader byte_reader(params.endianness == kLittleEndian ? ENDIANNESS_LITTLE : ENDIANNESS_BIG); @@ -291,9 +341,9 @@ struct DwarfForms: public DwarfFormsFixture, public TestWithParam<DwarfHeaderParams> { }; TEST_P(DwarfForms, addr) { - StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr); + StartSingleAttributeDIE(GetParam(), google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr); uint64_t value; if (GetParam().address_size == 4) { value = 0xc8e9ffcc; @@ -304,9 +354,93 @@ TEST_P(DwarfForms, addr) { } info.Finish(); - ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit); - EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, + ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, + value)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, strx1) { + if (GetParam().version != 5) { + return; + } + Label abbrev_table = abbrevs.Here(); + abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_children_no) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_strx1) + .Attribute(google_breakpad::DW_AT_low_pc, google_breakpad::DW_FORM_addr) + .Attribute(google_breakpad::DW_AT_str_offsets_base, + google_breakpad::DW_FORM_sec_offset) + .EndAbbrev() + .EndTable(); + + info.set_format_size(GetParam().format_size); + info.set_endianness(GetParam().endianness); + info.Header(GetParam().version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_compile) + .ULEB128(1) // abbrev index + .D8(2); // string index + + uint64_t value; + uint64_t offsets_base; + if (GetParam().address_size == 4) { + value = 0xc8e9ffcc; + offsets_base = 8; + info.D32(value); // low pc + info.D32(offsets_base); // str_offsets_base + } else { + value = 0xe942517fc2768564ULL; + offsets_base = 16; + info.D64(value); // low_pc + info.D64(offsets_base); // str_offsets_base + } + info.Finish(); + + Section debug_strings; + // no header, just a series of null-terminated strings. + debug_strings.AppendCString("apple"); // offset = 0 + debug_strings.AppendCString("bird"); // offset = 6 + debug_strings.AppendCString("canary"); // offset = 11 + debug_strings.AppendCString("dinosaur"); // offset = 18 + + Section str_offsets; + str_offsets.set_endianness(GetParam().endianness); + // Header for .debug_str_offsets + if (GetParam().address_size == 4) { + str_offsets.D32(24); // section length (4 bytes) + } else { + str_offsets.D32(0xffffffff); + str_offsets.D64(48); // section length (12 bytes) + } + str_offsets.D16(GetParam().version); // version (2 bytes) + str_offsets.D16(0); // padding (2 bytes) + + // .debug_str_offsets data (the offsets) + if (GetParam().address_size == 4) { + str_offsets.D32(0); + str_offsets.D32(6); + str_offsets.D32(11); + str_offsets.D32(18); + } else { + str_offsets.D64(0); + str_offsets.D64(6); + str_offsets.D64(11); + str_offsets.D64(18); + } + + + ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit); + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strx1, + "bird")) + .WillOnce(Return()); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, value)) .InSequence(s) .WillOnce(Return()); @@ -318,13 +452,13 @@ TEST_P(DwarfForms, addr) { TEST_P(DwarfForms, block2_empty) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); + google_breakpad::DW_FORM_block2); info.D16(0); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, + google_breakpad::DW_FORM_block2, _, 0)) .InSequence(s) .WillOnce(Return()); @@ -336,7 +470,7 @@ TEST_P(DwarfForms, block2_empty) { TEST_P(DwarfForms, block2) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); + google_breakpad::DW_FORM_block2); unsigned char data[258]; memset(data, '*', sizeof(data)); info.D16(sizeof(data)) @@ -345,7 +479,7 @@ TEST_P(DwarfForms, block2) { ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, + google_breakpad::DW_FORM_block2, Pointee('*'), 258)) .InSequence(s) .WillOnce(Return()); @@ -357,14 +491,14 @@ TEST_P(DwarfForms, block2) { TEST_P(DwarfForms, flag_present) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2, (DwarfAttribute) 0x359d1972, - dwarf2reader::DW_FORM_flag_present); + google_breakpad::DW_FORM_flag_present); // DW_FORM_flag_present occupies no space in the DIE. info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2); EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972, - dwarf2reader::DW_FORM_flag_present, + google_breakpad::DW_FORM_flag_present, 1)) .InSequence(s) .WillOnce(Return()); @@ -376,7 +510,7 @@ TEST_P(DwarfForms, flag_present) { TEST_P(DwarfForms, sec_offset) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689, (DwarfAttribute) 0xa060bfd1, - dwarf2reader::DW_FORM_sec_offset); + google_breakpad::DW_FORM_sec_offset); uint64_t value; if (GetParam().format_size == 4) { value = 0xacc9c388; @@ -389,7 +523,7 @@ TEST_P(DwarfForms, sec_offset) { ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689); EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1, - dwarf2reader::DW_FORM_sec_offset, + google_breakpad::DW_FORM_sec_offset, value)) .InSequence(s) .WillOnce(Return()); @@ -401,14 +535,14 @@ TEST_P(DwarfForms, sec_offset) { TEST_P(DwarfForms, exprloc) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb, (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc); + google_breakpad::DW_FORM_exprloc); info.ULEB128(29) .Append(29, 173); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb); EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc, + google_breakpad::DW_FORM_exprloc, Pointee(173), 29)) .InSequence(s) .WillOnce(Return()); @@ -420,13 +554,13 @@ TEST_P(DwarfForms, exprloc) { TEST_P(DwarfForms, ref_sig8) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); + google_breakpad::DW_FORM_ref_sig8); info.D64(0xf72fa0cb6ddcf9d6ULL); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8, + google_breakpad::DW_FORM_ref_sig8, 0xf72fa0cb6ddcf9d6ULL)) .InSequence(s) .WillOnce(Return()); @@ -444,13 +578,13 @@ TEST_P(DwarfForms, ref_sig8_not_first) { info.Append(98, '*'); StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); + google_breakpad::DW_FORM_ref_sig8); info.D64(0xf72fa0cb6ddcf9d6ULL); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98); EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8, + google_breakpad::DW_FORM_ref_sig8, 0xf72fa0cb6ddcf9d6ULL)) .InSequence(s) .WillOnce(Return()); @@ -459,31 +593,371 @@ TEST_P(DwarfForms, ref_sig8_not_first) { ParseCompilationUnit(GetParam(), 98); } +TEST_P(DwarfForms, implicit_const) { + const DwarfHeaderParams& params = GetParam(); + const uint64_t implicit_constant_value = 0x1234; + // Create the abbreviation table. + Label abbrev_table = abbrevs.Here(); + abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, google_breakpad::DW_children_no) + .Attribute((DwarfAttribute) 0xd708d908, + google_breakpad::DW_FORM_implicit_const) + .ULEB128(implicit_constant_value); + abbrevs.EndAbbrev().EndTable(); + + info.set_format_size(params.format_size); + info.set_endianness(params.endianness); + info.Header(params.version, abbrev_table, params.address_size, + google_breakpad::DW_UT_compile) + .ULEB128(1); // abbrev code + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); + EXPECT_CALL(handler, + ProcessAttributeUnsigned(_, (DwarfAttribute) 0xd708d908, + google_breakpad::DW_FORM_implicit_const, + implicit_constant_value)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + // Tests for the other attribute forms could go here. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( HeaderVariants, DwarfForms, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - DwarfHeaderParams(kLittleEndian, 4, 2, 8), - DwarfHeaderParams(kLittleEndian, 4, 3, 4), - DwarfHeaderParams(kLittleEndian, 4, 3, 8), - DwarfHeaderParams(kLittleEndian, 4, 4, 4), - DwarfHeaderParams(kLittleEndian, 4, 4, 8), - DwarfHeaderParams(kLittleEndian, 8, 2, 4), - DwarfHeaderParams(kLittleEndian, 8, 2, 8), - DwarfHeaderParams(kLittleEndian, 8, 3, 4), - DwarfHeaderParams(kLittleEndian, 8, 3, 8), - DwarfHeaderParams(kLittleEndian, 8, 4, 4), - DwarfHeaderParams(kLittleEndian, 8, 4, 8), - DwarfHeaderParams(kBigEndian, 4, 2, 4), - DwarfHeaderParams(kBigEndian, 4, 2, 8), - DwarfHeaderParams(kBigEndian, 4, 3, 4), - DwarfHeaderParams(kBigEndian, 4, 3, 8), - DwarfHeaderParams(kBigEndian, 4, 4, 4), - DwarfHeaderParams(kBigEndian, 4, 4, 8), - DwarfHeaderParams(kBigEndian, 8, 2, 4), - DwarfHeaderParams(kBigEndian, 8, 2, 8), - DwarfHeaderParams(kBigEndian, 8, 3, 4), - DwarfHeaderParams(kBigEndian, 8, 3, 8), - DwarfHeaderParams(kBigEndian, 8, 4, 4), - DwarfHeaderParams(kBigEndian, 8, 4, 8))); + ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 8, 1))); + +class MockRangeListHandler: public google_breakpad::RangeListHandler { + public: + MOCK_METHOD(void, AddRange, (uint64_t begin, uint64_t end)); + MOCK_METHOD(void, Finish, ()); +}; + +TEST(RangeList, Dwarf4ReadRangeList) { + using google_breakpad::RangeListReader; + using google_breakpad::DW_FORM_sec_offset; + + // Create a dwarf4 .debug_ranges section. + google_breakpad::test_assembler::Section ranges(kBigEndian); + std::string padding_offset = "padding offset"; + ranges.Append(padding_offset); + const uint64_t section_offset = ranges.Size(); + ranges.D32(1).D32(2); // (2, 3) + ranges.D32(0xFFFFFFFF).D32(3); // base_address = 3. + ranges.D32(1).D32(2); // (4, 5) + ranges.D32(0).D32(1); // (3, 4) An out of order entry is legal. + ranges.D32(0).D32(0); // End of range. + + std::string section_contents; + ranges.GetContents(§ion_contents); + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + + RangeListReader::CURangesInfo cu_info; + // Only set the fields that matter for dwarf 4. + cu_info.version_ = 4; + cu_info.base_address_ = 1; + cu_info.buffer_ = reinterpret_cast<const uint8_t*>(section_contents.data()); + cu_info.size_ = section_contents.size(); + + MockRangeListHandler handler; + google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(3, 4)); + EXPECT_CALL(handler, Finish()); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + section_offset)); +} + +TEST(RangeList, Dwarf5ReadRangeList_rnglists) { + using google_breakpad::RangeListReader; + using google_breakpad::DW_RLE_base_addressx; + using google_breakpad::DW_RLE_startx_endx; + using google_breakpad::DW_RLE_startx_length; + using google_breakpad::DW_RLE_offset_pair; + using google_breakpad::DW_RLE_end_of_list; + using google_breakpad::DW_RLE_base_address; + using google_breakpad::DW_RLE_start_end; + using google_breakpad::DW_RLE_start_length; + using google_breakpad::DW_FORM_sec_offset; + using google_breakpad::DW_FORM_rnglistx; + + // Size of header + const uint64_t header_size = 12; + // Size of length field in header + const uint64_t length_size = 4; + + // .debug_addr for the indexed entries like startx. + Section addr; + addr.set_endianness(kBigEndian); + // Test addr_base handling with a padding address at 0. + addr.D32(0).D32(1).D32(2).D32(3).D32(4); + std::string addr_contents; + assert(addr.GetContents(&addr_contents)); + + // .debug_rnglists is the dwarf 5 section. + Section rnglists1(kBigEndian); + Section rnglists2(kBigEndian); + + // First header and body. + Label section_size1; + rnglists1.Append(kBigEndian, length_size, section_size1); + rnglists1.D16(5); // Version + rnglists1.D8(4); // Address size + rnglists1.D8(0); // Segment selector size + rnglists1.D32(2); // Offset entry count + const uint64_t ranges_base_1 = rnglists1.Size(); + + // Offset entries. + Label range0; + rnglists1.Append(kBigEndian, 4, range0); + Label range1; + rnglists1.Append(kBigEndian, 4, range1); + + // Range 0 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range0 = rnglists1.Size() - header_size; + rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists1.D8(DW_RLE_end_of_list); + + // Range 1 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range1 = rnglists1.Size() - header_size; + rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8 + rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10) + rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11) + rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13) + rnglists1.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size1 = rnglists1.Size() - length_size; + + // Second header and body. + Label section_size2; + rnglists2.Append(kBigEndian, length_size, section_size2); + rnglists2.D16(5); // Version + rnglists2.D8(4); // Address size + rnglists2.D8(0); // Segment selector size + rnglists2.D32(2); // Offset entry count + const uint64_t ranges_base_2 = rnglists1.Size() + rnglists2.Size(); + + // Offset entries. + Label range2; + rnglists2.Append(kBigEndian, 4, range2); + Label range3; + rnglists2.Append(kBigEndian, 4, range3); + + // Range 2 (will be read via DW_AT_ranges, DW_FORM_sec_offset). + range2 = rnglists2.Size() - header_size; + rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists2.D8(DW_RLE_end_of_list); + + // Range 3 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range3 = rnglists2.Size() - header_size; + rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15 + rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17) + rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18) + rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20) + rnglists2.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size2 = rnglists2.Size() - length_size; + + rnglists1.Append(rnglists2); + string rnglists_contents; + assert(rnglists1.GetContents(&rnglists_contents)); + + RangeListReader::CURangesInfo cu_info; + cu_info.version_ = 5; + cu_info.base_address_ = 1; + cu_info.ranges_base_ = ranges_base_1; + cu_info.buffer_ = + reinterpret_cast<const uint8_t*>(rnglists_contents.data()); + cu_info.size_ = rnglists_contents.size(); + cu_info.addr_buffer_ = + reinterpret_cast<const uint8_t*>(addr_contents.data()); + cu_info.addr_buffer_size_ = addr_contents.size(); + cu_info.addr_base_ = 4; + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetOffsetSize(4); + byte_reader.SetAddressSize(4); + MockRangeListHandler handler; + google_breakpad::RangeListReader range_list_reader1(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(9, 10)); + EXPECT_CALL(handler, AddRange(10, 11)); + EXPECT_CALL(handler, AddRange(12, 13)); + EXPECT_CALL(handler, Finish()).Times(2); + EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 0)); + EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 1)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 2)); + + // Set to new ranges_base + cu_info.ranges_base_ = ranges_base_2; + google_breakpad::RangeListReader range_list_reader2(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(16, 17)); + EXPECT_CALL(handler, AddRange(17, 18)); + EXPECT_CALL(handler, AddRange(19, 20)); + EXPECT_CALL(handler, Finish()).Times(2); + EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 0)); + EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 1)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 2)); +} + +TEST(RangeList, Dwarf5ReadRangeList_sec_offset) { + using google_breakpad::RangeListReader; + using google_breakpad::DW_RLE_base_addressx; + using google_breakpad::DW_RLE_startx_endx; + using google_breakpad::DW_RLE_startx_length; + using google_breakpad::DW_RLE_offset_pair; + using google_breakpad::DW_RLE_end_of_list; + using google_breakpad::DW_RLE_base_address; + using google_breakpad::DW_RLE_start_end; + using google_breakpad::DW_RLE_start_length; + using google_breakpad::DW_FORM_sec_offset; + using google_breakpad::DW_FORM_rnglistx; + + // Size of length field in header + const uint64_t length_size = 4; + + // .debug_addr for the indexed entries like startx. + Section addr; + addr.set_endianness(kBigEndian); + // Test addr_base handling with a padding address at 0. + addr.D32(0).D32(1).D32(2).D32(3).D32(4).D32(21).D32(22); + std::string addr_contents; + assert(addr.GetContents(&addr_contents)); + + // .debug_rnglists is the dwarf 5 section. + Section rnglists1(kBigEndian); + Section rnglists2(kBigEndian); + + // First header and body. + Label section_size1; + rnglists1.Append(kBigEndian, length_size, section_size1); + rnglists1.D16(5); // Version + rnglists1.D8(4); // Address size + rnglists1.D8(0); // Segment selector size + rnglists1.D32(0); // Offset entry count + + const uint64_t offset1 = rnglists1.Size(); + + rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8 + rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10) + rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11) + rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13) + rnglists1.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size1 = rnglists1.Size() - length_size; + + // Second header and body. + Label section_size2; + rnglists2.Append(kBigEndian, length_size, section_size2); + rnglists2.D16(5); // Version + rnglists2.D8(4); // Address size + rnglists2.D8(0); // Segment selector size + rnglists2.D32(0); // Offset entry count + + const uint64_t offset2 = rnglists1.Size() + rnglists2.Size(); + + rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15 + rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17) + rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18) + rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20) + rnglists2.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size2 = rnglists2.Size() - length_size; + + rnglists1.Append(rnglists2); + string rnglists_contents; + assert(rnglists1.GetContents(&rnglists_contents)); + + RangeListReader::CURangesInfo cu_info; + cu_info.version_ = 5; + cu_info.base_address_ = 1; + cu_info.buffer_ = + reinterpret_cast<const uint8_t*>(rnglists_contents.data()); + cu_info.size_ = rnglists_contents.size(); + cu_info.addr_buffer_ = + reinterpret_cast<const uint8_t*>(addr_contents.data()); + cu_info.addr_buffer_size_ = addr_contents.size(); + cu_info.addr_base_ = 4; + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetOffsetSize(4); + byte_reader.SetAddressSize(4); + MockRangeListHandler handler; + google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(9, 10)); + EXPECT_CALL(handler, AddRange(10, 11)); + EXPECT_CALL(handler, AddRange(12, 13)); + EXPECT_CALL(handler, Finish()).Times(1); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset1)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + rnglists_contents.size())); + + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(16, 17)); + EXPECT_CALL(handler, AddRange(17, 18)); + EXPECT_CALL(handler, AddRange(19, 20)); + EXPECT_CALL(handler, Finish()).Times(1); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset2)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + rnglists_contents.size())); +} diff --git a/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc new file mode 100644 index 00000000..033c6333 --- /dev/null +++ b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc @@ -0,0 +1,186 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Sterling Augustine <saugustine@google.com> + +// dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo + +#include <stdint.h> +#include <stdlib.h> + +#include <string> +#include <vector> + +#include "breakpad_googletest_includes.h" +#include "common/dwarf/bytereader.h" +#include "common/dwarf/dwarf2reader.h" +#include "google_breakpad/common/breakpad_types.h" + +using std::vector; +using testing::InSequence; +using testing::Return; +using testing::Sequence; +using testing::Test; +using testing::_; + +using namespace google_breakpad; + +namespace { + +const uint8_t dwarf5_line_program[] = { + 0x40, 0x0, 0x0, 0x0, // unit_length (end - begin) + // begin + 0x05, 0x0, // version + 0x8, // address_size + 0x0, // segment_selector_size + 0x26, 0x0, 0x0, 0x0, // header_length (end_header_end - begin_header) + // begin_header: + 0x1, // minimum_instruction_length + 0x1, // maximum_operations_per_instruction + 0x1, // default_is_stmt + 0xfb, // line_base + 0xe, // line_range + 0xd, // opcode_base and lengths + 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, + 0x1, // directory entry format count + DW_LNCT_path, DW_FORM_strp, + 0x1, // directories count + 0x1, 0x0, 0x0, 0x0, // offset into .debug_line_str + 0x2, // file_name_entry_format_count + DW_LNCT_directory_index, DW_FORM_data1, + DW_LNCT_path, DW_FORM_line_strp, + 0x1, // filename count + 0x0, // directory index + 0x1, 0x0, 0x0, 0x0, // offset into .debug_str + // end_header + DW_LNS_set_file, 0x0, + // set address to 0x0 + 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + // Advance Address by 0 and line by 3 + 0x15, + // Advance PC by 1 + 0x2, 0x1, + 0x0, + DW_LNE_end_sequence, + DW_LNE_end_sequence, + // end +}; + +const uint8_t dwarf4_line_program[] = { + 0x37, 0x0, 0x0, 0x0, // unit_length (end - begin) + // begin + 0x04, 0x0, // version + 0x1d, 0x0, 0x0, 0x0, // header_length (end_header - begin_header) + // begin_header: + 0x1, // minimum_instruction_length + 0x1, // maximum_operations_per_instruction + 0x1, // default_is_stmt + 0xfb, // line_base + 0xe, // line_range + 0xd, // opcode_base and lengths + 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, + '/', 'a', '\0', // directory entry 1 (zeroth entry implied) + '\0', // end of directory table + 'b', '/', 'c', '\0', // file entry 1 (zeroth entry implied) + 0, // file 1 directory + 0, // file 1 modification time + 0, // file 1 length + '\0', // end of file table + // end_header + DW_LNS_set_file, 0x0, + // set address to 0x0 + 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + // Advance Address by 0 and line by 3 + 0x15, + // Advance PC by 1 + 0x2, 0x1, + 0x0, + DW_LNE_end_sequence, + DW_LNE_end_sequence, + // end +}; + +class MockLineInfoHandler: public LineInfoHandler { + public: + MOCK_METHOD(void, DefineDir, (const string&, uint32_t dir_num), (override)); + MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num, + uint32_t dir_num, uint64_t mod_time, + uint64_t length), (override)); + MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length, + uint32_t file_num, uint32_t line_num, + uint32_t column_num), (override)); +}; + +const uint8_t string_section[] = {'x', '/', 'a', '\0'}; +const uint8_t line_string_section[] = {'x', 'b', '/', 'c', '\0' }; + +struct LineProgram: public Test { + MockLineInfoHandler handler_; +}; + +TEST_F(LineProgram, ReadLinesDwarf5) { + ByteReader byte_reader(ENDIANNESS_LITTLE); + // LineTables don't specify the offset size like Compilation Units do. + byte_reader.SetOffsetSize(4); + LineInfo line_reader(dwarf5_line_program, + sizeof(dwarf5_line_program), + &byte_reader, + string_section, + sizeof(string_section), + line_string_section, + sizeof(line_string_section), + &handler_); + EXPECT_CALL(handler_, DefineDir("/a", 0)).Times(1); + EXPECT_CALL(handler_, DefineFile("b/c", 0, 0, 0, 0)).Times(1); + EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1); + EXPECT_EQ(line_reader.Start(), sizeof(dwarf5_line_program)); +} + +TEST_F(LineProgram, ReadLinesDwarf4) { + ByteReader byte_reader(ENDIANNESS_LITTLE); + // LineTables don't specify the offset size like Compilation Units do. + byte_reader.SetOffsetSize(4); + // dwarf4 line info headers don't encode the address size. + byte_reader.SetAddressSize(8); + LineInfo line_reader(dwarf4_line_program, + sizeof(dwarf4_line_program), + &byte_reader, + // dwarf4 line tables can't access the string sections + // so pass values likely to make assertions fail if + // the code uses them improperly. + nullptr, 0, nullptr, 0, + &handler_); + EXPECT_CALL(handler_, DefineDir("", 0)).Times(1); + EXPECT_CALL(handler_, DefineDir("/a", 1)).Times(1); + EXPECT_CALL(handler_, DefineFile("", 0, 0, 0, 0)).Times(1); + EXPECT_CALL(handler_, DefineFile("b/c", 1, 0, 0, 0)).Times(1); + EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1); + EXPECT_EQ(line_reader.Start(), sizeof(dwarf4_line_program)); +} + +} // anonymous namespace diff --git a/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc new file mode 100644 index 00000000..9ceea109 --- /dev/null +++ b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc @@ -0,0 +1,125 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Snehasish Kumar <snehasishk@google.com> + +// dwarf2reader_splitfunctions_unittest.cc: Unit tests for with a focus on debug +// information generated when with splitting optimizations such as +// -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc). + +#include <stdint.h> +#include <stdlib.h> + +#include <string> + +#include "breakpad_googletest_includes.h" +#include "common/dwarf/bytereader.h" +#include "common/dwarf/dwarf2reader.h" +#include "google_breakpad/common/breakpad_types.h" + +using testing::_; +using namespace google_breakpad; + +namespace { + +class MockLineInfoHandler: public LineInfoHandler { + public: + MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num, + uint32_t dir_num, uint64_t mod_time, + uint64_t length), (override)); + MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length, + uint32_t file_num, uint32_t line_num, + uint32_t column_num), (override)); +}; + +struct LineProgram: public testing::Test { + MockLineInfoHandler handler_; +}; + +// The debug information is generated from the following program -- +// $ cat -n split_functions.c +// 1 #include <stdio.h> +// 2 +// 3 __attribute__((noinline)) int foo(int i) { +// 4 if (i % 100) { +// 5 return i + 1; +// 6 } else { +// 7 return i * 10 % 3; +// 8 } +// 9 } +// 10 +// 11 +// 12 int main(int argc, char *argv[]) { +// 13 int total = 0; +// 14 for (int i = 0; i < 1000; ++i) { +// 15 total += foo(i); +// 16 } +// 17 printf("%d\n", total); +// 18 } +// +// $ bin/clang -fprofile-generate -O2 split_functions.c +// $ ./a.out > /dev/null +// $ bin/llvm-profdata merge -o default.profdata default_*.profraw +// $ bin/clang -fprofile-use -O2 -gmlt -gdwarf-5 -fsplit-machine-functions \ +// split_functions.c -o split.out +// +// For the test we pick the first instruction in foo.cold which should be the +// else part of the function foo above. + +const uint8_t debug_line[] = { + 0xb0,0x0,0x0,0x0,0x5,0x0,0x8,0x0,0x37,0x0,0x0,0x0,0x1,0x1,0x1,0xfb,0xe,0xd,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x3,0x1,0x1f,0x2,0xf,0x5,0x1e,0x1,0x3d,0x0,0x0,0x0,0x0,0x24,0xb2,0xb6,0xb5,0xbb,0xf,0xf7,0x6d,0x27,0x92,0xab,0x55,0x3a,0x29,0x48,0x81,0x4,0x0,0x0,0x9,0x2,0x40,0x10,0x40,0x0,0x0,0x0,0x0,0x0,0x14,0x5,0x9,0xa,0x2f,0x5,0x7,0x6,0x8,0x4a,0x5,0xe,0x6,0x67,0x5,0x1,0x40,0x5,0x0,0xf5,0x5,0xe,0xa,0xf5,0x5,0xb,0x6,0x74,0x5,0x1d,0x6,0x2d,0x5,0x15,0x6,0x3c,0x5,0x3,0x66,0x2,0x7,0x0,0x1,0x1,0x4,0x0,0x5,0xe,0x0,0x9,0x2,0x84,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x18,0x5,0x13,0x6,0x58,0x5,0x1,0x6,0x8,0xa0,0x2,0x1,0x0,0x1,0x1,0x4,0x0,0x5,0x3,0x0,0x9,0x2,0xa5,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x3,0x10,0x1,0x5,0x1,0xd7,0x2,0x9,0x0,0x1,0x1 +}; + +const uint8_t debug_str[] = { + 0x63,0x6c,0x61,0x6e,0x67,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x32,0x2e,0x30,0x2e,0x30,0x20,0x28,0x67,0x69,0x74,0x40,0x67,0x69,0x74,0x68,0x75,0x62,0x2e,0x63,0x6f,0x6d,0x3a,0x6c,0x6c,0x76,0x6d,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x67,0x69,0x74,0x20,0x63,0x37,0x35,0x61,0x30,0x61,0x31,0x65,0x39,0x64,0x63,0x32,0x39,0x62,0x65,0x34,0x65,0x30,0x30,0x64,0x33,0x37,0x64,0x30,0x64,0x30,0x30,0x32,0x38,0x38,0x61,0x66,0x63,0x31,0x61,0x36,0x31,0x35,0x33,0x66,0x29,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0,0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x66,0x6f,0x6f,0x0,0x69,0x6e,0x74,0x0,0x6d,0x61,0x69,0x6e,0x0,0x69,0x0,0x61,0x72,0x67,0x63,0x0,0x61,0x72,0x67,0x76,0x0,0x63,0x68,0x61,0x72,0x0,0x74,0x6f,0x74,0x61,0x6c,0x0 +}; + +const uint8_t debug_line_str[] = { + 0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0 +}; + +TEST_F(LineProgram, ReadLinesSplitFunctions) { + ByteReader byte_reader(ENDIANNESS_LITTLE); + // LineTables don't specify the offset size like Compilation Units do. + byte_reader.SetOffsetSize(4); + LineInfo line_reader(debug_line, + sizeof(debug_line), + &byte_reader, + debug_str, + sizeof(debug_str), + debug_line_str, + sizeof(debug_line_str), + &handler_); + EXPECT_CALL(handler_, DefineFile("split_functions.c", 0, 0, 0, 0)).Times(1); + EXPECT_CALL(handler_, AddLine(_, _, _, _, _)).Times(testing::AtLeast(1)); + // Pick the first address from the foo.cold symbol and check the line number. + EXPECT_CALL(handler_, AddLine(testing::Eq(0x401184lu), _, _, /*line_num*/ 7, _)).Times(1); + EXPECT_EQ(line_reader.Start(), sizeof(debug_line)); +} + +} // anonymous namespace diff --git a/src/common/dwarf/dwarf2reader_test_common.h b/src/common/dwarf/dwarf2reader_test_common.h index e91de906..1c45d527 100644 --- a/src/common/dwarf/dwarf2reader_test_common.h +++ b/src/common/dwarf/dwarf2reader_test_common.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,9 +44,9 @@ // DWARF compilation units. class TestCompilationUnit: public google_breakpad::test_assembler::Section { public: - typedef dwarf2reader::DwarfTag DwarfTag; - typedef dwarf2reader::DwarfAttribute DwarfAttribute; - typedef dwarf2reader::DwarfForm DwarfForm; + typedef google_breakpad::DwarfTag DwarfTag; + typedef google_breakpad::DwarfAttribute DwarfAttribute; + typedef google_breakpad::DwarfForm DwarfForm; typedef google_breakpad::test_assembler::Label Label; // Set the section's DWARF format size (the 32-bit DWARF format or the @@ -57,7 +56,7 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { assert(format_size == 4 || format_size == 8); format_size_ = format_size; } - + // Append a DWARF section offset value, of the appropriate size for this // compilation unit. template<typename T> @@ -70,8 +69,8 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { // Append a DWARF compilation unit header to the section, with the given // DWARF version, abbrev table offset, and address size. - TestCompilationUnit &Header(int version, const Label &abbrev_offset, - size_t address_size) { + TestCompilationUnit& Header(int version, const Label& abbrev_offset, + size_t address_size, int header_type) { if (format_size_ == 4) { D32(length_); } else { @@ -80,13 +79,28 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { } post_length_offset_ = Size(); D16(version); - SectionOffset(abbrev_offset); - D8(address_size); + if (version <= 4) { + SectionOffset(abbrev_offset); + D8(address_size); + } else { + D8(header_type); // DW_UT_compile, DW_UT_type, etc. + D8(address_size); + SectionOffset(abbrev_offset); + if (header_type == google_breakpad::DW_UT_type) { + uint64_t dummy_type_signature = 0xdeadbeef; + uint64_t dummy_type_offset = 0x2b; + D64(dummy_type_signature); + if (format_size_ == 4) + D32(dummy_type_offset); + else + D64(dummy_type_offset); + } + } return *this; } // Mark the end of this header's DIEs. - TestCompilationUnit &Finish() { + TestCompilationUnit& Finish() { length_ = Size() - post_length_offset_; return *this; } @@ -107,16 +121,16 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { // abbreviation tables. class TestAbbrevTable: public google_breakpad::test_assembler::Section { public: - typedef dwarf2reader::DwarfTag DwarfTag; - typedef dwarf2reader::DwarfAttribute DwarfAttribute; - typedef dwarf2reader::DwarfForm DwarfForm; - typedef dwarf2reader::DwarfHasChild DwarfHasChild; + typedef google_breakpad::DwarfTag DwarfTag; + typedef google_breakpad::DwarfAttribute DwarfAttribute; + typedef google_breakpad::DwarfForm DwarfForm; + typedef google_breakpad::DwarfHasChild DwarfHasChild; typedef google_breakpad::test_assembler::Label Label; // Start a new abbreviation table entry for abbreviation code |code|, // encoding a DIE whose tag is |tag|, and which has children if and only // if |has_children| is true. - TestAbbrevTable &Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) { + TestAbbrevTable& Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) { assert(code != 0); ULEB128(code); ULEB128(static_cast<unsigned>(tag)); @@ -126,21 +140,21 @@ class TestAbbrevTable: public google_breakpad::test_assembler::Section { // Add an attribute to the current abbreviation code whose name is |name| // and whose form is |form|. - TestAbbrevTable &Attribute(DwarfAttribute name, DwarfForm form) { + TestAbbrevTable& Attribute(DwarfAttribute name, DwarfForm form) { ULEB128(static_cast<unsigned>(name)); ULEB128(static_cast<unsigned>(form)); return *this; } // Finish the current abbreviation code. - TestAbbrevTable &EndAbbrev() { + TestAbbrevTable& EndAbbrev() { ULEB128(0); ULEB128(0); return *this; } // Finish the current abbreviation table. - TestAbbrevTable &EndTable() { + TestAbbrevTable& EndTable() { ULEB128(0); return *this; } diff --git a/src/common/dwarf/elf_reader.cc b/src/common/dwarf/elf_reader.cc index 1b665213..7664377c 100644 --- a/src/common/dwarf/elf_reader.cc +++ b/src/common/dwarf/elf_reader.cc @@ -1,4 +1,4 @@ -// Copyright 2005 Google Inc. All Rights Reserved. +// Copyright 2005 Google LLC // Author: chatham@google.com (Andrew Chatham) // Author: satorux@google.com (Satoru Takabayashi) // @@ -41,6 +41,7 @@ #include <algorithm> #include <map> #include <string> +#include <string_view> #include <vector> // TODO(saugustine): Add support for compressed debug. // Also need to add configure tests for zlib. @@ -106,9 +107,15 @@ const int kAARCH64PLT0Size = 0x20; // Suffix for PLT functions when it needs to be explicitly identified as such. const char kPLTFunctionSuffix[] = "@plt"; +// Replace callsites of this function to std::string_view::starts_with after +// adopting C++20. +bool StringViewStartsWith(std::string_view sv, std::string_view prefix) { + return sv.compare(0, prefix.size(), prefix) == 0; +} + } // namespace -namespace dwarf2reader { +namespace google_breakpad { template <class ElfArch> class ElfReaderImpl; @@ -130,11 +137,11 @@ class Elf32 { static const int kElfClass = ELFCLASS32; // Given a symbol pointer, return the binding type (eg STB_WEAK). - static char Bind(const Elf32_Sym *sym) { + static char Bind(const Elf32_Sym* sym) { return ELF32_ST_BIND(sym->st_info); } // Given a symbol pointer, return the symbol type (eg STT_FUNC). - static char Type(const Elf32_Sym *sym) { + static char Type(const Elf32_Sym* sym) { return ELF32_ST_TYPE(sym->st_info); } @@ -158,10 +165,10 @@ class Elf64 { // What should be in the EI_CLASS header. static const int kElfClass = ELFCLASS64; - static char Bind(const Elf64_Sym *sym) { + static char Bind(const Elf64_Sym* sym) { return ELF64_ST_BIND(sym->st_info); } - static char Type(const Elf64_Sym *sym) { + static char Type(const Elf64_Sym* sym) { return ELF64_ST_TYPE(sym->st_info); } static int r_sym(const Elf64_Xword r_info) { @@ -182,8 +189,8 @@ class Elf64 { template<class ElfArch> class ElfSectionReader { public: - ElfSectionReader(const char *name, const string &path, int fd, - const typename ElfArch::Shdr §ion_header) + ElfSectionReader(const char* cname, const string& path, int fd, + const typename ElfArch::Shdr& section_header) : contents_aligned_(NULL), contents_(NULL), header_(section_header) { @@ -196,14 +203,25 @@ class ElfSectionReader { // to process its contents. if (header_.sh_type == SHT_NOBITS || header_.sh_size == 0) return; + // extra sh_type check for string table. + std::string_view name{cname}; + if ((name == ".strtab" || name == ".shstrtab") && + header_.sh_type != SHT_STRTAB) { + fprintf(stderr, + "Invalid sh_type for string table section: expected " + "SHT_STRTAB or SHT_DYNSYM, but got %d\n", + header_.sh_type); + return; + } + contents_aligned_ = mmap(NULL, size_aligned_, PROT_READ, MAP_SHARED, fd, offset_aligned); // Set where the offset really should begin. - contents_ = reinterpret_cast<char *>(contents_aligned_) + + contents_ = reinterpret_cast<char*>(contents_aligned_) + (header_.sh_offset - offset_aligned); // Check for and handle any compressed contents. - //if (strncmp(name, ".zdebug_", strlen(".zdebug_")) == 0) + //if (StringViewStartsWith(name, ".zdebug_")) // DecompressZlibContents(); // TODO(saugustine): Add support for proposed elf-section flag // "SHF_COMPRESS". @@ -217,24 +235,24 @@ class ElfSectionReader { } // Return the section header for this section. - typename ElfArch::Shdr const &header() const { return header_; } + typename ElfArch::Shdr const& header() const { return header_; } // Return memory at the given offset within this section. - const char *GetOffset(typename ElfArch::Word bytes) const { + const char* GetOffset(typename ElfArch::Word bytes) const { return contents_ + bytes; } - const char *contents() const { return contents_; } + const char* contents() const { return contents_; } size_t section_size() const { return section_size_; } private: // page-aligned file contents - void *contents_aligned_; + void* contents_aligned_; // contents as usable by the client. For non-compressed sections, // pointer within contents_aligned_ to where the section data // begins; for compressed sections, pointer to the decompressed // data. - char *contents_; + char* contents_; // size of contents_aligned_ size_t size_aligned_; // size of contents. @@ -249,7 +267,7 @@ class ElfSectionReader { template<class ElfArch> class SymbolIterator { public: - SymbolIterator(ElfReaderImpl<ElfArch> *reader, + SymbolIterator(ElfReaderImpl<ElfArch>* reader, typename ElfArch::Word section_type) : symbol_section_(reader->GetSectionByType(section_type)), string_section_(NULL), @@ -280,7 +298,7 @@ class SymbolIterator { // Return a pointer to the current symbol. // REQUIRES: !done() - const typename ElfArch::Sym *GetSymbol() const { + const typename ElfArch::Sym* GetSymbol() const { return reinterpret_cast<const typename ElfArch::Sym*>( symbol_section_->GetOffset(symbol_within_section_ * symbol_section_->header().sh_entsize)); @@ -288,7 +306,7 @@ class SymbolIterator { // Return the name of the current symbol, NULL if it has none. // REQUIRES: !done() - const char *GetSymbolName() const { + const char* GetSymbolName() const { int name_offset = GetSymbol()->st_name; if (name_offset == 0) return NULL; @@ -300,8 +318,8 @@ class SymbolIterator { } private: - const ElfSectionReader<ElfArch> *const symbol_section_; - const ElfSectionReader<ElfArch> *string_section_; + const ElfSectionReader<ElfArch>* const symbol_section_; + const ElfSectionReader<ElfArch>* string_section_; int num_symbols_in_section_; int symbol_within_section_; }; @@ -326,7 +344,7 @@ static inline bool MyHasSuffixString(const string& str, const string& suffix) { template<class ElfArch> class ElfReaderImpl { public: - explicit ElfReaderImpl(const string &path, int fd) + explicit ElfReaderImpl(const string& path, int fd) : path_(path), fd_(fd), section_headers_(NULL), @@ -347,8 +365,8 @@ class ElfReaderImpl { // "opd_section_" must always be checked for NULL before use. opd_section_ = GetSectionInfoByName(".opd", &opd_info_); for (unsigned int k = 0u; k < GetNumSections(); ++k) { - const char *name = GetSectionName(section_headers_[k].sh_name); - if (strncmp(name, ".text", strlen(".text")) == 0) { + std::string_view name{GetSectionName(section_headers_[k].sh_name)}; + if (StringViewStartsWith(name, ".text")) { base_for_text_ = section_headers_[k].sh_addr - section_headers_[k].sh_offset; break; @@ -384,7 +402,7 @@ class ElfReaderImpl { // to see if the ELF file appears to match the current // architecture. If error is non-NULL, it will be set with a reason // in case of failure. - static bool IsArchElfFile(int fd, string *error) { + static bool IsArchElfFile(int fd, string* error) { unsigned char header[EI_NIDENT]; if (pread(fd, header, sizeof(header), 0) != sizeof(header)) { if (error != NULL) *error = "Could not read header"; @@ -415,7 +433,7 @@ class ElfReaderImpl { } // Return true if we can use this symbol in Address-to-Symbol map. - bool CanUseSymbol(const char *name, const typename ElfArch::Sym *sym) { + bool CanUseSymbol(const char* name, const typename ElfArch::Sym* sym) { // For now we only save FUNC and NOTYPE symbols. For now we just // care about functions, but some functions written in assembler // don't have a proper ELF type attached to them, so we store @@ -444,7 +462,7 @@ class ElfReaderImpl { // Iterate over the symbols in a section, either SHT_DYNSYM or // SHT_SYMTAB. Add all symbols to the given SymbolMap. /* - void GetSymbolPositions(SymbolMap *symbols, + void GetSymbolPositions(SymbolMap* symbols, typename ElfArch::Word section_type, uint64_t mem_offset, uint64_t file_offset) { @@ -453,10 +471,10 @@ class ElfReaderImpl { AddrToSymMap addr_to_sym_map; for (SymbolIterator<ElfArch> it(this, section_type); !it.done(); it.Next()) { - const char *name = it.GetSymbolName(); + const char* name = it.GetSymbolName(); if (name == NULL) continue; - const typename ElfArch::Sym *sym = it.GetSymbol(); + const typename ElfArch::Sym* sym = it.GetSymbol(); if (CanUseSymbol(name, sym)) { const int sec = sym->st_shndx; @@ -519,9 +537,9 @@ class ElfReaderImpl { if (addr_to_sym_map.empty()) { return; } - const ElfSectionReader<ElfArch> *const symbol_section = + const ElfSectionReader<ElfArch>* const symbol_section = this->GetSectionByType(section_type); - const ElfSectionReader<ElfArch> *const string_section = + const ElfSectionReader<ElfArch>* const string_section = this->GetSection(symbol_section->header().sh_link); typename AddrToSymMap::iterator curr = addr_to_sym_map.begin(); @@ -532,8 +550,8 @@ class ElfReaderImpl { for (; curr != addr_to_sym_map.end(); ++curr) { const uint64_t prev_addr = prev->first; const uint64_t curr_addr = curr->first; - const typename ElfArch::Sym *const prev_sym = prev->second; - const typename ElfArch::Sym *const curr_sym = curr->second; + const typename ElfArch::Sym* const prev_sym = prev->second; + const typename ElfArch::Sym* const curr_sym = curr->second; if (prev_addr + prev_sym->st_size <= curr_addr || // The next condition is true if two symbols overlap like this: // @@ -552,7 +570,7 @@ class ElfReaderImpl { // (e.g. 0619e071) will produce the current symbol, // which is the desired outcome. prev_addr + prev_sym->st_size < curr_addr + curr_sym->st_size) { - const char *name = string_section->GetOffset(curr_sym->st_name); + const char* name = string_section->GetOffset(curr_sym->st_name); symbols->AddSymbol(name, curr_addr, curr_sym->st_size); prev = curr; } else { @@ -572,20 +590,20 @@ class ElfReaderImpl { */ void VisitSymbols(typename ElfArch::Word section_type, - ElfReader::SymbolSink *sink) { + ElfReader::SymbolSink* sink) { VisitSymbols(section_type, sink, -1, -1, false); } void VisitSymbols(typename ElfArch::Word section_type, - ElfReader::SymbolSink *sink, + ElfReader::SymbolSink* sink, int symbol_binding, int symbol_type, bool get_raw_symbol_values) { for (SymbolIterator<ElfArch> it(this, section_type); !it.done(); it.Next()) { - const char *name = it.GetSymbolName(); + const char* name = it.GetSymbolName(); if (!name) continue; - const typename ElfArch::Sym *sym = it.GetSymbol(); + const typename ElfArch::Sym* sym = it.GetSymbol(); if ((symbol_binding < 0 || ElfArch::Bind(sym) == symbol_binding) && (symbol_type < 0 || ElfArch::Type(sym) == symbol_type)) { typename ElfArch::Sym symbol = *sym; @@ -691,7 +709,7 @@ class ElfReaderImpl { // Return an ElfSectionReader for the first section of the given // type by iterating through all section headers. Returns NULL if // the section type is not found. - const ElfSectionReader<ElfArch> *GetSectionByType( + const ElfSectionReader<ElfArch>* GetSectionByType( typename ElfArch::Word section_type) { for (unsigned int k = 0u; k < GetNumSections(); ++k) { if (section_headers_[k].sh_type == section_type) { @@ -703,14 +721,14 @@ class ElfReaderImpl { // Return the name of section "shndx". Returns NULL if the section // is not found. - const char *GetSectionNameByIndex(int shndx) { + const char* GetSectionNameByIndex(int shndx) { return GetSectionName(section_headers_[shndx].sh_name); } // Return a pointer to section "shndx", and store the size in // "size". Returns NULL if the section is not found. - const char *GetSectionContentsByIndex(int shndx, size_t *size) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); + const char* GetSectionContentsByIndex(int shndx, size_t* size) { + const ElfSectionReader<ElfArch>* section = GetSection(shndx); if (section != NULL) { *size = section->section_size(); return section->contents(); @@ -721,16 +739,16 @@ class ElfReaderImpl { // Return a pointer to the first section of the given name by // iterating through all section headers, and store the size in // "size". Returns NULL if the section name is not found. - const char *GetSectionContentsByName(const string §ion_name, - size_t *size) { + const char* GetSectionContentsByName(const string& section_name, + size_t* size) { for (unsigned int k = 0u; k < GetNumSections(); ++k) { // When searching for sections in a .dwp file, the sections // we're looking for will always be at the end of the section // table, so reverse the direction of iteration. int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; - const char *name = GetSectionName(section_headers_[shndx].sh_name); + const char* name = GetSectionName(section_headers_[shndx].sh_name); if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); + const ElfSectionReader<ElfArch>* section = GetSection(shndx); if (section == NULL) { return NULL; } else { @@ -744,16 +762,16 @@ class ElfReaderImpl { // This is like GetSectionContentsByName() but it returns a lot of extra // information about the section. - const char *GetSectionInfoByName(const string §ion_name, - ElfReader::SectionInfo *info) { + const char* GetSectionInfoByName(const string& section_name, + ElfReader::SectionInfo* info) { for (unsigned int k = 0u; k < GetNumSections(); ++k) { // When searching for sections in a .dwp file, the sections // we're looking for will always be at the end of the section // table, so reverse the direction of iteration. int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; - const char *name = GetSectionName(section_headers_[shndx].sh_name); + const char* name = GetSectionName(section_headers_[shndx].sh_name); if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); + const ElfSectionReader<ElfArch>* section = GetSection(shndx); if (section == NULL) { return NULL; } else { @@ -797,9 +815,11 @@ class ElfReaderImpl { // Debug sections are likely to be near the end, so reverse the // direction of iteration. for (int k = GetNumSections() - 1; k >= 0; --k) { - const char *name = GetSectionName(section_headers_[k].sh_name); - if (strncmp(name, ".debug", strlen(".debug")) == 0) return true; - if (strncmp(name, ".zdebug", strlen(".zdebug")) == 0) return true; + std::string_view name{GetSectionName(section_headers_[k].sh_name)}; + if (StringViewStartsWith(name, ".debug") || + StringViewStartsWith(name, ".zdebug")) { + return true; + } } return false; } @@ -816,7 +836,7 @@ class ElfReaderImpl { } private: - typedef vector<pair<uint64_t, const typename ElfArch::Sym *> > AddrToSymMap; + typedef vector<pair<uint64_t, const typename ElfArch::Sym*> > AddrToSymMap; static bool AddrToSymSorter(const typename AddrToSymMap::value_type& lhs, const typename AddrToSymMap::value_type& rhs) { @@ -854,8 +874,8 @@ class ElfReaderImpl { // Given an offset into the section header string table, return the // section name. - const char *GetSectionName(typename ElfArch::Word sh_name) { - const ElfSectionReader<ElfArch> *shstrtab = + const char* GetSectionName(typename ElfArch::Word sh_name) { + const ElfSectionReader<ElfArch>* shstrtab = GetSection(GetStringTableIndex()); if (shstrtab != NULL) { return shstrtab->GetOffset(sh_name); @@ -865,25 +885,25 @@ class ElfReaderImpl { // Return an ElfSectionReader for the given section. The reader will // be freed when this object is destroyed. - const ElfSectionReader<ElfArch> *GetSection(int num) { - const char *name; + const ElfSectionReader<ElfArch>* GetSection(int num) { + const char* name; // Hard-coding the name for the section-name string table prevents // infinite recursion. if (num == GetStringTableIndex()) name = ".shstrtab"; else name = GetSectionNameByIndex(num); - ElfSectionReader<ElfArch> *& reader = sections_[num]; + ElfSectionReader<ElfArch>*& reader = sections_[num]; if (reader == NULL) reader = new ElfSectionReader<ElfArch>(name, path_, fd_, section_headers_[num]); - return reader; + return reader->contents() ? reader : nullptr; } // Parse out the overall header information from the file and assert // that it looks sane. This contains information like the magic // number and target architecture. - bool ParseHeaders(int fd, const string &path) { + bool ParseHeaders(int fd, const string& path) { // Read in the global ELF header. if (pread(fd, &header_, sizeof(header_), 0) != sizeof(header_)) { return false; @@ -985,11 +1005,11 @@ class ElfReaderImpl { // Array of GetNumSections() section headers, allocated when we read // in the global header. - typename ElfArch::Shdr *section_headers_; + typename ElfArch::Shdr* section_headers_; // Array of GetNumProgramHeaders() program headers, allocated when we read // in the global header. - typename ElfArch::Phdr *program_headers_; + typename ElfArch::Phdr* program_headers_; // An array of pointers to ElfSectionReaders. Sections are // mmaped as they're needed and not released until this object is @@ -1000,7 +1020,7 @@ class ElfReaderImpl { // values for funtion symbols values. Function descriptors are kept in the // .opd section and are dereferenced to find the function address. ElfReader::SectionInfo opd_info_; - const char *opd_section_; // Must be checked for NULL before use. + const char* opd_section_; // Must be checked for NULL before use. int64_t base_for_text_; // Read PLT-related sections for the current architecture. @@ -1026,7 +1046,7 @@ class ElfReaderImpl { bool is_dwp_; }; -ElfReader::ElfReader(const string &path) +ElfReader::ElfReader(const string& path) : path_(path), fd_(-1), impl32_(NULL), impl64_(NULL) { // linux 2.6.XX kernel can show deleted files like this: // /var/run/nscd/dbYLJYaE (deleted) @@ -1063,7 +1083,7 @@ ElfReader::~ElfReader() { #endif template <typename ElfArch> -static bool IsElfFile(const int fd, const string &path) { +static bool IsElfFile(const int fd, const string& path) { if (fd < 0) return false; if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) { @@ -1086,7 +1106,7 @@ bool ElfReader::IsElf64File() const { } /* -void ElfReader::AddSymbols(SymbolMap *symbols, +void ElfReader::AddSymbols(SymbolMap* symbols, uint64_t mem_offset, uint64_t file_offset, uint64_t length) { if (fd_ < 0) @@ -1109,17 +1129,17 @@ void ElfReader::AddSymbols(SymbolMap *symbols, } */ -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink) { +void ElfReader::VisitSymbols(ElfReader::SymbolSink* sink) { VisitSymbols(sink, -1, -1); } -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, +void ElfReader::VisitSymbols(ElfReader::SymbolSink* sink, int symbol_binding, int symbol_type) { VisitSymbols(sink, symbol_binding, symbol_type, false); } -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, +void ElfReader::VisitSymbols(ElfReader::SymbolSink* sink, int symbol_binding, int symbol_type, bool get_raw_symbol_values) { @@ -1148,7 +1168,7 @@ uint64_t ElfReader::VaddrOfFirstLoadSegment() { } } -const char *ElfReader::GetSectionName(int shndx) { +const char* ElfReader::GetSectionName(int shndx) { if (shndx < 0 || static_cast<unsigned int>(shndx) >= GetNumSections()) return NULL; if (IsElf32File()) { return GetImpl32()->GetSectionNameByIndex(shndx); @@ -1169,7 +1189,7 @@ uint64_t ElfReader::GetNumSections() { } } -const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) { +const char* ElfReader::GetSectionByIndex(int shndx, size_t* size) { if (IsElf32File()) { return GetImpl32()->GetSectionContentsByIndex(shndx, size); } else if (IsElf64File()) { @@ -1179,8 +1199,8 @@ const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) { } } -const char *ElfReader::GetSectionByName(const string §ion_name, - size_t *size) { +const char* ElfReader::GetSectionByName(const string& section_name, + size_t* size) { if (IsElf32File()) { return GetImpl32()->GetSectionContentsByName(section_name, size); } else if (IsElf64File()) { @@ -1190,8 +1210,8 @@ const char *ElfReader::GetSectionByName(const string §ion_name, } } -const char *ElfReader::GetSectionInfoByName(const string §ion_name, - SectionInfo *info) { +const char* ElfReader::GetSectionInfoByName(const string& section_name, + SectionInfo* info) { if (IsElf32File()) { return GetImpl32()->GetSectionInfoByName(section_name, info); } else if (IsElf64File()) { @@ -1201,11 +1221,15 @@ const char *ElfReader::GetSectionInfoByName(const string §ion_name, } } -bool ElfReader::SectionNamesMatch(const string &name, const string &sh_name) { - if ((name.find(".debug_", 0) == 0) && (sh_name.find(".zdebug_", 0) == 0)) { - const string name_suffix(name, strlen(".debug_")); - const string sh_name_suffix(sh_name, strlen(".zdebug_")); - return name_suffix == sh_name_suffix; +bool ElfReader::SectionNamesMatch(std::string_view name, + std::string_view sh_name) { + std::string_view debug_prefix{".debug_"}; + std::string_view zdebug_prefix{".zdebug_"}; + if (StringViewStartsWith(name, debug_prefix) && + StringViewStartsWith(sh_name, zdebug_prefix)) { + name.remove_prefix(debug_prefix.length()); + sh_name.remove_prefix(zdebug_prefix.length()); + return name == sh_name; } return name == sh_name; } @@ -1220,14 +1244,14 @@ bool ElfReader::IsDynamicSharedObject() { } } -ElfReaderImpl<Elf32> *ElfReader::GetImpl32() { +ElfReaderImpl<Elf32>* ElfReader::GetImpl32() { if (impl32_ == NULL) { impl32_ = new ElfReaderImpl<Elf32>(path_, fd_); } return impl32_; } -ElfReaderImpl<Elf64> *ElfReader::GetImpl64() { +ElfReaderImpl<Elf64>* ElfReader::GetImpl64() { if (impl64_ == NULL) { impl64_ = new ElfReaderImpl<Elf64>(path_, fd_); } @@ -1238,7 +1262,7 @@ ElfReaderImpl<Elf64> *ElfReader::GetImpl64() { // debug info (debug_only=true) or symbol table (debug_only=false). // Otherwise, return false. template <typename ElfArch> -static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd, +static bool IsNonStrippedELFBinaryImpl(const string& path, const int fd, bool debug_only) { if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) return false; ElfReaderImpl<ElfArch> elf_reader(path, fd); @@ -1248,7 +1272,7 @@ static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd, } // Helper for the IsNon[Debug]StrippedELFBinary functions. -static bool IsNonStrippedELFBinaryHelper(const string &path, +static bool IsNonStrippedELFBinaryHelper(const string& path, bool debug_only) { const int fd = open(path.c_str(), O_RDONLY); if (fd == -1) { @@ -1264,11 +1288,11 @@ static bool IsNonStrippedELFBinaryHelper(const string &path, return false; } -bool ElfReader::IsNonStrippedELFBinary(const string &path) { +bool ElfReader::IsNonStrippedELFBinary(const string& path) { return IsNonStrippedELFBinaryHelper(path, false); } -bool ElfReader::IsNonDebugStrippedELFBinary(const string &path) { +bool ElfReader::IsNonDebugStrippedELFBinary(const string& path) { return IsNonStrippedELFBinaryHelper(path, true); } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/elf_reader.h b/src/common/dwarf/elf_reader.h index 8eaa5aa9..a6dec755 100644 --- a/src/common/dwarf/elf_reader.h +++ b/src/common/dwarf/elf_reader.h @@ -1,4 +1,4 @@ -// Copyright 2005 Google Inc. All Rights Reserved. +// Copyright 2005 Google LLC // Author: chatham@google.com (Andrew Chatham) // Author: satorux@google.com (Satoru Takabayashi) // @@ -16,6 +16,7 @@ #define COMMON_DWARF_ELF_READER_H__ #include <string> +#include <string_view> #include <vector> #include "common/dwarf/types.h" @@ -24,7 +25,7 @@ using std::vector; using std::pair; -namespace dwarf2reader { +namespace google_breakpad { class SymbolMap; class Elf32; @@ -34,7 +35,7 @@ class ElfReaderImpl; class ElfReader { public: - explicit ElfReader(const string &path); + explicit ElfReader(const string& path); ~ElfReader(); // Parse the ELF prologue of this file and return whether it was @@ -62,29 +63,29 @@ class ElfReader { // mem_offset - position at which the segment is mapped into memory // file_offset - offset in the file where the mapping begins // length - length of the mapped segment - void AddSymbols(SymbolMap *symbols, + void AddSymbols(SymbolMap* symbols, uint64_t mem_offset, uint64_t file_offset, uint64_t length); class SymbolSink { public: virtual ~SymbolSink() {} - virtual void AddSymbol(const char *name, uint64_t address, + virtual void AddSymbol(const char* name, uint64_t address, uint64_t size) = 0; }; // Like AddSymbols above, but with no address correction. // Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section. - void VisitSymbols(SymbolSink *sink); + void VisitSymbols(SymbolSink* sink); // Like VisitSymbols above, but for a specific symbol binding/type. // A negative value for the binding and type parameters means any // binding or type. - void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type); + void VisitSymbols(SymbolSink* sink, int symbol_binding, int symbol_type); // Like VisitSymbols above but can optionally export raw symbol values instead // of adjusted ones. - void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type, + void VisitSymbols(SymbolSink* sink, int symbol_binding, int symbol_type, bool get_raw_symbol_values); // p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD @@ -95,7 +96,7 @@ class ElfReader { // Return the name of section "shndx". Returns NULL if the section // is not found. - const char *GetSectionName(int shndx); + const char* GetSectionName(int shndx); // Return the number of sections in the given ELF file. uint64_t GetNumSections(); @@ -104,14 +105,14 @@ class ElfReader { // the pointer to the section and store the size in "size". // On error, return NULL. The returned section data is only valid // until the ElfReader gets destroyed. - const char *GetSectionByIndex(int shndx, size_t *size); + const char* GetSectionByIndex(int shndx, size_t* size); // Get section with "section_name" (ex. ".text", ".symtab") in the // given ELF file. On success, return the pointer to the section // and store the size in "size". On error, return NULL. The // returned section data is only valid until the ElfReader gets // destroyed. - const char *GetSectionByName(const string §ion_name, size_t *size); + const char* GetSectionByName(const string& section_name, size_t* size); // This is like GetSectionByName() but it returns a lot of extra information // about the section. The SectionInfo structure is almost identical to @@ -129,39 +130,40 @@ class ElfReader { uint64_t addralign; // Section alignment. uint64_t entsize; // Entry size if section holds a table. }; - const char *GetSectionInfoByName(const string §ion_name, - SectionInfo *info); + const char* GetSectionInfoByName(const string& section_name, + SectionInfo* info); // Check if "path" is an ELF binary that has not been stripped of symbol // tables. This function supports both 32-bit and 64-bit ELF binaries. - static bool IsNonStrippedELFBinary(const string &path); + static bool IsNonStrippedELFBinary(const string& path); // Check if "path" is an ELF binary that has not been stripped of debug // info. Unlike IsNonStrippedELFBinary, this function will return // false for binaries passed through "strip -S". - static bool IsNonDebugStrippedELFBinary(const string &path); + static bool IsNonDebugStrippedELFBinary(const string& path); // Match a requested section name with the section name as it // appears in the elf-file, adjusting for compressed debug section // names. For example, returns true if name == ".debug_abbrev" and // sh_name == ".zdebug_abbrev" - static bool SectionNamesMatch(const string &name, const string &sh_name); + static bool SectionNamesMatch(std::string_view name, + std::string_view sh_name); private: // Lazily initialize impl32_ and return it. - ElfReaderImpl<Elf32> *GetImpl32(); + ElfReaderImpl<Elf32>* GetImpl32(); // Ditto for impl64_. - ElfReaderImpl<Elf64> *GetImpl64(); + ElfReaderImpl<Elf64>* GetImpl64(); // Path of the file we're reading. const string path_; // Read-only file descriptor for the file. May be -1 if there was an // error during open. int fd_; - ElfReaderImpl<Elf32> *impl32_; - ElfReaderImpl<Elf64> *impl64_; + ElfReaderImpl<Elf32>* impl32_; + ElfReaderImpl<Elf64>* impl64_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_ELF_READER_H__ diff --git a/src/common/dwarf/functioninfo.cc b/src/common/dwarf/functioninfo.cc index 358a6eef..d8fdb842 100644 --- a/src/common/dwarf/functioninfo.cc +++ b/src/common/dwarf/functioninfo.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,24 +42,16 @@ #include "common/scoped_ptr.h" #include "common/using_std_string.h" -using google_breakpad::scoped_ptr; - -namespace dwarf2reader { +namespace google_breakpad { CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files, std::vector<string>* dirs, LineMap* linemap):linemap_(linemap), files_(files), dirs_(dirs) { - // The dirs and files are 1 indexed, so just make sure we put - // nothing in the 0 vector. - assert(dirs->size() == 0); - assert(files->size() == 0); - dirs->push_back(""); - SourceFileInfo s; - s.name = ""; - s.lowpc = ULLONG_MAX; - files->push_back(s); + // In dwarf4, the dirs and files are 1 indexed, and in dwarf5 they are zero + // indexed. This is handled in the LineInfo reader, so empty files are not + // needed here. } void CULineInfoHandler::DefineDir(const string& name, uint32_t dir_num) { @@ -150,7 +142,7 @@ bool CUFunctionInfoHandler::StartDIE(uint64_t offset, enum DwarfTag tag) { void CUFunctionInfoHandler::ProcessAttributeString(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const string &data) { + const string& data) { if (current_function_info_) { if (attr == DW_AT_name) current_function_info_->name = data; @@ -164,7 +156,8 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64_t offset, enum DwarfForm form, uint64_t data) { if (attr == DW_AT_stmt_list) { - SectionMap::const_iterator iter = sections_.find("__debug_line"); + SectionMap::const_iterator iter = + GetSectionByName(sections_, ".debug_line"); assert(iter != sections_.end()); scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data, @@ -232,4 +225,4 @@ void CUFunctionInfoHandler::EndDIE(uint64_t offset) { current_function_info_)); } -} // namespace dwarf2reader +} // namespace google_breakpad diff --git a/src/common/dwarf/functioninfo.h b/src/common/dwarf/functioninfo.h index 5c733c6d..1387c5ba 100644 --- a/src/common/dwarf/functioninfo.h +++ b/src/common/dwarf/functioninfo.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -43,7 +43,7 @@ #include "common/using_std_string.h" -namespace dwarf2reader { +namespace google_breakpad { struct FunctionInfo { // Name of the function @@ -187,5 +187,5 @@ class CUFunctionInfoHandler: public Dwarf2Handler { uint64_t current_compilation_unit_offset_; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_FUNCTIONINFO_H__ diff --git a/src/common/dwarf/line_state_machine.h b/src/common/dwarf/line_state_machine.h index fc301c76..1797e3bc 100644 --- a/src/common/dwarf/line_state_machine.h +++ b/src/common/dwarf/line_state_machine.h @@ -1,4 +1,4 @@ -// Copyright 2008 Google Inc. All Rights Reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -30,7 +30,9 @@ #ifndef COMMON_DWARF_LINE_STATE_MACHINE_H__ #define COMMON_DWARF_LINE_STATE_MACHINE_H__ -namespace dwarf2reader { +#include <stdint.h> + +namespace google_breakpad { // This is the format of a DWARF2/3 line state machine that we process // opcodes using. There is no need for anything outside the lineinfo @@ -55,7 +57,7 @@ struct LineStateMachine { bool end_sequence; }; -} // namespace dwarf2reader +} // namespace google_breakpad #endif // COMMON_DWARF_LINE_STATE_MACHINE_H__ diff --git a/src/common/dwarf/types.h b/src/common/dwarf/types.h index 23412d0e..b14d7a3e 100644 --- a/src/common/dwarf/types.h +++ b/src/common/dwarf/types.h @@ -1,4 +1,4 @@ -// Copyright 2008 Google, Inc. All Rights reserved +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/dwarf_cfi_to_module.cc b/src/common/dwarf_cfi_to_module.cc index 3dd85edd..7da8507d 100644 --- a/src/common/dwarf_cfi_to_module.cc +++ b/src/common/dwarf_cfi_to_module.cc @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -34,7 +33,9 @@ // Implementation of google_breakpad::DwarfCFIToModule. // See dwarf_cfi_to_module.h for details. +#include <memory> #include <sstream> +#include <utility> #include "common/dwarf_cfi_to_module.h" @@ -143,16 +144,16 @@ vector<string> DwarfCFIToModule::RegisterNames::MIPS() { } bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length, - uint8_t version, const string &augmentation, + uint8_t version, const string& augmentation, unsigned return_address) { assert(!entry_); - // If dwarf2reader::CallFrameInfo can handle this version and + // If CallFrameInfo can handle this version and // augmentation, then we should be okay with that, so there's no // need to check them here. // Get ready to collect entries. - entry_ = new Module::StackFrameEntry; + entry_ = std::make_unique<Module::StackFrameEntry>(); entry_->address = address; entry_->size = length; entry_offset_ = offset; @@ -184,13 +185,11 @@ string DwarfCFIToModule::RegisterName(int i) { return register_names_[reg]; reporter_->UnnamedRegister(entry_offset_, reg); - char buf[30]; - sprintf(buf, "unnamed_register%u", reg); - return buf; + return string("unnamed_register") + std::to_string(reg); } void DwarfCFIToModule::Record(Module::Address address, int reg, - const string &rule) { + const string& rule) { assert(entry_); // Place the name in our global set of strings, and then use the string @@ -247,25 +246,28 @@ bool DwarfCFIToModule::RegisterRule(uint64_t address, int reg, } bool DwarfCFIToModule::ExpressionRule(uint64_t address, int reg, - const string &expression) { + const string& expression) { reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); // Treat this as a non-fatal error. return true; } bool DwarfCFIToModule::ValExpressionRule(uint64_t address, int reg, - const string &expression) { + const string& expression) { reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); // Treat this as a non-fatal error. return true; } bool DwarfCFIToModule::End() { - module_->AddStackFrameEntry(entry_); - entry_ = NULL; + module_->AddStackFrameEntry(std::move(entry_)); return true; } +string DwarfCFIToModule::Architecture() { + return module_->architecture(); +} + void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { fprintf(stderr, "%s, section '%s': " "the call frame entry at offset 0x%zx refers to register %d," @@ -274,7 +276,7 @@ void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { } void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset, - const string ®) { + const string& reg) { fprintf(stderr, "%s, section '%s': " "the call frame entry at offset 0x%zx sets the rule for " "register '%s' to 'undefined', but the Breakpad symbol file format" @@ -283,7 +285,7 @@ void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset, } void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset, - const string ®) { + const string& reg) { fprintf(stderr, "%s, section '%s': " "the call frame entry at offset 0x%zx uses a DWARF expression to" " describe how to recover register '%s', " diff --git a/src/common/dwarf_cfi_to_module.h b/src/common/dwarf_cfi_to_module.h index 4d2db7ee..42b618d5 100644 --- a/src/common/dwarf_cfi_to_module.h +++ b/src/common/dwarf_cfi_to_module.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,6 +43,7 @@ #include <set> #include <string> +#include <memory> #include <vector> #include "common/module.h" @@ -52,7 +52,6 @@ namespace google_breakpad { -using dwarf2reader::CallFrameInfo; using google_breakpad::Module; using std::set; using std::vector; @@ -71,7 +70,7 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { // stream. FILE is the name of the file we're processing, and // SECTION is the name of the section within that file that we're // looking at (.debug_frame, .eh_frame, etc.). - Reporter(const string &file, const string §ion) + Reporter(const string& file, const string& section) : file_(file), section_(section) { } virtual ~Reporter() { } @@ -83,13 +82,13 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { // The DWARF CFI entry at OFFSET says that REG is undefined, but the // Breakpad symbol file format cannot express this. - virtual void UndefinedNotSupported(size_t offset, const string ®); + virtual void UndefinedNotSupported(size_t offset, const string& reg); // The DWARF CFI entry at OFFSET says that REG uses a DWARF // expression to find its value, but DwarfCFIToModule is not // capable of translating DWARF expressions to Breakpad postfix // expressions. - virtual void ExpressionsNotSupported(size_t offset, const string ®); + virtual void ExpressionsNotSupported(size_t offset, const string& reg); protected: string file_, section_; @@ -118,10 +117,10 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { private: // Given STRINGS, an array of C strings with SIZE elements, return an // equivalent vector<string>. - static vector<string> MakeVector(const char * const *strings, size_t size); + static vector<string> MakeVector(const char* const* strings, size_t size); }; - // Create a handler for the dwarf2reader::CallFrameInfo parser that + // Create a handler for the CallFrameInfo parser that // records the stack unwinding information it receives in MODULE. // // Use REGISTER_NAMES[I] as the name of register number I; *this @@ -130,15 +129,15 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { // // Use REPORTER for reporting problems encountered in the conversion // process. - DwarfCFIToModule(Module *module, const vector<string> ®ister_names, - Reporter *reporter) + DwarfCFIToModule(Module* module, const vector<string>& register_names, + Reporter* reporter) : module_(module), register_names_(register_names), reporter_(reporter), - entry_(NULL), return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") { + return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") { } - virtual ~DwarfCFIToModule() { delete entry_; } + virtual ~DwarfCFIToModule() = default; virtual bool Entry(size_t offset, uint64_t address, uint64_t length, - uint8_t version, const string &augmentation, + uint8_t version, const string& augmentation, unsigned return_address); virtual bool UndefinedRule(uint64_t address, int reg); virtual bool SameValueRule(uint64_t address, int reg); @@ -148,29 +147,31 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { int base_register, long offset); virtual bool RegisterRule(uint64_t address, int reg, int base_register); virtual bool ExpressionRule(uint64_t address, int reg, - const string &expression); + const string& expression); virtual bool ValExpressionRule(uint64_t address, int reg, - const string &expression); + const string& expression); virtual bool End(); + virtual string Architecture(); + private: // Return the name to use for register REG. string RegisterName(int i); // Record RULE for register REG at ADDRESS. - void Record(Module::Address address, int reg, const string &rule); + void Record(Module::Address address, int reg, const string& rule); // The module to which we should add entries. - Module *module_; + Module* module_; // Map from register numbers to register names. - const vector<string> ®ister_names_; + const vector<string>& register_names_; // The reporter to use to report problems. - Reporter *reporter_; + Reporter* reporter_; // The current entry we're constructing. - Module::StackFrameEntry *entry_; + std::unique_ptr<Module::StackFrameEntry> entry_; // The section offset of the current frame description entry, for // use in error messages. diff --git a/src/common/dwarf_cfi_to_module_unittest.cc b/src/common/dwarf_cfi_to_module_unittest.cc index 60a9a3ee..0b677b21 100644 --- a/src/common/dwarf_cfi_to_module_unittest.cc +++ b/src/common/dwarf_cfi_to_module_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,11 +46,11 @@ using testing::Test; using testing::_; struct MockCFIReporter: public DwarfCFIToModule::Reporter { - MockCFIReporter(const string &file, const string §ion) + MockCFIReporter(const string& file, const string& section) : Reporter(file, section) { } MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg)); - MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string ®)); - MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string ®)); + MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string& reg)); + MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string& reg)); }; struct DwarfCFIToModuleFixture { @@ -80,7 +79,7 @@ struct DwarfCFIToModuleFixture { vector<string> register_names; MockCFIReporter reporter; DwarfCFIToModule handler; - vector<Module::StackFrameEntry *> entries; + vector<Module::StackFrameEntry*> entries; }; class Entry: public DwarfCFIToModuleFixture, public Test { }; diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index ad873059..a5a1fd06 100644 --- a/src/common/dwarf_cu_to_module.cc +++ b/src/common/dwarf_cu_to_module.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,11 +43,12 @@ #include <stdio.h> #include <algorithm> +#include <memory> #include <numeric> #include <utility> +#include "common/string_view.h" #include "common/dwarf_line_to_module.h" -#include "common/unordered.h" #include "google_breakpad/common/breakpad_types.h" namespace google_breakpad { @@ -58,6 +58,7 @@ using std::map; using std::pair; using std::sort; using std::vector; +using std::unique_ptr; // Data provided by a DWARF specification DIE. // @@ -78,22 +79,21 @@ using std::vector; // we may need if we find a DW_AT_specification link pointing to it. struct DwarfCUToModule::Specification { // The qualified name that can be found by demangling DW_AT_MIPS_linkage_name. - string qualified_name; + StringView qualified_name; // The name of the enclosing scope, or the empty string if there is none. - string enclosing_name; + StringView enclosing_name; // The name for the specification DIE itself, without any enclosing // name components. - string unqualified_name; + StringView unqualified_name; }; // An abstract origin -- base definition of an inline function. struct AbstractOrigin { - AbstractOrigin() : name() {} - explicit AbstractOrigin(const string& name) : name(name) {} + explicit AbstractOrigin(StringView name) : name(name) {} - string name; + StringView name; }; typedef map<uint64_t, AbstractOrigin> AbstractOriginByOffset; @@ -101,35 +101,20 @@ typedef map<uint64_t, AbstractOrigin> AbstractOriginByOffset; // Data global to the DWARF-bearing file that is private to the // DWARF-to-Module process. struct DwarfCUToModule::FilePrivate { - // A set of strings used in this CU. Before storing a string in one of - // our data structures, insert it into this set, and then use the string - // from the set. - // - // In some STL implementations, strings are reference-counted internally, - // meaning that simply using strings from this set, even if passed by - // value, assigned, or held directly in structures and containers - // (map<string, ...>, for example), causes those strings to share a - // single instance of each distinct piece of text. GNU's libstdc++ uses - // reference counts, and I believe MSVC did as well, at some point. - // However, C++ '11 implementations are moving away from reference - // counting. - // - // In other implementations, string assignments copy the string's text, - // 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. - unordered_set<string> common_strings; - // A map from offsets of DIEs within the .debug_info section to // Specifications describing those DIEs. Specification references can // cross compilation unit boundaries. SpecificationByOffset specifications; AbstractOriginByOffset origins; + + // Keep a list of forward references from DW_AT_abstract_origin and + // DW_AT_specification attributes so names can be fixed up. + std::map<uint64_t, Module::Function*> forward_ref_die_to_func; }; -DwarfCUToModule::FileContext::FileContext(const string &filename, - Module *module, +DwarfCUToModule::FileContext::FileContext(const string& filename, + Module* module, bool handle_inter_cu_refs) : filename_(filename), module_(module), @@ -138,18 +123,28 @@ DwarfCUToModule::FileContext::FileContext(const string &filename, } DwarfCUToModule::FileContext::~FileContext() { + for (std::vector<uint8_t *>::iterator i = uncompressed_sections_.begin(); + i != uncompressed_sections_.end(); ++i) { + delete[] *i; + } } void DwarfCUToModule::FileContext::AddSectionToSectionMap( - const string& name, const uint8_t *contents, uint64_t length) { + const string& name, const uint8_t* contents, uint64_t length) { section_map_[name] = std::make_pair(contents, length); } +void DwarfCUToModule::FileContext::AddManagedSectionToSectionMap( + const string& name, uint8_t* contents, uint64_t length) { + section_map_[name] = std::make_pair(contents, length); + uncompressed_sections_.push_back(contents); +} + void DwarfCUToModule::FileContext::ClearSectionMapForTest() { section_map_.clear(); } -const dwarf2reader::SectionMap& +const SectionMap& DwarfCUToModule::FileContext::section_map() const { return section_map_; } @@ -170,52 +165,104 @@ bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference( // parsing. This is for data shared across the CU's entire DIE tree, // and parameters from the code invoking the CU parser. struct DwarfCUToModule::CUContext { - CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg, - RangesHandler *ranges_handler_arg) - : file_context(file_context_arg), + CUContext(FileContext* file_context_arg, WarningReporter* reporter_arg, + RangesHandler* ranges_handler_arg) + : version(0), + file_context(file_context_arg), reporter(reporter_arg), ranges_handler(ranges_handler_arg), language(Language::CPlusPlus), low_pc(0), high_pc(0), - ranges(0) {} + ranges_form(DW_FORM_sec_offset), + ranges_data(0), + ranges_base(0), + str_offsets_base(0) { } ~CUContext() { - for (vector<Module::Function *>::iterator it = functions.begin(); + for (vector<Module::Function*>::iterator it = functions.begin(); it != functions.end(); ++it) { delete *it; } }; + // Dwarf version of the source CU. + uint8_t version; + // The DWARF-bearing file into which this CU was incorporated. - FileContext *file_context; + FileContext* file_context; // For printing error messages. - WarningReporter *reporter; + WarningReporter* reporter; // For reading ranges from the .debug_ranges section - RangesHandler *ranges_handler; + RangesHandler* ranges_handler; // The source language of this compilation unit. - const Language *language; + const Language* language; // Addresses covered by this CU. If high_pc_ is non-zero then the CU covers - // low_pc to high_pc, otherwise ranges is non-zero and low_pc represents - // the base address of the ranges covered by the CU. + // low_pc to high_pc, otherwise ranges_data is non-zero and low_pc represents + // the base address of the ranges covered by the CU. ranges_data will define + // the CU's actual ranges. uint64_t low_pc; uint64_t high_pc; - uint64_t ranges; + + // Ranges for this CU are read according to this form. + enum DwarfForm ranges_form; + uint64_t ranges_data; + + // Offset into .debug_rngslists where this CU's ranges are stored. + // Data in DW_FORM_rnglistx is relative to this offset. + uint64_t ranges_base; + + // Offset into .debug_addr where this CU's addresses are stored. Data in + // form DW_FORM_addrxX is relative to this offset. + uint64_t addr_base; + + // Offset into this CU's contribution to .debug_str_offsets. + uint64_t str_offsets_base; + + // Collect all the data from the CU that a RangeListReader needs to read a + // range. + bool AssembleRangeListInfo( + RangeListReader::CURangesInfo* info) { + const SectionMap& section_map + = file_context->section_map(); + info->version_ = version; + info->base_address_ = low_pc; + info->ranges_base_ = ranges_base; + const char* section_name = (version <= 4 ? + ".debug_ranges" : ".debug_rnglists"); + SectionMap::const_iterator map_entry + = GetSectionByName(section_map, section_name); + if (map_entry == section_map.end()) { + return false; + } + info->buffer_ = map_entry->second.first; + info->size_ = map_entry->second.second; + if (version > 4) { + SectionMap::const_iterator map_entry + = GetSectionByName(section_map, ".debug_addr"); + if (map_entry == section_map.end()) { + return false; + } + info->addr_buffer_ = map_entry->second.first; + info->addr_buffer_size_ = map_entry->second.second; + info->addr_base_ = addr_base; + } + return true; + } // The functions defined in this compilation unit. We accumulate // them here during parsing. Then, in DwarfCUToModule::Finish, we // assign them lines and add them to file_context->module. // // Destroying this destroys all the functions this vector points to. - vector<Module::Function *> functions; + vector<Module::Function*> functions; - // Keep a list of forward references from DW_AT_abstract_origin and - // DW_AT_specification attributes so names can be fixed up. - std::map<uint64_t, Module::Function *> forward_ref_die_to_func; + // A map of function pointers to the its forward specification DIE's offset. + map<Module::Function*, uint64_t> spec_function_offsets; }; // Information about the context of a particular DIE. This is for @@ -232,23 +279,25 @@ struct DwarfCUToModule::DIEContext { // in a C++ compilation unit, the DIEContext's name for the // DW_TAG_subprogram DIE would be "Foo::Bar". The DIEContext's // name for the DW_TAG_namespace DIE would be "". - string name; + StringView name; }; // An abstract base class for all the dumper's DIE handlers. -class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { +class DwarfCUToModule::GenericDIEHandler: public DIEHandler { public: // Create a handler for the DIE at OFFSET whose compilation unit is // described by CU_CONTEXT, and whose immediate context is described // by PARENT_CONTEXT. - GenericDIEHandler(CUContext *cu_context, DIEContext *parent_context, + GenericDIEHandler(CUContext* cu_context, DIEContext* parent_context, uint64_t offset) : cu_context_(cu_context), parent_context_(parent_context), offset_(offset), declaration_(false), specification_(NULL), - forward_ref_die_offset_(0) { } + no_specification(false), + abstract_origin_(NULL), + forward_ref_die_offset_(0), specification_offset_(0) { } // Derived classes' ProcessAttributeUnsigned can defer to this to // handle DW_AT_declaration, or simply not override it. @@ -266,7 +315,7 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { // handle DW_AT_specification, or simply not override it. void ProcessAttributeString(enum DwarfAttribute attr, enum DwarfForm form, - const string &data); + const string& data); protected: // Compute and return the fully-qualified name of the DIE. If this @@ -277,20 +326,12 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { // Use this from EndAttributes member functions, not ProcessAttribute* // functions; only the former can be sure that all the DIE's attributes // have been seen. - string ComputeQualifiedName(); + StringView ComputeQualifiedName(); - CUContext *cu_context_; - DIEContext *parent_context_; + CUContext* cu_context_; + DIEContext* parent_context_; uint64_t offset_; - // Place the name in the global set of strings. Even though this looks - // like a copy, all the major string implementations use reference - // counting internally, so the effect is to have all the data structures - // share copies of strings whenever possible. - // FIXME: Should this return something like a string_ref to avoid the - // assumption about how strings are implemented? - string AddStringToPool(const string &str); - // If this DIE has a DW_AT_declaration attribute, this is its value. // It is false on DIEs with no DW_AT_declaration attribute. bool declaration_; @@ -298,25 +339,37 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { // If this DIE has a DW_AT_specification attribute, this is the // Specification structure for the DIE the attribute refers to. // Otherwise, this is NULL. - Specification *specification_; + Specification* specification_; + + // If this DIE has DW_AT_specification with offset smaller than this DIE and + // we can't find that in the specification map. + bool no_specification; + + // If this DIE has a DW_AT_abstract_origin attribute, this is the + // AbstractOrigin structure for the DIE the attribute refers to. + // Otherwise, this is NULL. + const AbstractOrigin* abstract_origin_; // If this DIE has a DW_AT_specification or DW_AT_abstract_origin and it is a // forward reference, no Specification will be available. Track the reference // to be fixed up when the DIE is parsed. uint64_t forward_ref_die_offset_; + // The root offset of Specification or abstract origin. + uint64_t specification_offset_; + // The value of the DW_AT_name attribute, or the empty string if the // DIE has no such attribute. - string name_attribute_; + StringView name_attribute_; // The demangled value of the DW_AT_MIPS_linkage_name attribute, or the empty // string if the DIE has no such attribute or its content could not be // demangled. - string demangled_name_; + StringView demangled_name_; // The non-demangled value of the DW_AT_MIPS_linkage_name attribute, // it its content count not be demangled. - string raw_name_; + StringView raw_name_; }; void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned( @@ -324,7 +377,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned( enum DwarfForm form, uint64_t data) { switch (attr) { - case dwarf2reader::DW_AT_declaration: declaration_ = (data != 0); break; + case DW_AT_declaration: declaration_ = (data != 0); break; default: break; } } @@ -334,8 +387,8 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( enum DwarfForm form, uint64_t data) { switch (attr) { - case dwarf2reader::DW_AT_specification: { - FileContext *file_context = cu_context_->file_context; + case DW_AT_specification: { + FileContext* file_context = cu_context_->file_context; if (file_context->IsUnhandledInterCUReference( data, cu_context_->reporter->cu_offset())) { cu_context_->reporter->UnhandledInterCUReference(offset_, data); @@ -346,7 +399,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( // here, but it's better to leave the real work to our // EndAttribute member function, at which point we know we have // seen all the DIE's attributes. - SpecificationByOffset *specifications = + SpecificationByOffset* specifications = &file_context->file_private_->specifications; SpecificationByOffset::iterator spec = specifications->find(data); if (spec != specifications->end()) { @@ -354,45 +407,53 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( } else if (data > offset_) { forward_ref_die_offset_ = data; } else { - cu_context_->reporter->UnknownSpecification(offset_, data); + no_specification = true; } + specification_offset_ = data; + break; + } + case DW_AT_abstract_origin: { + const AbstractOriginByOffset& origins = + cu_context_->file_context->file_private_->origins; + AbstractOriginByOffset::const_iterator origin = origins.find(data); + if (origin != origins.end()) { + abstract_origin_ = &(origin->second); + } else if (data > offset_) { + forward_ref_die_offset_ = data; + } + specification_offset_ = data; break; } default: break; } } -string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) { - pair<unordered_set<string>::iterator, bool> result = - cu_context_->file_context->file_private_->common_strings.insert(str); - return *result.first; -} - void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( enum DwarfAttribute attr, enum DwarfForm form, - const string &data) { + const string& data) { switch (attr) { - case dwarf2reader::DW_AT_name: - name_attribute_ = AddStringToPool(data); + case DW_AT_name: + name_attribute_ = + cu_context_->file_context->module_->AddStringToPool(data); break; - case dwarf2reader::DW_AT_MIPS_linkage_name: - case dwarf2reader::DW_AT_linkage_name: { + case DW_AT_MIPS_linkage_name: + case DW_AT_linkage_name: { string demangled; Language::DemangleResult result = cu_context_->language->DemangleName(data, &demangled); switch (result) { case Language::kDemangleSuccess: - demangled_name_ = AddStringToPool(demangled); + demangled_name_ = + cu_context_->file_context->module_->AddStringToPool(demangled); break; case Language::kDemangleFailure: cu_context_->reporter->DemangleError(data); // fallthrough - [[fallthrough]]; case Language::kDontDemangle: - demangled_name_.clear(); - raw_name_ = AddStringToPool(data); + demangled_name_ = StringView(); + raw_name_ = cu_context_->file_context->module_->AddStringToPool(data); break; } break; @@ -401,11 +462,11 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( } } -string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { +StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { // Use the demangled name, if one is available. Demangled names are // preferable to those inferred from the DWARF structure because they // include argument types. - const string *qualified_name = NULL; + StringView* qualified_name = nullptr; if (!demangled_name_.empty()) { // Found it is this DIE. qualified_name = &demangled_name_; @@ -414,37 +475,39 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { qualified_name = &specification_->qualified_name; } - const string *unqualified_name = NULL; - const string *enclosing_name; + StringView* unqualified_name = nullptr; + StringView* enclosing_name = nullptr; if (!qualified_name) { // Find the unqualified name. If the DIE has its own DW_AT_name // attribute, then use that; otherwise, check the specification. - if (!name_attribute_.empty()) + if (!name_attribute_.empty()) { unqualified_name = &name_attribute_; - else if (specification_) + } else if (specification_) { unqualified_name = &specification_->unqualified_name; - else if (!raw_name_.empty()) + } else if (!raw_name_.empty()) { unqualified_name = &raw_name_; + } // Find the name of the enclosing context. If this DIE has a // specification, it's the specification's enclosing context that // counts; otherwise, use this DIE's context. - if (specification_) + if (specification_) { enclosing_name = &specification_->enclosing_name; - else + } else if (parent_context_) { enclosing_name = &parent_context_->name; + } } // Prepare the return value before upcoming mutations possibly invalidate the // existing pointers. string return_value; if (qualified_name) { - return_value = *qualified_name; + return_value = qualified_name->str(); } else if (unqualified_name && enclosing_name) { // Combine the enclosing name and unqualified name to produce our // own fully-qualified name. - return_value = cu_context_->language->MakeQualifiedName(*enclosing_name, - *unqualified_name); + return_value = cu_context_->language->MakeQualifiedName( + enclosing_name->str(), unqualified_name->str()); } // If this DIE was marked as a declaration, record its names in the @@ -461,39 +524,224 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { cu_context_->file_context->file_private_->specifications[offset_] = spec; } - return return_value; + return cu_context_->file_context->module_->AddStringToPool(return_value); +} + +static bool IsEmptyRange(const vector<Module::Range>& ranges) { + uint64_t size = accumulate(ranges.cbegin(), ranges.cend(), 0, + [](uint64_t total, Module::Range entry) { + return total + entry.size; + } + ); + + return size == 0; +} + + +// A handler for DW_TAG_inlined_subroutine DIEs. +class DwarfCUToModule::InlineHandler : public GenericDIEHandler { + public: + InlineHandler(CUContext* cu_context, + DIEContext* parent_context, + uint64_t offset, + int inline_nest_level, + vector<unique_ptr<Module::Inline>>& inlines) + : GenericDIEHandler(cu_context, parent_context, offset), + low_pc_(0), + high_pc_(0), + high_pc_form_(DW_FORM_addr), + ranges_form_(DW_FORM_sec_offset), + ranges_data_(0), + call_site_line_(0), + inline_nest_level_(inline_nest_level), + inlines_(inlines) {} + + void ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t data); + DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag); + bool EndAttributes(); + void Finish(); + + private: + // The fully-qualified name, as derived from name_attribute_, + // specification_, parent_context_. Computed in EndAttributes. + StringView name_; + uint64_t low_pc_; // DW_AT_low_pc + uint64_t high_pc_; // DW_AT_high_pc + DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address. + DwarfForm ranges_form_; // DW_FORM_sec_offset or DW_FORM_rnglistx + uint64_t ranges_data_; // DW_AT_ranges + int call_site_line_; // DW_AT_call_line + int call_site_file_id_; // DW_AT_call_file + int inline_nest_level_; + // A vector of inlines in the same nest level. It's owned by its parent + // function/inline. At Finish(), add this inline into the vector. + vector<unique_ptr<Module::Inline>>& inlines_; + // A vector of child inlines. + vector<unique_ptr<Module::Inline>> child_inlines_; +}; + +void DwarfCUToModule::InlineHandler::ProcessAttributeUnsigned( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t data) { + switch (attr) { + case DW_AT_low_pc: + low_pc_ = data; + break; + case DW_AT_high_pc: + high_pc_form_ = form; + high_pc_ = data; + break; + case DW_AT_ranges: + ranges_data_ = data; + ranges_form_ = form; + break; + case DW_AT_call_line: + call_site_line_ = data; + break; + case DW_AT_call_file: + call_site_file_id_ = data; + break; + default: + GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); + break; + } +} + +DIEHandler* DwarfCUToModule::InlineHandler::FindChildHandler( + uint64_t offset, + enum DwarfTag tag) { + switch (tag) { + case DW_TAG_inlined_subroutine: + return new InlineHandler(cu_context_, nullptr, offset, + inline_nest_level_ + 1, child_inlines_); + default: + return NULL; + } } +bool DwarfCUToModule::InlineHandler::EndAttributes() { + if (abstract_origin_) + name_ = abstract_origin_->name; + if (name_.empty()) { + // We haven't seen the abstract origin yet, which might appears later and we + // will fix the name after calling + // InlineOriginMap::GetOrCreateInlineOrigin with right name. + name_ = + cu_context_->file_context->module_->AddStringToPool("<name omitted>"); + } + return true; +} + +void DwarfCUToModule::InlineHandler::Finish() { + vector<Module::Range> ranges; + + if (low_pc_ && high_pc_) { + if (high_pc_form_ != DW_FORM_addr && + high_pc_form_ != DW_FORM_GNU_addr_index && + high_pc_form_ != DW_FORM_addrx && + high_pc_form_ != DW_FORM_addrx1 && + high_pc_form_ != DW_FORM_addrx2 && + high_pc_form_ != DW_FORM_addrx3 && + high_pc_form_ != DW_FORM_addrx4) { + high_pc_ += low_pc_; + } + + Module::Range range(low_pc_, high_pc_ - low_pc_); + ranges.push_back(range); + } else { + RangesHandler* ranges_handler = cu_context_->ranges_handler; + if (ranges_handler) { + RangeListReader::CURangesInfo cu_info; + if (cu_context_->AssembleRangeListInfo(&cu_info)) { + if (!ranges_handler->ReadRanges(ranges_form_, ranges_data_, + &cu_info, &ranges)) { + ranges.clear(); + cu_context_->reporter->MalformedRangeList(ranges_data_); + } + } else { + cu_context_->reporter->MissingRanges(); + } + } + } + + // Ignore DW_TAG_inlined_subroutine with empty range. + if (ranges.empty()) { + return; + } + + // Every DW_TAG_inlined_subroutine should have a DW_AT_abstract_origin. + assert(specification_offset_ != 0); + + cu_context_->file_context->module_->inline_origin_map.SetReference( + specification_offset_, specification_offset_); + Module::InlineOrigin* origin = + cu_context_->file_context->module_->inline_origin_map + .GetOrCreateInlineOrigin(specification_offset_, name_); + unique_ptr<Module::Inline> in( + new Module::Inline(origin, ranges, call_site_line_, call_site_file_id_, + inline_nest_level_, std::move(child_inlines_))); + inlines_.push_back(std::move(in)); +} + +// A handler for DIEs that contain functions and contribute a +// component to their names: namespaces, classes, etc. +class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler { + public: + NamedScopeHandler(CUContext* cu_context, + DIEContext* parent_context, + uint64_t offset, + bool handle_inline) + : GenericDIEHandler(cu_context, parent_context, offset), + handle_inline_(handle_inline) {} + bool EndAttributes(); + DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag); + + private: + DIEContext child_context_; // A context for our children. + bool handle_inline_; +}; + // A handler class for DW_TAG_subprogram DIEs. class DwarfCUToModule::FuncHandler: public GenericDIEHandler { public: - FuncHandler(CUContext *cu_context, DIEContext *parent_context, - uint64_t offset) + FuncHandler(CUContext* cu_context, + DIEContext* parent_context, + uint64_t offset, + bool handle_inline) : GenericDIEHandler(cu_context, parent_context, offset), - low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr), - ranges_(0), abstract_origin_(NULL), inline_(false) { } + low_pc_(0), + high_pc_(0), + high_pc_form_(DW_FORM_addr), + ranges_form_(DW_FORM_sec_offset), + ranges_data_(0), + inline_(false), + handle_inline_(handle_inline) {} + void ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, uint64_t data); void ProcessAttributeSigned(enum DwarfAttribute attr, enum DwarfForm form, int64_t data); - void ProcessAttributeReference(enum DwarfAttribute attr, - enum DwarfForm form, - uint64_t data); - + DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag); bool EndAttributes(); void Finish(); private: // The fully-qualified name, as derived from name_attribute_, // specification_, parent_context_. Computed in EndAttributes. - string name_; + StringView name_; uint64_t low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address. - uint64_t ranges_; // DW_AT_ranges - const AbstractOrigin* abstract_origin_; + DwarfForm ranges_form_; // DW_FORM_sec_offset or DW_FORM_rnglistx + uint64_t ranges_data_; // DW_AT_ranges bool inline_; + vector<unique_ptr<Module::Inline>> child_inlines_; + bool handle_inline_; + DIEContext child_context_; // A context for our children. }; void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( @@ -504,17 +752,17 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( // If this attribute is present at all --- even if its value is // DW_INL_not_inlined --- then GCC may cite it as someone else's // DW_AT_abstract_origin attribute. - case dwarf2reader::DW_AT_inline: inline_ = true; break; + case DW_AT_inline: inline_ = true; break; - case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break; - case dwarf2reader::DW_AT_high_pc: + case DW_AT_low_pc: low_pc_ = data; break; + case DW_AT_high_pc: high_pc_form_ = form; high_pc_ = data; break; - case dwarf2reader::DW_AT_ranges: - ranges_ = data; + case DW_AT_ranges: + ranges_data_ = data; + ranges_form_ = form; break; - default: GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); break; @@ -529,34 +777,28 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeSigned( // If this attribute is present at all --- even if its value is // DW_INL_not_inlined --- then GCC may cite it as someone else's // DW_AT_abstract_origin attribute. - case dwarf2reader::DW_AT_inline: inline_ = true; break; + case DW_AT_inline: inline_ = true; break; default: break; } } -void DwarfCUToModule::FuncHandler::ProcessAttributeReference( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64_t data) { - switch (attr) { - case dwarf2reader::DW_AT_abstract_origin: { - const AbstractOriginByOffset& origins = - cu_context_->file_context->file_private_->origins; - AbstractOriginByOffset::const_iterator origin = origins.find(data); - if (origin != origins.end()) { - abstract_origin_ = &(origin->second); - } else if (data > offset_) { - forward_ref_die_offset_ = data; - } else { - cu_context_->reporter->UnknownAbstractOrigin(offset_, data); - } - break; - } +DIEHandler* DwarfCUToModule::FuncHandler::FindChildHandler( + uint64_t offset, + enum DwarfTag tag) { + switch (tag) { + case DW_TAG_inlined_subroutine: + if (handle_inline_) + return new InlineHandler(cu_context_, nullptr, offset, 0, + child_inlines_); + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + return new NamedScopeHandler(cu_context_, &child_context_, offset, + handle_inline_); default: - GenericDIEHandler::ProcessAttributeReference(attr, form, data); - break; + return NULL; } } @@ -566,19 +808,13 @@ bool DwarfCUToModule::FuncHandler::EndAttributes() { if (name_.empty() && abstract_origin_) { name_ = abstract_origin_->name; } + child_context_.name = name_; + if (name_.empty() && no_specification) { + cu_context_->reporter->UnknownSpecification(offset_, specification_offset_); + } return true; } -static bool IsEmptyRange(const vector<Module::Range>& ranges) { - uint64_t size = accumulate(ranges.cbegin(), ranges.cend(), 0, - [](uint64_t total, Module::Range entry) { - return total + entry.size; - } - ); - - return size == 0; -} - void DwarfCUToModule::FuncHandler::Finish() { vector<Module::Range> ranges; @@ -586,54 +822,56 @@ void DwarfCUToModule::FuncHandler::Finish() { // to be processed, and fix up the name of the appropriate Module::Function. // "name_" will have already been fixed up in EndAttributes(). if (!name_.empty()) { - auto iter = cu_context_->forward_ref_die_to_func.find(offset_); - if (iter != cu_context_->forward_ref_die_to_func.end()) + auto iter = + cu_context_->file_context->file_private_->forward_ref_die_to_func.find( + offset_); + if (iter != + cu_context_->file_context->file_private_->forward_ref_die_to_func.end()) iter->second->name = name_; } - if (!ranges_) { + if (!ranges_data_) { // Make high_pc_ an address, if it isn't already. - if (high_pc_form_ != dwarf2reader::DW_FORM_addr && - high_pc_form_ != dwarf2reader::DW_FORM_GNU_addr_index) { + if (high_pc_form_ != DW_FORM_addr && + high_pc_form_ != DW_FORM_GNU_addr_index && + high_pc_form_ != DW_FORM_addrx && + high_pc_form_ != DW_FORM_addrx1 && + high_pc_form_ != DW_FORM_addrx2 && + high_pc_form_ != DW_FORM_addrx3 && + high_pc_form_ != DW_FORM_addrx4) { high_pc_ += low_pc_; } Module::Range range(low_pc_, high_pc_ - low_pc_); ranges.push_back(range); } else { - RangesHandler *ranges_handler = cu_context_->ranges_handler; - + RangesHandler* ranges_handler = cu_context_->ranges_handler; if (ranges_handler) { - if (!ranges_handler->ReadRanges(ranges_, cu_context_->low_pc, &ranges)) { - ranges.clear(); - cu_context_->reporter->MalformedRangeList(ranges_); + RangeListReader::CURangesInfo cu_info; + if (cu_context_->AssembleRangeListInfo(&cu_info)) { + if (!ranges_handler->ReadRanges(ranges_form_, ranges_data_, + &cu_info, &ranges)) { + ranges.clear(); + cu_context_->reporter->MalformedRangeList(ranges_data_); + } + } else { + cu_context_->reporter->MissingRanges(); } - } else { - cu_context_->reporter->MissingRanges(); } } + StringView name_omitted = + cu_context_->file_context->module_->AddStringToPool("<name omitted>"); + bool empty_range = IsEmptyRange(ranges); // Did we collect the information we need? Not all DWARF function // entries are non-empty (for example, inlined functions that were never // used), but all the ones we're interested in cover a non-empty range of // bytes. - if (!IsEmptyRange(ranges)) { + if (!empty_range) { low_pc_ = ranges.front().address; - // Malformed DWARF may omit the name, but all Module::Functions must // have names. - string name; - if (!name_.empty()) { - name = name_; - } else { - // If we have a forward reference to a DW_AT_specification or - // DW_AT_abstract_origin, then don't warn, the name will be fixed up - // later - if (forward_ref_die_offset_ == 0) - cu_context_->reporter->UnnamedFunction(offset_); - name = "<name omitted>"; - } - + StringView name = name_.empty() ? name_omitted : name_; // Create a Module::Function based on the data we've gathered, and // add it to the functions_ list. scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_)); @@ -644,52 +882,55 @@ void DwarfCUToModule::FuncHandler::Finish() { // description is just empty debug data and should just be discarded. cu_context_->functions.push_back(func.release()); if (forward_ref_die_offset_ != 0) { - auto iter = - cu_context_->forward_ref_die_to_func.find(forward_ref_die_offset_); - if (iter == cu_context_->forward_ref_die_to_func.end()) { - cu_context_->reporter->UnknownSpecification(offset_, - forward_ref_die_offset_); - } else { - iter->second = cu_context_->functions.back(); - } + cu_context_->file_context->file_private_ + ->forward_ref_die_to_func[forward_ref_die_offset_] = + cu_context_->functions.back(); + + cu_context_->spec_function_offsets[cu_context_->functions.back()] = + forward_ref_die_offset_; } + + cu_context_->functions.back()->inlines.swap(child_inlines_); } } else if (inline_) { AbstractOrigin origin(name_); - cu_context_->file_context->file_private_->origins[offset_] = origin; + cu_context_->file_context->file_private_->origins.insert({offset_, origin}); } -} - -// A handler for DIEs that contain functions and contribute a -// component to their names: namespaces, classes, etc. -class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler { - public: - NamedScopeHandler(CUContext *cu_context, DIEContext *parent_context, - uint64_t offset) - : GenericDIEHandler(cu_context, parent_context, offset) { } - bool EndAttributes(); - DIEHandler *FindChildHandler(uint64_t offset, enum DwarfTag tag); - private: - DIEContext child_context_; // A context for our children. -}; + // Only keep track of DW_TAG_subprogram which have the attributes we are + // interested. + if (handle_inline_ && (!empty_range || inline_)) { + StringView name = name_.empty() ? name_omitted : name_; + uint64_t offset = + specification_offset_ != 0 ? specification_offset_ : offset_; + cu_context_->file_context->module_->inline_origin_map.SetReference(offset_, + offset); + cu_context_->file_context->module_->inline_origin_map + .GetOrCreateInlineOrigin(offset_, name); + } +} bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { child_context_.name = ComputeQualifiedName(); + if (child_context_.name.empty() && no_specification) { + cu_context_->reporter->UnknownSpecification(offset_, specification_offset_); + } return true; } -dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler( +DIEHandler* DwarfCUToModule::NamedScopeHandler::FindChildHandler( uint64_t offset, enum DwarfTag tag) { switch (tag) { - case dwarf2reader::DW_TAG_subprogram: - return new FuncHandler(cu_context_, &child_context_, offset); - case dwarf2reader::DW_TAG_namespace: - case dwarf2reader::DW_TAG_class_type: - case dwarf2reader::DW_TAG_structure_type: - case dwarf2reader::DW_TAG_union_type: - return new NamedScopeHandler(cu_context_, &child_context_, offset); + case DW_TAG_subprogram: + return new FuncHandler(cu_context_, &child_context_, offset, + handle_inline_); + case DW_TAG_namespace: + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + return new NamedScopeHandler(cu_context_, &child_context_, offset, + handle_inline_); default: return NULL; } @@ -721,7 +962,7 @@ void DwarfCUToModule::WarningReporter::UnknownAbstractOrigin(uint64_t offset, filename_.c_str(), offset, target); } -void DwarfCUToModule::WarningReporter::MissingSection(const string &name) { +void DwarfCUToModule::WarningReporter::MissingSection(const string& name) { CUHeading(); fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n", filename_.c_str(), name.c_str()); @@ -744,16 +985,16 @@ void DwarfCUToModule::WarningReporter::UncoveredHeading() { } void DwarfCUToModule::WarningReporter::UncoveredFunction( - const Module::Function &function) { + const Module::Function& function) { if (!uncovered_warnings_enabled_) return; UncoveredHeading(); fprintf(stderr, " function%s: %s\n", IsEmptyRange(function.ranges) ? " (zero-length)" : "", - function.name.c_str()); + function.name.str().c_str()); } -void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) { +void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line& line) { if (!uncovered_warnings_enabled_) return; UncoveredHeading(); @@ -768,7 +1009,7 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64_t offset) { filename_.c_str(), offset); } -void DwarfCUToModule::WarningReporter::DemangleError(const string &input) { +void DwarfCUToModule::WarningReporter::DemangleError(const string& input) { CUHeading(); fprintf(stderr, "%s: warning: failed to demangle %s\n", filename_.c_str(), input.c_str()); @@ -796,15 +1037,16 @@ void DwarfCUToModule::WarningReporter::MissingRanges() { "the .debug_ranges section is missing.\n", filename_.c_str()); } -DwarfCUToModule::DwarfCUToModule(FileContext *file_context, - LineToModuleHandler *line_reader, - RangesHandler *ranges_handler, - WarningReporter *reporter) - : line_reader_(line_reader), +DwarfCUToModule::DwarfCUToModule(FileContext* file_context, + LineToModuleHandler* line_reader, + RangesHandler* ranges_handler, + WarningReporter* reporter, + bool handle_inline) + : RootDIEHandler(handle_inline), + line_reader_(line_reader), cu_context_(new CUContext(file_context, reporter, ranges_handler)), child_context_(new DIEContext()), - has_source_line_info_(false) { -} + has_source_line_info_(false) {} DwarfCUToModule::~DwarfCUToModule() { } @@ -813,7 +1055,7 @@ void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr, enum DwarfForm form, int64_t data) { switch (attr) { - case dwarf2reader::DW_AT_language: // source language of this CU + case DW_AT_language: // source language of this CU SetLanguage(static_cast<DwarfLanguage>(data)); break; default: @@ -825,23 +1067,33 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, uint64_t data) { switch (attr) { - case dwarf2reader::DW_AT_stmt_list: // Line number information. + case DW_AT_stmt_list: // Line number information. has_source_line_info_ = true; source_line_offset_ = data; break; - case dwarf2reader::DW_AT_language: // source language of this CU + case DW_AT_language: // source language of this CU SetLanguage(static_cast<DwarfLanguage>(data)); break; - case dwarf2reader::DW_AT_low_pc: + case DW_AT_low_pc: cu_context_->low_pc = data; break; - case dwarf2reader::DW_AT_high_pc: + case DW_AT_high_pc: cu_context_->high_pc = data; break; - case dwarf2reader::DW_AT_ranges: - cu_context_->ranges = data; + case DW_AT_ranges: + cu_context_->ranges_data = data; + cu_context_->ranges_form = form; + break; + case DW_AT_rnglists_base: + cu_context_->ranges_base = data; + break; + case DW_AT_addr_base: + case DW_AT_GNU_addr_base: + cu_context_->addr_base = data; + break; + case DW_AT_str_offsets_base: + cu_context_->str_offsets_base = data; break; - default: break; } @@ -849,12 +1101,12 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr, enum DwarfForm form, - const string &data) { + const string& data) { switch (attr) { - case dwarf2reader::DW_AT_name: + case DW_AT_name: cu_context_->reporter->SetCUName(data); break; - case dwarf2reader::DW_AT_comp_dir: + case DW_AT_comp_dir: line_reader_->StartCompilationUnit(data); break; default: @@ -866,19 +1118,20 @@ bool DwarfCUToModule::EndAttributes() { return true; } -dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler( +DIEHandler* DwarfCUToModule::FindChildHandler( uint64_t offset, enum DwarfTag tag) { switch (tag) { - case dwarf2reader::DW_TAG_subprogram: - return new FuncHandler(cu_context_.get(), child_context_.get(), offset); - case dwarf2reader::DW_TAG_namespace: - case dwarf2reader::DW_TAG_class_type: - case dwarf2reader::DW_TAG_structure_type: - case dwarf2reader::DW_TAG_union_type: - case dwarf2reader::DW_TAG_module: + case DW_TAG_subprogram: + return new FuncHandler(cu_context_.get(), child_context_.get(), offset, + handle_inline); + case DW_TAG_namespace: + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_module: return new NamedScopeHandler(cu_context_.get(), child_context_.get(), - offset); + offset, handle_inline); default: return NULL; } @@ -886,21 +1139,21 @@ dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler( void DwarfCUToModule::SetLanguage(DwarfLanguage language) { switch (language) { - case dwarf2reader::DW_LANG_Java: + case DW_LANG_Java: cu_context_->language = Language::Java; break; - case dwarf2reader::DW_LANG_Swift: + case DW_LANG_Swift: cu_context_->language = Language::Swift; break; - case dwarf2reader::DW_LANG_Rust: + case DW_LANG_Rust: cu_context_->language = Language::Rust; break; // DWARF has no generic language code for assembly language; this is // what the GNU toolchain uses. - case dwarf2reader::DW_LANG_Mips_Assembler: + case DW_LANG_Mips_Assembler: cu_context_->language = Language::Assembler; break; @@ -916,67 +1169,83 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) { // nested in struct types, but if it ever does, then C++'s // notation is probably not a bad choice for that. default: - case dwarf2reader::DW_LANG_ObjC: - case dwarf2reader::DW_LANG_ObjC_plus_plus: - case dwarf2reader::DW_LANG_C: - case dwarf2reader::DW_LANG_C89: - case dwarf2reader::DW_LANG_C99: - case dwarf2reader::DW_LANG_C_plus_plus: + case DW_LANG_ObjC: + case DW_LANG_ObjC_plus_plus: + case DW_LANG_C: + case DW_LANG_C89: + case DW_LANG_C99: + case DW_LANG_C_plus_plus: cu_context_->language = Language::CPlusPlus; break; } } void DwarfCUToModule::ReadSourceLines(uint64_t offset) { - const dwarf2reader::SectionMap §ion_map + const SectionMap& section_map = cu_context_->file_context->section_map(); - dwarf2reader::SectionMap::const_iterator map_entry - = section_map.find(".debug_line"); - // Mac OS X puts DWARF data in sections whose names begin with "__" - // instead of ".". - if (map_entry == section_map.end()) - map_entry = section_map.find("__debug_line"); + SectionMap::const_iterator map_entry + = GetSectionByName(section_map, ".debug_line"); if (map_entry == section_map.end()) { cu_context_->reporter->MissingSection(".debug_line"); return; } - const uint8_t *section_start = map_entry->second.first; - uint64_t section_length = map_entry->second.second; - if (offset >= section_length) { + const uint8_t* line_section_start = map_entry->second.first + offset; + uint64_t line_section_length = map_entry->second.second; + if (offset >= line_section_length) { cu_context_->reporter->BadLineInfoOffset(offset); return; } - line_reader_->ReadProgram(section_start + offset, section_length - offset, - cu_context_->file_context->module_, &lines_); + line_section_length -= offset; + // When reading line tables, string sections are never needed for dwarf4, and + // may or may not be needed by dwarf5, so no error if they are missing. + const uint8_t* string_section_start = nullptr; + uint64_t string_section_length = 0; + map_entry = GetSectionByName(section_map, ".debug_str"); + if (map_entry != section_map.end()) { + string_section_start = map_entry->second.first; + string_section_length = map_entry->second.second; + } + const uint8_t* line_string_section_start = nullptr; + uint64_t line_string_section_length = 0; + map_entry = GetSectionByName(section_map, ".debug_line_str"); + if (map_entry != section_map.end()) { + line_string_section_start = map_entry->second.first; + line_string_section_length = map_entry->second.second; + } + line_reader_->ReadProgram( + line_section_start, line_section_length, + string_section_start, string_section_length, + line_string_section_start, line_string_section_length, + cu_context_->file_context->module_, &lines_, &files_); } namespace { class FunctionRange { public: - FunctionRange(const Module::Range &range, Module::Function *function) : + FunctionRange(const Module::Range& range, Module::Function* function) : address(range.address), size(range.size), function(function) { } - void AddLine(Module::Line &line) { + void AddLine(Module::Line& line) { function->lines.push_back(line); } Module::Address address; Module::Address size; - Module::Function *function; + Module::Function* function; }; // Fills an array of ranges with pointers to the functions which owns // them. The array is sorted in ascending order and the ranges are non // empty and non-overlapping. -static void FillSortedFunctionRanges(vector<FunctionRange> &dest_ranges, - vector<Module::Function *> *functions) { - for (vector<Module::Function *>::const_iterator func_it = functions->cbegin(); +static void FillSortedFunctionRanges(vector<FunctionRange>& dest_ranges, + vector<Module::Function*>* functions) { + for (vector<Module::Function*>::const_iterator func_it = functions->cbegin(); func_it != functions->cend(); func_it++) { - Module::Function *func = *func_it; - vector<Module::Range> &ranges = func->ranges; + Module::Function* func = *func_it; + vector<Module::Range>& ranges = func->ranges; for (vector<Module::Range>::const_iterator ranges_it = ranges.cbegin(); ranges_it != ranges.cend(); ++ranges_it) { @@ -988,7 +1257,7 @@ static void FillSortedFunctionRanges(vector<FunctionRange> &dest_ranges, } sort(dest_ranges.begin(), dest_ranges.end(), - [](const FunctionRange &fr1, const FunctionRange &fr2) { + [](const FunctionRange& fr1, const FunctionRange& fr2) { return fr1.address < fr2.address; } ); @@ -996,7 +1265,7 @@ static void FillSortedFunctionRanges(vector<FunctionRange> &dest_ranges, // Return true if ADDRESS falls within the range of ITEM. template <class T> -inline bool within(const T &item, Module::Address address) { +inline bool within(const T& item, Module::Address address) { // Because Module::Address is unsigned, and unsigned arithmetic // wraps around, this will be false if ADDRESS falls before the // start of ITEM, or if it falls after ITEM's end. @@ -1005,8 +1274,8 @@ inline bool within(const T &item, Module::Address address) { } void DwarfCUToModule::AssignLinesToFunctions() { - vector<Module::Function *> *functions = &cu_context_->functions; - WarningReporter *reporter = cu_context_->reporter; + vector<Module::Function*>* functions = &cu_context_->functions; + WarningReporter* reporter = cu_context_->reporter; // This would be simpler if we assumed that source line entries // don't cross function boundaries. However, there's no real reason @@ -1026,12 +1295,12 @@ void DwarfCUToModule::AssignLinesToFunctions() { // The last line that we used any piece of. We use this only for // generating warnings. - const Module::Line *last_line_used = NULL; + const Module::Line* last_line_used = NULL; // The last function and line we warned about --- so we can avoid // doing so more than once. - const Module::Function *last_function_cited = NULL; - const Module::Line *last_line_cited = NULL; + const Module::Function* last_function_cited = NULL; + const Module::Line* last_line_cited = NULL; // Prepare a sorted list of ranges with range-to-function mapping vector<FunctionRange> sorted_ranges; @@ -1047,8 +1316,8 @@ void DwarfCUToModule::AssignLinesToFunctions() { // Pointers to the referents of func_it and line_it, or NULL if the // iterator is at the end of the sequence. - FunctionRange *range; - const Module::Line *line; + FunctionRange* range; + const Module::Line* line; // Start current at the beginning of the first line or function, // whichever is earlier. @@ -1068,6 +1337,11 @@ void DwarfCUToModule::AssignLinesToFunctions() { return; } + // Some dwarf producers handle linker-removed functions by using -1 as a + // tombstone in the line table. So the end marker can be -1. + if (current == Module::kMaxAddress) + return; + while (range || line) { // This loop has two invariants that hold at the top. // @@ -1174,7 +1448,10 @@ void DwarfCUToModule::AssignLinesToFunctions() { // next_transition may end up being zero, in which case we've completed // our pass. Handle that here, instead of trying to deal with it in // each place we compute next_transition. - if (!next_transition) + + // Some dwarf producers handle linker-removed functions by using -1 as a + // tombstone in the line table. So the end marker can be -1. + if (!next_transition || next_transition == Module::kMaxAddress) break; // Advance iterators as needed. If lines overlap or functions overlap, @@ -1198,6 +1475,16 @@ void DwarfCUToModule::AssignLinesToFunctions() { } } +void DwarfCUToModule::AssignFilesToInlines() { + // Assign File* to Inlines inside this CU. + auto assignFile = [this](unique_ptr<Module::Inline>& in) { + in->call_site_file = files_[in->call_site_file_id]; + }; + for (auto func : cu_context_->functions) { + Module::Inline::InlineDFS(func->inlines, assignFile); + } +} + void DwarfCUToModule::Finish() { // Assembly language files have no function data, and that gives us // no place to store our line numbers (even though the GNU toolchain @@ -1211,15 +1498,23 @@ void DwarfCUToModule::Finish() { if (has_source_line_info_) ReadSourceLines(source_line_offset_); - vector<Module::Function *> *functions = &cu_context_->functions; + vector<Module::Function*>* functions = &cu_context_->functions; // Dole out lines to the appropriate functions. AssignLinesToFunctions(); + AssignFilesToInlines(); + // Add our functions, which now have source lines assigned to them, - // to module_. - cu_context_->file_context->module_->AddFunctions(functions->begin(), - functions->end()); + // to module_, and remove duplicate functions. + for (Module::Function* func : *functions) + if (!cu_context_->file_context->module_->AddFunction(func)) { + auto iter = cu_context_->spec_function_offsets.find(func); + if (iter != cu_context_->spec_function_offsets.end()) + cu_context_->file_context->file_private_->forward_ref_die_to_func.erase( + iter->second); + delete func; + } // Ownership of the function objects has shifted from cu_context to // the Module. @@ -1233,13 +1528,15 @@ bool DwarfCUToModule::StartCompilationUnit(uint64_t offset, uint8_t offset_size, uint64_t cu_length, uint8_t dwarf_version) { + cu_context_->version = dwarf_version; return dwarf_version >= 2; } bool DwarfCUToModule::StartRootDIE(uint64_t offset, enum DwarfTag tag) { // We don't deal with partial compilation units (the only other tag // likely to be used for root DIE). - return tag == dwarf2reader::DW_TAG_compile_unit; + return (tag == DW_TAG_compile_unit + || tag == DW_TAG_skeleton_unit); } } // namespace google_breakpad diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h index 2153bd96..5a800104 100644 --- a/src/common/dwarf_cu_to_module.h +++ b/src/common/dwarf_cu_to_module.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,10 +41,10 @@ #include <stdint.h> #include <string> +#include <vector> #include "common/language.h" #include "common/module.h" -#include "common/dwarf/bytereader.h" #include "common/dwarf/dwarf2diehandler.h" #include "common/dwarf/dwarf2reader.h" #include "common/scoped_ptr.h" @@ -53,19 +52,14 @@ namespace google_breakpad { -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfLanguage; -using dwarf2reader::DwarfTag; - // Populate a google_breakpad::Module with DWARF debugging information. // // An instance of this class can be provided as a handler to a -// dwarf2reader::DIEDispatcher, which can in turn be a handler for a -// dwarf2reader::CompilationUnit DWARF parser. The handler uses the results +// DIEDispatcher, which can in turn be a handler for a +// CompilationUnit DWARF parser. The handler uses the results // of parsing to populate a google_breakpad::Module with source file, // function, and source line information. -class DwarfCUToModule: public dwarf2reader::RootDIEHandler { +class DwarfCUToModule: public RootDIEHandler { struct FilePrivate; public: // Information global to the DWARF-bearing file we are processing, @@ -79,20 +73,24 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // to true to handle debugging symbols with DW_FORM_ref_addr entries. class FileContext { public: - FileContext(const string &filename, - Module *module, + FileContext(const string& filename, + Module* module, bool handle_inter_cu_refs); ~FileContext(); // Add CONTENTS of size LENGTH to the section map as NAME. void AddSectionToSectionMap(const string& name, - const uint8_t *contents, + const uint8_t* contents, + uint64_t length); + + void AddManagedSectionToSectionMap(const string& name, + uint8_t* contents, uint64_t length); // Clear the section map for testing. void ClearSectionMapForTest(); - const dwarf2reader::SectionMap& section_map() const; + const SectionMap& section_map() const; private: friend class DwarfCUToModule; @@ -111,16 +109,17 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // A map of this file's sections, used for finding other DWARF // sections that the .debug_info section may refer to. - dwarf2reader::SectionMap section_map_; + SectionMap section_map_; // The Module to which we're contributing definitions. - Module *module_; + Module* module_; // True if we are handling references between compilation units. const bool handle_inter_cu_refs_; // Inter-compilation unit data used internally by the handlers. scoped_ptr<FilePrivate> file_private_; + std::vector<uint8_t *> uncompressed_sections_; }; // An abstract base class for handlers that handle DWARF range lists for @@ -131,17 +130,16 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { virtual ~RangesHandler() { } // Called when finishing a function to populate the function's ranges. - // The ranges' entries are read starting from offset in the .debug_ranges - // section, base_address holds the base PC the range list values are - // offsets off. Return false if the rangelist falls out of the - // .debug_ranges section. - virtual bool ReadRanges(uint64_t offset, Module::Address base_address, - vector<Module::Range>* ranges) = 0; + // The entries are read according to the form and data. + virtual bool ReadRanges( + enum DwarfForm form, uint64_t data, + RangeListReader::CURangesInfo* cu_info, + vector<Module::Range>* ranges) = 0; }; // An abstract base class for handlers that handle DWARF line data // for DwarfCUToModule. DwarfCUToModule could certainly just use - // dwarf2reader::LineInfo itself directly, but decoupling things + // LineInfo itself directly, but decoupling things // this way makes unit testing a little easier. class LineToModuleHandler { public: @@ -158,8 +156,13 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // mappings, given a pointer to some DWARF line number data // PROGRAM, and an overestimate of its size. Add no zero-length // lines to LINES. - virtual void ReadProgram(const uint8_t *program, uint64_t length, - Module *module, vector<Module::Line> *lines) = 0; + virtual void ReadProgram(const uint8_t* program, uint64_t length, + const uint8_t* string_section, + uint64_t string_section_length, + const uint8_t* line_string_section, + uint64_t line_string_length, + Module* module, vector<Module::Line>* lines, + map<uint32_t, Module::File*>* files) = 0; }; // The interface DwarfCUToModule uses to report warnings. The member @@ -170,14 +173,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { public: // Warn about problems in the DWARF file FILENAME, in the // compilation unit at OFFSET. - WarningReporter(const string &filename, uint64_t cu_offset) + WarningReporter(const string& filename, uint64_t cu_offset) : filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false), printed_unpaired_header_(false), uncovered_warnings_enabled_(false) { } virtual ~WarningReporter() { } // Set the name of the compilation unit we're processing to NAME. - virtual void SetCUName(const string &name) { cu_name_ = name; } + virtual void SetCUName(const string& name) { cu_name_ = name; } // Accessor and setter for uncovered_warnings_enabled_. // UncoveredFunction and UncoveredLine only report a problem if that is @@ -200,17 +203,17 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { virtual void UnknownAbstractOrigin(uint64_t offset, uint64_t target); // We were unable to find the DWARF section named SECTION_NAME. - virtual void MissingSection(const string §ion_name); + virtual void MissingSection(const string& section_name); // The CU's DW_AT_stmt_list offset OFFSET is bogus. virtual void BadLineInfoOffset(uint64_t offset); // FUNCTION includes code covered by no line number data. - virtual void UncoveredFunction(const Module::Function &function); + virtual void UncoveredFunction(const Module::Function& function); // Line number NUMBER in LINE_FILE, of length LENGTH, includes code // covered by no function. - virtual void UncoveredLine(const Module::Line &line); + virtual void UncoveredLine(const Module::Line& line); // The DW_TAG_subprogram DIE at OFFSET has no name specified directly // in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin @@ -218,7 +221,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { virtual void UnnamedFunction(uint64_t offset); // __cxa_demangle() failed to demangle INPUT. - virtual void DemangleError(const string &input); + virtual void DemangleError(const string& input); // The DW_FORM_ref_addr at OFFSET to TARGET was not handled because // FilePrivate did not retain the inter-CU specification data. @@ -253,14 +256,15 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // Create a DWARF debugging info handler for a compilation unit // within FILE_CONTEXT. This uses information received from the - // dwarf2reader::CompilationUnit DWARF parser to populate + // CompilationUnit DWARF parser to populate // FILE_CONTEXT->module. Use LINE_READER to handle the compilation // unit's line number data. Use REPORTER to report problems with the // data we find. - DwarfCUToModule(FileContext *file_context, - LineToModuleHandler *line_reader, - RangesHandler *ranges_handler, - WarningReporter *reporter); + DwarfCUToModule(FileContext* file_context, + LineToModuleHandler* line_reader, + RangesHandler* ranges_handler, + WarningReporter* reporter, + bool handle_inline = false); ~DwarfCUToModule(); void ProcessAttributeSigned(enum DwarfAttribute attr, @@ -271,9 +275,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { uint64_t data); void ProcessAttributeString(enum DwarfAttribute attr, enum DwarfForm form, - const string &data); + const string& data); bool EndAttributes(); - DIEHandler *FindChildHandler(uint64_t offset, enum DwarfTag tag); + DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag); // Assign all our source Lines to the Functions that cover their // addresses, and then add them to module_. @@ -292,6 +296,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { struct Specification; class GenericDIEHandler; class FuncHandler; + class InlineHandler; class NamedScopeHandler; // A map from section offsets to specifications. @@ -312,6 +317,8 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // lines belong to which functions, beyond their addresses.) void AssignLinesToFunctions(); + void AssignFilesToInlines(); + // The only reason cu_context_ and child_context_ are pointers is // that we want to keep their definitions private to // dwarf_cu_to_module.cc, instead of listing them all here. They are @@ -319,7 +326,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // destructor deletes them. // The handler to use to handle line number data. - LineToModuleHandler *line_reader_; + LineToModuleHandler* line_reader_; // This compilation unit's context. scoped_ptr<CUContext> cu_context_; @@ -338,6 +345,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // during parsing. Then, in Finish, we call AssignLinesToFunctions // to dole them out to the appropriate functions. vector<Module::Line> lines_; + + // The map from file index to File* in this CU. + std::map<uint32_t, Module::File*> files_; }; } // namespace google_breakpad diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc index ed1d7c9b..f3fa4903 100644 --- a/src/common/dwarf_cu_to_module_unittest.cc +++ b/src/common/dwarf_cu_to_module_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,17 +43,17 @@ using std::make_pair; using std::vector; -using dwarf2reader::DIEHandler; -using dwarf2reader::DwarfTag; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfInline; -using dwarf2reader::RootDIEHandler; +using google_breakpad::DIEHandler; +using google_breakpad::DwarfTag; +using google_breakpad::DwarfAttribute; +using google_breakpad::DwarfForm; +using google_breakpad::DwarfInline; using google_breakpad::DwarfCUToModule; using google_breakpad::Module; using ::testing::_; using ::testing::AtMost; +using ::testing::DoAll; using ::testing::Invoke; using ::testing::Return; using ::testing::Test; @@ -67,23 +66,28 @@ using ::testing::ValuesIn; class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler { public: MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir)); - MOCK_METHOD4(ReadProgram, void(const uint8_t *program, uint64_t length, - Module *module, vector<Module::Line> *lines)); + MOCK_METHOD9(ReadProgram, void(const uint8_t* program, uint64_t length, + const uint8_t* string_section, + uint64_t string_section_length, + const uint8_t* line_string_section, + uint64_t line_string_section_length, + Module* module, vector<Module::Line>* lines, + std::map<uint32_t, Module::File*>* files)); }; class MockWarningReporter: public DwarfCUToModule::WarningReporter { public: - MockWarningReporter(const string &filename, uint64_t cu_offset) + MockWarningReporter(const string& filename, uint64_t cu_offset) : DwarfCUToModule::WarningReporter(filename, cu_offset) { } - MOCK_METHOD1(SetCUName, void(const string &name)); + MOCK_METHOD1(SetCUName, void(const string& name)); MOCK_METHOD2(UnknownSpecification, void(uint64_t offset, uint64_t target)); MOCK_METHOD2(UnknownAbstractOrigin, void(uint64_t offset, uint64_t target)); - MOCK_METHOD1(MissingSection, void(const string §ion_name)); + MOCK_METHOD1(MissingSection, void(const string& section_name)); MOCK_METHOD1(BadLineInfoOffset, void(uint64_t offset)); - MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function)); - MOCK_METHOD1(UncoveredLine, void(const Module::Line &line)); + MOCK_METHOD1(UncoveredFunction, void(const Module::Function& function)); + MOCK_METHOD1(UncoveredLine, void(const Module::Line& line)); MOCK_METHOD1(UnnamedFunction, void(uint64_t offset)); - MOCK_METHOD1(DemangleError, void(const string &input)); + MOCK_METHOD1(DemangleError, void(const string& input)); MOCK_METHOD2(UnhandledInterCUReference, void(uint64_t offset, uint64_t target)); }; @@ -112,19 +116,24 @@ class CUFixtureBase { class AppendLinesFunctor { public: explicit AppendLinesFunctor( - const vector<Module::Line> *lines) : lines_(lines) { } - void operator()(const uint8_t *program, uint64_t length, - Module *module, vector<Module::Line> *lines) { + const vector<Module::Line>* lines) : lines_(lines) { } + void operator()(const uint8_t* program, uint64_t length, + const uint8_t* string_section, + uint64_t string_section_length, + const uint8_t* line_string_section, + uint64_t line_string_section_length, + Module *module, vector<Module::Line>* lines, + std::map<uint32_t, Module::File*>* files) { lines->insert(lines->end(), lines_->begin(), lines_->end()); } private: - const vector<Module::Line> *lines_; + const vector<Module::Line>* lines_; }; CUFixtureBase() : module_("module-name", "module-os", "module-arch", "module-id"), file_context_("dwarf-filename", &module_, true), - language_(dwarf2reader::DW_LANG_none), + language_(google_breakpad::DW_LANG_none), language_signed_(false), appender_(&lines_), reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL), @@ -147,7 +156,7 @@ class CUFixtureBase { // By default, expect the line program reader not to be invoked. We // may override this in StartCU. EXPECT_CALL(line_reader_, StartCompilationUnit(_)).Times(0); - EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_)).Times(0); + EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_,_,_,_,_,_)).Times(0); // The handler will consult this section map to decide what to // pass to our line reader. @@ -161,12 +170,12 @@ class CUFixtureBase { // when it invokes its LineToModuleHandler. Call this before calling // StartCU. void PushLine(Module::Address address, Module::Address size, - const string &filename, int line_number); + const string& filename, int line_number); // Use LANGUAGE for the compilation unit. More precisely, arrange // for StartCU to pass the compilation unit's root DIE a // DW_AT_language attribute whose value is LANGUAGE. - void SetLanguage(dwarf2reader::DwarfLanguage language) { + void SetLanguage(google_breakpad::DwarfLanguage language) { language_ = language; } @@ -182,61 +191,61 @@ class CUFixtureBase { void StartCU(); // Have HANDLER process some strange attribute/form/value triples. - void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler); + void ProcessStrangeAttributes(google_breakpad::DIEHandler* handler); // Start a child DIE of PARENT with the given tag and name. Leave // the handler ready to hear about children: call EndAttributes, but // not Finish. - DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag, - const string &name); + DIEHandler* StartNamedDIE(DIEHandler* parent, DwarfTag tag, + const string& name); // Start a child DIE of PARENT with the given tag and a // DW_AT_specification attribute whose value is SPECIFICATION. Leave // the handler ready to hear about children: call EndAttributes, but // not Finish. If NAME is non-zero, use it as the DW_AT_name // attribute. - DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag, - uint64_t specification, const char *name = NULL); + DIEHandler* StartSpecifiedDIE(DIEHandler* parent, DwarfTag tag, + uint64_t specification, const char* name = NULL); // Define a function as a child of PARENT with the given name, address, and // size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute // will be written as an address; otherwise it will be written as the // function's size. Call EndAttributes and Finish; one cannot define // children of the defined function's DIE. - void DefineFunction(DIEHandler *parent, const string &name, + void DefineFunction(DIEHandler* parent, const string& name, Module::Address address, Module::Address size, const char* mangled_name, - DwarfForm high_pc_form = dwarf2reader::DW_FORM_addr); + DwarfForm high_pc_form = google_breakpad::DW_FORM_addr); // Create a declaration DIE as a child of PARENT with the given // offset, tag and name. If NAME is the empty string, don't provide // a DW_AT_name attribute. Call EndAttributes and Finish. - void DeclarationDIE(DIEHandler *parent, uint64_t offset, - DwarfTag tag, const string &name, - const string &mangled_name); + void DeclarationDIE(DIEHandler* parent, uint64_t offset, + DwarfTag tag, const string& name, + const string& mangled_name); // Create a definition DIE as a child of PARENT with the given tag // that refers to the declaration DIE at offset SPECIFICATION as its // specification. If NAME is non-empty, pass it as the DW_AT_name // attribute. If SIZE is non-zero, record ADDRESS and SIZE as // low_pc/high_pc attributes. - void DefinitionDIE(DIEHandler *parent, DwarfTag tag, - uint64_t specification, const string &name, + void DefinitionDIE(DIEHandler* parent, DwarfTag tag, + uint64_t specification, const string& name, Module::Address address = 0, Module::Address size = 0); // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at // offset SPECIFICATION as its specification. If Name is non-empty, pass it // as the DW_AT_name attribute. - void AbstractInstanceDIE(DIEHandler *parent, uint64_t offset, + void AbstractInstanceDIE(DIEHandler* parent, uint64_t offset, DwarfInline type, uint64_t specification, - const string &name, - DwarfForm form = dwarf2reader::DW_FORM_data1); + const string& name, + DwarfForm form = google_breakpad::DW_FORM_data1); // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty // string, don't provide a DW_AT_name attribute. - void DefineInlineInstanceDIE(DIEHandler *parent, const string &name, + void DefineInlineInstanceDIE(DIEHandler* parent, const string& name, uint64_t origin, Module::Address address, Module::Address size); @@ -251,7 +260,7 @@ class CUFixtureBase { // Test that the I'th function (ordered by address) in the module // this.module_ has the given name, address, and size, and that its // parameter size is zero. - void TestFunction(int i, const string &name, + void TestFunction(int i, const string& name, Module::Address address, Module::Address size); // Test that the number of source lines owned by the I'th function @@ -262,7 +271,7 @@ class CUFixtureBase { // (again, by address) has the given address, size, filename, and // line number. void TestLine(int i, int j, Module::Address address, Module::Address size, - const string &filename, int number); + const string& filename, int number); // Actual objects under test. Module module_; @@ -270,7 +279,7 @@ class CUFixtureBase { // If this is not DW_LANG_none, we'll pass it as a DW_AT_language // attribute to the compilation unit. This defaults to DW_LANG_none. - dwarf2reader::DwarfLanguage language_; + google_breakpad::DwarfLanguage language_; // If this is true, report DW_AT_language as a signed value; if false, // report it as an unsigned value. @@ -300,7 +309,7 @@ class CUFixtureBase { // If functions_filled_ is true, this is a table of functions we've // extracted from module_, sorted by address. - vector<Module::Function *> functions_; + vector<Module::Function*> functions_; // True if we have filled the above vector with this.module_'s function list. bool functions_filled_; }; @@ -310,7 +319,7 @@ const size_t CUFixtureBase::dummy_line_size_ = sizeof(CUFixtureBase::dummy_line_program_); void CUFixtureBase::PushLine(Module::Address address, Module::Address size, - const string &filename, int line_number) { + const string& filename, int line_number) { Module::Line l; l.address = address; l.size = size; @@ -332,43 +341,43 @@ void CUFixtureBase::StartCU() { if (!lines_.empty()) EXPECT_CALL(line_reader_, ReadProgram(&dummy_line_program_[0], dummy_line_size_, - &module_, _)) + _,_,_,_, + &module_, _,_)) .Times(AtMost(1)) .WillOnce(DoAll(Invoke(appender_), Return())); - ASSERT_TRUE(root_handler_ .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44, 0x4241b4f33720dd5cULL, 3)); { ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, - dwarf2reader::DW_TAG_compile_unit)); + google_breakpad::DW_TAG_compile_unit)); } - root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + root_handler_.ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, "compilation-unit-name"); if (!compilation_dir_.empty()) - root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_comp_dir, - dwarf2reader::DW_FORM_strp, + root_handler_.ProcessAttributeString(google_breakpad::DW_AT_comp_dir, + google_breakpad::DW_FORM_strp, compilation_dir_); if (!lines_.empty()) - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, - dwarf2reader::DW_FORM_ref4, + root_handler_.ProcessAttributeUnsigned(google_breakpad::DW_AT_stmt_list, + google_breakpad::DW_FORM_ref4, 0); - if (language_ != dwarf2reader::DW_LANG_none) { + if (language_ != google_breakpad::DW_LANG_none) { if (language_signed_) - root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language, - dwarf2reader::DW_FORM_sdata, + root_handler_.ProcessAttributeSigned(google_breakpad::DW_AT_language, + google_breakpad::DW_FORM_sdata, language_); else - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language, - dwarf2reader::DW_FORM_udata, + root_handler_.ProcessAttributeUnsigned(google_breakpad::DW_AT_language, + google_breakpad::DW_FORM_udata, language_); } ASSERT_TRUE(root_handler_.EndAttributes()); } void CUFixtureBase::ProcessStrangeAttributes( - dwarf2reader::DIEHandler *handler) { + google_breakpad::DIEHandler* handler) { handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead, (DwarfForm) 0x4106e4db, 0xa592571997facda1ULL); @@ -387,15 +396,15 @@ void CUFixtureBase::ProcessStrangeAttributes( "strange string"); } -DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent, +DIEHandler* CUFixtureBase::StartNamedDIE(DIEHandler* parent, DwarfTag tag, - const string &name) { - dwarf2reader::DIEHandler *handler + const string& name) { + google_breakpad::DIEHandler* handler = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); if (!handler) return NULL; - handler->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + handler->ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, name); ProcessStrangeAttributes(handler); if (!handler->EndAttributes()) { @@ -407,20 +416,20 @@ DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent, return handler; } -DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, +DIEHandler* CUFixtureBase::StartSpecifiedDIE(DIEHandler* parent, DwarfTag tag, uint64_t specification, - const char *name) { - dwarf2reader::DIEHandler *handler + const char* name) { + google_breakpad::DIEHandler* handler = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); if (!handler) return NULL; if (name) - handler->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + handler->ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, name); - handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, + handler->ProcessAttributeReference(google_breakpad::DW_AT_specification, + google_breakpad::DW_FORM_ref4, specification); if (!handler->EndAttributes()) { handler->Finish(); @@ -431,33 +440,33 @@ DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, return handler; } -void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, - const string &name, Module::Address address, +void CUFixtureBase::DefineFunction(google_breakpad::DIEHandler* parent, + const string& name, Module::Address address, Module::Address size, const char* mangled_name, DwarfForm high_pc_form) { - dwarf2reader::DIEHandler *func + google_breakpad::DIEHandler* func = parent->FindChildHandler(0xe34797c7e68590a8LL, - dwarf2reader::DW_TAG_subprogram); + google_breakpad::DW_TAG_subprogram); ASSERT_TRUE(func != NULL); - func->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + func->ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, name); - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, + func->ProcessAttributeUnsigned(google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, address); Module::Address high_pc = size; - if (high_pc_form == dwarf2reader::DW_FORM_addr) { + if (high_pc_form == google_breakpad::DW_FORM_addr) { high_pc += address; } - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, + func->ProcessAttributeUnsigned(google_breakpad::DW_AT_high_pc, high_pc_form, high_pc); if (mangled_name) - func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, - dwarf2reader::DW_FORM_strp, + func->ProcessAttributeString(google_breakpad::DW_AT_MIPS_linkage_name, + google_breakpad::DW_FORM_strp, mangled_name); ProcessStrangeAttributes(func); @@ -466,51 +475,51 @@ void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, delete func; } -void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64_t offset, +void CUFixtureBase::DeclarationDIE(DIEHandler* parent, uint64_t offset, DwarfTag tag, - const string &name, - const string &mangled_name) { - dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag); + const string& name, + const string& mangled_name) { + google_breakpad::DIEHandler* die = parent->FindChildHandler(offset, tag); ASSERT_TRUE(die != NULL); if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + die->ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, name); if (!mangled_name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, - dwarf2reader::DW_FORM_strp, + die->ProcessAttributeString(google_breakpad::DW_AT_MIPS_linkage_name, + google_breakpad::DW_FORM_strp, mangled_name); - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration, - dwarf2reader::DW_FORM_flag, + die->ProcessAttributeUnsigned(google_breakpad::DW_AT_declaration, + google_breakpad::DW_FORM_flag, 1); EXPECT_TRUE(die->EndAttributes()); die->Finish(); delete die; } -void CUFixtureBase::DefinitionDIE(DIEHandler *parent, +void CUFixtureBase::DefinitionDIE(DIEHandler* parent, DwarfTag tag, uint64_t specification, - const string &name, + const string& name, Module::Address address, Module::Address size) { - dwarf2reader::DIEHandler *die + google_breakpad::DIEHandler* die = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag); ASSERT_TRUE(die != NULL); - die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, + die->ProcessAttributeReference(google_breakpad::DW_AT_specification, + google_breakpad::DW_FORM_ref4, specification); if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + die->ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, name); if (size) { - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, + die->ProcessAttributeUnsigned(google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, address); - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr, + die->ProcessAttributeUnsigned(google_breakpad::DW_AT_high_pc, + google_breakpad::DW_FORM_addr, address + size); } EXPECT_TRUE(die->EndAttributes()); @@ -518,27 +527,27 @@ void CUFixtureBase::DefinitionDIE(DIEHandler *parent, delete die; } -void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent, +void CUFixtureBase::AbstractInstanceDIE(DIEHandler* parent, uint64_t offset, DwarfInline type, uint64_t specification, - const string &name, + const string& name, DwarfForm form) { - dwarf2reader::DIEHandler *die - = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram); + google_breakpad::DIEHandler* die + = parent->FindChildHandler(offset, google_breakpad::DW_TAG_subprogram); ASSERT_TRUE(die != NULL); if (specification != 0ULL) - die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, + die->ProcessAttributeReference(google_breakpad::DW_AT_specification, + google_breakpad::DW_FORM_ref4, specification); - if (form == dwarf2reader::DW_FORM_sdata) { - die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type); + if (form == google_breakpad::DW_FORM_sdata) { + die->ProcessAttributeSigned(google_breakpad::DW_AT_inline, form, type); } else { - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type); + die->ProcessAttributeUnsigned(google_breakpad::DW_AT_inline, form, type); } if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + die->ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, name); EXPECT_TRUE(die->EndAttributes()); @@ -546,28 +555,28 @@ void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent, delete die; } -void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent, - const string &name, +void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler* parent, + const string& name, uint64_t origin, Module::Address address, Module::Address size) { - dwarf2reader::DIEHandler *func + google_breakpad::DIEHandler* func = parent->FindChildHandler(0x11c70f94c6e87ccdLL, - dwarf2reader::DW_TAG_subprogram); + google_breakpad::DW_TAG_subprogram); ASSERT_TRUE(func != NULL); if (!name.empty()) { - func->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + func->ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, name); } - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, + func->ProcessAttributeUnsigned(google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, address); - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr, + func->ProcessAttributeUnsigned(google_breakpad::DW_AT_high_pc, + google_breakpad::DW_FORM_addr, address + size); - func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin, - dwarf2reader::DW_FORM_ref4, + func->ProcessAttributeReference(google_breakpad::DW_AT_abstract_origin, + google_breakpad::DW_FORM_ref4, origin); ProcessStrangeAttributes(func); EXPECT_TRUE(func->EndAttributes()); @@ -589,13 +598,13 @@ void CUFixtureBase::TestFunctionCount(size_t expected) { ASSERT_EQ(expected, functions_.size()); } -void CUFixtureBase::TestFunction(int i, const string &name, +void CUFixtureBase::TestFunction(int i, const string& name, Module::Address address, Module::Address size) { FillFunctions(); ASSERT_LT((size_t) i, functions_.size()); - Module::Function *function = functions_[i]; + Module::Function* function = functions_[i]; EXPECT_EQ(name, function->name); EXPECT_EQ(address, function->address); EXPECT_EQ(size, function->ranges[0].size); @@ -611,12 +620,12 @@ void CUFixtureBase::TestLineCount(int i, size_t expected) { void CUFixtureBase::TestLine(int i, int j, Module::Address address, Module::Address size, - const string &filename, int number) { + const string& filename, int number) { FillFunctions(); ASSERT_LT((size_t) i, functions_.size()); ASSERT_LT((size_t) j, functions_[i]->lines.size()); - Module::Line *line = &functions_[i]->lines[j]; + Module::Line* line = &functions_[i]->lines[j]; EXPECT_EQ(address, line->address); EXPECT_EQ(size, line->size); EXPECT_EQ(filename, line->file->name.c_str()); @@ -672,7 +681,7 @@ TEST_F(SimpleCU, OneFuncHighPcIsLength) { StartCU(); DefineFunction6(&root_handler_, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL, - dwarf2reader::DW_FORM_udata); + google_breakpad::DW_FORM_udata); root_handler_.Finish(); TestFunctionCount(1); @@ -698,17 +707,17 @@ TEST_F(SimpleCU, IrrelevantRootChildren) { StartCU(); EXPECT_FALSE(root_handler_ .FindChildHandler(0x7db32bff4e2dcfb1ULL, - dwarf2reader::DW_TAG_lexical_block)); + google_breakpad::DW_TAG_lexical_block)); } TEST_F(SimpleCU, IrrelevantNamedScopeChildren) { StartCU(); - DIEHandler *class_A_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); + DIEHandler* class_A_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); EXPECT_TRUE(class_A_handler != NULL); EXPECT_FALSE(class_A_handler ->FindChildHandler(0x02e55999b865e4e9ULL, - dwarf2reader::DW_TAG_lexical_block)); + google_breakpad::DW_TAG_lexical_block)); delete class_A_handler; } @@ -726,7 +735,7 @@ TEST_F(SimpleCU, InlineFunction) { StartCU(); AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name"); + google_breakpad::DW_INL_inlined, 0, "inline-name"); DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); root_handler_.Finish(); @@ -741,8 +750,8 @@ TEST_F(SimpleCU, InlineFunctionSignedAttribute) { StartCU(); AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name", - dwarf2reader::DW_FORM_sdata); + google_breakpad::DW_INL_inlined, 0, "inline-name", + google_breakpad::DW_FORM_sdata); DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); root_handler_.Finish(); @@ -760,7 +769,7 @@ TEST_F(SimpleCU, AbstractOriginNotInlined) { StartCU(); AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL, - dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance"); + google_breakpad::DW_INL_not_inlined, 0, "abstract-instance"); DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL, 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); root_handler_.Finish(); @@ -771,14 +780,11 @@ TEST_F(SimpleCU, AbstractOriginNotInlined) { } TEST_F(SimpleCU, UnknownAbstractOrigin) { - EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return()); - EXPECT_CALL(reporter_, UnnamedFunction(0x11c70f94c6e87ccdLL)) - .WillOnce(Return()); PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); StartCU(); AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name"); + google_breakpad::DW_INL_inlined, 0, "inline-name"); DefineInlineInstanceDIE(&root_handler_, "", 1ULL, 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); root_handler_.Finish(); @@ -789,8 +795,6 @@ TEST_F(SimpleCU, UnknownAbstractOrigin) { } TEST_F(SimpleCU, UnnamedFunction) { - EXPECT_CALL(reporter_, UnnamedFunction(0xe34797c7e68590a8LL)) - .WillOnce(Return()); PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850); StartCU(); @@ -849,11 +853,11 @@ Situation situations[] = { class FuncLinePairing: public CUFixtureBase, public TestWithParam<Situation> { }; -INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing, - ValuesIn(situations)); +INSTANTIATE_TEST_SUITE_P(AllSituations, FuncLinePairing, + ValuesIn(situations)); TEST_P(FuncLinePairing, Pairing) { - const Situation &s = GetParam(); + const Situation& s = GetParam(); PushLine(s.lines[0].start, s.lines[0].end - s.lines[0].start, "line-file", 67636963); @@ -1035,21 +1039,21 @@ TEST_F(FuncLinePairing, WarnOnceLine) { class CXXQualifiedNames: public CUFixtureBase, public TestWithParam<DwarfTag> { }; -INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames, - Values(dwarf2reader::DW_TAG_class_type, - dwarf2reader::DW_TAG_structure_type, - dwarf2reader::DW_TAG_union_type, - dwarf2reader::DW_TAG_namespace)); +INSTANTIATE_TEST_SUITE_P(VersusEnclosures, CXXQualifiedNames, + Values(google_breakpad::DW_TAG_class_type, + google_breakpad::DW_TAG_structure_type, + google_breakpad::DW_TAG_union_type, + google_breakpad::DW_TAG_namespace)); TEST_P(CXXQualifiedNames, TwoFunctions) { DwarfTag tag = GetParam(); - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + SetLanguage(google_breakpad::DW_LANG_C_plus_plus); PushLine(10, 1, "filename1", 69819327); PushLine(20, 1, "filename2", 95115701); StartCU(); - DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag, + DIEHandler* enclosure_handler = StartNamedDIE(&root_handler_, tag, "Enclosure"); EXPECT_TRUE(enclosure_handler != NULL); DefineFunction(enclosure_handler, "func_B", 10, 1, NULL); @@ -1066,15 +1070,15 @@ TEST_P(CXXQualifiedNames, TwoFunctions) { TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) { DwarfTag tag = GetParam(); - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + SetLanguage(google_breakpad::DW_LANG_C_plus_plus); PushLine(10, 1, "line-file", 69819327); StartCU(); - DIEHandler *namespace_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + DIEHandler* namespace_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, "Namespace"); EXPECT_TRUE(namespace_handler != NULL); - DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag, + DIEHandler* enclosure_handler = StartNamedDIE(namespace_handler, tag, "Enclosure"); EXPECT_TRUE(enclosure_handler != NULL); DefineFunction(enclosure_handler, "function", 10, 1, NULL); @@ -1089,20 +1093,20 @@ TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) { } TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) { - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + SetLanguage(google_breakpad::DW_LANG_C_plus_plus); PushLine(10, 1, "filename1", 69819327); StartCU(); - DIEHandler *namespace_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + DIEHandler* namespace_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, "namespace_A"); EXPECT_TRUE(namespace_handler != NULL); - DIEHandler *struct_handler - = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type, + DIEHandler* struct_handler + = StartNamedDIE(namespace_handler, google_breakpad::DW_TAG_structure_type, "struct_B"); EXPECT_TRUE(struct_handler != NULL); - DIEHandler *class_handler - = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_handler + = StartNamedDIE(struct_handler, google_breakpad::DW_TAG_class_type, "class_C"); DefineFunction(class_handler, "function_D", 10, 1, NULL); class_handler->Finish(); @@ -1118,37 +1122,37 @@ TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) { } struct LanguageAndQualifiedName { - dwarf2reader::DwarfLanguage language; - const char *name; + google_breakpad::DwarfLanguage language; + const char* name; }; const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = { - { dwarf2reader::DW_LANG_none, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C89, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C99, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" }, - { dwarf2reader::DW_LANG_Java, "class_A.function_B" }, - { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" }, - { dwarf2reader::DW_LANG_Mips_Assembler, NULL } + { google_breakpad::DW_LANG_none, "class_A::function_B" }, + { google_breakpad::DW_LANG_C, "class_A::function_B" }, + { google_breakpad::DW_LANG_C89, "class_A::function_B" }, + { google_breakpad::DW_LANG_C99, "class_A::function_B" }, + { google_breakpad::DW_LANG_C_plus_plus, "class_A::function_B" }, + { google_breakpad::DW_LANG_Java, "class_A.function_B" }, + { google_breakpad::DW_LANG_Cobol74, "class_A::function_B" }, + { google_breakpad::DW_LANG_Mips_Assembler, NULL } }; class QualifiedForLanguage : public CUFixtureBase, public TestWithParam<LanguageAndQualifiedName> { }; -INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage, - ValuesIn(LanguageAndQualifiedNameCases)); +INSTANTIATE_TEST_SUITE_P(LanguageAndQualifiedName, QualifiedForLanguage, + ValuesIn(LanguageAndQualifiedNameCases)); TEST_P(QualifiedForLanguage, MemberFunction) { - const LanguageAndQualifiedName ¶m = GetParam(); + const LanguageAndQualifiedName& param = GetParam(); PushLine(10, 1, "line-file", 212966758); SetLanguage(param.language); StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); DefineFunction(class_handler, "function_B", 10, 1, NULL); class_handler->Finish(); @@ -1164,15 +1168,15 @@ TEST_P(QualifiedForLanguage, MemberFunction) { } TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) { - const LanguageAndQualifiedName ¶m = GetParam(); + const LanguageAndQualifiedName& param = GetParam(); PushLine(10, 1, "line-file", 212966758); SetLanguage(param.language); SetLanguageSigned(true); StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); DefineFunction(class_handler, "function_B", 10, 1, NULL); class_handler->Finish(); @@ -1194,8 +1198,8 @@ TEST_F(Specifications, Function) { StartCU(); DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + google_breakpad::DW_TAG_subprogram, "declaration-name", ""); + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0xcd3c51b946fb1eeeLL, "", 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); root_handler_.Finish(); @@ -1211,9 +1215,9 @@ TEST_F(Specifications, MangledName) { StartCU(); DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", + google_breakpad::DW_TAG_subprogram, "declaration-name", "_ZN1C1fEi"); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0xcd3c51b946fb1eeeLL, "", 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); root_handler_.Finish(); @@ -1225,14 +1229,14 @@ TEST_F(Specifications, MangledName) { TEST_F(Specifications, MangledNameSwift) { // Swift mangled names should pass through untouched. - SetLanguage(dwarf2reader::DW_LANG_Swift); + SetLanguage(google_breakpad::DW_LANG_Swift); PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); StartCU(); const string kName = "_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si"; DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", + google_breakpad::DW_TAG_subprogram, "declaration-name", kName); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0xcd3c51b946fb1eeeLL, "", 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); root_handler_.Finish(); @@ -1243,27 +1247,27 @@ TEST_F(Specifications, MangledNameSwift) { } TEST_F(Specifications, MangledNameRust) { - SetLanguage(dwarf2reader::DW_LANG_Rust); + SetLanguage(google_breakpad::DW_LANG_Rust); PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); StartCU(); const string kName = "_ZN14rustc_demangle8demangle17h373defa94bffacdeE"; DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", + google_breakpad::DW_TAG_subprogram, "declaration-name", kName); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0xcd3c51b946fb1eeeLL, "", 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); root_handler_.Finish(); TestFunctionCount(1); TestFunction(0, -#ifndef HAVE_RUST_DEMANGLE +#ifndef HAVE_RUSTC_DEMANGLE // Rust mangled names should pass through untouched if not - // using rust-demangle. + // using rustc-demangle. kName, #else - // If rust-demangle is available this should be properly + // If rustc-demangle is available this should be properly // demangled. "rustc_demangle::demangle", #endif @@ -1274,13 +1278,13 @@ TEST_F(Specifications, MemberFunction) { PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691); StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); + DIEHandler* class_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); DeclarationDIE(class_handler, 0x7d83028c431406e8ULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + google_breakpad::DW_TAG_subprogram, "declaration-name", ""); class_handler->Finish(); delete class_handler; - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0x7d83028c431406e8ULL, "", 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); root_handler_.Finish(); @@ -1297,17 +1301,17 @@ TEST_F(Specifications, FunctionDeclarationParent) { StartCU(); { - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A"); ASSERT_TRUE(class_handler != NULL); DeclarationDIE(class_handler, 0x0e0e877c8404544aULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + google_breakpad::DW_TAG_subprogram, "declaration-name", ""); class_handler->Finish(); delete class_handler; } - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0x0e0e877c8404544aULL, "definition-name", 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); @@ -1325,20 +1329,20 @@ TEST_F(Specifications, NamedScopeDeclarationParent) { StartCU(); { - DIEHandler *space_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + DIEHandler* space_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, "space_A"); ASSERT_TRUE(space_handler != NULL); DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL, - dwarf2reader::DW_TAG_class_type, "class-declaration-name", + google_breakpad::DW_TAG_class_type, "class-declaration-name", ""); space_handler->Finish(); delete space_handler; } { - DIEHandler *class_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_handler + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, 0x419bb1d12f9a73a2ULL, "class-definition-name"); ASSERT_TRUE(class_handler != NULL); DefineFunction(class_handler, "function", @@ -1360,9 +1364,9 @@ TEST_F(Specifications, InlineFunction) { StartCU(); DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "inline-name", ""); + google_breakpad::DW_TAG_subprogram, "inline-name", ""); AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, ""); + google_breakpad::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, ""); DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); root_handler_.Finish(); @@ -1379,11 +1383,11 @@ TEST_F(Specifications, InlineFunctionInNamespace) { StartCU(); DIEHandler* space_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, "Namespace"); ASSERT_TRUE(space_handler != NULL); AbstractInstanceDIE(space_handler, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0LL, "func-name"); + google_breakpad::DW_INL_inlined, 0LL, "func-name"); DefineInlineInstanceDIE(space_handler, "", 0x1e8dac5d507ed7abULL, 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); space_handler->Finish(); @@ -1400,7 +1404,7 @@ TEST_F(Specifications, InlineFunctionInNamespace) { // - direct and definition TEST_F(Specifications, LongChain) { PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926); - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + SetLanguage(google_breakpad::DW_LANG_C_plus_plus); StartCU(); // The structure we're building here is: @@ -1429,24 +1433,24 @@ TEST_F(Specifications, LongChain) { // space_A::space_B::struct_C::struct_D::union_E::union_F:: // class_G::class_H::func_I { - DIEHandler *space_A_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + DIEHandler* space_A_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, "space_A"); DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL, - dwarf2reader::DW_TAG_namespace, "space_B", ""); + google_breakpad::DW_TAG_namespace, "space_B", ""); space_A_handler->Finish(); delete space_A_handler; } { - DIEHandler *space_B_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + DIEHandler* space_B_handler + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_namespace, 0x2e111126496596e2ULL); - DIEHandler *struct_C_handler - = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type, + DIEHandler* struct_C_handler + = StartNamedDIE(space_B_handler, google_breakpad::DW_TAG_structure_type, "struct_C"); DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL, - dwarf2reader::DW_TAG_structure_type, "struct_D", ""); + google_breakpad::DW_TAG_structure_type, "struct_D", ""); struct_C_handler->Finish(); delete struct_C_handler; space_B_handler->Finish(); @@ -1454,14 +1458,14 @@ TEST_F(Specifications, LongChain) { } { - DIEHandler *struct_D_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type, + DIEHandler* struct_D_handler + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_structure_type, 0x20cd423bf2a25a4cULL); - DIEHandler *union_E_handler - = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type, + DIEHandler* union_E_handler + = StartNamedDIE(struct_D_handler, google_breakpad::DW_TAG_union_type, "union_E"); DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL, - dwarf2reader::DW_TAG_union_type, "union_F", ""); + google_breakpad::DW_TAG_union_type, "union_F", ""); union_E_handler->Finish(); delete union_E_handler; struct_D_handler->Finish(); @@ -1469,14 +1473,14 @@ TEST_F(Specifications, LongChain) { } { - DIEHandler *union_F_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type, + DIEHandler* union_F_handler + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_union_type, 0xe25c84805aa58c32ULL); - DIEHandler *class_G_handler - = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_G_handler + = StartNamedDIE(union_F_handler, google_breakpad::DW_TAG_class_type, "class_G"); DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL, - dwarf2reader::DW_TAG_class_type, "class_H", ""); + google_breakpad::DW_TAG_class_type, "class_H", ""); class_G_handler->Finish(); delete class_G_handler; union_F_handler->Finish(); @@ -1484,16 +1488,16 @@ TEST_F(Specifications, LongChain) { } { - DIEHandler *class_H_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_H_handler + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, 0xb70d960dcc173b6eULL); DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL, - dwarf2reader::DW_TAG_subprogram, "func_I", ""); + google_breakpad::DW_TAG_subprogram, "func_I", ""); class_H_handler->Finish(); delete class_H_handler; } - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0x27ff829e3bf69f37ULL, "", 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); root_handler_.Finish(); @@ -1509,7 +1513,7 @@ TEST_F(Specifications, InterCU) { DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); MockLineToModuleHandler lr; - EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); + EXPECT_CALL(lr, ReadProgram(_,_,_,_,_,_,_,_,_)).Times(0); // Kludge: satisfy reporter_'s expectation. reporter_.SetCUName("compilation-unit-name"); @@ -1519,11 +1523,11 @@ TEST_F(Specifications, InterCU) { DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root1_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); + google_breakpad::DW_TAG_compile_unit)); ProcessStrangeAttributes(&root1_handler); ASSERT_TRUE(root1_handler.EndAttributes()); DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, - dwarf2reader::DW_TAG_class_type, "class_A", ""); + google_breakpad::DW_TAG_class_type, "class_A", ""); root1_handler.Finish(); } @@ -1532,13 +1536,13 @@ TEST_F(Specifications, InterCU) { DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root2_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); + google_breakpad::DW_TAG_compile_unit)); ASSERT_TRUE(root2_handler.EndAttributes()); - DIEHandler *class_A_handler - = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_A_handler + = StartSpecifiedDIE(&root2_handler, google_breakpad::DW_TAG_class_type, 0xb8fbfdd5f0b26fceULL); DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, - dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); + google_breakpad::DW_TAG_subprogram, "member_func_B", ""); class_A_handler->Finish(); delete class_A_handler; root2_handler.Finish(); @@ -1549,18 +1553,18 @@ TEST_F(Specifications, InterCU) { DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root3_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); + google_breakpad::DW_TAG_compile_unit)); ASSERT_TRUE(root3_handler.EndAttributes()); - DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root3_handler, google_breakpad::DW_TAG_subprogram, 0xb01fef8b380bd1a2ULL, "", 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); root3_handler.Finish(); } - vector<Module::Function *> functions; + vector<Module::Function*> functions; m.GetFunctions(&functions, functions.end()); EXPECT_EQ(1U, functions.size()); - EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str()); + EXPECT_STREQ("class_A::member_func_B", functions[0]->name.str().c_str()); } TEST_F(Specifications, UnhandledInterCU) { @@ -1568,7 +1572,7 @@ TEST_F(Specifications, UnhandledInterCU) { DwarfCUToModule::FileContext fc("dwarf-filename", &m, false); EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); MockLineToModuleHandler lr; - EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); + EXPECT_CALL(lr, ReadProgram(_,_,_,_,_,_,_,_,_)).Times(0); // Kludge: satisfy reporter_'s expectation. reporter_.SetCUName("compilation-unit-name"); @@ -1578,11 +1582,11 @@ TEST_F(Specifications, UnhandledInterCU) { DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root1_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); + google_breakpad::DW_TAG_compile_unit)); ProcessStrangeAttributes(&root1_handler); ASSERT_TRUE(root1_handler.EndAttributes()); DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, - dwarf2reader::DW_TAG_class_type, "class_A", ""); + google_breakpad::DW_TAG_class_type, "class_A", ""); root1_handler.Finish(); } @@ -1591,14 +1595,14 @@ TEST_F(Specifications, UnhandledInterCU) { DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root2_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); + google_breakpad::DW_TAG_compile_unit)); ASSERT_TRUE(root2_handler.EndAttributes()); EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); - DIEHandler *class_A_handler - = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, + DIEHandler* class_A_handler + = StartSpecifiedDIE(&root2_handler, google_breakpad::DW_TAG_class_type, 0xb8fbfdd5f0b26fceULL); DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, - dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); + google_breakpad::DW_TAG_subprogram, "member_func_B", ""); class_A_handler->Finish(); delete class_A_handler; root2_handler.Finish(); @@ -1609,11 +1613,10 @@ TEST_F(Specifications, UnhandledInterCU) { DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root3_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); + google_breakpad::DW_TAG_compile_unit)); ASSERT_TRUE(root3_handler.EndAttributes()); EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); - EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1); - DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root3_handler, google_breakpad::DW_TAG_subprogram, 0xb01fef8b380bd1a2ULL, "", 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); root3_handler.Finish(); @@ -1622,13 +1625,11 @@ TEST_F(Specifications, UnhandledInterCU) { TEST_F(Specifications, BadOffset) { PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272); - EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL)) - .WillOnce(Return()); StartCU(); DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL, - dwarf2reader::DW_TAG_subprogram, "", ""); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + google_breakpad::DW_TAG_subprogram, "", ""); + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0x2be953efa6f9a996ULL, "function", 0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL); root_handler_.Finish(); @@ -1639,8 +1640,8 @@ TEST_F(Specifications, FunctionDefinitionHasOwnName) { StartCU(); DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + google_breakpad::DW_TAG_subprogram, "declaration-name", ""); + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0xc34ff4786cae78bdULL, "definition-name", 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); root_handler_.Finish(); @@ -1655,19 +1656,19 @@ TEST_F(Specifications, ClassDefinitionHasOwnName) { StartCU(); DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL, - dwarf2reader::DW_TAG_class_type, "class-declaration-name", ""); + google_breakpad::DW_TAG_class_type, "class-declaration-name", ""); - dwarf2reader::DIEHandler *class_definition - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + google_breakpad::DIEHandler* class_definition + = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, 0xd0fe467ec2f1a58cULL, "class-definition-name"); ASSERT_TRUE(class_definition); DeclarationDIE(class_definition, 0x6d028229c15623dbULL, - dwarf2reader::DW_TAG_subprogram, + google_breakpad::DW_TAG_subprogram, "function-declaration-name", ""); class_definition->Finish(); delete class_definition; - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram, 0x6d028229c15623dbULL, "function-definition-name", 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); @@ -1688,20 +1689,20 @@ TEST_F(Specifications, PreferSpecificationParents) { StartCU(); { - dwarf2reader::DIEHandler *declaration_class_handler = - StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + google_breakpad::DIEHandler* declaration_class_handler = + StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "declaration-class"); DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL, - dwarf2reader::DW_TAG_subprogram, "function-declaration", + google_breakpad::DW_TAG_subprogram, "function-declaration", ""); declaration_class_handler->Finish(); delete declaration_class_handler; } { - dwarf2reader::DIEHandler *definition_class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + google_breakpad::DIEHandler* definition_class_handler + = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "definition-class"); - DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram, + DefinitionDIE(definition_class_handler, google_breakpad::DW_TAG_subprogram, 0x9ddb35517455ef7aULL, "function-definition", 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); definition_class_handler->Finish(); @@ -1723,12 +1724,12 @@ TEST_F(CUErrors, BadStmtList) { .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd, 0x2d7d19546cf6590cULL, 3)); ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL, - dwarf2reader::DW_TAG_compile_unit)); - root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, + google_breakpad::DW_TAG_compile_unit)); + root_handler_.ProcessAttributeString(google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strp, "compilation-unit-name"); - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, - dwarf2reader::DW_FORM_ref4, + root_handler_.ProcessAttributeUnsigned(google_breakpad::DW_AT_stmt_list, + google_breakpad::DW_FORM_ref4, dummy_line_size_ + 10); root_handler_.EndAttributes(); root_handler_.Finish(); @@ -1780,7 +1781,7 @@ TEST_F(CUErrors, BadCURootDIETag) { 0xc9de224ccb99ac3eULL, 3)); ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, - dwarf2reader::DW_TAG_subprogram)); + google_breakpad::DW_TAG_subprogram)); } // Tests for DwarfCUToModule::Reporter. These just produce (or fail to diff --git a/src/common/dwarf_line_to_module.cc b/src/common/dwarf_line_to_module.cc index 443d7448..e716d483 100644 --- a/src/common/dwarf_line_to_module.cc +++ b/src/common/dwarf_line_to_module.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,18 +43,18 @@ // it until we actually have to deal with DWARF on Windows. // Return true if PATH is an absolute path, false if it is relative. -static bool PathIsAbsolute(const string &path) { +static bool PathIsAbsolute(const string& path) { return (path.size() >= 1 && path[0] == '/'); } -static bool HasTrailingSlash(const string &path) { +static bool HasTrailingSlash(const string& path) { return (path.size() >= 1 && path[path.size() - 1] == '/'); } // If PATH is an absolute path, return PATH. If PATH is a relative path, // treat it as relative to BASE and return the combined path. -static string ExpandPath(const string &path, - const string &base) { +static string ExpandPath(const string& path, + const string& base) { if (PathIsAbsolute(path) || base.empty()) return path; return base + (HasTrailingSlash(base) ? "" : "/") + path; @@ -63,14 +62,14 @@ static string ExpandPath(const string &path, namespace google_breakpad { -void DwarfLineToModule::DefineDir(const string &name, uint32_t dir_num) { +void DwarfLineToModule::DefineDir(const string& name, uint32_t dir_num) { // Directory number zero is reserved to mean the compilation // directory. Silently ignore attempts to redefine it. if (dir_num != 0) directories_[dir_num] = ExpandPath(name, compilation_dir_); } -void DwarfLineToModule::DefineFile(const string &name, int32_t file_num, +void DwarfLineToModule::DefineFile(const string& name, int32_t file_num, uint32_t dir_num, uint64_t mod_time, uint64_t length) { if (file_num == -1) @@ -100,7 +99,7 @@ void DwarfLineToModule::DefineFile(const string &name, int32_t file_num, // Find a Module::File object of the given name, and add it to the // file table. - files_[file_num] = module_->FindFile(full_name); + (*files_)[file_num] = module_->FindFile(full_name); } void DwarfLineToModule::AddLine(uint64_t address, uint64_t length, @@ -122,7 +121,7 @@ void DwarfLineToModule::AddLine(uint64_t address, uint64_t length, } // Find the source file being referred to. - Module::File *file = files_[file_num]; + Module::File *file = (*files_)[file_num]; if (!file) { if (!warned_bad_file_number_) { fprintf(stderr, "warning: DWARF line number data refers to " diff --git a/src/common/dwarf_line_to_module.h b/src/common/dwarf_line_to_module.h index f54ccaf5..c93a9bf5 100644 --- a/src/common/dwarf_line_to_module.h +++ b/src/common/dwarf_line_to_module.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -50,7 +49,7 @@ namespace google_breakpad { // instances from parsed DWARF line number data. // // An instance of this class can be provided as a handler to a -// dwarf2reader::LineInfo DWARF line number information parser. The +// LineInfo DWARF line number information parser. The // handler accepts source location information from the parser and // uses it to produce a vector of google_breakpad::Module::Line // objects, referring to google_breakpad::Module::File objects added @@ -111,7 +110,7 @@ namespace google_breakpad { // at address zero.) // // - If a line starts immediately after an omitted line, omit it too. -class DwarfLineToModule: public dwarf2reader::LineInfoHandler { +class DwarfLineToModule: public LineInfoHandler { public: // As the DWARF line info parser passes us line records, add source // files to MODULE, and add all lines to the end of LINES. LINES @@ -120,20 +119,23 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler { // end of the address space, we clip it. It's up to our client to // sort out which lines belong to which functions; we don't add them // to any particular function in MODULE ourselves. - DwarfLineToModule(Module *module, const string& compilation_dir, - vector<Module::Line> *lines) + DwarfLineToModule(Module* module, + const string& compilation_dir, + vector<Module::Line>* lines, + std::map<uint32_t, Module::File*>* files) : module_(module), compilation_dir_(compilation_dir), lines_(lines), + files_(files), highest_file_number_(-1), omitted_line_end_(0), warned_bad_file_number_(false), warned_bad_directory_number_(false) { } - + ~DwarfLineToModule() { } - void DefineDir(const string &name, uint32_t dir_num); - void DefineFile(const string &name, int32_t file_num, + void DefineDir(const string& name, uint32_t dir_num); + void DefineFile(const string& name, int32_t file_num, uint32_t dir_num, uint64_t mod_time, uint64_t length); void AddLine(uint64_t address, uint64_t length, @@ -142,7 +144,7 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler { private: typedef std::map<uint32_t, string> DirectoryTable; - typedef std::map<uint32_t, Module::File *> FileTable; + typedef std::map<uint32_t, Module::File*> FileTable; // The module we're contributing debugging info to. Owned by our // client. @@ -161,18 +163,18 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler { // to the appropriate function from module_ until we've read the // function info as well. Instead, we accumulate lines here, and let // whoever constructed this sort it all out. - vector<Module::Line> *lines_; + vector<Module::Line>* lines_; // A table mapping directory numbers to paths. DirectoryTable directories_; // A table mapping file numbers to Module::File pointers. - FileTable files_; + FileTable* files_; // The highest file number we've seen so far, or -1 if we've seen // none. Used for dynamically defined file numbers. int32_t highest_file_number_; - + // This is the ending address of the last line we omitted, or zero if we // didn't omit the previous line. It is zero before we have received any // AddLine calls. diff --git a/src/common/dwarf_line_to_module_unittest.cc b/src/common/dwarf_line_to_module_unittest.cc index 7c0fcfd3..c4a02dfa 100644 --- a/src/common/dwarf_line_to_module_unittest.cc +++ b/src/common/dwarf_line_to_module_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,13 +44,14 @@ using google_breakpad::Module; TEST(SimpleModule, One) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("file1", 0x30bf0f27, 0, 0, 0); h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27, 0x4c090cbf, 0x1cf9fe0d); - vector<Module::File *> files; + vector<Module::File*> files; m.GetFiles(&files); EXPECT_EQ(1U, files.size()); EXPECT_STREQ("/file1", files[0]->name.c_str()); @@ -66,7 +66,8 @@ TEST(SimpleModule, One) { TEST(SimpleModule, Many) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 0x838299ab); h.DefineDir("directory2", 0xf85de023); @@ -86,7 +87,7 @@ TEST(SimpleModule, Many) { h.AddLine(0xe2d72a37f8d9403aULL, 0x034dfab5b0d4d236ULL, 0x63beb4a5, 0x75047044U, 0xb6a0016cU); - vector<Module::File *> files; + vector<Module::File*> files; m.GetFiles(&files); ASSERT_EQ(5U, files.size()); EXPECT_STREQ("/directory1/file1", files[0]->name.c_str()); @@ -126,14 +127,15 @@ TEST(SimpleModule, Many) { TEST(Filenames, Absolute) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 1); h.DefineFile("/absolute", 1, 1, 0, 0); h.AddLine(1, 1, 1, 0, 0); - vector<Module::File *> files; + vector<Module::File*> files; m.GetFiles(&files); ASSERT_EQ(1U, files.size()); EXPECT_STREQ("/absolute", files[0]->name.c_str()); @@ -144,14 +146,15 @@ TEST(Filenames, Absolute) { TEST(Filenames, Relative) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 1); h.DefineFile("relative", 1, 1, 0, 0); h.AddLine(1, 1, 1, 0, 0); - vector<Module::File *> files; + vector<Module::File*> files; m.GetFiles(&files); ASSERT_EQ(1U, files.size()); EXPECT_STREQ("/directory1/relative", files[0]->name.c_str()); @@ -162,7 +165,8 @@ TEST(Filenames, Relative) { TEST(Filenames, StrangeFile) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 1); h.DefineFile("", 1, 1, 0, 0); @@ -175,7 +179,8 @@ TEST(Filenames, StrangeFile) { TEST(Filenames, StrangeDirectory) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("", 1); h.DefineFile("file1", 1, 1, 0, 0); @@ -188,7 +193,8 @@ TEST(Filenames, StrangeDirectory) { TEST(Filenames, StrangeDirectoryAndFile) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("", 1); h.DefineFile("", 1, 1, 0, 0); @@ -203,7 +209,8 @@ TEST(Filenames, StrangeDirectoryAndFile) { TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "src/build", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "src/build", &lines, &cu_files); h.DefineDir("Dir", 1); h.DefineFile("File", 1, 0, 0, 0); @@ -219,7 +226,8 @@ TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) { TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "src/build", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "src/build", &lines, &cu_files); h.DefineDir("Dir", 1); h.DefineFile("File", 1, 1, 0, 0); @@ -235,7 +243,8 @@ TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) { TEST(Filenames, IncludeDirectoryAbsolute) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "src/build", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "src/build", &lines, &cu_files); h.DefineDir("/Dir", 1); h.DefineFile("File", 1, 1, 0, 0); @@ -251,7 +260,8 @@ TEST(Filenames, IncludeDirectoryAbsolute) { TEST(ModuleErrors, DirectoryZero) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory0", 0); // should be ignored h.DefineFile("relative", 1, 0, 0, 0); @@ -267,7 +277,8 @@ TEST(ModuleErrors, DirectoryZero) { TEST(ModuleErrors, BadFileNumber) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("relative", 1, 0, 0, 0); h.AddLine(1, 1, 2, 0, 0); // bad file number @@ -281,7 +292,8 @@ TEST(ModuleErrors, BadFileNumber) { TEST(ModuleErrors, BadDirectoryNumber) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineDir("directory1", 1); h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number @@ -296,7 +308,8 @@ TEST(ModuleErrors, BadDirectoryNumber) { TEST(ModuleErrors, EmptyLine) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("filename1", 1, 0, 0, 0); h.AddLine(1, 0, 1, 0, 0); @@ -309,7 +322,8 @@ TEST(ModuleErrors, EmptyLine) { TEST(ModuleErrors, BigLine) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("filename1", 1, 0, 0, 0); h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0); @@ -326,7 +340,8 @@ TEST(ModuleErrors, BigLine) { TEST(Omitted, DroppedThenGood) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("filename1", 1, 0, 0, 0); h.AddLine(0, 10, 1, 83816211, 0); // should be omitted @@ -339,7 +354,8 @@ TEST(Omitted, DroppedThenGood) { TEST(Omitted, GoodThenDropped) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("filename1", 1, 0, 0, 0); h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded @@ -352,7 +368,8 @@ TEST(Omitted, GoodThenDropped) { TEST(Omitted, Mix1) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("filename1", 1, 0, 0, 0); h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded @@ -373,7 +390,8 @@ TEST(Omitted, Mix1) { TEST(Omitted, Mix2) { Module m("name", "os", "architecture", "id"); vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); + std::map<uint32_t, Module::File*> cu_files; + DwarfLineToModule h(&m, "/", &lines, &cu_files); h.DefineFile("filename1", 1, 0, 0, 0); h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted diff --git a/src/common/dwarf_range_list_handler.cc b/src/common/dwarf_range_list_handler.cc index cc9e39ce..4d3dbd2e 100644 --- a/src/common/dwarf_range_list_handler.cc +++ b/src/common/dwarf_range_list_handler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2018 Google Inc. -// All rights reserved. +// Copyright 2018 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,18 +39,14 @@ namespace google_breakpad { void DwarfRangeListHandler::AddRange(uint64_t begin, uint64_t end) { - Module::Range r(begin + base_address_, end - begin); + Module::Range r(begin, end - begin); ranges_->push_back(r); } -void DwarfRangeListHandler::SetBaseAddress(uint64_t base_address) { - base_address_ = base_address; -} - void DwarfRangeListHandler::Finish() { std::sort(ranges_->begin(), ranges_->end(), - [](const Module::Range &a, const Module::Range &b) { + [](const Module::Range& a, const Module::Range& b) { return a.address < b.address; } ); diff --git a/src/common/dwarf_range_list_handler.h b/src/common/dwarf_range_list_handler.h index 83a34694..cb1b8b1e 100644 --- a/src/common/dwarf_range_list_handler.h +++ b/src/common/dwarf_range_list_handler.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2018 Google Inc. -// All rights reserved. +// Copyright 2018 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -49,29 +48,22 @@ namespace google_breakpad { // A class for producing a vector of google_breakpad::Module::Range // instances from a parsed DWARF range list. -class DwarfRangeListHandler: public dwarf2reader::RangeListHandler { +class DwarfRangeListHandler: public RangeListHandler { public: - DwarfRangeListHandler(uint64_t base_address, vector<Module::Range> *ranges) - : base_address_(base_address), ranges_(ranges) { } + DwarfRangeListHandler(vector<Module::Range>* ranges) + : ranges_(ranges) { } ~DwarfRangeListHandler() { } // Add a range to the list void AddRange(uint64_t begin, uint64_t end); - // Record the new base address and use it for the following entries - void SetBaseAddress(uint64_t base_address); - // Sort the ranges so that they are in ascending order of starting address void Finish(); private: - // The current PC to add to every entry, this can be overridden by a special - // list entry - uint64_t base_address_; - // The list of ranges to be populated - vector<Module::Range> *ranges_; + vector<Module::Range>* ranges_; }; } // namespace google_breakpad diff --git a/src/common/language.cc b/src/common/language.cc index 978fb855..0096a8d1 100644 --- a/src/common/language.cc +++ b/src/common/language.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -35,13 +34,14 @@ #include "common/language.h" #include <stdlib.h> +#include <array> #if !defined(__ANDROID__) #include <cxxabi.h> #endif -#if defined(HAVE_RUST_DEMANGLE) -#include <rust_demangle.h> +#if defined(HAVE_RUSTC_DEMANGLE) +#include <rustc_demangle.h> #endif #include <limits> @@ -67,8 +67,8 @@ class CPPLanguage: public Language { public: CPPLanguage() {} - string MakeQualifiedName(const string &parent_name, - const string &name) const { + string MakeQualifiedName(const string& parent_name, + const string& name) const { return MakeQualifiedNameWithSeparator(parent_name, "::", name); } @@ -79,6 +79,13 @@ class CPPLanguage: public Language { demangled->clear(); return kDontDemangle; #else + // Attempting to demangle non-C++ symbols with the C++ demangler would print + // warnings and fail, so return kDontDemangle for these. + if (!IsMangledName(mangled)) { + demangled->clear(); + return kDontDemangle; + } + int status; char* demangled_c = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); @@ -99,6 +106,21 @@ class CPPLanguage: public Language { return result; #endif } + + private: + static bool IsMangledName(const string& name) { + // NOTE: For proper cross-compilation support, this should depend on target + // binary's platform, not current build platform. +#if defined(__APPLE__) + // Mac C++ symbols can have up to 4 underscores, followed by a "Z". + // Non-C++ symbols are not coded that way, but may have leading underscores. + size_t i = name.find_first_not_of('_'); + return i > 0 && i != string::npos && i <= 4 && name[i] == 'Z'; +#else + // Linux C++ symbols always start with "_Z". + return name.size() > 2 && name[0] == '_' && name[1] == 'Z'; +#endif + } }; CPPLanguage CPPLanguageSingleton; @@ -108,8 +130,8 @@ class JavaLanguage: public Language { public: JavaLanguage() {} - string MakeQualifiedName(const string &parent_name, - const string &name) const { + string MakeQualifiedName(const string& parent_name, + const string& name) const { return MakeQualifiedNameWithSeparator(parent_name, ".", name); } }; @@ -121,8 +143,8 @@ class SwiftLanguage: public Language { public: SwiftLanguage() {} - string MakeQualifiedName(const string &parent_name, - const string &name) const { + string MakeQualifiedName(const string& parent_name, + const string& name) const { return MakeQualifiedNameWithSeparator(parent_name, ".", name); } @@ -145,8 +167,8 @@ class RustLanguage: public Language { public: RustLanguage() {} - string MakeQualifiedName(const string &parent_name, - const string &name) const { + string MakeQualifiedName(const string& parent_name, + const string& name) const { return MakeQualifiedNameWithSeparator(parent_name, ".", name); } @@ -156,13 +178,13 @@ class RustLanguage: public Language { // abi_demangle doesn't produce stellar results due to them having // another layer of encoding. // If callers provide rustc-demangle, use that. -#if defined(HAVE_RUST_DEMANGLE) - char* rust_demangled = rust_demangle(mangled.c_str()); - if (rust_demangled == nullptr) { +#if defined(HAVE_RUSTC_DEMANGLE) + std::array<char, 1 * 1024 * 1024> rustc_demangled; + if (rustc_demangle(mangled.c_str(), rustc_demangled.data(), + rustc_demangled.size()) == 0) { return kDemangleFailure; } - demangled->assign(rust_demangled); - free_rust_demangled_name(rust_demangled); + demangled->assign(rustc_demangled.data()); #else // Otherwise, pass through the mangled name so callers can demangle // after the fact. @@ -180,8 +202,8 @@ class AssemblerLanguage: public Language { AssemblerLanguage() {} bool HasFunctions() const { return false; } - string MakeQualifiedName(const string &parent_name, - const string &name) const { + string MakeQualifiedName(const string& parent_name, + const string& name) const { return name; } }; diff --git a/src/common/language.h b/src/common/language.h index 2d2dbcd9..9ce8f1a6 100644 --- a/src/common/language.h +++ b/src/common/language.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -74,8 +73,8 @@ class Language { // take into account the parent and child DIE types, allow languages // to use their own data type for complex parent names, etc. But if // C++ doesn't need all that, who would? - virtual string MakeQualifiedName (const string &parent_name, - const string &name) const = 0; + virtual string MakeQualifiedName (const string& parent_name, + const string& name) const = 0; enum DemangleResult { // Demangling was not performed because it’s not appropriate to attempt. diff --git a/src/common/linux/breakpad_getcontext.S b/src/common/linux/breakpad_getcontext.S index fea0109d..286047bf 100644 --- a/src/common/linux/breakpad_getcontext.S +++ b/src/common/linux/breakpad_getcontext.S @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -32,7 +31,7 @@ #include "common/linux/ucontext_constants.h" -/* int getcontext (ucontext_t *ucp) */ +/* int getcontext (ucontext_t* ucp) */ #if defined(__arm__) @@ -90,6 +89,47 @@ breakpad_getcontext: #elif defined(__aarch64__) +#if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT + // ENABLE_PAUTH must be defined to 1 since this value will be used in + // bitwise-shift later! + #define ENABLE_PAUTH 1 + + #if ((__ARM_FEATURE_PAC_DEFAULT&((1<<0)|(1<<1)))==0) + #error Pointer authentication defines no valid key! + #endif +#else + #define ENABLE_PAUTH 0 +#endif + +#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT==1) + // ENABLE_BTI must be defined to 1 since this value will be used in + // bitwise-shift later! + #define ENABLE_BTI 1 +#else + #define ENABLE_BTI 0 +#endif + + +// Although Pointer Authentication and Branch Target Instructions are technically +// seperate features they work together, i.e. the paciasp and pacibsp instructions +// serve as BTI landing pads. +// Therefore PA-instructions are enabled when PA _or_ BTI is enabled! +#if ENABLE_PAUTH || ENABLE_BTI + // See section "Pointer Authentication" of + // https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros + // for details how to interpret __ARM_FEATURE_PAC_DEFAULT + #if (__ARM_FEATURE_PAC_DEFAULT & (1<<0)) + #define PAUTH_SIGN_SP paciasp + #define PAUTH_AUTH_SP autiasp + #else + #define PAUTH_SIGN_SP pacibsp + #define PAUTH_AUTH_SP autibsp + #endif +#else + #define PAUTH_SIGN_SP + #define PAUTH_AUTH_SP +#endif + #define _NSIG 64 #define __NR_rt_sigprocmask 135 @@ -101,6 +141,8 @@ breakpad_getcontext: .cfi_startproc breakpad_getcontext: + PAUTH_SIGN_SP + /* The saved context will return to the getcontext() call point with a return value of 0 */ str xzr, [x0, MCONTEXT_GREGS_OFFSET + 0 * REGISTER_SIZE] @@ -170,6 +212,9 @@ breakpad_getcontext: /* Return x0 for success */ mov x0, 0 + + PAUTH_AUTH_SP + ret .cfi_endproc @@ -336,7 +381,7 @@ symbol: .frame sp, framesize, rpc; .size function,.-function #endif -/* int getcontext (ucontext_t *ucp) */ +/* int getcontext (ucontext_t* ucp) */ NESTED (breakpad_getcontext, FRAME_SIZE, ra) .mask 0x10000000, 0 @@ -481,6 +526,120 @@ breakpad_getcontext: .cfi_endproc .size breakpad_getcontext, . - breakpad_getcontext +#elif defined(__riscv) + +# define SIG_BLOCK 0 +# define _NSIG8 8 +# define __NR_rt_sigprocmask 135 + + .text + .globl breakpad_getcontext + .type breakpad_getcontext, @function + .align 0 + .cfi_startproc +breakpad_getcontext: + REG_S ra, MCONTEXT_GREGS_PC(a0) + REG_S ra, MCONTEXT_GREGS_RA(a0) + REG_S sp, MCONTEXT_GREGS_SP(a0) + REG_S gp, MCONTEXT_GREGS_SP(a0) + REG_S tp, MCONTEXT_GREGS_TP(a0) + REG_S t0, MCONTEXT_GREGS_T0(a0) + REG_S t1, MCONTEXT_GREGS_T1(a0) + REG_S t2, MCONTEXT_GREGS_T2(a0) + REG_S s0, MCONTEXT_GREGS_S0(a0) + REG_S s1, MCONTEXT_GREGS_S1(a0) + REG_S a0, MCONTEXT_GREGS_A0(a0) + REG_S a1, MCONTEXT_GREGS_A1(a0) + REG_S a2, MCONTEXT_GREGS_A2(a0) + REG_S a3, MCONTEXT_GREGS_A3(a0) + REG_S a4, MCONTEXT_GREGS_A4(a0) + REG_S a5, MCONTEXT_GREGS_A5(a0) + REG_S a6, MCONTEXT_GREGS_A6(a0) + REG_S a7, MCONTEXT_GREGS_A7(a0) + REG_S s2, MCONTEXT_GREGS_S2(a0) + REG_S s3, MCONTEXT_GREGS_S3(a0) + REG_S s4, MCONTEXT_GREGS_S4(a0) + REG_S s5, MCONTEXT_GREGS_S5(a0) + REG_S s6, MCONTEXT_GREGS_S6(a0) + REG_S s7, MCONTEXT_GREGS_S7(a0) + REG_S s8, MCONTEXT_GREGS_S8(a0) + REG_S s9, MCONTEXT_GREGS_S9(a0) + REG_S s10, MCONTEXT_GREGS_S10(a0) + REG_S s11, MCONTEXT_GREGS_S11(a0) + REG_S t3, MCONTEXT_GREGS_T3(a0) + REG_S t4, MCONTEXT_GREGS_T4(a0) + REG_S t5, MCONTEXT_GREGS_T5(a0) + REG_S t6 , MCONTEXT_GREGS_T6(a0) +# ifndef __riscv_float_abi_soft + frsr a1 + + FREG_S ft0, MCONTEXT_FPREGS_FT0(a0) + FREG_S ft1, MCONTEXT_FPREGS_FT1(a0) + FREG_S ft2, MCONTEXT_FPREGS_FT2(a0) + FREG_S ft3, MCONTEXT_FPREGS_FT3(a0) + FREG_S ft4, MCONTEXT_FPREGS_FT4(a0) + FREG_S ft5, MCONTEXT_FPREGS_FT5(a0) + FREG_S ft6, MCONTEXT_FPREGS_FT6(a0) + FREG_S ft7, MCONTEXT_FPREGS_FT7(a0) + FREG_S fs0, MCONTEXT_FPREGS_FS0(a0) + FREG_S fs1, MCONTEXT_FPREGS_FS1(a0) + FREG_S fa0, MCONTEXT_FPREGS_FA0(a0) + FREG_S fa1, MCONTEXT_FPREGS_FA1(a0) + FREG_S fa2, MCONTEXT_FPREGS_FA2(a0) + FREG_S fa3, MCONTEXT_FPREGS_FA3(a0) + FREG_S fa4, MCONTEXT_FPREGS_FA4(a0) + FREG_S fa5, MCONTEXT_FPREGS_FA5(a0) + FREG_S fa6, MCONTEXT_FPREGS_FA6(a0) + FREG_S fa7, MCONTEXT_FPREGS_FA7(a0) + FREG_S fs2, MCONTEXT_FPREGS_FS2(a0) + FREG_S fs3, MCONTEXT_FPREGS_FS3(a0) + FREG_S fs4, MCONTEXT_FPREGS_FS4(a0) + FREG_S fs5, MCONTEXT_FPREGS_FS5(a0) + FREG_S fs6, MCONTEXT_FPREGS_FS6(a0) + FREG_S fs7, MCONTEXT_FPREGS_FS7(a0) + FREG_S fs8, MCONTEXT_FPREGS_FS8(a0) + FREG_S fs9, MCONTEXT_FPREGS_FS9(a0) + FREG_S fs10, MCONTEXT_FPREGS_FS10(a0) + FREG_S fs11, MCONTEXT_FPREGS_FS11(a0) + FREG_S ft8, MCONTEXT_FPREGS_FT8(a0) + FREG_S ft9, MCONTEXT_FPREGS_FT9(a0) + FREG_S ft10, MCONTEXT_FPREGS_FT10(a0) + FREG_S ft11, MCONTEXT_FPREGS_FT11(a0) + + sw a1, MCONTEXT_FPC_CSR(a0) +# endif // __riscv_float_abi_soft + mv a1, zero + add a2, a0, UCONTEXT_SIGMASK_OFFSET + li a3, _NSIG8 + mv a0, zero + li a7, __NR_rt_sigprocmask + ecall + mv a0, zero + ret + + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + #else -#error "This file has not been ported for your CPU!" +# error "This file has not been ported for your CPU!" +#endif + +#if defined(__aarch64__) +// ENABLE_PAUTH and ENABLE_BTI would be enabled at the definition +// of AArch64 specific breakpad_getcontext function +#if ENABLE_PAUTH || ENABLE_BTI +// for further information on the .note.gnu.property section see +// https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#program-property +.pushsection .note.gnu.property, "a"; + .balign 8 + .long 4 + .long 0x10 + .long 0x5 + .asciz "GNU" + .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ + .long 4 + .long ((ENABLE_PAUTH)<<1) | ((ENABLE_BTI)<<0) /* PAuth and BTI */ + .long 0 +.popsection +#endif #endif diff --git a/src/common/linux/breakpad_getcontext.h b/src/common/linux/breakpad_getcontext.h index 1418cde6..c553219f 100644 --- a/src/common/linux/breakpad_getcontext.h +++ b/src/common/linux/breakpad_getcontext.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/breakpad_getcontext_unittest.cc b/src/common/linux/breakpad_getcontext_unittest.cc index a57bfedf..573ddd88 100644 --- a/src/common/linux/breakpad_getcontext_unittest.cc +++ b/src/common/linux/breakpad_getcontext_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -114,6 +113,25 @@ TEST(AndroidUContext, GRegsOffset) { ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPC_CSR), offsetof(ucontext_t,uc_mcontext.fpc_csr)); +#elif defined(__riscv) + ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.__gregs[0])); + +#define CHECK_REG(x) \ + ASSERT_EQ(static_cast<size_t>(MCONTEXT_##x##_OFFSET), \ + offsetof(ucontext_t,uc_mcontext.__gregs[REG_##x])) + CHECK_REG(PC) + CHECK_REG(RA) + CHECK_REG(SP) + CHECK_REG(S0) + CHECK_REG(S1) + CHECK_REG(S2) + + ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.__fpregs)); + + ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPC_CSR), + offsetof(ucontext_t,uc_mcontext.__fpregs.__fcsr)); #elif defined(__x86_64__) COMPILE_ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET), diff --git a/src/common/linux/crc32.cc b/src/common/linux/crc32.cc index 8df636ce..c02f06c4 100644 --- a/src/common/linux/crc32.cc +++ b/src/common/linux/crc32.cc @@ -1,5 +1,4 @@ -// Copyright 2014 Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/crc32.h b/src/common/linux/crc32.h index e3d9db92..7df46999 100644 --- a/src/common/linux/crc32.h +++ b/src/common/linux/crc32.h @@ -1,5 +1,4 @@ -// Copyright 2014 Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index b7e77ab7..b436f765 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,8 +46,8 @@ #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> +#include <zlib.h> -#include <iostream> #include <set> #include <string> #include <utility> @@ -87,11 +86,11 @@ using google_breakpad::DwarfRangeListHandler; using google_breakpad::ElfClass; using google_breakpad::ElfClass32; using google_breakpad::ElfClass64; -using google_breakpad::FileID; +using google_breakpad::elf::FileID; using google_breakpad::FindElfSectionByName; using google_breakpad::GetOffset; using google_breakpad::IsValidElf; -using google_breakpad::kDefaultBuildIdSize; +using google_breakpad::elf::kDefaultBuildIdSize; using google_breakpad::Module; using google_breakpad::PageAllocator; #ifndef NO_STABS_SUPPORT @@ -144,7 +143,7 @@ class MmapWrapper { munmap(base_, size_); } } - void set(void *mapped_address, size_t mapped_size) { + void set(void* mapped_address, size_t mapped_size) { is_set_ = true; base_ = mapped_address; size_ = mapped_size; @@ -228,62 +227,121 @@ bool LoadStabs(const typename ElfClass::Ehdr* elf_header, #endif // NO_STABS_SUPPORT // A range handler that accepts rangelist data parsed by -// dwarf2reader::RangeListReader and populates a range vector (typically +// google_breakpad::RangeListReader and populates a range vector (typically // owned by a function) with the results. class DumperRangesHandler : public DwarfCUToModule::RangesHandler { public: - DumperRangesHandler(const uint8_t *buffer, uint64_t size, - dwarf2reader::ByteReader* reader) - : buffer_(buffer), size_(size), reader_(reader) { } - - bool ReadRanges(uint64_t offset, Module::Address base_address, - vector<Module::Range>* ranges) { - DwarfRangeListHandler handler(base_address, ranges); - dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_, - &handler); - - return rangelist_reader.ReadRangeList(offset); + DumperRangesHandler(google_breakpad::ByteReader* reader) : + reader_(reader) { } + + bool ReadRanges( + enum google_breakpad::DwarfForm form, uint64_t data, + google_breakpad::RangeListReader::CURangesInfo* cu_info, + vector<Module::Range>* ranges) { + DwarfRangeListHandler handler(ranges); + google_breakpad::RangeListReader range_list_reader(reader_, cu_info, + &handler); + return range_list_reader.ReadRanges(form, data); } private: - const uint8_t *buffer_; - uint64_t size_; - dwarf2reader::ByteReader* reader_; + google_breakpad::ByteReader* reader_; }; // A line-to-module loader that accepts line number info parsed by -// dwarf2reader::LineInfo and populates a Module and a line vector +// google_breakpad::LineInfo and populates a Module and a line vector // with the results. class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { public: // Create a line-to-module converter using BYTE_READER. - explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader) + explicit DumperLineToModule(google_breakpad::ByteReader* byte_reader) : byte_reader_(byte_reader) { } void StartCompilationUnit(const string& compilation_dir) { compilation_dir_ = compilation_dir; } - void ReadProgram(const uint8_t *program, uint64_t length, - Module* module, std::vector<Module::Line>* lines) { - DwarfLineToModule handler(module, compilation_dir_, lines); - dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); + void ReadProgram(const uint8_t* program, + uint64_t length, + const uint8_t* string_section, + uint64_t string_section_length, + const uint8_t* line_string_section, + uint64_t line_string_section_length, + Module* module, + std::vector<Module::Line>* lines, + std::map<uint32_t, Module::File*>* files) { + DwarfLineToModule handler(module, compilation_dir_, lines, files); + google_breakpad::LineInfo parser(program, length, byte_reader_, + string_section, string_section_length, + line_string_section, + line_string_section_length, + &handler); parser.Start(); } private: string compilation_dir_; - dwarf2reader::ByteReader *byte_reader_; + google_breakpad::ByteReader* byte_reader_; }; template<typename ElfClass> +bool IsCompressedHeader(const typename ElfClass::Shdr* section) { + return (section->sh_flags & SHF_COMPRESSED) != 0; +} + +template<typename ElfClass> +uint32_t GetCompressionHeader( + typename ElfClass::Chdr& compression_header, + const uint8_t* content, uint64_t size) { + const typename ElfClass::Chdr* header = + reinterpret_cast<const typename ElfClass::Chdr *>(content); + + if (size < sizeof (*header)) { + return 0; + } + + compression_header = *header; + return sizeof (*header); +} + +std::pair<uint8_t *, uint64_t> UncompressSectionContents( + const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) { + z_stream stream; + memset(&stream, 0, sizeof stream); + + stream.avail_in = compressed_size; + stream.avail_out = uncompressed_size; + stream.next_in = const_cast<uint8_t *>(compressed_buffer); + + google_breakpad::scoped_array<uint8_t> uncompressed_buffer( + new uint8_t[uncompressed_size]); + + int status = inflateInit(&stream); + while (stream.avail_in != 0 && status == Z_OK) { + stream.next_out = + uncompressed_buffer.get() + uncompressed_size - stream.avail_out; + + if ((status = inflate(&stream, Z_FINISH)) != Z_STREAM_END) { + break; + } + + status = inflateReset(&stream); + } + + return inflateEnd(&stream) != Z_OK || status != Z_OK || stream.avail_out != 0 + ? std::make_pair(nullptr, 0) + : std::make_pair(uncompressed_buffer.release(), uncompressed_size); +} + +template<typename ElfClass> bool LoadDwarf(const string& dwarf_filename, const typename ElfClass::Ehdr* elf_header, const bool big_endian, bool handle_inter_cu_refs, + bool handle_inline, Module* module) { typedef typename ElfClass::Shdr Shdr; - const dwarf2reader::Endianness endianness = big_endian ? - dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; - dwarf2reader::ByteReader byte_reader(endianness); + const google_breakpad::Endianness endianness = big_endian ? + google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE; + google_breakpad::ByteReader byte_reader(endianness); // Construct a context for this file. DwarfCUToModule::FileContext file_context(dwarf_filename, @@ -300,29 +358,44 @@ bool LoadDwarf(const string& dwarf_filename, string name = GetOffset<ElfClass, char>(elf_header, section_names->sh_offset) + section->sh_name; - const uint8_t *contents = GetOffset<ElfClass, uint8_t>(elf_header, + const uint8_t* contents = GetOffset<ElfClass, uint8_t>(elf_header, section->sh_offset); - file_context.AddSectionToSectionMap(name, contents, section->sh_size); - } + uint64_t size = section->sh_size; + + if (!IsCompressedHeader<ElfClass>(section)) { + file_context.AddSectionToSectionMap(name, contents, size); + continue; + } + + typename ElfClass::Chdr chdr; - // Optional .debug_ranges reader - scoped_ptr<DumperRangesHandler> ranges_handler; - dwarf2reader::SectionMap::const_iterator ranges_entry = - file_context.section_map().find(".debug_ranges"); - if (ranges_entry != file_context.section_map().end()) { - const std::pair<const uint8_t *, uint64_t>& ranges_section = - ranges_entry->second; - ranges_handler.reset( - new DumperRangesHandler(ranges_section.first, ranges_section.second, - &byte_reader)); + uint32_t compression_header_size = + GetCompressionHeader<ElfClass>(chdr, contents, size); + + if (compression_header_size == 0 || chdr.ch_size == 0) { + continue; + } + + contents += compression_header_size; + size -= compression_header_size; + + std::pair<uint8_t *, uint64_t> uncompressed = + UncompressSectionContents(contents, size, chdr.ch_size); + + if (uncompressed.first != nullptr && uncompressed.second != 0) { + file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second); + } } + // .debug_ranges and .debug_rnglists reader + DumperRangesHandler ranges_handler(&byte_reader); + // Parse all the compilation units in the .debug_info section. DumperLineToModule line_to_module(&byte_reader); - dwarf2reader::SectionMap::const_iterator debug_info_entry = + google_breakpad::SectionMap::const_iterator debug_info_entry = file_context.section_map().find(".debug_info"); assert(debug_info_entry != file_context.section_map().end()); - const std::pair<const uint8_t *, uint64_t>& debug_info_section = + const std::pair<const uint8_t*, uint64_t>& debug_info_section = debug_info_entry->second; // This should never have been called if the file doesn't have a // .debug_info section. @@ -333,11 +406,11 @@ bool LoadDwarf(const string& dwarf_filename, // data that was found. DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset); DwarfCUToModule root_handler(&file_context, &line_to_module, - ranges_handler.get(), &reporter); + &ranges_handler, &reporter, handle_inline); // Make a Dwarf2Handler that drives the DIEHandler. - dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET. - dwarf2reader::CompilationUnit reader(dwarf_filename, + google_breakpad::CompilationUnit reader(dwarf_filename, file_context.section_map(), offset, &byte_reader, @@ -397,18 +470,18 @@ bool LoadDwarfCFI(const string& dwarf_filename, return false; } - const dwarf2reader::Endianness endianness = big_endian ? - dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; + const google_breakpad::Endianness endianness = big_endian ? + google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE; // Find the call frame information and its size. - const uint8_t *cfi = + const uint8_t* cfi = GetOffset<ElfClass, uint8_t>(elf_header, section->sh_offset); size_t cfi_size = section->sh_size; // Plug together the parser, handler, and their entourages. DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name); DwarfCFIToModule handler(module, register_names, &module_reporter); - dwarf2reader::ByteReader byte_reader(endianness); + google_breakpad::ByteReader byte_reader(endianness); byte_reader.SetAddressSize(ElfClass::kAddrSize); @@ -420,11 +493,44 @@ bool LoadDwarfCFI(const string& dwarf_filename, if (text_section) byte_reader.SetTextBase(text_section->sh_addr); - dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename, + google_breakpad::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename, section_name); - dwarf2reader::CallFrameInfo parser(cfi, cfi_size, - &byte_reader, &handler, &dwarf_reporter, - eh_frame); + if (!IsCompressedHeader<ElfClass>(section)) { + google_breakpad::CallFrameInfo parser(cfi, cfi_size, + &byte_reader, &handler, + &dwarf_reporter, eh_frame); + parser.Start(); + return true; + } + + typename ElfClass::Chdr chdr; + uint32_t compression_header_size = + GetCompressionHeader<ElfClass>(chdr, cfi, cfi_size); + + if (compression_header_size == 0 || chdr.ch_size == 0) { + fprintf(stderr, "%s: decompression failed at header\n", + dwarf_filename.c_str()); + return false; + } + if (compression_header_size > cfi_size) { + fprintf(stderr, "%s: decompression error, compression_header too large\n", + dwarf_filename.c_str()); + return false; + } + + cfi += compression_header_size; + cfi_size -= compression_header_size; + + std::pair<uint8_t *, uint64_t> uncompressed = + UncompressSectionContents(cfi, cfi_size, chdr.ch_size); + + if (uncompressed.first == nullptr || uncompressed.second == 0) { + fprintf(stderr, "%s: decompression failed\n", dwarf_filename.c_str()); + return false; + } + google_breakpad::CallFrameInfo parser(uncompressed.first, uncompressed.second, + &byte_reader, &handler, &dwarf_reporter, + eh_frame); parser.Start(); return true; } @@ -489,13 +595,13 @@ bool IsSameFile(const char* left_abspath, const string& right_path) { // Read the .gnu_debuglink and get the debug file name. If anything goes // wrong, return an empty string. -string ReadDebugLink(const uint8_t *debuglink, +string ReadDebugLink(const uint8_t* debuglink, const size_t debuglink_size, const bool big_endian, const string& obj_file, const std::vector<string>& debug_dirs) { // Include '\0' + CRC32 (4 bytes). - size_t debuglink_len = strlen(reinterpret_cast<const char *>(debuglink)) + 5; + size_t debuglink_len = strlen(reinterpret_cast<const char*>(debuglink)) + 5; debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes. // Sanity check. @@ -517,7 +623,7 @@ string ReadDebugLink(const uint8_t *debuglink, for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) { const string& debug_dir = *it; debuglink_path = debug_dir + "/" + - reinterpret_cast<const char *>(debuglink); + reinterpret_cast<const char*>(debuglink); // There is the annoying case of /path/to/foo.so having foo.so as the // debug link file name. Thus this may end up opening /path/to/foo.so again, @@ -533,9 +639,9 @@ string ReadDebugLink(const uint8_t *debuglink, FDWrapper debuglink_fd_wrapper(debuglink_fd); // The CRC is the last 4 bytes in |debuglink|. - const dwarf2reader::Endianness endianness = big_endian ? - dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; - dwarf2reader::ByteReader byte_reader(endianness); + const google_breakpad::Endianness endianness = big_endian ? + google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE; + google_breakpad::ByteReader byte_reader(endianness); uint32_t expected_crc = byte_reader.ReadFourBytes(&debuglink[debuglink_size - 4]); @@ -591,7 +697,7 @@ class LoadSymbolsInfo { // Keeps track of which sections have been loaded so sections don't // accidentally get loaded twice from two different files. - void LoadedSection(const string §ion) { + void LoadedSection(const string& section) { if (loaded_sections_.count(section) == 0) { loaded_sections_.insert(section); } else { @@ -602,7 +708,7 @@ class LoadSymbolsInfo { // The ELF file and linked debug file are expected to have the same preferred // loading address. - void set_loading_addr(Addr addr, const string &filename) { + void set_loading_addr(Addr addr, const string& filename) { if (!has_loading_addr_) { loading_addr_ = addr; loaded_file_ = filename; @@ -679,11 +785,12 @@ bool LoadSymbols(const string& obj_file, const Shdr* section_names = sections + elf_header->e_shstrndx; const char* names = GetOffset<ElfClass, char>(elf_header, section_names->sh_offset); - const char *names_end = names + section_names->sh_size; + const char* names_end = names + section_names->sh_size; bool found_debug_info_section = false; bool found_usable_info = false; - if (options.symbol_data != ONLY_CFI) { + if ((options.symbol_data & SYMBOLS_AND_FILES) || + (options.symbol_data & INLINES)) { #ifndef NO_STABS_SUPPORT // Look for STABS debugging information, and load it if present. const Shdr* stab_section = @@ -705,32 +812,6 @@ bool LoadSymbols(const string& obj_file, } #endif // NO_STABS_SUPPORT - // Look for DWARF debugging information, and load it if present. - const Shdr* dwarf_section = - FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS, - sections, names, names_end, - elf_header->e_shnum); - - // .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains, - // but MIPS_DWARF for regular gnu toolchains, so both need to be checked - if (elf_header->e_machine == EM_MIPS && !dwarf_section) { - dwarf_section = - FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF, - sections, names, names_end, - elf_header->e_shnum); - } - - if (dwarf_section) { - found_debug_info_section = true; - found_usable_info = true; - info->LoadedSection(".debug_info"); - if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian, - options.handle_inter_cu_refs, module)) { - fprintf(stderr, "%s: \".debug_info\" section found, but failed to load " - "DWARF debugging information\n", obj_file.c_str()); - } - } - // See if there are export symbols available. const Shdr* symtab_section = FindElfSectionByName<ElfClass>(".symtab", SHT_SYMTAB, @@ -788,9 +869,38 @@ bool LoadSymbols(const string& obj_file, found_usable_info = found_usable_info || result; } } + + // Only Load .debug_info after loading symbol table to avoid duplicate + // PUBLIC records. + // Look for DWARF debugging information, and load it if present. + const Shdr* dwarf_section = + FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + + // .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains, + // but MIPS_DWARF for regular gnu toolchains, so both need to be checked + if (elf_header->e_machine == EM_MIPS && !dwarf_section) { + dwarf_section = + FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF, + sections, names, names_end, + elf_header->e_shnum); + } + + if (dwarf_section) { + found_debug_info_section = true; + found_usable_info = true; + info->LoadedSection(".debug_info"); + if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian, + options.handle_inter_cu_refs, + options.symbol_data & INLINES, module)) { + fprintf(stderr, "%s: \".debug_info\" section found, but failed to load " + "DWARF debugging information\n", obj_file.c_str()); + } + } } - if (options.symbol_data != NO_CFI) { + if (options.symbol_data & CFI) { // Dwarf Call Frame Information (CFI) is actually independent from // the other DWARF debugging information, and can be used alone. const Shdr* dwarf_cfi_section = @@ -859,7 +969,7 @@ bool LoadSymbols(const string& obj_file, names_end, elf_header->e_shnum); if (gnu_debuglink_section) { if (!info->debug_dirs().empty()) { - const uint8_t *debuglink_contents = + const uint8_t* debuglink_contents = GetOffset<ElfClass, uint8_t>(elf_header, gnu_debuglink_section->sh_offset); string debuglink_file = @@ -947,7 +1057,8 @@ template<typename ElfClass> bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, const string& obj_filename, const string& obj_os, - scoped_ptr<Module>& module) { + scoped_ptr<Module>& module, + bool enable_multiple_field) { PageAllocator allocator; wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize); if (!FileID::ElfFileIdentifierFromMappedFile(elf_header, identifier)) { @@ -956,7 +1067,7 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, return false; } - const char *architecture = ElfArchitecture<ElfClass>(elf_header); + const char* architecture = ElfArchitecture<ElfClass>(elf_header); if (!architecture) { fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n", obj_filename.c_str(), elf_header->e_machine); @@ -976,7 +1087,8 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, // This is just the raw Build ID in hex. string code_id = FileID::ConvertIdentifierToString(identifier); - module.reset(new Module(name, obj_os, architecture, id, code_id)); + module.reset(new Module(name, obj_os, architecture, id, code_id, + enable_multiple_field)); return true; } @@ -993,8 +1105,8 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, *out_module = NULL; scoped_ptr<Module> module; - if (!InitModuleForElfClass<ElfClass>(elf_header, obj_filename, obj_os, - module)) { + if (!InitModuleForElfClass<ElfClass>(elf_header, obj_filename, obj_os, module, + options.enable_multiple_field)) { return false; } @@ -1066,12 +1178,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file, return false; } -bool WriteSymbolFile(const string &load_path, - const string &obj_file, - const string &obj_os, +bool WriteSymbolFile(const string& load_path, + const string& obj_file, + const string& obj_os, const std::vector<string>& debug_dirs, const DumpOptions& options, - std::ostream &sym_stream) { + std::ostream& sym_stream) { Module* module; if (!ReadSymbolData(load_path, obj_file, obj_os, debug_dirs, options, &module)) @@ -1088,7 +1200,7 @@ bool WriteSymbolFile(const string &load_path, bool WriteSymbolFileHeader(const string& load_path, const string& obj_file, const string& obj_os, - std::ostream &sym_stream) { + std::ostream& sym_stream) { MmapWrapper map_wrapper; void* elf_header = NULL; if (!LoadELF(load_path, &map_wrapper, &elf_header)) { @@ -1106,14 +1218,14 @@ bool WriteSymbolFileHeader(const string& load_path, if (elfclass == ELFCLASS32) { if (!InitModuleForElfClass<ElfClass32>( reinterpret_cast<const Elf32_Ehdr*>(elf_header), obj_file, obj_os, - module)) { + module, /*enable_multiple_field=*/false)) { fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); return false; } } else if (elfclass == ELFCLASS64) { if (!InitModuleForElfClass<ElfClass64>( reinterpret_cast<const Elf64_Ehdr*>(elf_header), obj_file, obj_os, - module)) { + module, /*enable_multiple_field=*/false)) { fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); return false; } diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h index eaddd8b2..f1802ecc 100644 --- a/src/common/linux/dump_symbols.h +++ b/src/common/linux/dump_symbols.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,13 +46,16 @@ namespace google_breakpad { class Module; struct DumpOptions { - DumpOptions(SymbolData symbol_data, bool handle_inter_cu_refs) + DumpOptions(SymbolData symbol_data, + bool handle_inter_cu_refs, + bool enable_multiple_field) : symbol_data(symbol_data), - handle_inter_cu_refs(handle_inter_cu_refs) { - } + handle_inter_cu_refs(handle_inter_cu_refs), + enable_multiple_field(enable_multiple_field) {} SymbolData symbol_data; bool handle_inter_cu_refs; + bool enable_multiple_field; }; // Find all the debugging information in OBJ_FILE, an ELF executable @@ -62,12 +64,12 @@ struct DumpOptions { // If OBJ_FILE has been stripped but contains a .gnu_debuglink section, // then look for the debug file in DEBUG_DIRS. // SYMBOL_DATA allows limiting the type of symbol data written. -bool WriteSymbolFile(const string &load_path, - const string &obj_file, - const string &obj_os, +bool WriteSymbolFile(const string& load_path, + const string& obj_file, + const string& obj_os, const std::vector<string>& debug_dirs, const DumpOptions& options, - std::ostream &sym_stream); + std::ostream& sym_stream); // Read the selected object file's debugging information, and write out the // header only to |stream|. Return true on success; if an error occurs, report @@ -76,7 +78,7 @@ bool WriteSymbolFile(const string &load_path, bool WriteSymbolFileHeader(const string& load_path, const string& obj_file, const string& obj_os, - std::ostream &sym_stream); + std::ostream& sym_stream); // As above, but simply return the debugging information in MODULE // instead of writing it to a stream. The caller owns the resulting diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc index 54c21096..97d5827e 100644 --- a/src/common/linux/dump_symbols_unittest.cc +++ b/src/common/linux/dump_symbols_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -92,7 +91,7 @@ TYPED_TEST(DumpSymbols, Invalid) { Elf32_Ehdr header; memset(&header, 0, sizeof(header)); Module* module; - DumpOptions options(ALL_SYMBOL_DATA, true); + DumpOptions options(ALL_SYMBOL_DATA, true, false); EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header), "foo", "Linux", @@ -129,7 +128,7 @@ TYPED_TEST(DumpSymbols, SimplePublic) { this->GetElfContents(elf); Module* module; - DumpOptions options(ALL_SYMBOL_DATA, true); + DumpOptions options(ALL_SYMBOL_DATA, true, false); EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, "foo", "Linux", @@ -186,7 +185,7 @@ TYPED_TEST(DumpSymbols, SimpleBuildID) { this->GetElfContents(elf); Module* module; - DumpOptions options(ALL_SYMBOL_DATA, true); + DumpOptions options(ALL_SYMBOL_DATA, true, false); EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, "foo", "Linux", diff --git a/src/common/linux/eintr_wrapper.h b/src/common/linux/eintr_wrapper.h index 3f1d1848..a8428a9d 100644 --- a/src/common/linux/eintr_wrapper.h +++ b/src/common/linux/eintr_wrapper.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/elf_core_dump.cc b/src/common/linux/elf_core_dump.cc index 0e7db7b1..f5ee3033 100644 --- a/src/common/linux/elf_core_dump.cc +++ b/src/common/linux/elf_core_dump.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -34,6 +33,7 @@ #include <stddef.h> #include <string.h> +#include <unistd.h> namespace google_breakpad { @@ -95,16 +95,29 @@ size_t ElfCoreDump::Note::AlignedSize(size_t size) { // Implementation of ElfCoreDump. -ElfCoreDump::ElfCoreDump() {} +ElfCoreDump::ElfCoreDump() : proc_mem_fd_(-1) {} ElfCoreDump::ElfCoreDump(const MemoryRange& content) - : content_(content) { + : content_(content), proc_mem_fd_(-1) {} + +ElfCoreDump::~ElfCoreDump() { + if (proc_mem_fd_ != -1) { + close(proc_mem_fd_); + proc_mem_fd_ = -1; + } } void ElfCoreDump::SetContent(const MemoryRange& content) { content_ = content; } +void ElfCoreDump::SetProcMem(int fd) { + if (proc_mem_fd_ != -1) { + close(proc_mem_fd_); + } + proc_mem_fd_ = fd; +} + bool ElfCoreDump::IsValid() const { const Ehdr* header = GetHeader(); return (header && @@ -163,6 +176,16 @@ bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) { } } } + + /* fallback: if available, read from /proc/<pid>/mem */ + if (proc_mem_fd_ != -1) { + off_t offset = virtual_address; + ssize_t r = pread(proc_mem_fd_, buffer, length, offset); + if (r < ssize_t(length)) { + return false; + } + return true; + } return false; } diff --git a/src/common/linux/elf_core_dump.h b/src/common/linux/elf_core_dump.h index 6e153745..4f27179f 100644 --- a/src/common/linux/elf_core_dump.h +++ b/src/common/linux/elf_core_dump.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -106,6 +105,8 @@ class ElfCoreDump { // Constructor that takes the core dump content from |content|. explicit ElfCoreDump(const MemoryRange& content); + ~ElfCoreDump(); + // Sets the core dump content to |content|. void SetContent(const MemoryRange& content); @@ -139,9 +140,15 @@ class ElfCoreDump { // an empty note if no note is found. Note GetFirstNote() const; + // Sets the mem fd. + void SetProcMem(const int fd); + private: // Core dump content. MemoryRange content_; + + // Descriptor for /proc/<pid>/mem. + int proc_mem_fd_; }; } // namespace google_breakpad diff --git a/src/common/linux/elf_core_dump_unittest.cc b/src/common/linux/elf_core_dump_unittest.cc index 2399c12f..6789dd84 100644 --- a/src/common/linux/elf_core_dump_unittest.cc +++ b/src/common/linux/elf_core_dump_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -130,9 +129,13 @@ TEST(ElfCoreDumpTest, TestElfHeader) { TEST(ElfCoreDumpTest, ValidCoreFile) { CrashGenerator crash_generator; if (!crash_generator.HasDefaultCorePattern()) { - fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " - "due to non-default core pattern"); - return; + GTEST_SKIP() << "ElfCoreDumpTest.ValidCoreFile test is skipped " + "due to non-default core pattern"; + } + + if (!crash_generator.HasResourceLimitsAmenableToCrashCollection()) { + GTEST_SKIP() << "ElfCoreDumpTest.ValidCoreFile test is skipped " + "due to inadequate system resource limits"; } const unsigned kNumOfThreads = 3; diff --git a/src/common/linux/elf_gnu_compat.h b/src/common/linux/elf_gnu_compat.h index 0a3dfedb..5d56c1e9 100644 --- a/src/common/linux/elf_gnu_compat.h +++ b/src/common/linux/elf_gnu_compat.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc index 562875e1..3c33be99 100644 --- a/src/common/linux/elf_symbols_to_module.cc +++ b/src/common/linux/elf_symbols_to_module.cc @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2011 Google Inc. All Rights Reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -36,6 +36,9 @@ #include <elf.h> #include <string.h> +#include <memory> +#include <utility> + #include "common/byte_cursor.h" #include "common/module.h" @@ -69,7 +72,7 @@ public: // otherwise. Assume each symbol has a 'value' field whose size is // VALUE_SIZE. // - ELFSymbolIterator(const ByteBuffer *buffer, bool big_endian, + ELFSymbolIterator(const ByteBuffer* buffer, bool big_endian, size_t value_size) : value_size_(value_size), cursor_(buffer, big_endian) { // Actually, weird sizes could be handled just fine, but they're @@ -81,13 +84,13 @@ public: // Move to the next symbol. This function's behavior is undefined if // at_end() is true when it is called. - ELFSymbolIterator &operator++() { Fetch(); symbol_.index++; return *this; } + ELFSymbolIterator& operator++() { Fetch(); symbol_.index++; return *this; } // Dereferencing this iterator produces a reference to an Symbol structure // that holds the current symbol's values. The symbol is owned by this // SymbolIterator, and will be invalidated at the next call to operator++. - const Symbol &operator*() const { return symbol_; } - const Symbol *operator->() const { return &symbol_; } + const Symbol& operator*() const { return symbol_; } + const Symbol* operator->() const { return &symbol_; } private: // Read the symbol at cursor_, and set symbol_ appropriately. @@ -126,21 +129,21 @@ private: Symbol symbol_; }; -const char *SymbolString(ptrdiff_t offset, ByteBuffer& strings) { +const char* SymbolString(ptrdiff_t offset, ByteBuffer& strings) { if (offset < 0 || (size_t) offset >= strings.Size()) { // Return the null string. offset = 0; } - return reinterpret_cast<const char *>(strings.start + offset); + return reinterpret_cast<const char*>(strings.start + offset); } -bool ELFSymbolsToModule(const uint8_t *symtab_section, +bool ELFSymbolsToModule(const uint8_t* symtab_section, size_t symtab_size, - const uint8_t *string_section, + const uint8_t* string_section, size_t string_size, const bool big_endian, size_t value_size, - Module *module) { + Module* module) { ByteBuffer symbols(symtab_section, symtab_size); // Ensure that the string section is null-terminated. if (string_section[string_size - 1] != '\0') { @@ -156,7 +159,7 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section, while(!iterator->at_end) { if (ELF32_ST_TYPE(iterator->info) == STT_FUNC && iterator->shndx != SHN_UNDEF) { - Module::Extern *ext = new Module::Extern(iterator->value); + auto ext = std::make_unique<Module::Extern>(iterator->value); ext->name = SymbolString(iterator->name_offset, strings); #if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle. int status = 0; @@ -168,7 +171,7 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section, free(demangled); } #endif - module->AddExtern(ext); + module->AddExtern(std::move(ext)); } ++iterator; } diff --git a/src/common/linux/elf_symbols_to_module.h b/src/common/linux/elf_symbols_to_module.h index 2e7c0971..ab27ef6b 100644 --- a/src/common/linux/elf_symbols_to_module.h +++ b/src/common/linux/elf_symbols_to_module.h @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2011 Google Inc. All Rights Reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,13 +44,13 @@ namespace google_breakpad { class Module; -bool ELFSymbolsToModule(const uint8_t *symtab_section, +bool ELFSymbolsToModule(const uint8_t* symtab_section, size_t symtab_size, - const uint8_t *string_section, + const uint8_t* string_section, size_t string_size, const bool big_endian, size_t value_size, - Module *module); + Module* module); } // namespace google_breakpad diff --git a/src/common/linux/elf_symbols_to_module_unittest.cc b/src/common/linux/elf_symbols_to_module_unittest.cc index 8984449a..17eb670f 100644 --- a/src/common/linux/elf_symbols_to_module_unittest.cc +++ b/src/common/linux/elf_symbols_to_module_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -86,7 +85,7 @@ public: // 4 or 8 (bytes) size_t value_size; - vector<Module::Extern *> externs; + vector<Module::Extern*> externs; }; class ELFSymbolsToModuleTest32 : public ELFSymbolsToModuleTestFixture, @@ -248,9 +247,9 @@ TEST_P(ELFSymbolsToModuleTest32, SkipStuff) { } // Run all the 32-bit tests with both endianness -INSTANTIATE_TEST_CASE_P(Endian, - ELFSymbolsToModuleTest32, - ::testing::Values(kLittleEndian, kBigEndian)); +INSTANTIATE_TEST_SUITE_P(Endian, + ELFSymbolsToModuleTest32, + ::testing::Values(kLittleEndian, kBigEndian)); // Similar tests, but with 64-bit values. Ostensibly this could be // shoehorned into the parameterization by using ::testing::Combine, @@ -365,6 +364,6 @@ TEST_P(ELFSymbolsToModuleTest64, SkipStuff) { } // Run all the 64-bit tests with both endianness -INSTANTIATE_TEST_CASE_P(Endian, - ELFSymbolsToModuleTest64, - ::testing::Values(kLittleEndian, kBigEndian)); +INSTANTIATE_TEST_SUITE_P(Endian, + ELFSymbolsToModuleTest64, + ::testing::Values(kLittleEndian, kBigEndian)); diff --git a/src/common/linux/elfutils-inl.h b/src/common/linux/elfutils-inl.h index e56b37a9..5fcc9c44 100644 --- a/src/common/linux/elfutils-inl.h +++ b/src/common/linux/elfutils-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/elfutils.cc b/src/common/linux/elfutils.cc index 9532d5ad..a68cc0af 100644 --- a/src/common/linux/elfutils.cc +++ b/src/common/linux/elfutils.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,11 +39,11 @@ namespace google_breakpad { namespace { template<typename ElfClass> -void FindElfClassSection(const char *elf_base, - const char *section_name, +void FindElfClassSection(const char* elf_base, + const char* section_name, typename ElfClass::Word section_type, - const void **section_start, - size_t *section_size) { + const void** section_start, + size_t* section_size) { typedef typename ElfClass::Ehdr Ehdr; typedef typename ElfClass::Shdr Shdr; @@ -57,12 +56,18 @@ void FindElfClassSection(const char *elf_base, const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base); assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); + if (elf_header->e_shoff == 0) { + *section_start = NULL; + *section_size = 0; + return; + } + const Shdr* sections = 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); - const char *names_end = names + section_names->sh_size; + const char* names_end = names + section_names->sh_size; const Shdr* section = FindElfSectionByName<ElfClass>(section_name, section_type, @@ -76,9 +81,9 @@ void FindElfClassSection(const char *elf_base, } template<typename ElfClass> -void FindElfClassSegment(const char *elf_base, +void FindElfClassSegment(const char* elf_base, typename ElfClass::Word segment_type, - wasteful_vector<ElfSegment> *segments) { + wasteful_vector<ElfSegment>* segments) { typedef typename ElfClass::Ehdr Ehdr; typedef typename ElfClass::Phdr Phdr; @@ -117,11 +122,11 @@ int ElfClass(const void* elf_base) { return elf_header->e_ident[EI_CLASS]; } -bool FindElfSection(const void *elf_mapped_base, - const char *section_name, +bool FindElfSection(const void* elf_mapped_base, + const char* section_name, uint32_t section_type, - const void **section_start, - size_t *section_size) { + const void** section_start, + size_t* section_size) { assert(elf_mapped_base); assert(section_start); assert(section_size); diff --git a/src/common/linux/elfutils.h b/src/common/linux/elfutils.h index aefb6cf5..130a8ac1 100644 --- a/src/common/linux/elfutils.h +++ b/src/common/linux/elfutils.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -41,6 +40,39 @@ namespace google_breakpad { +typedef struct Elf32_Chdr { + typedef Elf32_Word Type; + typedef Elf32_Word Size; + typedef Elf32_Addr Addr; + + static_assert(sizeof (Type) == 4); + static_assert(sizeof (Size) == 4); + static_assert(sizeof (Addr) == 4); + + Type ch_type; // Compression type + Size ch_size; // Uncompressed data size in bytes + Addr ch_addralign; // Uncompressed data alignment +} Elf32_Chdr; + +static_assert(sizeof (Elf32_Chdr) == 12); + +typedef struct Elf64_Chdr { + typedef Elf64_Word Type; + typedef Elf64_Xword Size; + typedef Elf64_Addr Addr; + + static_assert(sizeof (Type) == 4); + static_assert(sizeof (Size) == 8); + static_assert(sizeof (Addr) == 8); + + Type ch_type; // Compression type + Type ch_reserved; // Padding + Size ch_size; // Uncompressed data size in bytes + Addr ch_addralign; // Uncompressed data alignment +} Elf64_Chdr; + +static_assert(sizeof (Elf64_Chdr) == 24); + // Traits classes so consumers can write templatized code to deal // with specific ELF bits. struct ElfClass32 { @@ -50,6 +82,7 @@ struct ElfClass32 { typedef Elf32_Nhdr Nhdr; typedef Elf32_Phdr Phdr; typedef Elf32_Shdr Shdr; + typedef Elf32_Chdr Chdr; typedef Elf32_Half Half; typedef Elf32_Off Off; typedef Elf32_Sym Sym; @@ -68,6 +101,7 @@ struct ElfClass64 { typedef Elf64_Nhdr Nhdr; typedef Elf64_Phdr Phdr; typedef Elf64_Shdr Shdr; + typedef Elf64_Chdr Chdr; typedef Elf64_Half Half; typedef Elf64_Off Off; typedef Elf64_Sym Sym; @@ -86,11 +120,11 @@ int ElfClass(const void* elf_base); // in the ELF binary data at |elf_mapped_base|. On success, returns true // and sets |*section_start| to point to the start of the section data, // and |*section_size| to the size of the section's data. -bool FindElfSection(const void *elf_mapped_base, - const char *section_name, +bool FindElfSection(const void* elf_mapped_base, + const char* section_name, uint32_t section_type, - const void **section_start, - size_t *section_size); + const void** section_start, + size_t* section_size); // Internal helper method, exposed for convenience for callers // that already have more info. diff --git a/src/common/linux/file_id.cc b/src/common/linux/file_id.cc index 67921c45..0bd2a759 100644 --- a/src/common/linux/file_id.cc +++ b/src/common/linux/file_id.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -49,6 +48,7 @@ #include "third_party/lss/linux_syscall_support.h" namespace google_breakpad { +namespace elf { // Used in a few places for backwards-compatibility. const size_t kMDGUIDSize = sizeof(MDGUID); @@ -61,7 +61,7 @@ FileID::FileID(const char* path) : path_(path) {} // These functions are also used inside the crashed process, so be safe // and use the syscall/libc wrappers instead of direct syscalls or libc. -static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, +static bool ElfClassBuildIDNoteIdentifier(const void* section, size_t length, wasteful_vector<uint8_t>& identifier) { static_assert(sizeof(ElfClass32::Nhdr) == sizeof(ElfClass64::Nhdr), "Elf32_Nhdr and Elf64_Nhdr should be the same"); @@ -69,7 +69,7 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, const void* section_end = reinterpret_cast<const char*>(section) + length; const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section); - while (reinterpret_cast<const void *>(note_header) < section_end) { + while (reinterpret_cast<const void*>(note_header) < section_end) { if (note_header->n_type == NT_GNU_BUILD_ID) break; note_header = reinterpret_cast<const Nhdr*>( @@ -77,7 +77,7 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, NOTE_PADDING(note_header->n_namesz) + NOTE_PADDING(note_header->n_descsz)); } - if (reinterpret_cast<const void *>(note_header) >= section_end || + if (reinterpret_cast<const void*>(note_header) >= section_end || note_header->n_descsz == 0) { return false; } @@ -198,4 +198,5 @@ string FileID::ConvertIdentifierToString( return bytes_to_hex_string(&identifier[0], identifier.size()); } +} // elf } // namespace google_breakpad diff --git a/src/common/linux/file_id.h b/src/common/linux/file_id.h index 4aff021d..8e58d56e 100644 --- a/src/common/linux/file_id.h +++ b/src/common/linux/file_id.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -41,6 +40,7 @@ #include "common/using_std_string.h" namespace google_breakpad { +namespace elf { // GNU binutils' ld defaults to 'sha1', which is 160 bits == 20 bytes, // so this is enough to fit that, which most binaries will use. @@ -83,6 +83,7 @@ class FileID { string path_; }; +} // namespace elf } // namespace google_breakpad #endif // COMMON_LINUX_FILE_ID_H__ diff --git a/src/common/linux/file_id_unittest.cc b/src/common/linux/file_id_unittest.cc index f4f9ac45..74bf9e1b 100644 --- a/src/common/linux/file_id_unittest.cc +++ b/src/common/linux/file_id_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -30,7 +29,10 @@ // Unit tests for FileID #include <elf.h> +#include <spawn.h> #include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> #include <string> #include <vector> @@ -42,10 +44,13 @@ #include "common/linux/synth_elf.h" #include "common/test_assembler.h" #include "common/tests/auto_tempdir.h" +#include "common/tests/file_utils.h" #include "common/using_std_string.h" #include "breakpad_googletest_includes.h" using namespace google_breakpad; +using google_breakpad::elf::FileID; +using google_breakpad::elf::kDefaultBuildIdSize; using google_breakpad::synth_elf::ELF; using google_breakpad::synth_elf::Notes; using google_breakpad::test_assembler::kLittleEndian; @@ -80,13 +85,18 @@ TEST(FileIDStripTest, StripSelf) { // copy our binary to a temp file, and strip it AutoTempDir temp_dir; string templ = temp_dir.path() + "/file-id-unittest"; - char cmdline[4096]; - sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ.c_str()); - ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; - sprintf(cmdline, "chmod u+w \"%s\"", templ.c_str()); - ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; - sprintf(cmdline, "strip \"%s\"", templ.c_str()); - ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; + ASSERT_TRUE(CopyFile(exe_name, templ)); + pid_t pid; + char* argv[] = { + const_cast<char*>("strip"), + const_cast<char*>(templ.c_str()), + nullptr, + }; + ASSERT_EQ(0, posix_spawnp(&pid, argv[0], nullptr, nullptr, argv, nullptr)); + int status; + ASSERT_EQ(pid, waitpid(pid, &status, 0)); + ASSERT_TRUE(WIFEXITED(status)); + ASSERT_EQ(0, WEXITSTATUS(status)); PageAllocator allocator; id_vector identifier1(&allocator, kDefaultBuildIdSize); @@ -261,7 +271,7 @@ TYPED_TEST(FileIDTest, BuildIDPH) { elf.AddSection(".text", text, SHT_PROGBITS); Notes notes(kLittleEndian); notes.AddNote(0, "Linux", - reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4); + reinterpret_cast<const uint8_t*>("\0x42\0x02\0\0"), 4); notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, sizeof(kExpectedIdentifierBytes)); int note_idx = elf.AddSection(".note", notes, SHT_NOTE); @@ -292,7 +302,7 @@ TYPED_TEST(FileIDTest, BuildIDMultiplePH) { elf.AddSection(".text", text, SHT_PROGBITS); Notes notes1(kLittleEndian); notes1.AddNote(0, "Linux", - reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4); + reinterpret_cast<const uint8_t*>("\0x42\0x02\0\0"), 4); Notes notes2(kLittleEndian); notes2.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, sizeof(kExpectedIdentifierBytes)); diff --git a/src/common/linux/google_crashdump_uploader.cc b/src/common/linux/google_crashdump_uploader.cc index a0d940b6..6242e6d2 100644 --- a/src/common/linux/google_crashdump_uploader.cc +++ b/src/common/linux/google_crashdump_uploader.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -35,6 +34,7 @@ #include <unistd.h> #include <iostream> +#include <utility> #include "common/using_std_string.h" @@ -51,7 +51,7 @@ GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product, const string& crash_server, const string& proxy_host, const string& proxy_userpassword) { - LibcurlWrapper* http_layer = new LibcurlWrapper(); + std::unique_ptr<LibcurlWrapper> http_layer{new LibcurlWrapper()}; Init(product, version, guid, @@ -63,21 +63,22 @@ GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product, crash_server, proxy_host, proxy_userpassword, - http_layer); + std::move(http_layer)); } -GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product, - const string& version, - const string& guid, - const string& ptime, - const string& ctime, - const string& email, - const string& comments, - const string& minidump_pathname, - const string& crash_server, - const string& proxy_host, - const string& proxy_userpassword, - LibcurlWrapper* http_layer) { +GoogleCrashdumpUploader::GoogleCrashdumpUploader( + const string& product, + const string& version, + const string& guid, + const string& ptime, + const string& ctime, + const string& email, + const string& comments, + const string& minidump_pathname, + const string& crash_server, + const string& proxy_host, + const string& proxy_userpassword, + std::unique_ptr<LibcurlWrapper> http_layer) { Init(product, version, guid, @@ -89,7 +90,7 @@ GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product, crash_server, proxy_host, proxy_userpassword, - http_layer); + std::move(http_layer)); } void GoogleCrashdumpUploader::Init(const string& product, @@ -103,7 +104,7 @@ void GoogleCrashdumpUploader::Init(const string& product, const string& crash_server, const string& proxy_host, const string& proxy_userpassword, - LibcurlWrapper* http_layer) { + std::unique_ptr<LibcurlWrapper> http_layer) { product_ = product; version_ = version; guid_ = guid; @@ -111,7 +112,7 @@ void GoogleCrashdumpUploader::Init(const string& product, ctime_ = ctime; email_ = email; comments_ = comments; - http_layer_.reset(http_layer); + http_layer_ = std::move(http_layer); crash_server_ = crash_server; proxy_host_ = proxy_host; diff --git a/src/common/linux/google_crashdump_uploader.h b/src/common/linux/google_crashdump_uploader.h index a2d0575b..74b5e1be 100644 --- a/src/common/linux/google_crashdump_uploader.h +++ b/src/common/linux/google_crashdump_uploader.h @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,11 +30,11 @@ #ifndef COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ #define COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ -#include <string> #include <map> +#include <memory> +#include <string> #include "common/linux/libcurl_wrapper.h" -#include "common/scoped_ptr.h" #include "common/using_std_string.h" namespace google_breakpad { @@ -65,7 +64,7 @@ class GoogleCrashdumpUploader { const string& crash_server, const string& proxy_host, const string& proxy_userpassword, - LibcurlWrapper* http_layer); + std::unique_ptr<LibcurlWrapper> http_layer); void Init(const string& product, const string& version, @@ -78,7 +77,7 @@ class GoogleCrashdumpUploader { const string& crash_server, const string& proxy_host, const string& proxy_userpassword, - LibcurlWrapper* http_layer); + std::unique_ptr<LibcurlWrapper> http_layer); bool Upload(int* http_status_code, string* http_response_header, string* http_response_body); @@ -86,7 +85,7 @@ class GoogleCrashdumpUploader { private: bool CheckRequiredParametersArePresent(); - scoped_ptr<LibcurlWrapper> http_layer_; + std::unique_ptr<LibcurlWrapper> http_layer_; string product_; string version_; string guid_; diff --git a/src/common/linux/google_crashdump_uploader_test.cc b/src/common/linux/google_crashdump_uploader_test.cc index 3d6612e8..39aab65d 100644 --- a/src/common/linux/google_crashdump_uploader_test.cc +++ b/src/common/linux/google_crashdump_uploader_test.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -59,21 +58,12 @@ class GoogleCrashdumpUploaderTest : public ::testing::Test { }; TEST_F(GoogleCrashdumpUploaderTest, InitFailsCausesUploadFailure) { - MockLibcurlWrapper m; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(false)); - GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", - "1.0", - "AAA-BBB", - "", - "", - "test@test.com", - "none", - "/tmp/foo.dmp", - "http://foo.com", - "", - "", - &m); - ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL)); + std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()}; + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(false)); + GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "", + "test@test.com", "none", "/tmp/foo.dmp", + "http://foo.com", "", "", std::move(m)); + ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL)); } TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { @@ -83,44 +73,27 @@ TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { ASSERT_NE(fd, -1); close(fd); - MockLibcurlWrapper m; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - EXPECT_CALL(m, AddFile(tempfn, _)).WillOnce(Return(true)); - EXPECT_CALL(m, - SendRequest("http://foo.com",_,_,_,_)).Times(1).WillOnce(Return(true)); - GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", - "1.0", - "AAA-BBB", - "", - "", - "test@test.com", - "none", - tempfn, - "http://foo.com", - "", - "", - &m); - ASSERT_TRUE(uploader->Upload(NULL, NULL, NULL)); + std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()}; + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*m, AddFile(tempfn, _)).WillOnce(Return(true)); + EXPECT_CALL(*m, SendRequest("http://foo.com", _, _, _, _)) + .Times(1) + .WillOnce(Return(true)); + GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "", + "test@test.com", "none", tempfn, + "http://foo.com", "", "", std::move(m)); + ASSERT_TRUE(uploader.Upload(NULL, NULL, NULL)); } TEST_F(GoogleCrashdumpUploaderTest, InvalidPathname) { - MockLibcurlWrapper m; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - EXPECT_CALL(m, SendRequest(_,_,_,_,_)).Times(0); - GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", - "1.0", - "AAA-BBB", - "", - "", - "test@test.com", - "none", - "/tmp/foo.dmp", - "http://foo.com", - "", - "", - &m); - ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL)); + std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()}; + EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*m, SendRequest(_,_,_,_,_)).Times(0); + GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "", + "test@test.com", "none", "/tmp/foo.dmp", + "http://foo.com", "", "", std::move(m)); + ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL)); } TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { diff --git a/src/common/linux/guid_creator.cc b/src/common/linux/guid_creator.cc index 03e3d781..31a326c7 100644 --- a/src/common/linux/guid_creator.cc +++ b/src/common/linux/guid_creator.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -105,7 +104,7 @@ class GUIDGenerator { private: #ifdef HAVE_ARC4RANDOM static void CreateGuidFromArc4Random(GUID *guid) { - char *buf = reinterpret_cast<char *>(guid); + char *buf = reinterpret_cast<char*>(guid); for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) { uint32_t random_data = arc4random(); @@ -129,7 +128,7 @@ class GUIDGenerator { #if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM) static bool CreateGUIDFromGetrandom(GUID *guid) { - char *buf = reinterpret_cast<char *>(guid); + char *buf = reinterpret_cast<char*>(guid); int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK); return (read_bytes == static_cast<int>(sizeof(GUID))); @@ -139,7 +138,7 @@ class GUIDGenerator { // Populate the GUID using random bytes read from /dev/urandom, returns false // if the GUID wasn't fully populated with random data. static bool CreateGUIDFromDevUrandom(GUID *guid) { - char *buf = reinterpret_cast<char *>(guid); + char *buf = reinterpret_cast<char*>(guid); int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); if (fd == -1) { @@ -154,7 +153,7 @@ class GUIDGenerator { // Populate the GUID using a stream of random bytes obtained from rand(). static void CreateGUIDFromRand(GUID *guid) { - char *buf = reinterpret_cast<char *>(guid); + char *buf = reinterpret_cast<char*>(guid); InitOnce(); diff --git a/src/common/linux/guid_creator.h b/src/common/linux/guid_creator.h index c86d856c..c02f5552 100644 --- a/src/common/linux/guid_creator.h +++ b/src/common/linux/guid_creator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/http_upload.cc b/src/common/linux/http_upload.cc index 702526af..1b576ea6 100644 --- a/src/common/linux/http_upload.cc +++ b/src/common/linux/http_upload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -36,14 +35,14 @@ namespace { // Callback to get the response data from server. -static size_t WriteCallback(void *ptr, size_t size, - size_t nmemb, void *userp) { +static size_t WriteCallback(void* ptr, size_t size, + size_t nmemb, void* userp) { if (!userp) return 0; - string *response = reinterpret_cast<string *>(userp); + string* response = reinterpret_cast<string*>(userp); size_t real_size = size * nmemb; - response->append(reinterpret_cast<char *>(ptr), real_size); + response->append(reinterpret_cast<char*>(ptr), real_size); return real_size; } @@ -54,15 +53,15 @@ namespace google_breakpad { static const char kUserAgent[] = "Breakpad/1.0 (Linux)"; // static -bool HTTPUpload::SendRequest(const string &url, - const map<string, string> ¶meters, - const map<string, string> &files, - const string &proxy, - const string &proxy_user_pwd, - const string &ca_certificate_file, - string *response_body, - long *response_code, - string *error_description) { +bool HTTPUpload::SendRequest(const string& url, + const map<string, string>& parameters, + const map<string, string>& files, + const string& proxy, + const string& proxy_user_pwd, + const string& ca_certificate_file, + string* response_body, + long* response_code, + string* error_description) { if (response_code != NULL) *response_code = 0; @@ -101,7 +100,7 @@ bool HTTPUpload::SendRequest(const string &url, CURL* (*curl_easy_init)(void); *(void**) (&curl_easy_init) = dlsym(curl_lib, "curl_easy_init"); - CURL *curl = (*curl_easy_init)(); + CURL* curl = (*curl_easy_init)(); if (error_description != NULL) *error_description = "No Error"; @@ -111,7 +110,7 @@ bool HTTPUpload::SendRequest(const string &url, } CURLcode err_code = CURLE_OK; - CURLcode (*curl_easy_setopt)(CURL *, CURLoption, ...); + CURLcode (*curl_easy_setopt)(CURL*, CURLoption, ...); *(void**) (&curl_easy_setopt) = dlsym(curl_lib, "curl_easy_setopt"); (*curl_easy_setopt)(curl, CURLOPT_URL, url.c_str()); (*curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent); @@ -128,10 +127,10 @@ bool HTTPUpload::SendRequest(const string &url, if (!ca_certificate_file.empty()) (*curl_easy_setopt)(curl, CURLOPT_CAINFO, ca_certificate_file.c_str()); - struct curl_httppost *formpost = NULL; - struct curl_httppost *lastptr = NULL; + struct curl_httppost* formpost = NULL; + struct curl_httppost* lastptr = NULL; // Add form data. - CURLFORMcode (*curl_formadd)(struct curl_httppost **, struct curl_httppost **, ...); + CURLFORMcode (*curl_formadd)(struct curl_httppost**, struct curl_httppost**, ...); *(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd"); map<string, string>::const_iterator iter = parameters.begin(); for (; iter != parameters.end(); ++iter) @@ -151,9 +150,9 @@ bool HTTPUpload::SendRequest(const string &url, (*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost); // Disable 100-continue header. - struct curl_slist *headerlist = NULL; + struct curl_slist* headerlist = NULL; char buf[] = "Expect:"; - struct curl_slist* (*curl_slist_append)(struct curl_slist *, const char *); + struct curl_slist* (*curl_slist_append)(struct curl_slist*, const char*); *(void**) (&curl_slist_append) = dlsym(curl_lib, "curl_slist_append"); headerlist = (*curl_slist_append)(headerlist, buf); (*curl_easy_setopt)(curl, CURLOPT_HTTPHEADER, headerlist); @@ -161,17 +160,17 @@ bool HTTPUpload::SendRequest(const string &url, if (response_body != NULL) { (*curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback); (*curl_easy_setopt)(curl, CURLOPT_WRITEDATA, - reinterpret_cast<void *>(response_body)); + reinterpret_cast<void*>(response_body)); } // Fail if 400+ is returned from the web server. (*curl_easy_setopt)(curl, CURLOPT_FAILONERROR, 1); - CURLcode (*curl_easy_perform)(CURL *); + CURLcode (*curl_easy_perform)(CURL*); *(void**) (&curl_easy_perform) = dlsym(curl_lib, "curl_easy_perform"); err_code = (*curl_easy_perform)(curl); if (response_code != NULL) { - CURLcode (*curl_easy_getinfo)(CURL *, CURLINFO, ...); + CURLcode (*curl_easy_getinfo)(CURL*, CURLINFO, ...); *(void**) (&curl_easy_getinfo) = dlsym(curl_lib, "curl_easy_getinfo"); (*curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code); } @@ -186,16 +185,16 @@ bool HTTPUpload::SendRequest(const string &url, if (error_description != NULL) *error_description = (*curl_easy_strerror)(err_code); - void (*curl_easy_cleanup)(CURL *); + void (*curl_easy_cleanup)(CURL*); *(void**) (&curl_easy_cleanup) = dlsym(curl_lib, "curl_easy_cleanup"); (*curl_easy_cleanup)(curl); if (formpost != NULL) { - void (*curl_formfree)(struct curl_httppost *); + void (*curl_formfree)(struct curl_httppost*); *(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree"); (*curl_formfree)(formpost); } if (headerlist != NULL) { - void (*curl_slist_free_all)(struct curl_slist *); + void (*curl_slist_free_all)(struct curl_slist*); *(void**) (&curl_slist_free_all) = dlsym(curl_lib, "curl_slist_free_all"); (*curl_slist_free_all)(headerlist); } @@ -211,10 +210,10 @@ bool HTTPUpload::CheckCurlLib(void* curl_lib) { } // static -bool HTTPUpload::CheckParameters(const map<string, string> ¶meters) { +bool HTTPUpload::CheckParameters(const map<string, string>& parameters) { for (map<string, string>::const_iterator pos = parameters.begin(); pos != parameters.end(); ++pos) { - const string &str = pos->first; + const string& str = pos->first; if (str.size() == 0) return false; // disallow empty parameter names for (unsigned int i = 0; i < str.size(); ++i) { diff --git a/src/common/linux/http_upload.h b/src/common/linux/http_upload.h index bc1d5d57..b7e557a0 100644 --- a/src/common/linux/http_upload.h +++ b/src/common/linux/http_upload.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -58,21 +57,21 @@ class HTTPUpload { // received (or 0 if the request failed before getting an HTTP response). // If the send fails, a description of the error will be // returned in error_description. - static bool SendRequest(const string &url, - const map<string, string> ¶meters, - const map<string, string> &files, - const string &proxy, - const string &proxy_user_pwd, - const string &ca_certificate_file, - string *response_body, - long *response_code, - string *error_description); + static bool SendRequest(const string& url, + const map<string, string>& parameters, + const map<string, string>& files, + const string& proxy, + const string& proxy_user_pwd, + const string& ca_certificate_file, + string* response_body, + long* response_code, + string* error_description); private: // Checks that the given list of parameters has only printable // ASCII characters in the parameter name, and does not contain // any quote (") characters. Returns true if so. - static bool CheckParameters(const map<string, string> ¶meters); + static bool CheckParameters(const map<string, string>& parameters); // Checks the curl_lib parameter points to a valid curl lib. static bool CheckCurlLib(void* curl_lib); @@ -80,8 +79,8 @@ class HTTPUpload { // No instances of this class should be created. // Disallow all constructors, destructors, and operator=. HTTPUpload(); - explicit HTTPUpload(const HTTPUpload &); - void operator=(const HTTPUpload &); + explicit HTTPUpload(const HTTPUpload&); + void operator=(const HTTPUpload&); ~HTTPUpload(); }; diff --git a/src/common/linux/ignore_ret.h b/src/common/linux/ignore_ret.h index efd274c2..1f879e8f 100644 --- a/src/common/linux/ignore_ret.h +++ b/src/common/linux/ignore_ret.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012 Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/libcurl_wrapper.cc b/src/common/linux/libcurl_wrapper.cc index e96c2038..a53087d9 100644 --- a/src/common/linux/libcurl_wrapper.cc +++ b/src/common/linux/libcurl_wrapper.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -48,6 +47,7 @@ LibcurlWrapper::LibcurlWrapper() LibcurlWrapper::~LibcurlWrapper() { if (init_ok_) { (*easy_cleanup_)(curl_); + (*global_cleanup_)(); dlclose(curl_lib_); } } @@ -88,14 +88,14 @@ bool LibcurlWrapper::AddFile(const string& upload_file_path, } // Callback to get the response data from server. -static size_t WriteCallback(void *ptr, size_t size, - size_t nmemb, void *userp) { +static size_t WriteCallback(void* ptr, size_t size, + size_t nmemb, void* userp) { if (!userp) return 0; - string *response = reinterpret_cast<string *>(userp); + string* response = reinterpret_cast<string*>(userp); size_t real_size = size * nmemb; - response->append(reinterpret_cast<char *>(ptr), real_size); + response->append(reinterpret_cast<char*>(ptr), real_size); return real_size; } @@ -250,7 +250,7 @@ bool LibcurlWrapper::SetFunctionPointers() { SET_AND_CHECK_FUNCTION_POINTER(easy_getinfo_, "curl_easy_getinfo", - CURLcode(*)(CURL *, CURLINFO info, ...)); + CURLcode(*)(CURL*, CURLINFO info, ...)); SET_AND_CHECK_FUNCTION_POINTER(easy_reset_, "curl_easy_reset", @@ -263,6 +263,10 @@ bool LibcurlWrapper::SetFunctionPointers() { SET_AND_CHECK_FUNCTION_POINTER(formfree_, "curl_formfree", void(*)(curl_httppost*)); + + SET_AND_CHECK_FUNCTION_POINTER(global_cleanup_, + "curl_global_cleanup", + void(*)(void)); return true; } diff --git a/src/common/linux/libcurl_wrapper.h b/src/common/linux/libcurl_wrapper.h index 77aa6cbb..f8f961c1 100644 --- a/src/common/linux/libcurl_wrapper.h +++ b/src/common/linux/libcurl_wrapper.h @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,6 +39,9 @@ #include "third_party/curl/curl.h" namespace google_breakpad { + +// This class is only safe to be used on single-threaded code because of its +// usage of libcurl's curl_global_cleanup(). class LibcurlWrapper { public: LibcurlWrapper(); @@ -91,27 +93,28 @@ class LibcurlWrapper { // dealing // with CURL. - CURL *curl_; // Pointer for handle for CURL calls. + CURL* curl_; // Pointer for handle for CURL calls. CURL* (*easy_init_)(void); // Stateful pointers for calling into curl_formadd() - struct curl_httppost *formpost_; - struct curl_httppost *lastptr_; - struct curl_slist *headerlist_; + struct curl_httppost* formpost_; + struct curl_httppost* lastptr_; + struct curl_slist* headerlist_; // Function pointers into CURL library - CURLcode (*easy_setopt_)(CURL *, CURLoption, ...); - CURLFORMcode (*formadd_)(struct curl_httppost **, - struct curl_httppost **, ...); - struct curl_slist* (*slist_append_)(struct curl_slist *, const char *); - void (*slist_free_all_)(struct curl_slist *); - CURLcode (*easy_perform_)(CURL *); + CURLcode (*easy_setopt_)(CURL*, CURLoption, ...); + CURLFORMcode (*formadd_)(struct curl_httppost**, + struct curl_httppost**, ...); + struct curl_slist* (*slist_append_)(struct curl_slist*, const char*); + void (*slist_free_all_)(struct curl_slist*); + CURLcode (*easy_perform_)(CURL*); const char* (*easy_strerror_)(CURLcode); - void (*easy_cleanup_)(CURL *); - CURLcode (*easy_getinfo_)(CURL *, CURLINFO info, ...); + void (*easy_cleanup_)(CURL*); + CURLcode (*easy_getinfo_)(CURL*, CURLINFO info, ...); void (*easy_reset_)(CURL*); - void (*formfree_)(struct curl_httppost *); + void (*formfree_)(struct curl_httppost*); + void (*global_cleanup_)(void); }; } diff --git a/src/common/linux/linux_libc_support.cc b/src/common/linux/linux_libc_support.cc index 08b0325e..10cbeaef 100644 --- a/src/common/linux/linux_libc_support.cc +++ b/src/common/linux/linux_libc_support.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -190,7 +189,7 @@ const char* my_read_decimal_ptr(uintptr_t* result, const char* s) { } void my_memset(void* ip, char c, size_t len) { - char* p = (char *) ip; + char* p = (char*) ip; while (len--) *p++ = c; } diff --git a/src/common/linux/linux_libc_support.h b/src/common/linux/linux_libc_support.h index ec5a8d6b..05e2aa24 100644 --- a/src/common/linux/linux_libc_support.h +++ b/src/common/linux/linux_libc_support.h @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/linux_libc_support_unittest.cc b/src/common/linux/linux_libc_support_unittest.cc index adadfed4..449f995f 100644 --- a/src/common/linux/linux_libc_support_unittest.cc +++ b/src/common/linux/linux_libc_support_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/memory_mapped_file.cc b/src/common/linux/memory_mapped_file.cc index 4e938269..7e444607 100644 --- a/src/common/linux/memory_mapped_file.cc +++ b/src/common/linux/memory_mapped_file.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -65,7 +64,8 @@ bool MemoryMappedFile::Map(const char* path, size_t offset) { } #if defined(__x86_64__) || defined(__aarch64__) || \ - (defined(__mips__) && _MIPS_SIM == _ABI64) + (defined(__mips__) && _MIPS_SIM == _ABI64) || \ + (defined(__riscv) && __riscv_xlen == 64) struct kernel_stat st; if (sys_fstat(fd, &st) == -1 || st.st_size < 0) { @@ -87,13 +87,14 @@ bool MemoryMappedFile::Map(const char* path, size_t offset) { return true; } - void* data = sys_mmap(NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset); + size_t content_len = file_len - offset; + void* data = sys_mmap(NULL, content_len, PROT_READ, MAP_PRIVATE, fd, offset); sys_close(fd); if (data == MAP_FAILED) { return false; } - content_.Set(data, file_len - offset); + content_.Set(data, content_len); return true; } diff --git a/src/common/linux/memory_mapped_file.h b/src/common/linux/memory_mapped_file.h index fa660cc9..d4a85051 100644 --- a/src/common/linux/memory_mapped_file.h +++ b/src/common/linux/memory_mapped_file.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/memory_mapped_file_unittest.cc b/src/common/linux/memory_mapped_file_unittest.cc index fad59f40..5ed677df 100644 --- a/src/common/linux/memory_mapped_file_unittest.cc +++ b/src/common/linux/memory_mapped_file_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/safe_readlink.cc b/src/common/linux/safe_readlink.cc index 870c28af..97ea62c0 100644 --- a/src/common/linux/safe_readlink.cc +++ b/src/common/linux/safe_readlink.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/safe_readlink.h b/src/common/linux/safe_readlink.h index 4ae131b5..f3aa9332 100644 --- a/src/common/linux/safe_readlink.h +++ b/src/common/linux/safe_readlink.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/safe_readlink_unittest.cc b/src/common/linux/safe_readlink_unittest.cc index d346b2a8..6f5f9d75 100644 --- a/src/common/linux/safe_readlink_unittest.cc +++ b/src/common/linux/safe_readlink_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/symbol_collector_client.cc b/src/common/linux/symbol_collector_client.cc index 92b25ddb..1c1dc97a 100644 --- a/src/common/linux/symbol_collector_client.cc +++ b/src/common/linux/symbol_collector_client.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2019 Google Inc. -// All rights reserved. +// Copyright 2019 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/symbol_collector_client.h b/src/common/linux/symbol_collector_client.h index 0e23242a..6190376f 100644 --- a/src/common/linux/symbol_collector_client.h +++ b/src/common/linux/symbol_collector_client.h @@ -1,5 +1,4 @@ -// Copyright (c) 2019, Google Inc. -// All rights reserved. +// Copyright 2019 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/symbol_upload.cc b/src/common/linux/symbol_upload.cc index 87741a0a..c080533a 100644 --- a/src/common/linux/symbol_upload.cc +++ b/src/common/linux/symbol_upload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -46,8 +45,8 @@ namespace google_breakpad { namespace sym_upload { -void TokenizeByChar(const string &source_string, int c, - std::vector<string> *results) { +void TokenizeByChar(const string& source_string, int c, + std::vector<string>* results) { assert(results); string::size_type cur_pos = 0, next_pos = 0; while ((next_pos = source_string.find(c, cur_pos)) != string::npos) { @@ -62,8 +61,8 @@ void TokenizeByChar(const string &source_string, int c, //============================================================================= // Parse out the module line which have 5 parts. // MODULE <os> <cpu> <uuid> <module-name> -bool ModuleDataForSymbolFile(const string &file, - std::vector<string> *module_parts) { +bool ModuleDataForSymbolFile(const string& file, + std::vector<string>* module_parts) { assert(module_parts); const size_t kModulePartNumber = 5; FILE* fp = fopen(file.c_str(), "r"); @@ -90,7 +89,7 @@ bool ModuleDataForSymbolFile(const string &file, } //============================================================================= -string CompactIdentifier(const string &uuid) { +string CompactIdentifier(const string& uuid) { std::vector<string> components; TokenizeByChar(uuid, '-', &components); string result; diff --git a/src/common/linux/symbol_upload.h b/src/common/linux/symbol_upload.h index 9033152b..a9d30e7b 100644 --- a/src/common/linux/symbol_upload.h +++ b/src/common/linux/symbol_upload.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/synth_elf.cc b/src/common/linux/synth_elf.cc index 98e81dab..2ba25e61 100644 --- a/src/common/linux/synth_elf.cc +++ b/src/common/linux/synth_elf.cc @@ -118,7 +118,7 @@ int ELF::AddSection(const string& name, const Section& section, return index; } -void ELF::AppendSection(ElfSection §ion) { +void ELF::AppendSection(ElfSection& section) { // NULL and NOBITS sections have no content, so they // don't need to be written to the file. if (section.type_ == SHT_NULL) { @@ -242,7 +242,7 @@ void SymbolTable::AddSymbol(const string& name, uint64_t value, D64(size); } -void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes, +void Notes::AddNote(int type, const string& name, const uint8_t* desc_bytes, size_t desc_size) { // Elf32_Nhdr and Elf64_Nhdr are exactly the same. Elf32_Nhdr note_header; diff --git a/src/common/linux/synth_elf.h b/src/common/linux/synth_elf.h index 1d2a20ca..bf22081b 100644 --- a/src/common/linux/synth_elf.h +++ b/src/common/linux/synth_elf.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -154,7 +153,7 @@ class ELF : public Section { vector<ElfSection> sections_; - void AppendSection(ElfSection §ion); + void AppendSection(ElfSection& section); }; // A class to build .symtab or .dynsym sections. @@ -187,7 +186,7 @@ public: } // Add a note. - void AddNote(int type, const string &name, const uint8_t* desc_bytes, + void AddNote(int type, const string& name, const uint8_t* desc_bytes, size_t desc_size); }; diff --git a/src/common/linux/synth_elf_unittest.cc b/src/common/linux/synth_elf_unittest.cc index cd74c286..44ef6ef3 100644 --- a/src/common/linux/synth_elf_unittest.cc +++ b/src/common/linux/synth_elf_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -381,9 +380,9 @@ TEST_F(ElfNotesTest, Empty) { TEST_F(ElfNotesTest, Notes) { Notes notes(kLittleEndian); - notes.AddNote(1, "Linux", reinterpret_cast<const uint8_t *>("\x42\x02\0\0"), + notes.AddNote(1, "Linux", reinterpret_cast<const uint8_t*>("\x42\x02\0\0"), 4); - notes.AddNote(2, "a", reinterpret_cast<const uint8_t *>("foobar"), + notes.AddNote(2, "a", reinterpret_cast<const uint8_t*>("foobar"), sizeof("foobar") - 1); const uint8_t kExpectedNotesContents[] = { diff --git a/src/common/linux/tests/auto_testfile.h b/src/common/linux/tests/auto_testfile.h index 92fe017b..e2d2ff23 100644 --- a/src/common/linux/tests/auto_testfile.h +++ b/src/common/linux/tests/auto_testfile.h @@ -1,5 +1,4 @@ -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/linux/tests/crash_generator.cc b/src/common/linux/tests/crash_generator.cc index 6896a688..0db0c4a2 100644 --- a/src/common/linux/tests/crash_generator.cc +++ b/src/common/linux/tests/crash_generator.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -79,7 +78,7 @@ int tkill(pid_t tid, int sig) { // Core file size limit set to 1 MB, which is big enough for test purposes. const rlim_t kCoreSizeLimit = 1024 * 1024; -void *thread_function(void *data) { +void* thread_function(void* data) { ThreadData* thread_data = reinterpret_cast<ThreadData*>(data); volatile pid_t thread_id = gettid(); *(thread_data->thread_id_ptr) = thread_id; @@ -169,6 +168,15 @@ bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const { return true; } +bool CrashGenerator::HasResourceLimitsAmenableToCrashCollection() const { + struct rlimit limits; + if (getrlimit(RLIMIT_CORE, &limits) == -1) { + perror("CrashGenerator: Failed to get core file size limit"); + return false; + } + return limits.rlim_max >= kCoreSizeLimit; +} + bool CrashGenerator::CreateChildCrash( unsigned num_threads, unsigned crash_thread, int crash_signal, pid_t* child_pid) { diff --git a/src/common/linux/tests/crash_generator.h b/src/common/linux/tests/crash_generator.h index 7e2fcbf9..71c05d27 100644 --- a/src/common/linux/tests/crash_generator.h +++ b/src/common/linux/tests/crash_generator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -65,6 +64,10 @@ class CrashGenerator { // Returns the directory of a copy of proc files of the child process. string GetDirectoryOfProcFilesCopy() const; + // Returns whether current resource limits would prevent `CreateChildCrash` + // from operating. + bool HasResourceLimitsAmenableToCrashCollection() const; + // Creates a crash (and a core dump file) by creating a child process with // |num_threads| threads, and the terminating the child process by sending // a signal with number |crash_signal| to the |crash_thread|-th thread. diff --git a/src/common/linux/ucontext_constants.h b/src/common/linux/ucontext_constants.h index c390508a..3dcdecb0 100644 --- a/src/common/linux/ucontext_constants.h +++ b/src/common/linux/ucontext_constants.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -146,8 +145,107 @@ #endif #define FPREGS_OFFSET_MXCSR 24 +#elif defined(__riscv) + +#if __riscv_xlen == 32 +#define UCONTEXT_SIGMASK_OFFSET 20 +#define MCONTEXT_GREGS_OFFSET 148 +#define MCONTEXT_GREGS_SIZE 4 +#define REG_S sw +#elif __riscv_xlen == 64 +#define UCONTEXT_SIGMASK_OFFSET 40 +#define MCONTEXT_GREGS_OFFSET 168 +#define MCONTEXT_GREGS_SIZE 8 +#define REG_S sd #else -#error "This header has not been ported for your CPU" +#error "Unexpected __riscv_xlen" +#endif + +#define MCONTEXT_GREGS_PC MCONTEXT_GREGS_OFFSET + 0*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_RA MCONTEXT_GREGS_OFFSET + 1*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_SP MCONTEXT_GREGS_OFFSET + 2*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_GP MCONTEXT_GREGS_OFFSET + 3*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_TP MCONTEXT_GREGS_OFFSET + 4*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_T0 MCONTEXT_GREGS_OFFSET + 5*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_T1 MCONTEXT_GREGS_OFFSET + 6*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_T2 MCONTEXT_GREGS_OFFSET + 7*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S0 MCONTEXT_GREGS_OFFSET + 8*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S1 MCONTEXT_GREGS_OFFSET + 9*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_A0 MCONTEXT_GREGS_OFFSET + 10*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_A1 MCONTEXT_GREGS_OFFSET + 11*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_A2 MCONTEXT_GREGS_OFFSET + 12*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_A3 MCONTEXT_GREGS_OFFSET + 13*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_A4 MCONTEXT_GREGS_OFFSET + 14*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_A5 MCONTEXT_GREGS_OFFSET + 15*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_A6 MCONTEXT_GREGS_OFFSET + 16*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_A7 MCONTEXT_GREGS_OFFSET + 17*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S2 MCONTEXT_GREGS_OFFSET + 18*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S3 MCONTEXT_GREGS_OFFSET + 19*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S4 MCONTEXT_GREGS_OFFSET + 20*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S5 MCONTEXT_GREGS_OFFSET + 21*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S6 MCONTEXT_GREGS_OFFSET + 22*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S7 MCONTEXT_GREGS_OFFSET + 23*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S8 MCONTEXT_GREGS_OFFSET + 24*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S9 MCONTEXT_GREGS_OFFSET + 25*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S10 MCONTEXT_GREGS_OFFSET + 26*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_S11 MCONTEXT_GREGS_OFFSET + 27*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_T3 MCONTEXT_GREGS_OFFSET + 28*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_T4 MCONTEXT_GREGS_OFFSET + 29*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_T5 MCONTEXT_GREGS_OFFSET + 30*MCONTEXT_GREGS_SIZE +#define MCONTEXT_GREGS_T6 MCONTEXT_GREGS_OFFSET + 31*MCONTEXT_GREGS_SIZE + +#define MCONTEXT_FPREGS_OFFSET MCONTEXT_GREGS_OFFSET + 32*MCONTEXT_GREGS_SIZE + +#if __riscv_flen == 32 +#define MCONTEXT_FPREGS_SIZE 4 +#define FREG_S fsw +#elif __riscv_flen == 64 +#define MCONTEXT_FPREGS_SIZE 8 +#define FREG_S fsd +#elif __riscv_flen == 128 +#define MCONTEXT_FPREGS_SIZE 16 +#define FREG_S fsq +#else +#error "Unexpected __riscv_flen" +#endif + +#define MCONTEXT_FPREGS_FT0 MCONTEXT_FPREGS_OFFSET + 0*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT1 MCONTEXT_FPREGS_OFFSET + 1*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT2 MCONTEXT_FPREGS_OFFSET + 2*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT3 MCONTEXT_FPREGS_OFFSET + 3*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT4 MCONTEXT_FPREGS_OFFSET + 4*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT5 MCONTEXT_FPREGS_OFFSET + 5*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT6 MCONTEXT_FPREGS_OFFSET + 6*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT7 MCONTEXT_FPREGS_OFFSET + 7*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS0 MCONTEXT_FPREGS_OFFSET + 8*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS1 MCONTEXT_FPREGS_OFFSET + 9*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FA0 MCONTEXT_FPREGS_OFFSET + 10*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FA1 MCONTEXT_FPREGS_OFFSET + 11*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FA2 MCONTEXT_FPREGS_OFFSET + 12*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FA3 MCONTEXT_FPREGS_OFFSET + 13*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FA4 MCONTEXT_FPREGS_OFFSET + 14*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FA5 MCONTEXT_FPREGS_OFFSET + 15*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FA6 MCONTEXT_FPREGS_OFFSET + 16*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FA7 MCONTEXT_FPREGS_OFFSET + 17*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS2 MCONTEXT_FPREGS_OFFSET + 18*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS3 MCONTEXT_FPREGS_OFFSET + 19*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS4 MCONTEXT_FPREGS_OFFSET + 20*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS5 MCONTEXT_FPREGS_OFFSET + 21*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS6 MCONTEXT_FPREGS_OFFSET + 22*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS7 MCONTEXT_FPREGS_OFFSET + 23*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS8 MCONTEXT_FPREGS_OFFSET + 24*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS9 MCONTEXT_FPREGS_OFFSET + 25*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS10 MCONTEXT_FPREGS_OFFSET + 26*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FS11 MCONTEXT_FPREGS_OFFSET + 27*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT8 MCONTEXT_FPREGS_OFFSET + 28*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT9 MCONTEXT_FPREGS_OFFSET + 29*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT10 MCONTEXT_FPREGS_OFFSET + 30*MCONTEXT_FPREGS_SIZE +#define MCONTEXT_FPREGS_FT11 MCONTEXT_FPREGS_OFFSET + 31*MCONTEXT_FPREGS_SIZE + +#define MCONTEXT_FPC_CSR MCONTEXT_FPREGS_OFFSET + 32*MCONTEXT_FPREGS_SIZE + +#else +# error "This header has not been ported for your CPU" #endif #endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H diff --git a/src/common/long_string_dictionary.cc b/src/common/long_string_dictionary.cc index 46bbf613..f504aa42 100644 --- a/src/common/long_string_dictionary.cc +++ b/src/common/long_string_dictionary.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2017, Google Inc. -// All rights reserved. +// Copyright 2017 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/long_string_dictionary.h b/src/common/long_string_dictionary.h index 68bf03de..9319b27f 100644 --- a/src/common/long_string_dictionary.h +++ b/src/common/long_string_dictionary.h @@ -1,5 +1,4 @@ -// Copyright (c) 2017, Google Inc. -// All rights reserved. +// Copyright 2017 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/long_string_dictionary_unittest.cc b/src/common/long_string_dictionary_unittest.cc index f9b645ba..be34efdf 100644 --- a/src/common/long_string_dictionary_unittest.cc +++ b/src/common/long_string_dictionary_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2017, Google Inc. -// All rights reserved. +// Copyright 2017 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/Breakpad.xcconfig b/src/common/mac/Breakpad.xcconfig index f0913690..fd28d3ce 100644 --- a/src/common/mac/Breakpad.xcconfig +++ b/src/common/mac/Breakpad.xcconfig @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/BreakpadDebug.xcconfig b/src/common/mac/BreakpadDebug.xcconfig index 94cdd8cf..6ec7c00e 100644 --- a/src/common/mac/BreakpadDebug.xcconfig +++ b/src/common/mac/BreakpadDebug.xcconfig @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/BreakpadRelease.xcconfig b/src/common/mac/BreakpadRelease.xcconfig index 920f277d..9121b0d0 100644 --- a/src/common/mac/BreakpadRelease.xcconfig +++ b/src/common/mac/BreakpadRelease.xcconfig @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/GTMDefines.h b/src/common/mac/GTMDefines.h index 04fcf6d0..ae5368cd 100644 --- a/src/common/mac/GTMDefines.h +++ b/src/common/mac/GTMDefines.h @@ -1,7 +1,7 @@ // // GTMDefines.h // -// Copyright 2008 Google Inc. +// Copyright 2008 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy diff --git a/src/common/mac/GTMLogger.h b/src/common/mac/GTMLogger.h index c4fd1402..dcc7da44 100644 --- a/src/common/mac/GTMLogger.h +++ b/src/common/mac/GTMLogger.h @@ -1,7 +1,7 @@ // // GTMLogger.h // -// Copyright 2007-2008 Google Inc. +// Copyright 2007-2008 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy diff --git a/src/common/mac/GTMLogger.m b/src/common/mac/GTMLogger.m index ebc5836a..17db83d6 100644 --- a/src/common/mac/GTMLogger.m +++ b/src/common/mac/GTMLogger.m @@ -1,7 +1,7 @@ // // GTMLogger.m // -// Copyright 2007-2008 Google Inc. +// Copyright 2007-2008 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy diff --git a/src/common/mac/HTTPGetRequest.h b/src/common/mac/HTTPGetRequest.h new file mode 100644 index 00000000..9c3cb3f9 --- /dev/null +++ b/src/common/mac/HTTPGetRequest.h @@ -0,0 +1,41 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import <Foundation/Foundation.h> + +#import "HTTPRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Represents a HTTP GET request + */ +@interface HTTPGetRequest : HTTPRequest +@end + +NS_ASSUME_NONNULL_END diff --git a/src/common/mac/HTTPGetRequest.m b/src/common/mac/HTTPGetRequest.m new file mode 100644 index 00000000..e151cfd8 --- /dev/null +++ b/src/common/mac/HTTPGetRequest.m @@ -0,0 +1,38 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "HTTPGetRequest.h" + +@implementation HTTPGetRequest + +//============================================================================= +- (NSString*)HTTPMethod { + return @"GET"; +} + +@end diff --git a/src/common/mac/HTTPMultipartUpload.h b/src/common/mac/HTTPMultipartUpload.h index 42e8fed3..27b9cf86 100644 --- a/src/common/mac/HTTPMultipartUpload.h +++ b/src/common/mac/HTTPMultipartUpload.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -27,35 +26,37 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// HTTPMultipartUpload: A multipart/form-data HTTP uploader. -// Each parameter pair is sent as a boundary -// Each file is sent with a name field in addition to the filename and data -// The data will be sent synchronously. - #import <Foundation/Foundation.h> -@interface HTTPMultipartUpload : NSObject { +#import "HTTPRequest.h" +/** + Represents a multipart/form-data HTTP upload (POST request). + Each parameter pair is sent as a boundary. + Each file is sent with a name field in addition to the filename and data. + */ +@interface HTTPMultipartUpload : HTTPRequest { @protected - NSURL *url_; // The destination URL (STRONG) - NSDictionary *parameters_; // The key/value pairs for sending data (STRONG) - NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG) - NSString *boundary_; // The boundary string (STRONG) - NSHTTPURLResponse *response_; // The response from the send (STRONG) + NSDictionary* parameters_; // The key/value pairs for sending data (STRONG) + NSMutableDictionary* files_; // Dictionary of name/file-path (STRONG) + NSString* boundary_; // The boundary string (STRONG) } -- (id)initWithURL:(NSURL *)url; - -- (NSURL *)URL; - -- (void)setParameters:(NSDictionary *)parameters; -- (NSDictionary *)parameters; - -- (void)addFileAtPath:(NSString *)path name:(NSString *)name; -- (void)addFileContents:(NSData *)data name:(NSString *)name; -- (NSDictionary *)files; - -// Set the data and return the response -- (NSData *)send:(NSError **)error; -- (NSHTTPURLResponse *)response; +/** + Sets the parameters that will be sent in the multipart POST request. + */ +- (void)setParameters:(NSDictionary*)parameters; +- (NSDictionary*)parameters; + +/** + Adds a file to be uploaded in the multipart POST request, by its file path. + */ +- (void)addFileAtPath:(NSString*)path name:(NSString*)name; + +/** + Adds a file to be uploaded in the multipart POST request, by its name and + contents. + */ +- (void)addFileContents:(NSData*)data name:(NSString*)name; +- (NSDictionary*)files; @end diff --git a/src/common/mac/HTTPMultipartUpload.m b/src/common/mac/HTTPMultipartUpload.m index a3677f25..b3a084a9 100644 --- a/src/common/mac/HTTPMultipartUpload.m +++ b/src/common/mac/HTTPMultipartUpload.m @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -28,74 +27,17 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #import "HTTPMultipartUpload.h" -#import "GTMDefines.h" -// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been -// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it -// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when -// using those SDKs. -static NSString *PercentEncodeNSString(NSString *key) { -#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \ - __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \ - (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ - defined(MAC_OS_X_VERSION_10_11) && \ - MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) - return [key stringByAddingPercentEncodingWithAllowedCharacters: - [NSCharacterSet URLQueryAllowedCharacterSet]]; -#else - return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; -#endif -} +#import "GTMDefines.h" +#import "encoding_util.h" -// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has -// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements -// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is -// available on iOS 7+. -static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, - NSURLResponse **out_response, - NSError **out_error) { -#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \ - __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \ - (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ - defined(MAC_OS_X_VERSION_10_11) && \ - MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) - __block NSData* result = nil; - __block NSError* error = nil; - __block NSURLResponse* response = nil; - dispatch_semaphore_t wait_semaphone = dispatch_semaphore_create(0); - [[[NSURLSession sharedSession] - dataTaskWithRequest:req - completionHandler:^(NSData *data, - NSURLResponse *resp, - NSError *err) { - if (out_error) - error = [err retain]; - if (out_response) - response = [resp retain]; - if (err == nil) - result = [data retain]; - dispatch_semaphore_signal(wait_semaphone); - }] resume]; - dispatch_semaphore_wait(wait_semaphone, DISPATCH_TIME_FOREVER); - dispatch_release(wait_semaphone); - if (out_error) - *out_error = [error autorelease]; - if (out_response) - *out_response = [response autorelease]; - return [result autorelease]; -#else - return [NSURLConnection sendSynchronousRequest:req - returningResponse:out_response - error:out_error]; -#endif -} -@interface HTTPMultipartUpload(PrivateMethods) -- (NSString *)multipartBoundary; +@interface HTTPMultipartUpload (PrivateMethods) +- (NSString*)multipartBoundary; // Each of the following methods will append the starting multipart boundary, // but not the ending one. -- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value; -- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name; -- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name; +- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value; +- (NSData*)formDataForFileContents:(NSData*)contents name:(NSString*)name; +- (NSData*)formDataForFile:(NSString*)file name:(NSString*)name; @end @implementation HTTPMultipartUpload @@ -103,50 +45,39 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, #pragma mark - #pragma mark || Private || //============================================================================= -- (NSString *)multipartBoundary { +- (NSString*)multipartBoundary { // The boundary has 27 '-' characters followed by 16 hex digits - return [NSString stringWithFormat:@"---------------------------%08X%08X", - rand(), rand()]; -} - -//============================================================================= -- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value { - NSString *escaped = PercentEncodeNSString(key); - NSString *fmt = - @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n"; - NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value]; - - return [form dataUsingEncoding:NSUTF8StringEncoding]; + return [NSString + stringWithFormat:@"---------------------------%08X%08X", rand(), rand()]; } //============================================================================= -- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name { - NSMutableData *data = [NSMutableData data]; - NSString *escaped = PercentEncodeNSString(name); - NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; " - "filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n"; - NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped]; +- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value { + NSMutableData* data = [NSMutableData data]; + [self appendBoundaryData:data]; - [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]]; - [data appendData:contents]; + NSString* escaped = PercentEncodeNSString(key); + NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n"; + NSString *form = [NSString stringWithFormat:fmt, escaped, value]; + [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]]; return data; } //============================================================================= -- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name { - NSData *contents = [NSData dataWithContentsOfFile:file]; +- (void)appendBoundaryData:(NSMutableData*)data { + NSString* fmt = @"--%@\r\n"; + NSString* pre = [NSString stringWithFormat:fmt, boundary_]; - return [self formDataForFileContents:contents name:name]; + [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]]; } //============================================================================= #pragma mark - #pragma mark || Public || //============================================================================= -- (id)initWithURL:(NSURL *)url { - if ((self = [super init])) { - url_ = [url copy]; +- (id)initWithURL:(NSURL*)url { + if ((self = [super initWithURL:url])) { boundary_ = [[self multipartBoundary] retain]; files_ = [[NSMutableDictionary alloc] init]; } @@ -156,22 +87,15 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, //============================================================================= - (void)dealloc { - [url_ release]; [parameters_ release]; [files_ release]; [boundary_ release]; - [response_ release]; [super dealloc]; } //============================================================================= -- (NSURL *)URL { - return url_; -} - -//============================================================================= -- (void)setParameters:(NSDictionary *)parameters { +- (void)setParameters:(NSDictionary*)parameters { if (parameters != parameters_) { [parameters_ release]; parameters_ = [parameters copy]; @@ -179,40 +103,43 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, } //============================================================================= -- (NSDictionary *)parameters { +- (NSDictionary*)parameters { return parameters_; } //============================================================================= -- (void)addFileAtPath:(NSString *)path name:(NSString *)name { +- (void)addFileAtPath:(NSString*)path name:(NSString*)name { [files_ setObject:path forKey:name]; } //============================================================================= -- (void)addFileContents:(NSData *)data name:(NSString *)name { +- (void)addFileContents:(NSData*)data name:(NSString*)name { [files_ setObject:data forKey:name]; } //============================================================================= -- (NSDictionary *)files { +- (NSDictionary*)files { return files_; } //============================================================================= -- (NSData *)send:(NSError **)error { - NSMutableURLRequest *req = - [[NSMutableURLRequest alloc] - initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy - timeoutInterval:60.0]; +- (NSString*)HTTPMethod { + return @"POST"; +} - NSMutableData *postBody = [NSMutableData data]; +//============================================================================= +- (NSString*)contentType { + return [NSString + stringWithFormat:@"multipart/form-data; boundary=%@", boundary_]; +} - [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", - boundary_] forHTTPHeaderField:@"Content-type"]; +//============================================================================= +- (NSData*)bodyData { + NSMutableData* postBody = [NSMutableData data]; // Add any parameters to the message - NSArray *parameterKeys = [parameters_ allKeys]; - NSString *key; + NSArray* parameterKeys = [parameters_ allKeys]; + NSString* key; NSInteger count = [parameterKeys count]; for (NSInteger i = 0; i < count; ++i) { @@ -222,46 +149,21 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, } // Add any files to the message - NSArray *fileNames = [files_ allKeys]; - for (NSString *name in fileNames) { + NSArray* fileNames = [files_ allKeys]; + for (NSString* name in fileNames) { + // First append boundary + [self appendBoundaryData:postBody]; + // Then the formdata id fileOrData = [files_ objectForKey:name]; - NSData *fileData; - - // The object can be either the path to a file (NSString) or the contents - // of the file (NSData). - if ([fileOrData isKindOfClass:[NSData class]]) - fileData = [self formDataForFileContents:fileOrData name:name]; - else - fileData = [self formDataForFile:fileOrData name:name]; - - [postBody appendData:fileData]; + [HTTPRequest appendFileToBodyData:postBody + withName:name + withFileOrData:fileOrData]; } - NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_]; + NSString* epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_]; [postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]]; - [req setHTTPBody:postBody]; - [req setHTTPMethod:@"POST"]; - - [response_ release]; - response_ = nil; - - NSData *data = nil; - if ([[req URL] isFileURL]) { - [[req HTTPBody] writeToURL:[req URL] options:0 error:error]; - } else { - NSURLResponse *response = nil; - data = SendSynchronousNSURLRequest(req, &response, error); - response_ = (NSHTTPURLResponse *)[response retain]; - } - [req release]; - - return data; -} - -//============================================================================= -- (NSHTTPURLResponse *)response { - return response_; + return postBody; } @end diff --git a/src/common/mac/HTTPPutRequest.h b/src/common/mac/HTTPPutRequest.h new file mode 100644 index 00000000..36d38c01 --- /dev/null +++ b/src/common/mac/HTTPPutRequest.h @@ -0,0 +1,50 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import <Foundation/Foundation.h> + +#import "HTTPRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Represents an HTTP PUT request. + */ +@interface HTTPPutRequest : HTTPRequest { + @protected + NSString* file_; +} + +/** + Sets the path of the file that will be sent in the PUT request. + */ +- (void)setFile:(NSString*)file; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/common/mac/HTTPPutRequest.m b/src/common/mac/HTTPPutRequest.m new file mode 100644 index 00000000..b7c7e091 --- /dev/null +++ b/src/common/mac/HTTPPutRequest.m @@ -0,0 +1,55 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "HTTPPutRequest.h" + +@implementation HTTPPutRequest + +//============================================================================= +- (void)dealloc { + [file_ release]; + + [super dealloc]; +} + +//============================================================================= +- (void)setFile:(NSString*)file { + file_ = [file copy]; +} + +//============================================================================= +- (NSString*)HTTPMethod { + return @"PUT"; +} + +//============================================================================= +- (NSData*)bodyData { + return [NSData dataWithContentsOfFile:file_]; +} + +@end diff --git a/src/common/mac/HTTPRequest.h b/src/common/mac/HTTPRequest.h new file mode 100644 index 00000000..49374147 --- /dev/null +++ b/src/common/mac/HTTPRequest.h @@ -0,0 +1,72 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import <Foundation/Foundation.h> + +NS_ASSUME_NONNULL_BEGIN +/** + Represents a single HTTP request. Sending the request is synchronous. + Once the send is complete, the response will be set. + + This is a base interface that specific HTTP requests derive from. + It is not intended to be instantiated directly. + */ +@interface HTTPRequest : NSObject { + @protected + NSURL* URL_; // The destination URL (STRONG) + NSHTTPURLResponse* response_; // The response from the send (STRONG) +} + +/** + Initializes the HTTPRequest and sets its URL. + */ +- (id)initWithURL:(NSURL*)URL; + +- (NSURL*)URL; + +- (NSHTTPURLResponse*)response; + +- (NSString*)HTTPMethod; // Internal, don't call outside class hierarchy. + +- (NSString*)contentType; // Internal, don't call outside class hierarchy. + +- (NSData*)bodyData; // Internal, don't call outside class hierarchy. + +- (NSData*)send:(NSError**)error; + +/** + Appends a file to the HTTP request, either by filename or by file content + (in the form of NSData). + */ ++ (void)appendFileToBodyData:(NSMutableData*)data + withName:(NSString*)name + withFileOrData:(id)fileOrData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/common/mac/HTTPRequest.m b/src/common/mac/HTTPRequest.m new file mode 100644 index 00000000..af21874d --- /dev/null +++ b/src/common/mac/HTTPRequest.m @@ -0,0 +1,267 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "HTTPRequest.h" + +#include <Availability.h> +#include <AvailabilityMacros.h> + +#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) +#import <UIKit/UIKit.h> +#define HAS_BACKGROUND_TASK_API 1 +#else +#define HAS_BACKGROUND_TASK_API 0 +#endif + +#import "encoding_util.h" + +#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \ + (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ + defined(MAC_OS_X_VERSION_10_11) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) +#define USE_NSURLSESSION 1 +#else +#define USE_NSURLSESSION 0 +#endif + +// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has +// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements +// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is +// available on iOS 7+. +static NSData* SendSynchronousNSURLRequest(NSURLRequest* req, + NSURLResponse** outResponse, + NSError** outError) { +#if USE_NSURLSESSION + __block NSData* result = nil; + __block NSError* error = nil; + __block NSURLResponse* response = nil; + dispatch_semaphore_t waitSemaphone = dispatch_semaphore_create(0); + + NSURLSessionConfiguration* config = + [NSURLSessionConfiguration defaultSessionConfiguration]; + [config setTimeoutIntervalForRequest:240.0]; + NSURLSession* session = [NSURLSession sessionWithConfiguration:config]; + NSURLSessionDataTask *task = [session + dataTaskWithRequest:req + completionHandler:^(NSData* data, NSURLResponse* resp, NSError* err) { + if (outError) + error = [err retain]; + if (outResponse) + response = [resp retain]; + if (err == nil) + result = [data retain]; + dispatch_semaphore_signal(waitSemaphone); + }]; + [task resume]; + +#if HAS_BACKGROUND_TASK_API + // Used to guard against ending the background task twice, which UIKit + // considers to be an error. + __block BOOL isBackgroundTaskActive = YES; + __block UIBackgroundTaskIdentifier backgroundTaskIdentifier = + UIBackgroundTaskInvalid; + backgroundTaskIdentifier = [UIApplication.sharedApplication + beginBackgroundTaskWithName:@"Breakpad Upload" + expirationHandler:^{ + if (!isBackgroundTaskActive) { + return; + } + isBackgroundTaskActive = NO; + + [task cancel]; + [UIApplication.sharedApplication + endBackgroundTask:backgroundTaskIdentifier]; + }]; +#endif // HAS_BACKGROUND_TASK_API + + dispatch_semaphore_wait(waitSemaphone, DISPATCH_TIME_FOREVER); + dispatch_release(waitSemaphone); + +#if HAS_BACKGROUND_TASK_API + if (backgroundTaskIdentifier != UIBackgroundTaskInvalid) { + // Dispatch to main queue in order to synchronize access to + // `isBackgroundTaskActive` with the background task expiration handler, + // which is always run on the main thread. + dispatch_async(dispatch_get_main_queue(), ^{ + if (!isBackgroundTaskActive) { + return; + } + isBackgroundTaskActive = NO; + + [UIApplication.sharedApplication + endBackgroundTask:backgroundTaskIdentifier]; + }); + } +#endif // HAS_BACKGROUND_TASK_API + + if (outError) + *outError = [error autorelease]; + if (outResponse) + *outResponse = [response autorelease]; + return [result autorelease]; +#else // USE_NSURLSESSION + return [NSURLConnection sendSynchronousRequest:req + returningResponse:outResponse + error:outError]; +#endif // USE_NSURLSESSION +} + +@implementation HTTPRequest + +//============================================================================= +- (id)initWithURL:(NSURL*)URL { + if ((self = [super init])) { + URL_ = [URL copy]; + } + + return self; +} + +//============================================================================= +- (void)dealloc { + [URL_ release]; + [response_ release]; + + [super dealloc]; +} + +//============================================================================= +- (NSURL*)URL { + return URL_; +} + +//============================================================================= +- (NSHTTPURLResponse*)response { + return response_; +} + +//============================================================================= +- (NSString*)HTTPMethod { + @throw [NSException + exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must" + "override %@ in a subclass", + NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +//============================================================================= +- (NSString*)contentType { + return nil; +} + +//============================================================================= +- (NSData*)bodyData { + return nil; +} + +//============================================================================= +- (NSData*)send:(NSError**)withError { + NSMutableURLRequest* req = [[NSMutableURLRequest alloc] + initWithURL:URL_ + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:60.0]; + + NSString* contentType = [self contentType]; + if ([contentType length] > 0) { + [req setValue:contentType forHTTPHeaderField:@"Content-type"]; + } + + NSData* bodyData = [self bodyData]; + if ([bodyData length] > 0) { + [req setHTTPBody:bodyData]; + } + + [req setHTTPMethod:[self HTTPMethod]]; + + [response_ release]; + response_ = nil; + + NSData* data = nil; + if ([[req URL] isFileURL]) { + [[req HTTPBody] writeToURL:[req URL] options:0 error:withError]; + } else { + NSURLResponse* response = nil; + data = SendSynchronousNSURLRequest(req, &response, withError); + response_ = (NSHTTPURLResponse*)[response retain]; + } + [req release]; + + return data; +} + +//============================================================================= ++ (NSData*)formDataForFileContents:(NSData*)contents withName:(NSString*)name { + NSMutableData* data = [NSMutableData data]; + NSString* escaped = PercentEncodeNSString(name); + NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"; " + "filename=\"minidump.dmp\"\r\nContent-Type: " + "application/octet-stream\r\n\r\n"; + NSString* pre = [NSString stringWithFormat:fmt, escaped]; + + [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]]; + [data appendData:contents]; + + return data; +} + +//============================================================================= ++ (NSData*)formDataForFile:(NSString*)file withName:(NSString*)name { + NSData* contents = [NSData dataWithContentsOfFile:file]; + + return [HTTPRequest formDataForFileContents:contents withName:name]; +} + +//============================================================================= ++ (NSData*)formDataForKey:(NSString*)key value:(NSString*)value { + NSString* escaped = PercentEncodeNSString(key); + NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n"; + NSString* form = [NSString stringWithFormat:fmt, escaped, value]; + + return [form dataUsingEncoding:NSUTF8StringEncoding]; +} + +//============================================================================= ++ (void)appendFileToBodyData:(NSMutableData*)data + withName:(NSString*)name + withFileOrData:(id)fileOrData { + NSData* fileData; + + // The object can be either the path to a file (NSString) or the contents + // of the file (NSData). + if ([fileOrData isKindOfClass:[NSData class]]) + fileData = [self formDataForFileContents:fileOrData withName:name]; + else + fileData = [HTTPRequest formDataForFile:fileOrData withName:name]; + + [data appendData:fileData]; +} + +@end diff --git a/src/common/mac/HTTPSimplePostRequest.h b/src/common/mac/HTTPSimplePostRequest.h new file mode 100644 index 00000000..01a1e868 --- /dev/null +++ b/src/common/mac/HTTPSimplePostRequest.h @@ -0,0 +1,56 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import <Foundation/Foundation.h> + +#import "HTTPRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Represents a simple (non-multipart) HTTP POST request. + */ +@interface HTTPSimplePostRequest : HTTPRequest { + @protected + NSString* contentType_; + NSString* body_; +} + +/** + Sets the content type of the POST request. + */ +- (void)setContentType:(NSString*)contentType; + +/** + Sets the contents of the POST request's body. + */ +- (void)setBody:(NSString*)body; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/common/mac/HTTPSimplePostRequest.m b/src/common/mac/HTTPSimplePostRequest.m new file mode 100644 index 00000000..7aba94fd --- /dev/null +++ b/src/common/mac/HTTPSimplePostRequest.m @@ -0,0 +1,68 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "HTTPSimplePostRequest.h" + +@implementation HTTPSimplePostRequest + +//============================================================================= +- (void)dealloc { + [contentType_ release]; + [body_ release]; + + [super dealloc]; +} + +//============================================================================= +- (void)setContentType:(NSString*)contentType { + contentType_ = [contentType copy]; +} + +//============================================================================= +- (void)setBody:(NSString*)body { + body_ = [body copy]; +} + +//============================================================================= +- (NSString*)HTTPMethod { + return @"POST"; +} + +//============================================================================= +- (NSString*)contentType { + return contentType_; +} + +//============================================================================= +- (NSData*)bodyData { + NSMutableData* data = [NSMutableData data]; + [data appendData:[body_ dataUsingEncoding:NSUTF8StringEncoding]]; + return data; +} + +@end diff --git a/src/common/mac/MachIPC.h b/src/common/mac/MachIPC.h index 71419be9..78b97ad9 100644 --- a/src/common/mac/MachIPC.h +++ b/src/common/mac/MachIPC.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -73,7 +72,7 @@ // mach_port_t task = message.GetTranslatedPort(0); // mach_port_t thread = message.GetTranslatedPort(1); // -// char *messageString = message.GetData(); +// char* messageString = message.GetData(); // // printf("message string = %s\n", messageString); // } @@ -164,7 +163,7 @@ class MachMessage { public: // The receiver of the message can retrieve the raw data this way - uint8_t *GetData() { + uint8_t* GetData() { return GetDataLength() > 0 ? GetDataPacket()->data : NULL; } @@ -181,10 +180,10 @@ class MachMessage { // Adds a descriptor (typically a mach port) to be translated // returns true if successful, otherwise not enough space - bool AddDescriptor(const MachMsgPortDescriptor &desc); + bool AddDescriptor(const MachMsgPortDescriptor& desc); int GetDescriptorCount() const { return body.msgh_descriptor_count; } - MachMsgPortDescriptor *GetDescriptor(int n); + MachMsgPortDescriptor* GetDescriptor(int n); // Convenience method which gets the mach port described by the descriptor mach_port_t GetTranslatedPort(int n); @@ -193,7 +192,7 @@ class MachMessage { bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } // Sets raw data for the message (returns false if not enough space) - bool SetData(void *data, int32_t data_length); + bool SetData(void* data, int32_t data_length); protected: // Consider this an abstract base class - must create an actual instance @@ -216,7 +215,7 @@ class MachMessage { MessageDataPacket* GetDataPacket(); void SetDescriptorCount(int n); - void SetDescriptor(int n, const MachMsgPortDescriptor &desc); + void SetDescriptor(int n, const MachMsgPortDescriptor& desc); // Returns total message size setting msgh_size in the header to this value mach_msg_size_t CalculateSize(); @@ -250,7 +249,7 @@ class MachSendMessage : public MachMessage { class ReceivePort { public: // Creates a new mach port for receiving messages and registers a name for it - explicit ReceivePort(const char *receive_port_name); + explicit ReceivePort(const char* receive_port_name); // Given an already existing mach port, use it. We take ownership of the // port and deallocate it in our destructor. @@ -262,7 +261,7 @@ class ReceivePort { ~ReceivePort(); // Waits on the mach port until message received or timeout - kern_return_t WaitForMessage(MachReceiveMessage *out_message, + kern_return_t WaitForMessage(MachReceiveMessage* out_message, mach_msg_timeout_t timeout); // The underlying mach port that we wrap @@ -280,13 +279,13 @@ class ReceivePort { class MachPortSender { public: // get a port with send rights corresponding to a named registered service - explicit MachPortSender(const char *receive_port_name); + explicit MachPortSender(const char* receive_port_name); // Given an already existing mach port, use it. explicit MachPortSender(mach_port_t send_port); - kern_return_t SendMessage(MachSendMessage &message, + kern_return_t SendMessage(MachSendMessage& message, mach_msg_timeout_t timeout); private: diff --git a/src/common/mac/MachIPC.mm b/src/common/mac/MachIPC.mm index dc9773f7..62e0f6b5 100644 --- a/src/common/mac/MachIPC.mm +++ b/src/common/mac/MachIPC.mm @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,7 +51,7 @@ MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() { //============================================================================== // returns true if successful -bool MachMessage::SetData(void *data, +bool MachMessage::SetData(void* data, int32_t data_length) { // first check to make sure we have enough space size_t size = CalculateSize(); @@ -90,9 +89,9 @@ mach_msg_size_t MachMessage::CalculateSize() { } //============================================================================== -MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { +MachMessage::MessageDataPacket* MachMessage::GetDataPacket() { size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); - MessageDataPacket *packet = + MessageDataPacket* packet = reinterpret_cast<MessageDataPacket*>(padding + desc_size); return packet; @@ -100,15 +99,15 @@ MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { //============================================================================== void MachMessage::SetDescriptor(int n, - const MachMsgPortDescriptor &desc) { - MachMsgPortDescriptor *desc_array = + const MachMsgPortDescriptor& desc) { + MachMsgPortDescriptor* desc_array = reinterpret_cast<MachMsgPortDescriptor*>(padding); desc_array[n] = desc; } //============================================================================== // returns true if successful otherwise there was not enough space -bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) { +bool MachMessage::AddDescriptor(const MachMsgPortDescriptor& desc) { // first check to make sure we have enough space int size = CalculateSize(); size_t new_size = size + sizeof(MachMsgPortDescriptor); @@ -119,7 +118,7 @@ bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) { // unfortunately, we need to move the data to allow space for the // new descriptor - u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket()); + u_int8_t* p = reinterpret_cast<u_int8_t*>(GetDataPacket()); bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t)); SetDescriptor(GetDescriptorCount(), desc); @@ -142,9 +141,9 @@ void MachMessage::SetDescriptorCount(int n) { } //============================================================================== -MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) { +MachMsgPortDescriptor* MachMessage::GetDescriptor(int n) { if (n < GetDescriptorCount()) { - MachMsgPortDescriptor *desc = + MachMsgPortDescriptor* desc = reinterpret_cast<MachMsgPortDescriptor*>(padding); return desc + n; } @@ -164,7 +163,7 @@ mach_port_t MachMessage::GetTranslatedPort(int n) { //============================================================================== // create a new mach port for receiving messages and register a name for it -ReceivePort::ReceivePort(const char *receive_port_name) { +ReceivePort::ReceivePort(const char* receive_port_name) { mach_port_t current_task = mach_task_self(); init_result_ = mach_port_allocate(current_task, @@ -227,7 +226,7 @@ ReceivePort::~ReceivePort() { } //============================================================================== -kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message, +kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage* out_message, mach_msg_timeout_t timeout) { if (!out_message) { return KERN_INVALID_ARGUMENT; @@ -261,7 +260,7 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message, //============================================================================== // get a port with send rights corresponding to a named registered service -MachPortSender::MachPortSender(const char *receive_port_name) { +MachPortSender::MachPortSender(const char* receive_port_name) { mach_port_t task_bootstrap_port = 0; init_result_ = task_get_bootstrap_port(mach_task_self(), &task_bootstrap_port); @@ -281,7 +280,7 @@ MachPortSender::MachPortSender(mach_port_t send_port) } //============================================================================== -kern_return_t MachPortSender::SendMessage(MachSendMessage &message, +kern_return_t MachPortSender::SendMessage(MachSendMessage& message, mach_msg_timeout_t timeout) { if (message.head.msgh_size == 0) { return KERN_INVALID_VALUE; // just for safety -- never should occur diff --git a/src/common/mac/SymbolCollectorClient.h b/src/common/mac/SymbolCollectorClient.h new file mode 100644 index 00000000..367753a4 --- /dev/null +++ b/src/common/mac/SymbolCollectorClient.h @@ -0,0 +1,103 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import <Foundation/Foundation.h> + +NS_ASSUME_NONNULL_BEGIN + +/** + Represents a response from a sym-upload-v2 server to a createUploadURLOnServer + call. + */ +@interface UploadURLResponse : NSObject { + @protected + NSString* uploadURL_; + NSString* uploadKey_; +} + +- (id)initWithUploadURL:(NSString*)uploadURL withUploadKey:(NSString*)uploadKey; + +- (NSString*)uploadURL; +- (NSString*)uploadKey; +@end + +/** + Possible return statuses from a sym-upload-v2 server to a + completeUploadOnServer call. + */ +typedef NS_ENUM(NSInteger, CompleteUploadResult) { + CompleteUploadResultOk, + CompleteUploadResultDuplicateData, + CompleteUploadResultError +}; + +/** + Possible return statuses from a sym-upload-v2 server to a + checkSymbolStatusOnServer call. + */ +typedef NS_ENUM(NSInteger, SymbolStatus) { + SymbolStatusFound, + SymbolStatusMissing, + SymbolStatusUnknown +}; + +/** + Interface to help a client interact with a sym-upload-v2 server, over HTTP. + For details of the API and protocol, see :/docs/sym_upload_v2_protocol.md. + */ +@interface SymbolCollectorClient : NSObject +; + +/** + Calls the /v1/symbols/{debug_file}/{debug_id}:checkStatus API on the server. + */ ++ (SymbolStatus)checkSymbolStatusOnServer:(NSString*)APIURL + withAPIKey:(NSString*)APIKey + withDebugFile:(NSString*)debugFile + withDebugID:(NSString*)debugID; + +/** + Calls the /v1/uploads:create API on the server. + */ ++ (UploadURLResponse*)createUploadURLOnServer:(NSString*)APIURL + withAPIKey:(NSString*)APIKey; + +/** + Calls the /v1/uploads/{key}:complete API on the server. + */ ++ (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL + withAPIKey:(NSString*)APIKey + withUploadKey:(NSString*)uploadKey + withDebugFile:(NSString*)debugFile + withDebugID:(NSString*)debugID + withType:(NSString*)type + withProductName:(NSString*)productName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/common/mac/SymbolCollectorClient.m b/src/common/mac/SymbolCollectorClient.m new file mode 100644 index 00000000..fd33432b --- /dev/null +++ b/src/common/mac/SymbolCollectorClient.m @@ -0,0 +1,271 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import "SymbolCollectorClient.h" + +#import "HTTPGetRequest.h" +#import "HTTPSimplePostRequest.h" + +@implementation UploadURLResponse + +//============================================================================= +- (id)initWithUploadURL:(NSString*)uploadURL + withUploadKey:(NSString*)uploadKey { + if (self = [super init]) { + uploadURL_ = [uploadURL copy]; + uploadKey_ = [uploadKey copy]; + } + return self; +} + +//============================================================================= +- (void)dealloc { + [uploadURL_ release]; + [uploadKey_ release]; + + [super dealloc]; +} + +//============================================================================= +- (NSString*)uploadURL { + return uploadURL_; +} + +//============================================================================= +- (NSString*)uploadKey { + return uploadKey_; +} +@end + +@implementation SymbolCollectorClient + +//============================================================================= ++ (SymbolStatus)checkSymbolStatusOnServer:(NSString*)APIURL + withAPIKey:(NSString*)APIKey + withDebugFile:(NSString*)debugFile + withDebugID:(NSString*)debugID { + // Note that forward-slash is listed as a character to escape here, for + // completeness, however it is illegal in a debugFile input. + NSMutableCharacterSet* allowedDebugFileCharacters = [NSMutableCharacterSet + characterSetWithCharactersInString:@" \"\\/#%:?@|^`{}<>[]&=;"]; + [allowedDebugFileCharacters + formUnionWithCharacterSet:[NSCharacterSet controlCharacterSet]]; + [allowedDebugFileCharacters invert]; + NSString* escapedDebugFile = + [debugFile stringByAddingPercentEncodingWithAllowedCharacters: + allowedDebugFileCharacters]; + + NSURL* URL = [NSURL + URLWithString:[NSString + stringWithFormat:@"%@/v1/symbols/%@/%@:checkStatus" + @"?key=%@", + APIURL, escapedDebugFile, debugID, + APIKey]]; + + HTTPGetRequest* getRequest = [[HTTPGetRequest alloc] initWithURL:URL]; + NSError* error = nil; + NSData* data = [getRequest send:&error]; + NSString* result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + int responseCode = [[getRequest response] statusCode]; + [getRequest release]; + + if (error || responseCode != 200) { + fprintf(stdout, "Failed to check symbol status.\n"); + fprintf(stdout, "Response code: %d\n", responseCode); + fprintf(stdout, "Response:\n"); + fprintf(stdout, "%s\n", [result UTF8String]); + return SymbolStatusUnknown; + } + + error = nil; + NSRegularExpression* statusRegex = [NSRegularExpression + regularExpressionWithPattern:@"\"status\": \"([^\"]+)\"" + options:0 + error:&error]; + NSArray* matches = + [statusRegex matchesInString:result + options:0 + range:NSMakeRange(0, [result length])]; + if ([matches count] != 1) { + fprintf(stdout, "Failed to parse check symbol status response."); + fprintf(stdout, "Response:\n"); + fprintf(stdout, "%s\n", [result UTF8String]); + return SymbolStatusUnknown; + } + + NSString* status = [result substringWithRange:[matches[0] rangeAtIndex:1]]; + [result release]; + + return [status isEqualToString:@"FOUND"] ? SymbolStatusFound + : SymbolStatusMissing; +} + +//============================================================================= ++ (UploadURLResponse*)createUploadURLOnServer:(NSString*)APIURL + withAPIKey:(NSString*)APIKey { + NSURL* URL = [NSURL + URLWithString:[NSString stringWithFormat:@"%@/v1/uploads:create?key=%@", + APIURL, APIKey]]; + + HTTPSimplePostRequest* postRequest = + [[HTTPSimplePostRequest alloc] initWithURL:URL]; + NSError* error = nil; + NSData* data = [postRequest send:&error]; + NSString* result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + int responseCode = [[postRequest response] statusCode]; + [postRequest release]; + + if (error || responseCode != 200) { + fprintf(stdout, "Failed to create upload URL.\n"); + fprintf(stdout, "Response code: %d\n", responseCode); + fprintf(stdout, "Response:\n"); + fprintf(stdout, "%s\n", [result UTF8String]); + return nil; + } + + // Note camel-case rather than underscores. + NSRegularExpression* uploadURLRegex = [NSRegularExpression + regularExpressionWithPattern:@"\"uploadUrl\": \"([^\"]+)\"" + options:0 + error:&error]; + NSRegularExpression* uploadKeyRegex = [NSRegularExpression + regularExpressionWithPattern:@"\"uploadKey\": \"([^\"]+)\"" + options:0 + error:&error]; + + NSArray* uploadURLMatches = + [uploadURLRegex matchesInString:result + options:0 + range:NSMakeRange(0, [result length])]; + NSArray* uploadKeyMatches = + [uploadKeyRegex matchesInString:result + options:0 + range:NSMakeRange(0, [result length])]; + if ([uploadURLMatches count] != 1 || [uploadKeyMatches count] != 1) { + fprintf(stdout, "Failed to parse create url response."); + fprintf(stdout, "Response:\n"); + fprintf(stdout, "%s\n", [result UTF8String]); + return nil; + } + NSString* uploadURL = + [result substringWithRange:[uploadURLMatches[0] rangeAtIndex:1]]; + NSString* uploadKey = + [result substringWithRange:[uploadKeyMatches[0] rangeAtIndex:1]]; + + return [[UploadURLResponse alloc] initWithUploadURL:uploadURL + withUploadKey:uploadKey]; +} + +//============================================================================= ++ (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL + withAPIKey:(NSString*)APIKey + withUploadKey:(NSString*)uploadKey + withDebugFile:(NSString*)debugFile + withDebugID:(NSString*)debugID + withType:(NSString*)type + withProductName:(NSString*)productName { + NSURL* URL = [NSURL + URLWithString:[NSString + stringWithFormat:@"%@/v1/uploads/%@:complete?key=%@", + APIURL, uploadKey, APIKey]]; + + NSMutableDictionary* jsonDictionary = [@{ + @"symbol_id" : @{@"debug_file" : debugFile, @"debug_id" : debugID}, + @"symbol_upload_type" : type, @"use_async_processing" : @"true" + } mutableCopy]; + + if (productName != nil) { + jsonDictionary[@"metadata"] = @{@"product_name": productName}; + } + + NSError* error = nil; + NSData* jsonData = + [NSJSONSerialization dataWithJSONObject:jsonDictionary + options:NSJSONWritingPrettyPrinted + error:&error]; + if (jsonData == nil) { + fprintf(stdout, "Error: %s\n", [[error localizedDescription] UTF8String]); + fprintf(stdout, + "Failed to complete upload. Could not write JSON payload.\n"); + return CompleteUploadResultError; + } + + NSString* body = [[NSString alloc] initWithData:jsonData + encoding:NSUTF8StringEncoding]; + HTTPSimplePostRequest* postRequest = + [[HTTPSimplePostRequest alloc] initWithURL:URL]; + [postRequest setBody:body]; + [postRequest setContentType:@"application/json"]; + + NSData* data = [postRequest send:&error]; + if (data == nil) { + fprintf(stdout, "Error: %s\n", [[error localizedDescription] UTF8String]); + fprintf(stdout, "Failed to complete upload URL.\n"); + return CompleteUploadResultError; + } + + NSString* result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + int responseCode = [[postRequest response] statusCode]; + [postRequest release]; + if (responseCode != 200) { + fprintf(stdout, "Failed to complete upload URL.\n"); + fprintf(stdout, "Response code: %d\n", responseCode); + fprintf(stdout, "Response:\n"); + fprintf(stdout, "%s\n", [result UTF8String]); + return CompleteUploadResultError; + } + + // Note camel-case rather than underscores. + NSRegularExpression* completeResultRegex = [NSRegularExpression + regularExpressionWithPattern:@"\"result\": \"([^\"]+)\"" + options:0 + error:&error]; + + NSArray* completeResultMatches = + [completeResultRegex matchesInString:result + options:0 + range:NSMakeRange(0, [result length])]; + + if ([completeResultMatches count] != 1) { + fprintf(stdout, "Failed to parse complete upload response."); + fprintf(stdout, "Response:\n"); + fprintf(stdout, "%s\n", [result UTF8String]); + return CompleteUploadResultError; + } + NSString* completeResult = + [result substringWithRange:[completeResultMatches[0] rangeAtIndex:1]]; + [result release]; + + return ([completeResult isEqualToString:@"DUPLICATE_DATA"]) + ? CompleteUploadResultDuplicateData + : CompleteUploadResultOk; +} +@end diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc index c0e4bac5..392efe78 100644 --- a/src/common/mac/arch_utilities.cc +++ b/src/common/mac/arch_utilities.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -130,7 +129,10 @@ const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, } // namespace google_breakpad -#ifndef __APPLE__ +// TODO(crbug.com/1242776): The "#ifndef __APPLE__" should be here, but the +// system version of NXGetLocalArchInfo returns incorrect information on +// x86_64 machines (treating them as just x86), so use the Breakpad version +// all the time for now. namespace { enum Architecture { @@ -219,6 +221,8 @@ const NXArchInfo *NXGetLocalArchInfo(void) { return &kKnownArchitectures[arch]; } +#ifndef __APPLE__ + const NXArchInfo *NXGetArchInfoFromName(const char *name) { for (int arch = 0; arch < kNumArchitectures; ++arch) { if (!strcmp(name, kKnownArchitectures[arch].name)) { diff --git a/src/common/mac/arch_utilities.h b/src/common/mac/arch_utilities.h index 397c1f58..d267c43b 100644 --- a/src/common/mac/arch_utilities.h +++ b/src/common/mac/arch_utilities.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/bootstrap_compat.cc b/src/common/mac/bootstrap_compat.cc index d875d95b..6647bae3 100644 --- a/src/common/mac/bootstrap_compat.cc +++ b/src/common/mac/bootstrap_compat.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/bootstrap_compat.h b/src/common/mac/bootstrap_compat.h index 8ca7357c..b57d9070 100644 --- a/src/common/mac/bootstrap_compat.h +++ b/src/common/mac/bootstrap_compat.h @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/byteswap.h b/src/common/mac/byteswap.h index b7bbc0b9..c4c7e617 100644 --- a/src/common/mac/byteswap.h +++ b/src/common/mac/byteswap.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc index 3fbedd95..9658b2c6 100644 --- a/src/common/mac/dump_syms.cc +++ b/src/common/mac/dump_syms.cc @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -74,12 +73,12 @@ #define CPU_TYPE_ARM64 (static_cast<cpu_type_t>(16777228)) #endif // CPU_TYPE_ARM64 -using dwarf2reader::ByteReader; +using google_breakpad::ByteReader; using google_breakpad::DwarfCUToModule; using google_breakpad::DwarfLineToModule; using google_breakpad::DwarfRangeListHandler; -using google_breakpad::FileID; using google_breakpad::mach_o::FatReader; +using google_breakpad::mach_o::FileID; using google_breakpad::mach_o::Section; using google_breakpad::mach_o::Segment; using google_breakpad::Module; @@ -120,7 +119,8 @@ vector<string> list_directory(const string& directory) { namespace google_breakpad { -bool DumpSymbols::Read(const string &filename) { +bool DumpSymbols::Read(const string& filename) { + selected_object_file_ = nullptr; struct stat st; if (stat(filename.c_str(), &st) == -1) { fprintf(stderr, "Could not access object file %s: %s\n", @@ -128,10 +128,11 @@ bool DumpSymbols::Read(const string &filename) { return false; } - input_pathname_ = filename; + from_disk_ = true; // Does this filename refer to a dSYM bundle? - string contents_path = input_pathname_ + "/Contents/Resources/DWARF"; + string contents_path = filename + "/Contents/Resources/DWARF"; + string object_filename; if (S_ISDIR(st.st_mode) && access(contents_path.c_str(), F_OK) == 0) { // If there's one file under Contents/Resources/DWARF then use that, @@ -139,30 +140,31 @@ bool DumpSymbols::Read(const string &filename) { const vector<string> entries = list_directory(contents_path); if (entries.size() == 0) { fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", - input_pathname_.c_str()); + filename.c_str()); return false; } if (entries.size() > 1) { fprintf(stderr, "Too many DWARF files in bundle: %s\n", - input_pathname_.c_str()); + filename.c_str()); return false; } - object_filename_ = entries[0]; + object_filename = entries[0]; } else { - object_filename_ = input_pathname_; + object_filename = filename; } // Read the file's contents into memory. bool read_ok = true; string error; - if (stat(object_filename_.c_str(), &st) != -1) { - FILE* f = fopen(object_filename_.c_str(), "rb"); + scoped_array<uint8_t> contents; + off_t total = 0; + if (stat(object_filename.c_str(), &st) != -1) { + FILE* f = fopen(object_filename.c_str(), "rb"); if (f) { - contents_.reset(new uint8_t[st.st_size]); - off_t total = 0; + contents.reset(new uint8_t[st.st_size]); while (total < st.st_size && !feof(f)) { - size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f); + size_t read = fread(&contents[0] + total, 1, st.st_size - total, f); if (read == 0) { if (ferror(f)) { read_ok = false; @@ -180,22 +182,28 @@ bool DumpSymbols::Read(const string &filename) { if (!read_ok) { fprintf(stderr, "Error reading object file: %s: %s\n", - object_filename_.c_str(), - error.c_str()); + object_filename.c_str(), error.c_str()); return false; } + return ReadData(contents.release(), total, object_filename); +} + +bool DumpSymbols::ReadData(uint8_t* contents, size_t size, + const std::string& filename) { + contents_.reset(contents); + size_ = size; + object_filename_ = filename; // Get the list of object files present in the file. FatReader::Reporter fat_reporter(object_filename_); FatReader fat_reader(&fat_reporter); - if (!fat_reader.Read(&contents_[0], - st.st_size)) { + if (!fat_reader.Read(contents_.get(), size)) { return false; } // Get our own copy of fat_reader's object file list. size_t object_files_count; - const SuperFatArch *object_files = + const SuperFatArch* object_files = fat_reader.object_files(&object_files_count); if (object_files_count == 0) { fprintf(stderr, "Fat binary file contains *no* architectures: %s\n", @@ -212,7 +220,7 @@ bool DumpSymbols::Read(const string &filename) { bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { // Find the best match for the architecture the user requested. - const SuperFatArch *best_match = FindBestMatchForArchitecture( + const SuperFatArch* best_match = FindBestMatchForArchitecture( cpu_type, cpu_subtype); if (!best_match) return false; @@ -221,9 +229,9 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, return true; } -bool DumpSymbols::SetArchitecture(const std::string &arch_name) { +bool DumpSymbols::SetArchitecture(const std::string& arch_name) { bool arch_set = false; - const NXArchInfo *arch_info = + const NXArchInfo* arch_info = google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str()); if (arch_info) { arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype); @@ -251,7 +259,7 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( // If all the object files can be converted to struct fat_arch, use // NXFindBestFatArch. if (can_convert_to_fat_arch) { - const struct fat_arch *best_match + const struct fat_arch* best_match = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0], static_cast<uint32_t>(fat_arch_vector.size())); @@ -260,7 +268,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( return &object_files_[i]; } assert(best_match == NULL); - return NULL; + // Fall through since NXFindBestFatArch can't find arm slices on x86_64 + // macOS 13. See FB11955188. } // Check for an exact match with cpu_type and cpu_subtype. @@ -268,7 +277,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( it != object_files_.end(); ++it) { if (static_cast<cpu_type_t>(it->cputype) == cpu_type && - static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype) + (static_cast<cpu_subtype_t>(it->cpusubtype) & ~CPU_SUBTYPE_MASK) == + (cpu_subtype & ~CPU_SUBTYPE_MASK)) return &*it; } @@ -277,17 +287,31 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( // NXFindBestFatArch, located at // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c. fprintf(stderr, "Failed to find an exact match for an object file with cpu " - "type: %d and cpu subtype: %d. Furthermore, at least one object file is " - "larger than 2**32.\n", cpu_type, cpu_subtype); + "type: %d and cpu subtype: %d.\n", cpu_type, cpu_subtype); + if (!can_convert_to_fat_arch) { + fprintf(stderr, "Furthermore, at least one object file is larger " + "than 2**32.\n"); + } return NULL; } string DumpSymbols::Identifier() { - FileID file_id(object_filename_.c_str()); + scoped_ptr<FileID> file_id; + + if (from_disk_) { + file_id.reset(new FileID(object_filename_.c_str())); + } else { + file_id.reset(new FileID(contents_.get(), size_)); + } unsigned char identifier_bytes[16]; + scoped_ptr<Module> module; + if (!selected_object_file_) { + if (!CreateEmptyModule(module)) + return string(); + } cpu_type_t cpu_type = selected_object_file_->cputype; cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype; - if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { + if (!file_id->MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", object_filename_.c_str()); return ""; @@ -302,57 +326,67 @@ string DumpSymbols::Identifier() { i = compacted.find('-', i)) compacted.erase(i, 1); + // The pdb for these IDs has an extra byte, so to make everything uniform put + // a 0 on the end of mac IDs. + compacted += "0"; + return compacted; } // A range handler that accepts rangelist data parsed by -// dwarf2reader::RangeListReader and populates a range vector (typically +// RangeListReader and populates a range vector (typically // owned by a function) with the results. class DumpSymbols::DumperRangesHandler: public DwarfCUToModule::RangesHandler { public: - DumperRangesHandler(const uint8_t *buffer, uint64_t size, - dwarf2reader::ByteReader* reader) - : buffer_(buffer), size_(size), reader_(reader) { } - - bool ReadRanges(uint64_t offset, Module::Address base_address, - vector<Module::Range>* ranges) { - DwarfRangeListHandler handler(base_address, ranges); - dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_, - &handler); - - return rangelist_reader.ReadRangeList(offset); + DumperRangesHandler(ByteReader* reader) : + reader_(reader) { } + + bool ReadRanges( + enum DwarfForm form, uint64_t data, + RangeListReader::CURangesInfo* cu_info, + vector<Module::Range>* ranges) { + DwarfRangeListHandler handler(ranges); + RangeListReader range_list_reader(reader_, cu_info, + &handler); + return range_list_reader.ReadRanges(form, data); } private: - const uint8_t *buffer_; - uint64_t size_; - dwarf2reader::ByteReader* reader_; + ByteReader* reader_; }; // A line-to-module loader that accepts line number info parsed by -// dwarf2reader::LineInfo and populates a Module and a line vector +// LineInfo and populates a Module and a line vector // with the results. class DumpSymbols::DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { public: // Create a line-to-module converter using BYTE_READER. - DumperLineToModule(dwarf2reader::ByteReader *byte_reader) + DumperLineToModule(ByteReader* byte_reader) : byte_reader_(byte_reader) { } void StartCompilationUnit(const string& compilation_dir) { compilation_dir_ = compilation_dir; } - void ReadProgram(const uint8_t *program, uint64_t length, - Module *module, vector<Module::Line> *lines) { - DwarfLineToModule handler(module, compilation_dir_, lines); - dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); + void ReadProgram(const uint8_t* program, + uint64_t length, + const uint8_t* string_section, + uint64_t string_section_length, + const uint8_t* line_string_section, + uint64_t line_string_section_length, + Module* module, + vector<Module::Line>* lines, + std::map<uint32_t, Module::File*>* files) { + DwarfLineToModule handler(module, compilation_dir_, lines, files); + LineInfo parser(program, length, byte_reader_, nullptr, 0, + nullptr, 0, &handler); parser.Start(); } private: string compilation_dir_; - dwarf2reader::ByteReader *byte_reader_; // WEAK + ByteReader* byte_reader_; // WEAK }; bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { @@ -364,7 +398,7 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { selected_object_file_ = &object_files_[0]; else { // Look for an object file whose architecture matches our own. - const NXArchInfo *local_arch = NXGetLocalArchInfo(); + const NXArchInfo* local_arch = NXGetLocalArchInfo(); if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { fprintf(stderr, "%s: object file contains more than one" " architecture, none of which match the current" @@ -380,11 +414,18 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { // Find the name of the selected file's architecture, to appear in // the MODULE record and in error messages. - const NXArchInfo *selected_arch_info = + const NXArchInfo* selected_arch_info = google_breakpad::BreakpadGetArchInfoFromCpuType( selected_object_file_->cputype, selected_object_file_->cpusubtype); - const char *selected_arch_name = selected_arch_info->name; + // In certain cases, it is possible that architecture info can't be reliably + // determined, e.g. new architectures that breakpad is unware of. In that + // case, avoid crashing and return false instead. + if (selected_arch_info == NULL) { + return false; + } + + const char* selected_arch_name = selected_arch_info->name; if (strcmp(selected_arch_name, "i386") == 0) selected_arch_name = "x86"; @@ -403,31 +444,28 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { string identifier = Identifier(); if (identifier.empty()) return false; - identifier += "0"; // Create a module to hold the debugging information. - module.reset(new Module(module_name, - "mac", - selected_arch_name, - identifier)); + module.reset(new Module(module_name, "mac", selected_arch_name, identifier, + "", enable_multiple_)); return true; } -void DumpSymbols::ReadDwarf(google_breakpad::Module *module, - const mach_o::Reader &macho_reader, - const mach_o::SectionMap &dwarf_sections, +void DumpSymbols::ReadDwarf(google_breakpad::Module* module, + const mach_o::Reader& macho_reader, + const mach_o::SectionMap& dwarf_sections, bool handle_inter_cu_refs) const { // Build a byte reader of the appropriate endianness. ByteReader byte_reader(macho_reader.big_endian() - ? dwarf2reader::ENDIANNESS_BIG - : dwarf2reader::ENDIANNESS_LITTLE); + ? ENDIANNESS_BIG + : ENDIANNESS_LITTLE); // Construct a context for this file. DwarfCUToModule::FileContext file_context(selected_object_name_, module, handle_inter_cu_refs); - // Build a dwarf2reader::SectionMap from our mach_o::SectionMap. + // Build a SectionMap from our mach_o::SectionMap. for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin(); it != dwarf_sections.end(); ++it) { file_context.AddSectionToSectionMap( @@ -437,7 +475,7 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module, } // Find the __debug_info section. - dwarf2reader::SectionMap::const_iterator debug_info_entry = + SectionMap::const_iterator debug_info_entry = file_context.section_map().find("__debug_info"); // There had better be a __debug_info section! if (debug_info_entry == file_context.section_map().end()) { @@ -451,17 +489,8 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module, // Build a line-to-module loader for the root handler to use. DumperLineToModule line_to_module(&byte_reader); - // Optional .debug_ranges reader - scoped_ptr<DumperRangesHandler> ranges_handler; - dwarf2reader::SectionMap::const_iterator ranges_entry = - file_context.section_map().find("__debug_ranges"); - if (ranges_entry != file_context.section_map().end()) { - const std::pair<const uint8_t *, uint64_t>& ranges_section = - ranges_entry->second; - ranges_handler.reset( - new DumperRangesHandler(ranges_section.first, ranges_section.second, - &byte_reader)); - } + // .debug_ranges and .debug_rngslists reader + DumperRangesHandler ranges_handler(&byte_reader); // Walk the __debug_info section, one compilation unit at a time. uint64_t debug_info_length = debug_info_section.second; @@ -471,11 +500,12 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module, DwarfCUToModule::WarningReporter reporter(selected_object_name_, offset); DwarfCUToModule root_handler(&file_context, &line_to_module, - ranges_handler.get(), &reporter); + &ranges_handler, &reporter, + symbol_data_ & INLINES); // Make a Dwarf2Handler that drives our DIEHandler. - dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); + DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET. - dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_, + CompilationUnit dwarf_reader(selected_object_name_, file_context.section_map(), offset, &byte_reader, @@ -485,9 +515,9 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module, } } -bool DumpSymbols::ReadCFI(google_breakpad::Module *module, - const mach_o::Reader &macho_reader, - const mach_o::Section §ion, +bool DumpSymbols::ReadCFI(google_breakpad::Module* module, + const mach_o::Reader& macho_reader, + const mach_o::Section& section, bool eh_frame) const { // Find the appropriate set of register names for this file's // architecture. @@ -506,7 +536,7 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module, register_names = DwarfCFIToModule::RegisterNames::ARM64(); break; default: { - const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType( + const NXArchInfo* arch = google_breakpad::BreakpadGetArchInfoFromCpuType( macho_reader.cpu_type(), macho_reader.cpu_subtype()); fprintf(stderr, "%s: cannot convert DWARF call frame information for ", selected_object_name_.c_str()); @@ -521,25 +551,25 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module, } // Find the call frame information and its size. - const uint8_t *cfi = section.contents.start; + const uint8_t* cfi = section.contents.start; size_t cfi_size = section.contents.Size(); // Plug together the parser, handler, and their entourages. DwarfCFIToModule::Reporter module_reporter(selected_object_name_, section.section_name); DwarfCFIToModule handler(module, register_names, &module_reporter); - dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ? - dwarf2reader::ENDIANNESS_BIG : - dwarf2reader::ENDIANNESS_LITTLE); + ByteReader byte_reader(macho_reader.big_endian() ? + ENDIANNESS_BIG : + ENDIANNESS_LITTLE); byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4); // At the moment, according to folks at Apple and some cursory // investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so // this is the only base address the CFI parser will need. byte_reader.SetCFIDataBase(section.address, cfi); - dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_, + CallFrameInfo::Reporter dwarf_reporter(selected_object_name_, section.section_name); - dwarf2reader::CallFrameInfo parser(cfi, cfi_size, + CallFrameInfo parser(cfi, cfi_size, &byte_reader, &handler, &dwarf_reporter, eh_frame); parser.Start(); @@ -553,9 +583,9 @@ class DumpSymbols::LoadCommandDumper: public: // Create a load command dumper handling load commands from READER's // file, and adding data to MODULE. - LoadCommandDumper(const DumpSymbols &dumper, - google_breakpad::Module *module, - const mach_o::Reader &reader, + LoadCommandDumper(const DumpSymbols& dumper, + google_breakpad::Module* module, + const mach_o::Reader& reader, SymbolData symbol_data, bool handle_inter_cu_refs) : dumper_(dumper), @@ -564,25 +594,25 @@ class DumpSymbols::LoadCommandDumper: symbol_data_(symbol_data), handle_inter_cu_refs_(handle_inter_cu_refs) { } - bool SegmentCommand(const mach_o::Segment &segment); - bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings); + bool SegmentCommand(const mach_o::Segment& segment); + bool SymtabCommand(const ByteBuffer& entries, const ByteBuffer& strings); private: - const DumpSymbols &dumper_; - google_breakpad::Module *module_; // WEAK - const mach_o::Reader &reader_; + const DumpSymbols& dumper_; + google_breakpad::Module* module_; // WEAK + const mach_o::Reader& reader_; const SymbolData symbol_data_; const bool handle_inter_cu_refs_; }; -bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) { +bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment& segment) { mach_o::SectionMap section_map; if (!reader_.MapSegmentSections(segment, §ion_map)) return false; if (segment.name == "__TEXT") { module_->SetLoadAddress(segment.vmaddr); - if (symbol_data_ != NO_CFI) { + if (symbol_data_ & CFI) { mach_o::SectionMap::const_iterator eh_frame = section_map.find("__eh_frame"); if (eh_frame != section_map.end()) { @@ -594,10 +624,10 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) { } if (segment.name == "__DWARF") { - if (symbol_data_ != ONLY_CFI) { + if ((symbol_data_ & SYMBOLS_AND_FILES) || (symbol_data_ & INLINES)) { dumper_.ReadDwarf(module_, reader_, section_map, handle_inter_cu_refs_); } - if (symbol_data_ != NO_CFI) { + if (symbol_data_ & CFI) { mach_o::SectionMap::const_iterator debug_frame = section_map.find("__debug_frame"); if (debug_frame != section_map.end()) { @@ -610,8 +640,8 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) { return true; } -bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries, - const ByteBuffer &strings) { +bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer& entries, + const ByteBuffer& strings) { StabsToModule stabs_to_module(module_); // Mac OS X STABS are never "unitized", and the size of the 'value' field // matches the address size of the executable. @@ -653,22 +683,10 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { return true; } -bool DumpSymbols::WriteSymbolFile(std::ostream &stream) { - Module* module = NULL; - - if (ReadSymbolData(&module) && module) { - bool res = module->Write(stream, symbol_data_); - delete module; - return res; - } - - return false; -} - // Read the selected object file's debugging information, and write out the // header only to |stream|. Return true on success; if an error occurs, report // it and return false. -bool DumpSymbols::WriteSymbolFileHeader(std::ostream &stream) { +bool DumpSymbols::WriteSymbolFileHeader(std::ostream& stream) { scoped_ptr<Module> module; if (!CreateEmptyModule(module)) return false; diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h index 1e57f86d..c2e1b40b 100644 --- a/src/common/mac/dump_syms.h +++ b/src/common/mac/dump_syms.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -54,23 +53,34 @@ namespace google_breakpad { class DumpSymbols { public: - DumpSymbols(SymbolData symbol_data, bool handle_inter_cu_refs) + DumpSymbols(SymbolData symbol_data, + bool handle_inter_cu_refs, + bool enable_multiple = false) : symbol_data_(symbol_data), handle_inter_cu_refs_(handle_inter_cu_refs), - input_pathname_(), object_filename_(), contents_(), + size_(0), + from_disk_(false), object_files_(), selected_object_file_(), - selected_object_name_() { } - ~DumpSymbols() { - } + selected_object_name_(), + enable_multiple_(enable_multiple) {} + ~DumpSymbols() = default; // Prepare to read debugging information from |filename|. |filename| may be - // the name of a universal binary, a Mach-O file, or a dSYM bundle - // containing either of the above. On success, return true; if there is a - // problem reading |filename|, report it and return false. - bool Read(const std::string &filename); + // the name of a fat file, a Mach-O file, or a dSYM bundle containing either + // of the above. On success, return true; if there is a problem reading + // |filename|, report it and return false. + bool Read(const std::string& filename); + + // Prepare to read debugging information from |contents|. |contents| is + // expected to be the data obtained from reading a fat file, or a Mach-O file. + // |filename| is used to determine the object filename in the generated + // output; there will not be an attempt to open this file as the data + // is already expected to be in memory. On success, return true; if there is a + // problem reading |contents|, report it and return false. + bool ReadData(uint8_t* contents, size_t size, const std::string& filename); // If this dumper's file includes an object file for |cpu_type| and // |cpu_subtype|, then select that object file for dumping, and return @@ -91,7 +101,7 @@ class DumpSymbols { // the dumper will dump those symbols; and if it contains more than one // object file, then the dumper will dump the object file whose // architecture matches that of this dumper program. - bool SetArchitecture(const std::string &arch_name); + bool SetArchitecture(const std::string& arch_name); // Return a pointer to an array of SuperFatArch structures describing the // object files contained in this dumper's file. Set *|count| to the number @@ -100,28 +110,26 @@ class DumpSymbols { // // If there are no available architectures, this function // may return NULL. - const SuperFatArch* AvailableArchitectures(size_t *count) { + const SuperFatArch* AvailableArchitectures(size_t* count) { *count = object_files_.size(); if (object_files_.size() > 0) return &object_files_[0]; return NULL; } - // Read the selected object file's debugging information, and write it out to - // |stream|. Return true on success; if an error occurs, report it and - // return false. - bool WriteSymbolFile(std::ostream &stream); - // Read the selected object file's debugging information, and write out the // header only to |stream|. Return true on success; if an error occurs, report // it and return false. - bool WriteSymbolFileHeader(std::ostream &stream); + bool WriteSymbolFileHeader(std::ostream& stream); - // As above, but simply return the debugging information in module - // instead of writing it to a stream. The caller owns the resulting - // module object and must delete it when finished. + // Read the selected object file's debugging information and store it in + // `module`. The caller owns the resulting module object and must delete + // it when finished. bool ReadSymbolData(Module** module); + // Return an identifier string for the file this DumpSymbols is dumping. + std::string Identifier(); + private: // Used internally. class DumperLineToModule; @@ -133,18 +141,14 @@ class DumpSymbols { SuperFatArch* FindBestMatchForArchitecture( cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); - // Return an identifier string for the file this DumpSymbols is dumping. - std::string Identifier(); - - // Creates an empty module object. bool CreateEmptyModule(scoped_ptr<Module>& module); // Read debugging information from |dwarf_sections|, which was taken from // |macho_reader|, and add it to |module|. - void ReadDwarf(google_breakpad::Module *module, - const mach_o::Reader &macho_reader, - const mach_o::SectionMap &dwarf_sections, + void ReadDwarf(google_breakpad::Module* module, + const mach_o::Reader& macho_reader, + const mach_o::SectionMap& dwarf_sections, bool handle_inter_cu_refs) const; // Read DWARF CFI or .eh_frame data from |section|, belonging to @@ -152,9 +156,9 @@ class DumpSymbols { // then the data is .eh_frame-format data; otherwise, it is standard DWARF // .debug_frame data. On success, return true; on failure, report // the problem and return false. - bool ReadCFI(google_breakpad::Module *module, - const mach_o::Reader &macho_reader, - const mach_o::Section §ion, + bool ReadCFI(google_breakpad::Module* module, + const mach_o::Reader& macho_reader, + const mach_o::Section& section, bool eh_frame) const; // The selection of what type of symbol data to read/write. @@ -163,19 +167,22 @@ class DumpSymbols { // Whether to handle references between compilation units. const bool handle_inter_cu_refs_; - // The name of the file or bundle whose symbols this will dump. - // This is the path given to Read, for use in error messages. - std::string input_pathname_; - // The name of the file this DumpSymbols will actually read debugging - // information from. Normally, this is the same as input_pathname_, but if - // filename refers to a dSYM bundle, then this is the resource file - // within that bundle. + // information from. If the filename passed to Read refers to a dSYM bundle, + // then this is the resource file within that bundle. std::string object_filename_; // The complete contents of object_filename_, mapped into memory. scoped_array<uint8_t> contents_; + // The size of contents_. + size_t size_; + + // Indicates which entry point to DumpSymbols was used, i.e. Read vs ReadData. + // This is used to indicate that downstream code paths can/should also read + // from disk or not. + bool from_disk_; + // A vector of SuperFatArch structures describing the object files // object_filename_ contains. If object_filename_ refers to a fat binary, // this may have more than one element; if it refers to a Mach-O file, this @@ -184,13 +191,19 @@ class DumpSymbols { // The object file in object_files_ selected to dump, or NULL if // SetArchitecture hasn't been called yet. - const SuperFatArch *selected_object_file_; + const SuperFatArch* selected_object_file_; // A string that identifies the selected object file, for use in error // messages. This is usually object_filename_, but if that refers to a // fat binary, it includes an indication of the particular architecture // within that binary. string selected_object_name_; + + // Whether symbols sharing an address should be collapsed into a single entry + // and marked with an `m` in the output. + // See: https://crbug.com/google-breakpad/751 and docs at + // docs/symbol_files.md#records-3 + bool enable_multiple_; }; } // namespace google_breakpad diff --git a/src/common/mac/encoding_util.h b/src/common/mac/encoding_util.h new file mode 100644 index 00000000..3028f2e9 --- /dev/null +++ b/src/common/mac/encoding_util.h @@ -0,0 +1,40 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H +#define GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H + +#import <Foundation/Foundation.h> + +// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been +// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it +// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when +// using those SDKs. +NSString* PercentEncodeNSString(NSString* key); + +#endif // GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H diff --git a/src/common/mac/encoding_util.m b/src/common/mac/encoding_util.m new file mode 100644 index 00000000..5cf84fc5 --- /dev/null +++ b/src/common/mac/encoding_util.m @@ -0,0 +1,46 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "encoding_util.h" + +#include <Availability.h> +#include <AvailabilityMacros.h> +#import <Foundation/Foundation.h> + +NSString* PercentEncodeNSString(NSString* key) { +#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \ + (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ + defined(MAC_OS_X_VERSION_10_11) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) + return [key stringByAddingPercentEncodingWithAllowedCharacters: + [NSCharacterSet URLQueryAllowedCharacterSet]]; +#else + return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; +#endif +} diff --git a/src/common/mac/file_id.cc b/src/common/mac/file_id.cc index 4661d5d6..a6c1d26f 100644 --- a/src/common/mac/file_id.cc +++ b/src/common/mac/file_id.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -33,53 +32,41 @@ // // Author: Dan Waylonis +#include "common/mac/file_id.h" + #include <fcntl.h> #include <stdio.h> #include <string.h> -#include <unistd.h> -#include "common/mac/file_id.h" #include "common/mac/macho_id.h" +#include "common/scoped_ptr.h" using MacFileUtilities::MachoID; namespace google_breakpad { - -FileID::FileID(const char *path) { +namespace mach_o { +// Constructs a FileID given a path to a file +FileID::FileID(const char* path) : memory_(nullptr), size_(0) { snprintf(path_, sizeof(path_), "%s", path); } -bool FileID::FileIdentifier(unsigned char identifier[16]) { - int fd = open(path_, O_RDONLY); - if (fd == -1) - return false; - - MD5Context md5; - MD5Init(&md5); - - // Read 4k x 2 bytes at a time. This is faster than just 4k bytes, but - // doesn't seem to be an unreasonable size for the stack. - unsigned char buffer[4096 * 2]; - size_t buffer_size = sizeof(buffer); - while ((buffer_size = read(fd, buffer, buffer_size) > 0)) { - MD5Update(&md5, buffer, static_cast<unsigned>(buffer_size)); - } - - close(fd); - MD5Final(identifier, &md5); - - return true; -} +// Constructs a FileID given the contents of a file and its size +FileID::FileID(void* memory, size_t size) + : path_(), memory_(memory), size_(size) {} bool FileID::MachoIdentifier(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) { - MachoID macho(path_); - - if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier)) + scoped_ptr<MachoID> macho; + if (memory_) { + macho.reset(new MachoID(memory_, size_)); + } else { + macho.reset(new MachoID(path_)); + } + if (macho->UUIDCommand(cpu_type, cpu_subtype, identifier)) return true; - return macho.MD5(cpu_type, cpu_subtype, identifier); + return macho->MD5(cpu_type, cpu_subtype, identifier); } // static @@ -103,4 +90,5 @@ void FileID::ConvertIdentifierToString(const unsigned char identifier[16], buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0; } +} // namespace mach_o } // namespace google_breakpad diff --git a/src/common/mac/file_id.h b/src/common/mac/file_id.h index 5d60e84c..a14cd137 100644 --- a/src/common/mac/file_id.h +++ b/src/common/mac/file_id.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -36,19 +35,19 @@ #include <limits.h> #include <mach/machine.h> +#include <stddef.h> namespace google_breakpad { +namespace mach_o { class FileID { public: - FileID(const char *path); - ~FileID() {} + // Constructs a FileID given a path to a file + FileID(const char* path); - // Load the identifier for the file path specified in the constructor into - // |identifier|. Return false if the identifier could not be created for the - // file. - // The current implementation will return the MD5 hash of the file's bytes. - bool FileIdentifier(unsigned char identifier[16]); + // Constructs a FileID given the contents of a file and its size. + FileID(void* memory, size_t size); + ~FileID() {} // Treat the file as a mach-o file that will contain one or more archicture. // Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or @@ -74,8 +73,19 @@ class FileID { private: // Storage for the path specified char path_[PATH_MAX]; + + // Storage for contents of a file if this instance is used to operate on in + // memory file data rather than directly from a filesystem. If memory_ is + // null, the file represented by path_ will be opened/read. If memory_ is + // non-null, it is assumed to contain valid data, and no file operations will + // occur. + void* memory_; + + // Size of memory_ + size_t size_; }; +} // namespace mach_o } // namespace google_breakpad #endif // COMMON_MAC_FILE_ID_H__ diff --git a/src/common/mac/launch_reporter.cc b/src/common/mac/launch_reporter.cc index 245be826..de554ee3 100644 --- a/src/common/mac/launch_reporter.cc +++ b/src/common/mac/launch_reporter.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/launch_reporter.h b/src/common/mac/launch_reporter.h index 4531123c..0cf73547 100644 --- a/src/common/mac/launch_reporter.h +++ b/src/common/mac/launch_reporter.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/macho_id.cc b/src/common/mac/macho_id.cc index c396ad88..e67ccddb 100644 --- a/src/common/mac/macho_id.cc +++ b/src/common/mac/macho_id.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,11 +36,7 @@ #include <fcntl.h> #include <mach-o/loader.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> #include "common/mac/macho_id.h" #include "common/mac/macho_walker.h" @@ -53,80 +48,25 @@ using google_breakpad::MD5Init; using google_breakpad::MD5Update; using google_breakpad::MD5Final; -MachoID::MachoID(const char *path) - : memory_(0), - memory_size_(0), - crc_(0), - md5_context_(), - update_function_(NULL) { +MachoID::MachoID(const char* path) + : memory_(0), memory_size_(0), md5_context_(), update_function_(NULL) { snprintf(path_, sizeof(path_), "%s", path); } -MachoID::MachoID(const char *path, void *memory, size_t size) - : memory_(memory), - memory_size_(size), - crc_(0), - md5_context_(), - update_function_(NULL) { - snprintf(path_, sizeof(path_), "%s", path); -} - -MachoID::~MachoID() { -} +MachoID::MachoID(void* memory, size_t size) + : path_(), + memory_(memory), + memory_size_(size), + md5_context_(), + update_function_(NULL) {} -// The CRC info is from http://en.wikipedia.org/wiki/Adler-32 -// With optimizations from http://www.zlib.net/ - -// The largest prime smaller than 65536 -#define MOD_ADLER 65521 -// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1 -#define MAX_BLOCK 5552 - -void MachoID::UpdateCRC(unsigned char *bytes, size_t size) { -// Unrolled loops for summing -#define DO1(buf,i) {sum1 += (buf)[i]; sum2 += sum1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - // Split up the crc - uint32_t sum1 = crc_ & 0xFFFF; - uint32_t sum2 = (crc_ >> 16) & 0xFFFF; - - // Do large blocks - while (size >= MAX_BLOCK) { - size -= MAX_BLOCK; - int block_count = MAX_BLOCK / 16; - do { - DO16(bytes); - bytes += 16; - } while (--block_count); - sum1 %= MOD_ADLER; - sum2 %= MOD_ADLER; - } +MachoID::~MachoID() {} - // Do remaining bytes - if (size) { - while (size >= 16) { - size -= 16; - DO16(bytes); - bytes += 16; - } - while (size--) { - sum1 += *bytes++; - sum2 += sum1; - } - sum1 %= MOD_ADLER; - sum2 %= MOD_ADLER; - crc_ = (sum2 << 16) | sum1; - } -} - -void MachoID::UpdateMD5(unsigned char *bytes, size_t size) { +void MachoID::UpdateMD5(unsigned char* bytes, size_t size) { MD5Update(&md5_context_, bytes, static_cast<unsigned>(size)); } -void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) { +void MachoID::Update(MachoWalker* walker, off_t offset, size_t size) { if (!update_function_ || !size) return; @@ -169,59 +109,6 @@ bool MachoID::UUIDCommand(cpu_type_t cpu_type, return false; } -bool MachoID::IDCommand(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char identifier[16]) { - struct dylib_command dylib_cmd; - dylib_cmd.cmd = 0; - if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd)) - return false; - - // If we found the command, we'll have initialized the dylib_command - // structure - if (dylib_cmd.cmd == LC_ID_DYLIB) { - // Take the hashed filename, version, and compatability version bytes - // to form the first 12 bytes, pad the rest with zeros - - // create a crude hash of the filename to generate the first 4 bytes - identifier[0] = 0; - identifier[1] = 0; - identifier[2] = 0; - identifier[3] = 0; - - for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) { - identifier[j%4] += path_[i]; - } - - identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF; - identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF; - identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF; - identifier[7] = dylib_cmd.dylib.current_version & 0xFF; - identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF; - identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF; - identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF; - identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF; - identifier[12] = (cpu_type >> 24) & 0xFF; - identifier[13] = (cpu_type >> 16) & 0xFF; - identifier[14] = (cpu_type >> 8) & 0xFF; - identifier[15] = cpu_type & 0xFF; - - return true; - } - - return false; -} - -uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { - update_function_ = &MachoID::UpdateCRC; - crc_ = 0; - - if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this)) - return 0; - - return crc_; -} - bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) { update_function_ = &MachoID::UpdateMD5; @@ -237,7 +124,7 @@ bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char bool MachoID::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, MachoWalker::LoadCommandCallback callback, - void *context) { + void* context) { if (memory_) { MachoWalker walker(memory_, memory_size_, callback, context); return walker.WalkHeader(cpu_type, cpu_subtype); @@ -248,9 +135,9 @@ bool MachoID::WalkHeader(cpu_type_t cpu_type, } // static -bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context) { - MachoID *macho_id = (MachoID *)context; +bool MachoID::WalkerCB(MachoWalker* walker, load_command* cmd, off_t offset, + bool swap, void* context) { + MachoID* macho_id = (MachoID*)context; if (cmd->cmd == LC_SEGMENT) { struct segment_command seg; @@ -327,11 +214,11 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, } // static -bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context) { +bool MachoID::UUIDWalkerCB(MachoWalker* walker, load_command* cmd, off_t offset, + bool swap, void* context) { if (cmd->cmd == LC_UUID) { - struct breakpad_uuid_command *uuid_cmd = - (struct breakpad_uuid_command *)context; + struct breakpad_uuid_command* uuid_cmd = + (struct breakpad_uuid_command*)context; if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command), offset)) @@ -346,24 +233,4 @@ bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, // Continue processing return true; } - -// static -bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context) { - if (cmd->cmd == LC_ID_DYLIB) { - struct dylib_command *dylib_cmd = (struct dylib_command *)context; - - if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset)) - return false; - - if (swap) - breakpad_swap_dylib_command(dylib_cmd); - - return false; - } - - // Continue processing - return true; -} - } // namespace MacFileUtilities diff --git a/src/common/mac/macho_id.h b/src/common/mac/macho_id.h index 10375491..b9cbdb00 100644 --- a/src/common/mac/macho_id.h +++ b/src/common/mac/macho_id.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,8 +44,8 @@ namespace MacFileUtilities { class MachoID { public: - MachoID(const char *path); - MachoID(const char *path, void *memory, size_t size); + MachoID(const char* path); + MachoID(void* memory, size_t size); ~MachoID(); // For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID @@ -56,19 +55,6 @@ class MachoID { cpu_subtype_t cpu_subtype, unsigned char identifier[16]); - // For the given |cpu_type| and |cpu_subtype|, return a UUID from the - // LC_ID_DYLIB command. - // Return false if there isn't a LC_ID_DYLIB command. - bool IDCommand(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char identifier[16]); - - // For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the - // mach-o data segment(s). - // Return 0 on error (e.g., if the file is not a mach-o file) - uint32_t Adler32(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype); - // For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o // data segment(s). // Return true on success, false otherwise @@ -78,47 +64,36 @@ class MachoID { private: // Signature of class member function to be called with data read from file - typedef void (MachoID::*UpdateFunction)(unsigned char *bytes, size_t size); - - // Update the CRC value by examining |size| |bytes| and applying the algorithm - // to each byte. - void UpdateCRC(unsigned char *bytes, size_t size); + typedef void (MachoID::*UpdateFunction)(unsigned char* bytes, size_t size); // Update the MD5 value by examining |size| |bytes| and applying the algorithm // to each byte. - void UpdateMD5(unsigned char *bytes, size_t size); + void UpdateMD5(unsigned char* bytes, size_t size); // Bottleneck for update routines - void Update(MachoWalker *walker, off_t offset, size_t size); + void Update(MachoWalker* walker, off_t offset, size_t size); // Factory for the MachoWalker bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, - MachoWalker::LoadCommandCallback callback, void *context); + MachoWalker::LoadCommandCallback callback, void* context); // The callback from the MachoWalker for CRC and MD5 - static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context); + static bool WalkerCB(MachoWalker* walker, load_command* cmd, off_t offset, + bool swap, void* context); // The callback from the MachoWalker for LC_UUID - static bool UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context); - - // The callback from the MachoWalker for LC_ID_DYLIB - static bool IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context); + static bool UUIDWalkerCB(MachoWalker* walker, load_command* cmd, off_t offset, + bool swap, void* context); // File path char path_[PATH_MAX]; // Memory region to read from - void *memory_; + void* memory_; // Size of the memory region size_t memory_size_; - // The current crc value - uint32_t crc_; - // The MD5 context google_breakpad::MD5Context md5_context_; diff --git a/src/common/mac/macho_reader.cc b/src/common/mac/macho_reader.cc index 91e1fdd2..23c809c4 100644 --- a/src/common/mac/macho_reader.cc +++ b/src/common/mac/macho_reader.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -81,7 +80,7 @@ void FatReader::Reporter::MisplacedObjectFile() { " to contain\n", filename_.c_str()); } -bool FatReader::Read(const uint8_t *buffer, size_t size) { +bool FatReader::Read(const uint8_t* buffer, size_t size) { buffer_.start = buffer; buffer_.end = buffer + size; ByteCursor cursor(&buffer_); @@ -196,19 +195,19 @@ void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) { filename_.c_str(), i, type); } -void Reader::Reporter::SectionsMissing(const string &name) { +void Reader::Reporter::SectionsMissing(const string& name) { fprintf(stderr, "%s: the load command for segment '%s'" " is too short to hold the section headers it claims to have\n", filename_.c_str(), name.c_str()); } -void Reader::Reporter::MisplacedSegmentData(const string &name) { +void Reader::Reporter::MisplacedSegmentData(const string& name) { fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond" " the end of the file\n", filename_.c_str(), name.c_str()); } -void Reader::Reporter::MisplacedSectionData(const string §ion, - const string &segment) { +void Reader::Reporter::MisplacedSectionData(const string& section, + const string& segment) { fprintf(stderr, "%s: the section '%s' in segment '%s'" " claims its contents lie outside the segment's contents\n", filename_.c_str(), section.c_str(), segment.c_str()); @@ -225,7 +224,7 @@ void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) { filename_.c_str(), cpu_type); } -bool Reader::Read(const uint8_t *buffer, +bool Reader::Read(const uint8_t* buffer, size_t size, cpu_type_t expected_cpu_type, cpu_subtype_t expected_cpu_subtype) { @@ -309,7 +308,7 @@ bool Reader::Read(const uint8_t *buffer, return true; } -bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const { +bool Reader::WalkLoadCommands(Reader::LoadCommandHandler* handler) const { ByteCursor list_cursor(&load_commands_, big_endian_); for (size_t index = 0; index < load_command_count_; ++index) { @@ -422,13 +421,13 @@ class Reader::SegmentFinder : public LoadCommandHandler { public: // Create a load command handler that looks for a segment named NAME, // and sets SEGMENT to describe it if found. - SegmentFinder(const string &name, Segment *segment) + SegmentFinder(const string& name, Segment* segment) : name_(name), segment_(segment), found_() { } // Return true if the traversal found the segment, false otherwise. bool found() const { return found_; } - bool SegmentCommand(const Segment &segment) { + bool SegmentCommand(const Segment& segment) { if (segment.name == name_) { *segment_ = segment; found_ = true; @@ -439,23 +438,23 @@ class Reader::SegmentFinder : public LoadCommandHandler { private: // The name of the segment our creator is looking for. - const string &name_; + const string& name_; // Where we should store the segment if found. (WEAK) - Segment *segment_; + Segment* segment_; // True if we found the segment. bool found_; }; -bool Reader::FindSegment(const string &name, Segment *segment) const { +bool Reader::FindSegment(const string& name, Segment* segment) const { SegmentFinder finder(name, segment); WalkLoadCommands(&finder); return finder.found(); } -bool Reader::WalkSegmentSections(const Segment &segment, - SectionHandler *handler) const { +bool Reader::WalkSegmentSections(const Segment& segment, + SectionHandler* handler) const { size_t word_size = segment.bits_64 ? 8 : 4; ByteCursor cursor(&segment.section_list, big_endian_); @@ -518,12 +517,21 @@ bool Reader::WalkSegmentSections(const Segment &segment, if (offset < size_t(segment.contents.start - buffer_.start) || offset > size_t(segment.contents.end - buffer_.start) || size > size_t(segment.contents.end - buffer_.start - offset)) { - reporter_->MisplacedSectionData(section.section_name, - section.segment_name); - return false; + if (offset > 0) { + reporter_->MisplacedSectionData(section.section_name, + section.segment_name); + return false; + } else { + // Mach-O files in .dSYM bundles have the contents of the loaded + // segments partially removed. The removed sections will have zero as + // their offset. MisplacedSectionData should not be called in this + // case. + section.contents.start = section.contents.end = NULL; + } + } else { + section.contents.start = buffer_.start + offset; + section.contents.end = section.contents.start + size; } - section.contents.start = buffer_.start + offset; - section.contents.end = section.contents.start + size; } if (!handler->HandleSection(section)) return false; @@ -537,18 +545,18 @@ class Reader::SectionMapper: public SectionHandler { public: // Create a SectionHandler that populates MAP with an entry for // each section it is given. - SectionMapper(SectionMap *map) : map_(map) { } - bool HandleSection(const Section §ion) { + SectionMapper(SectionMap* map) : map_(map) { } + bool HandleSection(const Section& section) { (*map_)[section.section_name] = section; return true; } private: // The map under construction. (WEAK) - SectionMap *map_; + SectionMap* map_; }; -bool Reader::MapSegmentSections(const Segment &segment, - SectionMap *section_map) const { +bool Reader::MapSegmentSections(const Segment& segment, + SectionMap* section_map) const { section_map->clear(); SectionMapper mapper(section_map); return WalkSegmentSections(segment, &mapper); diff --git a/src/common/mac/macho_reader.h b/src/common/mac/macho_reader.h index 145d17d1..d3c61a06 100644 --- a/src/common/mac/macho_reader.h +++ b/src/common/mac/macho_reader.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -78,7 +77,7 @@ class FatReader { class Reporter { public: // Create a reporter that attributes problems to |filename|. - explicit Reporter(const string &filename) : filename_(filename) { } + explicit Reporter(const string& filename) : filename_(filename) { } virtual ~Reporter() { } @@ -101,7 +100,7 @@ class FatReader { }; // Create a fat binary file reader that uses |reporter| to report problems. - explicit FatReader(Reporter *reporter) : reporter_(reporter) { } + explicit FatReader(Reporter* reporter) : reporter_(reporter) { } // Read the |size| bytes at |buffer| as a fat binary file. On success, // return true; on failure, report the problem to reporter_ and return @@ -110,7 +109,7 @@ class FatReader { // If the data is a plain Mach-O file, rather than a fat binary file, // then the reader behaves as if it had found a fat binary file whose // single object file is the Mach-O file. - bool Read(const uint8_t *buffer, size_t size); + bool Read(const uint8_t* buffer, size_t size); // Return an array of 'SuperFatArch' structures describing the // object files present in this fat binary file. Set |size| to the @@ -130,7 +129,7 @@ class FatReader { // possible to use the result with OS X functions like NXFindBestFatArch, // so that the symbol dumper will behave consistently with other OS X // utilities that work with fat binaries. - const SuperFatArch* object_files(size_t *count) const { + const SuperFatArch* object_files(size_t* count) const { *count = object_files_.size(); if (object_files_.size() > 0) return &object_files_[0]; @@ -139,7 +138,7 @@ class FatReader { private: // We use this to report problems parsing the file's contents. (WEAK) - Reporter *reporter_; + Reporter* reporter_; // The contents of the fat binary or Mach-O file we're parsing. We do not // own the storage it refers to. @@ -240,7 +239,7 @@ class Reader { class Reporter { public: // Create a reporter that attributes problems to |filename|. - explicit Reporter(const string &filename) : filename_(filename) { } + explicit Reporter(const string& filename) : filename_(filename) { } virtual ~Reporter() { } // Reporter functions for fatal errors return void; the reader will @@ -282,16 +281,16 @@ class Reader { // The LC_SEGMENT or LC_SEGMENT_64 load command for the segment named // |name| is too short to hold the sections that its header says it does. // (This more specific than LoadCommandTooShort.) - virtual void SectionsMissing(const string &name); + virtual void SectionsMissing(const string& name); // The segment named |name| claims that its contents lie beyond the end // of the file. - virtual void MisplacedSegmentData(const string &name); + virtual void MisplacedSegmentData(const string& name); // The section named |section| in the segment named |segment| claims that // its contents do not lie entirely within the segment. - virtual void MisplacedSectionData(const string §ion, - const string &segment); + virtual void MisplacedSectionData(const string& section, + const string& segment); // The LC_SYMTAB command claims that symbol table contents are located // beyond the end of the file. @@ -315,7 +314,7 @@ class Reader { // Called to report that the segment's section list contains |section|. // This should return true if the iteration should continue, or false // if it should stop. - virtual bool HandleSection(const Section §ion) = 0; + virtual bool HandleSection(const Section& section) = 0; }; // A handler for the load commands in a Mach-O file. @@ -341,20 +340,20 @@ class Reader { // cannot parse the command type or its size, we call // reporter_->IncompleteLoadCommand instead.) virtual bool UnknownCommand(LoadCommandType type, - const ByteBuffer &contents) { + const ByteBuffer& contents) { return true; } // The load command is LC_SEGMENT or LC_SEGMENT_64, defining a segment // with the properties given in |segment|. - virtual bool SegmentCommand(const Segment &segment) { + virtual bool SegmentCommand(const Segment& segment) { return true; } // The load command is LC_SYMTAB. |entries| holds the array of nlist // entries, and |names| holds the strings the entries refer to. - virtual bool SymtabCommand(const ByteBuffer &entries, - const ByteBuffer &names) { + virtual bool SymtabCommand(const ByteBuffer& entries, + const ByteBuffer& names) { return true; } @@ -362,7 +361,7 @@ class Reader { }; // Create a Mach-O file reader that reports problems to |reporter|. - explicit Reader(Reporter *reporter) + explicit Reader(Reporter* reporter) : reporter_(reporter) { } // Read the given data as a Mach-O file. The reader retains pointers @@ -371,11 +370,11 @@ class Reader { // // At most one of these functions should be invoked once on each Reader // instance. - bool Read(const uint8_t *buffer, + bool Read(const uint8_t* buffer, size_t size, cpu_type_t expected_cpu_type, cpu_subtype_t expected_cpu_subtype); - bool Read(const ByteBuffer &buffer, + bool Read(const ByteBuffer& buffer, cpu_type_t expected_cpu_type, cpu_subtype_t expected_cpu_subtype) { return Read(buffer.start, @@ -402,25 +401,25 @@ class Reader { // a handler function returns false. If we encounter a malformed load // command, report it via reporter_ and return false. Return true if all // load commands were parseable and all handlers returned true. - bool WalkLoadCommands(LoadCommandHandler *handler) const; + bool WalkLoadCommands(LoadCommandHandler* handler) const; // Set |segment| to describe the segment named |name|, if present. If // found, |segment|'s byte buffers refer to a subregion of the bytes // passed to Read. If we find the section, return true; otherwise, // return false. - bool FindSegment(const string &name, Segment *segment) const; + bool FindSegment(const string& name, Segment* segment) const; // Apply |handler| to each section defined in |segment|. If |handler| returns // false, stop iterating and return false. If all calls to |handler| return // true and we reach the end of the section list, return true. - bool WalkSegmentSections(const Segment &segment, SectionHandler *handler) + bool WalkSegmentSections(const Segment& segment, SectionHandler* handler) const; // Clear |section_map| and then populate it with a map of the sections // in |segment|, from section names to Section structures. // Each Section's contents refer to bytes in |segment|'s contents. // On success, return true; if a problem occurs, report it and return false. - bool MapSegmentSections(const Segment &segment, SectionMap *section_map) + bool MapSegmentSections(const Segment& segment, SectionMap* section_map) const; private: @@ -429,7 +428,7 @@ class Reader { class SectionMapper; // We use this to report problems parsing the file's contents. (WEAK) - Reporter *reporter_; + Reporter* reporter_; // The contents of the Mach-O file we're parsing. We do not own the // storage it refers to. diff --git a/src/common/mac/macho_reader_unittest.cc b/src/common/mac/macho_reader_unittest.cc index d8459d8c..3beec341 100644 --- a/src/common/mac/macho_reader_unittest.cc +++ b/src/common/mac/macho_reader_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -75,7 +74,7 @@ using testing::_; class MockFatReaderReporter: public FatReader::Reporter { public: - MockFatReaderReporter(const string &filename) + MockFatReaderReporter(const string& filename) : FatReader::Reporter(filename) { } MOCK_METHOD0(BadHeader, void()); MOCK_METHOD0(MisplacedObjectFile, void()); @@ -84,7 +83,7 @@ class MockFatReaderReporter: public FatReader::Reporter { class MockReaderReporter: public Reader::Reporter { public: - MockReaderReporter(const string &filename) : Reader::Reporter(filename) { } + MockReaderReporter(const string& filename) : Reader::Reporter(filename) { } MOCK_METHOD0(BadHeader, void()); MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, @@ -95,24 +94,24 @@ class MockReaderReporter: public Reader::Reporter { MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i, LoadCommandType type)); MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type)); - MOCK_METHOD1(SectionsMissing, void(const string &name)); - MOCK_METHOD1(MisplacedSegmentData, void(const string &name)); - MOCK_METHOD2(MisplacedSectionData, void(const string §ion, - const string &segment)); + MOCK_METHOD1(SectionsMissing, void(const string& name)); + MOCK_METHOD1(MisplacedSegmentData, void(const string& name)); + MOCK_METHOD2(MisplacedSectionData, void(const string& section, + const string& segment)); MOCK_METHOD0(MisplacedSymbolTable, void()); MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type)); }; class MockLoadCommandHandler: public Reader::LoadCommandHandler { public: - MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &)); - MOCK_METHOD1(SegmentCommand, bool(const Segment &)); - MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &)); + MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer&)); + MOCK_METHOD1(SegmentCommand, bool(const Segment&)); + MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer&, const ByteBuffer&)); }; class MockSectionHandler: public Reader::SectionHandler { public: - MOCK_METHOD1(HandleSection, bool(const Section §ion)); + MOCK_METHOD1(HandleSection, bool(const Section& section)); }; @@ -221,7 +220,7 @@ struct FatReaderFixture { } void ReadFat(bool expect_parse_success = true) { ASSERT_TRUE(fat.GetContents(&contents)); - fat_bytes = reinterpret_cast<const uint8_t *>(contents.data()); + fat_bytes = reinterpret_cast<const uint8_t*>(contents.data()); if (expect_parse_success) { EXPECT_TRUE(reader.Read(fat_bytes, contents.size())); size_t fat_files_count; @@ -238,7 +237,7 @@ struct FatReaderFixture { MockFatReaderReporter reporter; FatReader reader; string contents; - const uint8_t *fat_bytes; + const uint8_t* fat_bytes; vector<struct fat_arch> object_files; }; @@ -487,16 +486,16 @@ class WithConfiguration { private: // The innermost WithConfiguration in whose dynamic scope we are // currently executing. - static WithConfiguration *current_; + static WithConfiguration* current_; // The innermost WithConfiguration whose dynamic scope encloses this // WithConfiguration. Endianness endianness_; size_t word_size_; - WithConfiguration *saved_; + WithConfiguration* saved_; }; -WithConfiguration *WithConfiguration::current_ = NULL; +WithConfiguration* WithConfiguration::current_ = NULL; // A test_assembler::Section with a size that we can cite. The start(), // Here() and Mark() member functions of a SizedSection always represent @@ -527,7 +526,7 @@ class SizedSection: public test_assembler::Section { // Append SECTION to the end of this section, and call its Finish member. // Return a reference to this section. - SizedSection &Place(SizedSection *section) { + SizedSection& Place(SizedSection* section) { assert(section->endianness() == endianness()); section->Finish(); section->start() = Here(); @@ -563,7 +562,7 @@ class LoadedSection: public SizedSection { // Placing a loaded section within a loaded section sets the relationship // between their addresses. - LoadedSection &Place(LoadedSection *section) { + LoadedSection& Place(LoadedSection* section) { section->address() = address() + Size(); SizedSection::Place(section); return *this; @@ -583,7 +582,7 @@ class SegmentLoadCommand: public SizedSection { // The load command will refer to CONTENTS, which must be Placed in the // file separately, at the desired position. Return a reference to this // section. - SegmentLoadCommand &Header(const string &name, const LoadedSection &contents, + SegmentLoadCommand& Header(const string& name, const LoadedSection& contents, uint32_t maxprot, uint32_t initprot, uint32_t flags) { assert(contents.word_size() == word_size()); @@ -608,16 +607,16 @@ class SegmentLoadCommand: public SizedSection { // memory. If this label is still undefined by the time we place this // segment, it defaults to the final size of the segment's in-file // contents. Return a reference to this load command. - Label &vmsize() { return vmsize_; } + Label& vmsize() { return vmsize_; } // Add a section entry with the given characteristics to this segment // load command. Return a reference to this. The section entry will refer // to CONTENTS, which must be Placed in the segment's contents // separately, at the desired position. - SegmentLoadCommand &AppendSectionEntry(const string §ion_name, - const string &segment_name, + SegmentLoadCommand& AppendSectionEntry(const string& section_name, + const string& segment_name, uint32_t alignment, uint32_t flags, - const LoadedSection &contents) { + const LoadedSection& contents) { AppendCString(section_name, 16); AppendCString(segment_name, 16); Append(endianness(), word_size() / 8, contents.address()); @@ -671,14 +670,14 @@ class LoadCommands: public SizedSection { Label final_command_count() const { return final_command_count_; } // Increment the command count; return a reference to this section. - LoadCommands &CountCommand() { + LoadCommands& CountCommand() { command_count_++; return *this; } // Place COMMAND, containing a load command, at the end of this section. // Return a reference to this section. - LoadCommands &Place(SizedSection *section) { + LoadCommands& Place(SizedSection* section) { SizedSection::Place(section); CountCommand(); return *this; @@ -710,7 +709,7 @@ class MachOFile: public SizedSection { // Create a Mach-O file header using the given characteristics and load // command list. This Places COMMANDS immediately after the header. // Return a reference to this section. - MachOFile &Header(LoadCommands *commands, + MachOFile& Header(LoadCommands* commands, cpu_type_t cpu_type = CPU_TYPE_X86, cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL, FileType file_type = MH_EXECUTE, @@ -752,12 +751,12 @@ struct ReaderFixture { EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0); } - void ReadFile(MachOFile *file, + void ReadFile(MachOFile* file, bool expect_parse_success, cpu_type_t expected_cpu_type, cpu_subtype_t expected_cpu_subtype) { ASSERT_TRUE(file->GetContents(&file_contents)); - file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data()); + file_bytes = reinterpret_cast<const uint8_t*>(file_contents.data()); if (expect_parse_success) { EXPECT_TRUE(reader.Read(file_bytes, file_contents.size(), @@ -772,7 +771,7 @@ struct ReaderFixture { } string file_contents; - const uint8_t *file_bytes; + const uint8_t* file_bytes; MockReaderReporter reporter; Reader reader; MockLoadCommandHandler load_command_handler; @@ -1343,14 +1342,14 @@ TEST_F(LoadCommand, ThreeLoadCommands) { EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); } -static inline Matcher<const Section &> MatchSection( +static inline Matcher<const Section&> MatchSection( Matcher<bool> bits_64, - Matcher<const string &> section_name, - Matcher<const string &> segment_name, + Matcher<const string&> section_name, + Matcher<const string&> segment_name, Matcher<uint64_t> address, Matcher<uint32_t> alignment, Matcher<uint32_t> flags, - Matcher<const ByteBuffer &> contents) { + Matcher<const ByteBuffer&> contents) { return AllOf(AllOf(Field(&Section::bits_64, bits_64), Field(&Section::section_name, section_name), Field(&Section::segment_name, segment_name), @@ -1360,10 +1359,10 @@ static inline Matcher<const Section &> MatchSection( Field(&Section::contents, contents))); } -static inline Matcher<const Section &> MatchSection( +static inline Matcher<const Section&> MatchSection( Matcher<bool> bits_64, - Matcher<const string &> section_name, - Matcher<const string &> segment_name, + Matcher<const string&> section_name, + Matcher<const string&> segment_name, Matcher<uint64_t> address) { return AllOf(Field(&Section::bits_64, bits_64), Field(&Section::section_name, section_name), @@ -1410,7 +1409,7 @@ TEST_F(LoadCommand, OneSegmentTwoSections) { contents1.start = file_bytes + section1.start().Value(); contents1.end = contents1.start + section1.final_size().Value(); EXPECT_EQ("buddha's hand", - string(reinterpret_cast<const char *>(contents1.start), + string(reinterpret_cast<const char*>(contents1.start), contents1.Size())); EXPECT_CALL(section_handler, HandleSection(MatchSection(true, "mandarin", "kishu", @@ -1422,7 +1421,7 @@ TEST_F(LoadCommand, OneSegmentTwoSections) { contents2.start = file_bytes + section2.start().Value(); contents2.end = contents2.start + section2.final_size().Value(); EXPECT_EQ("kumquat", - string(reinterpret_cast<const char *>(contents2.start), + string(reinterpret_cast<const char*>(contents2.start), contents2.Size())); EXPECT_CALL(section_handler, HandleSection(MatchSection(true, "bergamot", "cara cara", @@ -1529,6 +1528,51 @@ TEST_F(LoadCommand, MisplacedSectionTooBig) { // to set all their labels by hand to get the (impossible) // configurations we want. + // A section with 0 as is start address. + LoadedSection empty; + empty.Append(10, '4'); + empty.start() = 0; + empty.address() = segment.address() + 1; + empty.final_size() = empty.Size(); + + SegmentLoadCommand command; + command.Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) + .AppendSectionEntry("empty", "segment", 0, 0x8b53ae5c, empty); + + LoadCommands commands; + commands.Place(&command); + + MachOFile file; + file.Header(&commands).Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); + + EXPECT_CALL(reporter, MisplacedSectionData("empty", "segment")).Times(0); + + EXPECT_CALL(section_handler, + HandleSection(MatchSection(true, "empty", "segment", + empty.address().Value()))) + .WillOnce(Return(true)); + + EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler)); +} + +TEST_F(LoadCommand, MisplacedSectionButSectionIsEmpty) { + WithConfiguration config(kLittleEndian, 64); + + // The segment. + LoadedSection segment; + segment.address() = 0x696d83cc; + segment.Append(10, '0'); + + // The contents of the following sections don't matter, because + // we're not really going to Place them in segment; we're just going + // to set all their labels by hand to get the (impossible) + // configurations we want. + // A section that extends beyond the end of its section. LoadedSection too_big; too_big.Append(10, '3'); @@ -1716,7 +1760,7 @@ class StringAssembler: public SizedSection { public: // Add the string S to this StringAssembler, and return the string's // offset within this compilation unit's strings. - size_t Add(const string &s) { + size_t Add(const string& s) { size_t offset = Size(); AppendCString(s); return offset; @@ -1728,7 +1772,7 @@ class StringAssembler: public SizedSection { class SymbolAssembler: public SizedSection { public: // Create a SymbolAssembler that uses StringAssembler for its strings. - explicit SymbolAssembler(StringAssembler *string_assembler) + explicit SymbolAssembler(StringAssembler* string_assembler) : string_assembler_(string_assembler), entry_count_(0) { } @@ -1737,7 +1781,7 @@ class SymbolAssembler: public SizedSection { // its compilation unit's portion of the .stabstr section; this can be a // value generated by a StringAssembler. Return a reference to this // SymbolAssembler. - SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor, + SymbolAssembler& Symbol(uint8_t type, uint8_t other, Label descriptor, Label value, Label name) { D32(name); D8(type); @@ -1749,14 +1793,14 @@ class SymbolAssembler: public SizedSection { } // As above, but automatically add NAME to our StringAssembler. - SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor, - Label value, const string &name) { + SymbolAssembler& Symbol(uint8_t type, uint8_t other, Label descriptor, + Label value, const string& name) { return Symbol(type, other, descriptor, value, string_assembler_->Add(name)); } private: // The strings for our STABS entries. - StringAssembler *string_assembler_; + StringAssembler* string_assembler_; // The number of entries in this compilation unit so far. size_t entry_count_; diff --git a/src/common/mac/macho_utilities.cc b/src/common/mac/macho_utilities.cc index f56fe768..16e430df 100644 --- a/src/common/mac/macho_utilities.cc +++ b/src/common/mac/macho_utilities.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/macho_utilities.h b/src/common/mac/macho_utilities.h index 00563a77..470cb5d2 100644 --- a/src/common/mac/macho_utilities.h +++ b/src/common/mac/macho_utilities.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc index 1acd8665..505a4df1 100644 --- a/src/common/mac/macho_walker.cc +++ b/src/common/mac/macho_walker.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,8 +46,8 @@ namespace MacFileUtilities { -MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback, - void *context) +MachoWalker::MachoWalker(const char* path, LoadCommandCallback callback, + void* context) : file_(-1), memory_(NULL), memory_size_(0), @@ -60,8 +59,8 @@ MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback, file_ = open(path, O_RDONLY); } -MachoWalker::MachoWalker(void *memory, size_t size, - LoadCommandCallback callback, void *context) +MachoWalker::MachoWalker(void* memory, size_t size, + LoadCommandCallback callback, void* context) : file_(-1), memory_(memory), memory_size_(size), @@ -82,7 +81,7 @@ bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { cpu_subtype_t valid_cpu_subtype = cpu_subtype; // if |cpu_type| is 0, use the native cpu type. if (cpu_type == 0) { - const NXArchInfo *arch = NXGetLocalArchInfo(); + const NXArchInfo* arch = NXGetLocalArchInfo(); assert(arch); valid_cpu_type = arch->cputype; valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE; @@ -98,7 +97,7 @@ bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { return false; } -bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) { +bool MachoWalker::ReadBytes(void* buffer, size_t size, off_t offset) { if (memory_) { if (offset < 0) return false; @@ -109,14 +108,14 @@ bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) { size = memory_size_ - static_cast<size_t>(offset); result = false; } - memcpy(buffer, static_cast<char *>(memory_) + offset, size); + memcpy(buffer, static_cast<char*>(memory_) + offset, size); return result; } else { return pread(file_, buffer, size, offset) == (ssize_t)size; } } -bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { +bool MachoWalker::CurrentHeader(struct mach_header_64* header, off_t* offset) { if (current_header_) { memcpy(header, current_header_, sizeof(mach_header_64)); *offset = current_header_offset_; @@ -128,7 +127,7 @@ bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { bool MachoWalker::FindHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, - off_t &offset) { + off_t& offset) { // Read the magic bytes that's common amongst all mach-o files uint32_t magic; if (!ReadBytes(&magic, sizeof(magic), 0)) @@ -211,7 +210,7 @@ bool MachoWalker::WalkHeaderAtOffset(off_t offset) { // Copy the data into the mach_header_64 structure. Since the 32-bit and // 64-bit only differ in the last field (reserved), this is safe to do. struct mach_header_64 header64; - memcpy((void *)&header64, (const void *)&header, sizeof(header)); + memcpy((void*)&header64, (const void*)&header, sizeof(header)); header64.reserved = 0; current_header_ = &header64; diff --git a/src/common/mac/macho_walker.h b/src/common/mac/macho_walker.h index dd535814..13e8232e 100644 --- a/src/common/mac/macho_walker.h +++ b/src/common/mac/macho_walker.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -49,12 +48,12 @@ class MachoWalker { // beginning of the file (not header) where the command was read. If |swap| // is set, then any command data (other than the returned load_command) should // be swapped when read - typedef bool (*LoadCommandCallback)(MachoWalker *walker, load_command *cmd, - off_t offset, bool swap, void *context); + typedef bool (*LoadCommandCallback)(MachoWalker* walker, load_command* cmd, + off_t offset, bool swap, void* context); - MachoWalker(const char *path, LoadCommandCallback callback, void *context); - MachoWalker(void *memory, size_t size, LoadCommandCallback callback, - void *context); + MachoWalker(const char* path, LoadCommandCallback callback, void* context); + MachoWalker(void* memory, size_t size, LoadCommandCallback callback, + void* context); ~MachoWalker(); // Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type| @@ -67,17 +66,17 @@ class MachoWalker { bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); // Read |size| bytes from the opened file at |offset| into |buffer| - bool ReadBytes(void *buffer, size_t size, off_t offset); + bool ReadBytes(void* buffer, size_t size, off_t offset); // Return the current header and header offset - bool CurrentHeader(struct mach_header_64 *header, off_t *offset); + bool CurrentHeader(struct mach_header_64* header, off_t* offset); private: // Locate (if any) the header offset for |cpu_type| and return in |offset|. // Return true if found, false otherwise. bool FindHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, - off_t &offset); + off_t& offset); // Process an individual header starting at |offset| from the start of the // file. Return true if successful, false otherwise. @@ -91,27 +90,27 @@ class MachoWalker { int file_; // Memory location to read from. - void *memory_; + void* memory_; // Size of the memory segment we can read from. size_t memory_size_; // User specified callback & context LoadCommandCallback callback_; - void *callback_context_; + void* callback_context_; // Current header, size, and offset. The mach_header_64 is used for both // 32-bit and 64-bit headers because they only differ in their last field // (reserved). By adding the |current_header_size_| and the // |current_header_offset_|, you can determine the offset in the file just // after the header. - struct mach_header_64 *current_header_; + struct mach_header_64* current_header_; unsigned long current_header_size_; off_t current_header_offset_; private: - MachoWalker(const MachoWalker &); - MachoWalker &operator=(const MachoWalker &); + MachoWalker(const MachoWalker&); + MachoWalker& operator=(const MachoWalker&); }; } // namespace MacFileUtilities diff --git a/src/tools/mac/symupload/minidump_upload.m b/src/common/mac/minidump_upload.m index 741ad765..d8e2b24a 100644 --- a/src/tools/mac/symupload/minidump_upload.m +++ b/src/common/mac/minidump_upload.m @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,18 +39,18 @@ #import "common/mac/HTTPMultipartUpload.h" typedef struct { - NSString *minidumpPath; - NSString *uploadURLStr; - NSString *product; - NSString *version; + NSString* minidumpPath; + NSString* uploadURLStr; + NSString* product; + NSString* version; BOOL success; } Options; //============================================================================= -static void Start(Options *options) { - NSURL *url = [NSURL URLWithString:options->uploadURLStr]; - HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; - NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; +static void Start(Options* options) { + NSURL* url = [NSURL URLWithString:options->uploadURLStr]; + HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url]; + NSMutableDictionary* parameters = [NSMutableDictionary dictionary]; // Add parameters [parameters setObject:options->product forKey:@"prod"]; @@ -62,9 +61,9 @@ static void Start(Options *options) { [ul addFileAtPath:options->minidumpPath name:@"upload_file_minidump"]; // Send it - NSError *error = nil; - NSData *data = [ul send:&error]; - NSString *result = [[NSString alloc] initWithData:data + NSError* error = nil; + NSData* data = [ul send:&error]; + NSString* result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"Send: %@", error ? [error description] : @"No Error"); @@ -77,11 +76,12 @@ static void Start(Options *options) { } //============================================================================= -static void -Usage(int argc, const char *argv[]) { +static void Usage(int argc, const char* argv[]) { fprintf(stderr, "Submit minidump information.\n"); - fprintf(stderr, "Usage: %s -p <product> -v <version> <minidump> " - "<upload-URL>\n", argv[0]); + fprintf(stderr, + "Usage: %s -p <product> -v <version> <minidump> " + "<upload-URL>\n", + argv[0]); fprintf(stderr, "<minidump> should be a minidump.\n"); fprintf(stderr, "<upload-URL> is the destination for the upload\n"); @@ -90,12 +90,11 @@ Usage(int argc, const char *argv[]) { } //============================================================================= -static void -SetupOptions(int argc, const char *argv[], Options *options) { +static void SetupOptions(int argc, const char* argv[], Options* options) { extern int optind; char ch; - while ((ch = getopt(argc, (char * const *)argv, "p:v:h?")) != -1) { + while ((ch = getopt(argc, (char* const*)argv, "p:v:h?")) != -1) { switch (ch) { case 'p': options->product = [NSString stringWithUTF8String:optarg]; @@ -122,8 +121,8 @@ SetupOptions(int argc, const char *argv[], Options *options) { } //============================================================================= -int main (int argc, const char * argv[]) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +int main(int argc, const char* argv[]) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; Options options; bzero(&options, sizeof(Options)); diff --git a/src/common/mac/scoped_task_suspend-inl.h b/src/common/mac/scoped_task_suspend-inl.h index d6d1bef9..a4957d7a 100644 --- a/src/common/mac/scoped_task_suspend-inl.h +++ b/src/common/mac/scoped_task_suspend-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/mac/string_utilities.cc b/src/common/mac/string_utilities.cc index 07c0f426..861029d4 100644 --- a/src/common/mac/string_utilities.cc +++ b/src/common/mac/string_utilities.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -48,12 +47,12 @@ std::string ConvertToString(CFStringRef str) { CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingUTF8, 0, false, buffer.get(), maxUTF8Length, &actualUTF8Length); buffer[actualUTF8Length] = 0; - result.assign((const char *)buffer.get()); + result.assign((const char*)buffer.get()); return result; } -unsigned int IntegerValueAtIndex(string &str, unsigned int idx) { +unsigned int IntegerValueAtIndex(string& str, unsigned int idx) { string digits("0123456789"), temp; size_t start = 0; size_t end; diff --git a/src/common/mac/string_utilities.h b/src/common/mac/string_utilities.h index 6d89c834..de282a94 100644 --- a/src/common/mac/string_utilities.h +++ b/src/common/mac/string_utilities.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,7 +44,7 @@ string ConvertToString(CFStringRef str); // Return the idx'th decimal integer in str, separated by non-decimal-digits // E.g., str = 10.4.8, idx = 1 -> 4 -unsigned int IntegerValueAtIndex(string &str, unsigned int idx); +unsigned int IntegerValueAtIndex(string& str, unsigned int idx); } // namespace MacStringUtils diff --git a/src/common/mac/super_fat_arch.h b/src/common/mac/super_fat_arch.h index 501c8652..046fe166 100644 --- a/src/common/mac/super_fat_arch.h +++ b/src/common/mac/super_fat_arch.h @@ -1,5 +1,4 @@ -// Copyright (c) 2015, Google Inc. -// All rights reserved. +// Copyright 2015 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -57,7 +56,7 @@ class SuperFatArch { align(0) { } - explicit SuperFatArch(const struct fat_arch &arch) : + explicit SuperFatArch(const struct fat_arch& arch) : cputype(arch.cputype), cpusubtype(arch.cpusubtype), offset(arch.offset), diff --git a/src/common/mac/testing/GTMSenTestCase.h b/src/common/mac/testing/GTMSenTestCase.h index ce3d9022..cfef3ef1 100644 --- a/src/common/mac/testing/GTMSenTestCase.h +++ b/src/common/mac/testing/GTMSenTestCase.h @@ -1,7 +1,7 @@ // // GTMSenTestCase.h // -// Copyright 2007-2008 Google Inc. +// Copyright 2007-2008 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy diff --git a/src/common/mac/testing/GTMSenTestCase.m b/src/common/mac/testing/GTMSenTestCase.m index 162f01e9..eb9351bf 100644 --- a/src/common/mac/testing/GTMSenTestCase.m +++ b/src/common/mac/testing/GTMSenTestCase.m @@ -1,7 +1,7 @@ // // GTMSenTestCase.m // -// Copyright 2007-2008 Google Inc. +// Copyright 2007-2008 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy diff --git a/src/common/macros.h b/src/common/macros.h index 14bb3f7b..828d49d1 100644 --- a/src/common/macros.h +++ b/src/common/macros.h @@ -1,5 +1,4 @@ -// Copyright (c) 2019, Google Inc. -// All rights reserved. +// Copyright 2019 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/md5.cc b/src/common/md5.cc index 4f1ac8ca..b6e710da 100644 --- a/src/common/md5.cc +++ b/src/common/md5.cc @@ -31,7 +31,7 @@ static void byteReverse(unsigned char *buf, unsigned longs) do { t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); - *(u32 *) buf = t; + *(u32*) buf = t; buf += 4; } while (--longs); } @@ -74,7 +74,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len) /* Handle any leading odd-sized chunks */ if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; + unsigned char *p = (unsigned char*) ctx->in + t; t = 64 - t; if (len < t) { @@ -83,7 +83,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len) } memcpy(p, buf, t); byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); + MD5Transform(ctx->buf, (u32*) ctx->in); buf += t; len -= t; } @@ -92,7 +92,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len) while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); + MD5Transform(ctx->buf, (u32*) ctx->in); buf += 64; len -= 64; } @@ -127,7 +127,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); + MD5Transform(ctx->buf, (u32*) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); @@ -141,8 +141,8 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) memcpy(&ctx->in[14], &ctx->bits[0], sizeof(u32)); memcpy(&ctx->in[15], &ctx->bits[1], sizeof(u32)); - MD5Transform(ctx->buf, (u32 *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); + MD5Transform(ctx->buf, (u32*) ctx->in); + byteReverse((unsigned char*) ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } diff --git a/src/common/md5.h b/src/common/md5.h index 2ab0ab95..9d1f59b5 100644 --- a/src/common/md5.h +++ b/src/common/md5.h @@ -1,8 +1,9 @@ -// Copyright 2007 Google Inc. All Rights Reserved. +// Copyright 2007 Google LLC // Author: liuli@google.com (Liu Li) #ifndef COMMON_MD5_H__ #define COMMON_MD5_H__ +#include <stddef.h> #include <stdint.h> namespace google_breakpad { diff --git a/src/common/memory_allocator.h b/src/common/memory_allocator.h index a3159ea4..1c99913a 100644 --- a/src/common/memory_allocator.h +++ b/src/common/memory_allocator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -71,12 +70,12 @@ class PageAllocator { FreeAll(); } - void *Alloc(size_t bytes) { + void* Alloc(size_t bytes) { if (!bytes) return NULL; if (current_page_ && page_size_ - page_offset_ >= bytes) { - uint8_t *const ret = current_page_ + page_offset_; + uint8_t* const ret = current_page_ + page_offset_; page_offset_ += bytes; if (page_offset_ == page_size_) { page_offset_ = 0; @@ -88,7 +87,7 @@ class PageAllocator { const size_t pages = (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; - uint8_t *const ret = GetNPages(pages); + uint8_t* const ret = GetNPages(pages); if (!ret) return NULL; @@ -115,8 +114,8 @@ class PageAllocator { unsigned long pages_allocated() { return pages_allocated_; } private: - uint8_t *GetNPages(size_t num_pages) { - void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, + uint8_t* GetNPages(size_t num_pages) { + void* a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (a == MAP_FAILED) return NULL; @@ -127,7 +126,7 @@ class PageAllocator { __msan_unpoison(a, page_size_ * num_pages); #endif - struct PageHeader *header = reinterpret_cast<PageHeader*>(a); + struct PageHeader* header = reinterpret_cast<PageHeader*>(a); header->next = last_; header->num_pages = num_pages; last_ = header; @@ -138,31 +137,34 @@ class PageAllocator { } void FreeAll() { - PageHeader *next; + PageHeader* next; - for (PageHeader *cur = last_; cur; cur = next) { + for (PageHeader* cur = last_; cur; cur = next) { next = cur->next; sys_munmap(cur, cur->num_pages * page_size_); } } struct PageHeader { - PageHeader *next; // pointer to the start of the next set of pages. + PageHeader* next; // pointer to the start of the next set of pages. size_t num_pages; // the number of pages in this set. }; const size_t page_size_; - PageHeader *last_; - uint8_t *current_page_; + PageHeader* last_; + uint8_t* current_page_; size_t page_offset_; unsigned long pages_allocated_; }; // Wrapper to use with STL containers template <typename T> -struct PageStdAllocator : public std::allocator<T> { - typedef typename std::allocator<T>::pointer pointer; - typedef typename std::allocator<T>::size_type size_type; +struct PageStdAllocator { + using AllocatorTraits = std::allocator_traits<std::allocator<T>>; + using value_type = typename AllocatorTraits::value_type; + using pointer = typename AllocatorTraits::pointer; + using difference_type = typename AllocatorTraits::difference_type; + using size_type = typename AllocatorTraits::size_type; explicit PageStdAllocator(PageAllocator& allocator) : allocator_(allocator), stackdata_(NULL), diff --git a/src/common/memory_allocator_unittest.cc b/src/common/memory_allocator_unittest.cc index 43c86314..6ca625bb 100644 --- a/src/common/memory_allocator_unittest.cc +++ b/src/common/memory_allocator_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -46,7 +45,7 @@ TEST(PageAllocatorTest, SmallObjects) { EXPECT_EQ(0U, allocator.pages_allocated()); for (unsigned i = 1; i < 1024; ++i) { - uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i)); + uint8_t* p = reinterpret_cast<uint8_t*>(allocator.Alloc(i)); ASSERT_FALSE(p == NULL); memset(p, 0, i); } @@ -56,11 +55,11 @@ TEST(PageAllocatorTest, LargeObject) { PageAllocator allocator; EXPECT_EQ(0U, allocator.pages_allocated()); - uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000)); + uint8_t* p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000)); ASSERT_FALSE(p == NULL); EXPECT_EQ(3U, allocator.pages_allocated()); for (unsigned i = 1; i < 10; ++i) { - uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i)); + uint8_t* p = reinterpret_cast<uint8_t*>(allocator.Alloc(i)); ASSERT_FALSE(p == NULL); memset(p, 0, i); } diff --git a/src/common/memory_range.h b/src/common/memory_range.h index 41dd2da6..e2ab61d5 100644 --- a/src/common/memory_range.h +++ b/src/common/memory_range.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/memory_range_unittest.cc b/src/common/memory_range_unittest.cc index f6cf8c8b..f112e761 100644 --- a/src/common/memory_range_unittest.cc +++ b/src/common/memory_range_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/minidump_type_helper.h b/src/common/minidump_type_helper.h index 5a7d5a6a..04bafe7e 100644 --- a/src/common/minidump_type_helper.h +++ b/src/common/minidump_type_helper.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/module.cc b/src/common/module.cc index aff22127..75782ab1 100644 --- a/src/common/module.cc +++ b/src/common/module.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011 Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -32,30 +31,84 @@ // module.cc: Implement google_breakpad::Module. See module.h. #include "common/module.h" +#include "common/string_view.h" #include <assert.h> #include <errno.h> #include <stdio.h> #include <string.h> +#include <functional> #include <iostream> +#include <memory> #include <utility> namespace google_breakpad { using std::dec; using std::hex; +using std::unique_ptr; + +Module::InlineOrigin* Module::InlineOriginMap::GetOrCreateInlineOrigin( + uint64_t offset, + StringView name) { + uint64_t specification_offset = references_[offset]; + // Find the root offset. + auto iter = references_.find(specification_offset); + while (iter != references_.end() && + specification_offset != references_[specification_offset]) { + specification_offset = references_[specification_offset]; + iter = references_.find(specification_offset); + } + if (inline_origins_.find(specification_offset) != inline_origins_.end()) { + if (inline_origins_[specification_offset]->name == "<name omitted>") { + inline_origins_[specification_offset]->name = name; + } + return inline_origins_[specification_offset]; + } + inline_origins_[specification_offset] = new Module::InlineOrigin(name); + return inline_origins_[specification_offset]; +} + +void Module::InlineOriginMap::SetReference(uint64_t offset, + uint64_t specification_offset) { + // If we haven't seen this doesn't exist in reference map, always add it. + if (references_.find(offset) == references_.end()) { + references_[offset] = specification_offset; + return; + } + // If offset equals specification_offset and offset exists in + // references_, there is no need to update the references_ map. + // This early return is necessary because the call to erase in following if + // will remove the entry of specification_offset in inline_origins_. If + // specification_offset equals to references_[offset], it might be + // duplicate debug info. + if (offset == specification_offset || + specification_offset == references_[offset]) + return; + // Fix up mapping in inline_origins_. + auto remove = inline_origins_.find(references_[offset]); + if (remove != inline_origins_.end()) { + inline_origins_[specification_offset] = std::move(remove->second); + inline_origins_.erase(remove); + } + references_[offset] = specification_offset; +} -Module::Module(const string &name, const string &os, - const string &architecture, const string &id, - const string &code_id /* = "" */) : - name_(name), - os_(os), - architecture_(architecture), - id_(id), - code_id_(code_id), - load_address_(0) { } +Module::Module(const string& name, + const string& os, + const string& architecture, + const string& id, + const string& code_id /* = "" */, + bool enable_multiple_field /* = false*/) + : name_(name), + os_(os), + architecture_(architecture), + id_(id), + code_id_(code_id), + load_address_(0), + enable_multiple_field_(enable_multiple_field) {} Module::~Module() { for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) @@ -64,12 +117,6 @@ Module::~Module() { it != functions_.end(); ++it) { delete *it; } - for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin(); - it != stack_frame_entries_.end(); ++it) { - delete *it; - } - for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it) - delete *it; } void Module::SetLoadAddress(Address address) { @@ -80,13 +127,13 @@ void Module::SetAddressRanges(const vector<Range>& ranges) { address_ranges_ = ranges; } -void Module::AddFunction(Function *function) { +bool Module::AddFunction(Function* function) { // FUNC lines must not hold an empty name, so catch the problem early if // callers try to add one. assert(!function->name.empty()); if (!AddressIsInModule(function->address)) { - return; + return false; } // FUNCs are better than PUBLICs as they come with sizes, so remove an extern @@ -101,7 +148,12 @@ void Module::AddFunction(Function *function) { it_ext = externs_.find(&arm_thumb_ext); } if (it_ext != externs_.end()) { - delete *it_ext; + if (enable_multiple_field_) { + Extern* found_ext = it_ext->get(); + // If the PUBLIC is for the same symbol as the FUNC, don't mark multiple. + function->is_multiple |= + found_ext->name != function->name || found_ext->is_multiple; + } externs_.erase(it_ext); } #if _DEBUG @@ -115,53 +167,60 @@ void Module::AddFunction(Function *function) { } } #endif - - std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function); + if (enable_multiple_field_ && function_addresses_.count(function->address)) { + FunctionSet::iterator existing_function = std::find_if( + functions_.begin(), functions_.end(), + [&](Function* other) { return other->address == function->address; }); + assert(existing_function != functions_.end()); + (*existing_function)->is_multiple = true; + // Free the duplicate that was not inserted because this Module + // now owns it. + return false; + } + function_addresses_.emplace(function->address); + std::pair<FunctionSet::iterator, bool> ret = functions_.insert(function); if (!ret.second && (*ret.first != function)) { // Free the duplicate that was not inserted because this Module // now owns it. - delete function; + return false; } + return true; } -void Module::AddFunctions(vector<Function *>::iterator begin, - vector<Function *>::iterator end) { - for (vector<Function *>::iterator it = begin; it != end; ++it) - AddFunction(*it); -} - -void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) { +void Module::AddStackFrameEntry(std::unique_ptr<StackFrameEntry> stack_frame_entry) { if (!AddressIsInModule(stack_frame_entry->address)) { return; } - stack_frame_entries_.push_back(stack_frame_entry); + stack_frame_entries_.push_back(std::move(stack_frame_entry)); } -void Module::AddExtern(Extern *ext) { +void Module::AddExtern(std::unique_ptr<Extern> ext) { if (!AddressIsInModule(ext->address)) { return; } - std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext); - if (!ret.second) { - // Free the duplicate that was not inserted because this Module - // now owns it. - delete ext; + std::pair<ExternSet::iterator,bool> ret = externs_.emplace(std::move(ext)); + if (!ret.second && enable_multiple_field_) { + (*ret.first)->is_multiple = true; } } -void Module::GetFunctions(vector<Function *> *vec, - vector<Function *>::iterator i) { +void Module::GetFunctions(vector<Function*>* vec, + vector<Function*>::iterator i) { vec->insert(i, functions_.begin(), functions_.end()); } -void Module::GetExterns(vector<Extern *> *vec, - vector<Extern *>::iterator i) { - vec->insert(i, externs_.begin(), externs_.end()); +void Module::GetExterns(vector<Extern*>* vec, + vector<Extern*>::iterator i) { + auto pos = vec->insert(i, externs_.size(), nullptr); + for (const std::unique_ptr<Extern>& ext : externs_) { + *pos = ext.get(); + ++pos; + } } -Module::File *Module::FindFile(const string &name) { +Module::File* Module::FindFile(const string& name) { // A tricky bit here. The key of each map entry needs to be a // pointer to the entry's File's name string. This means that we // can't do the initial lookup with any operation that would create @@ -175,7 +234,7 @@ Module::File *Module::FindFile(const string &name) { FileByNameMap::iterator destiny = files_.lower_bound(&name); if (destiny == files_.end() || *destiny->first != name) { // Repeated string comparison, boo hoo. - File *file = new File(name); + File* file = new File(name); file->source_id = -1; destiny = files_.insert(destiny, FileByNameMap::value_type(&file->name, file)); @@ -183,27 +242,32 @@ Module::File *Module::FindFile(const string &name) { return destiny->second; } -Module::File *Module::FindFile(const char *name) { +Module::File* Module::FindFile(const char* name) { string name_string = name; return FindFile(name_string); } -Module::File *Module::FindExistingFile(const string &name) { +Module::File* Module::FindExistingFile(const string& name) { FileByNameMap::iterator it = files_.find(&name); return (it == files_.end()) ? NULL : it->second; } -void Module::GetFiles(vector<File *> *vec) { +void Module::GetFiles(vector<File*>* vec) { vec->clear(); for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) vec->push_back(it->second); } -void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const { - *vec = stack_frame_entries_; +void Module::GetStackFrameEntries(vector<StackFrameEntry*>* vec) const { + vec->clear(); + vec->reserve(stack_frame_entries_.size()); + for (const auto& ent : stack_frame_entries_) { + vec->push_back(ent.get()); + } } -void Module::AssignSourceIds() { +void Module::AssignSourceIds( + set<InlineOrigin*, InlineOriginCompare>& inline_origins) { // First, give every source file an id of -1. for (FileByNameMap::iterator file_it = files_.begin(); file_it != files_.end(); ++file_it) { @@ -214,12 +278,25 @@ void Module::AssignSourceIds() { // info, by setting each one's source id to zero. for (FunctionSet::const_iterator func_it = functions_.begin(); func_it != functions_.end(); ++func_it) { - Function *func = *func_it; + Function* func = *func_it; for (vector<Line>::iterator line_it = func->lines.begin(); line_it != func->lines.end(); ++line_it) line_it->file->source_id = 0; } + // Also mark all files cited by inline callsite by setting each one's source + // id to zero. + auto markInlineFiles = [](unique_ptr<Inline>& in) { + // There are some artificial inline functions which don't belong to + // any file. Those will have file id -1. + if (in->call_site_file) { + in->call_site_file->source_id = 0; + } + }; + for (auto func : functions_) { + Inline::InlineDFS(func->inlines, markInlineFiles); + } + // Finally, assign source ids to those files that have been marked. // We could have just assigned source id numbers while traversing // the line numbers, but doing it this way numbers the files in @@ -232,13 +309,32 @@ void Module::AssignSourceIds() { } } +void Module::CreateInlineOrigins( + set<InlineOrigin*, InlineOriginCompare>& inline_origins) { + // Only add origins that have file and deduplicate origins with same name and + // file id by doing a DFS. + auto addInlineOrigins = [&](unique_ptr<Inline>& in) { + auto it = inline_origins.find(in->origin); + if (it == inline_origins.end()) + inline_origins.insert(in->origin); + else + in->origin = *it; + }; + for (Function* func : functions_) + Module::Inline::InlineDFS(func->inlines, addInlineOrigins); + int next_id = 0; + for (InlineOrigin* origin : inline_origins) { + origin->id = next_id++; + } +} + bool Module::ReportError() { fprintf(stderr, "error writing symbol file: %s\n", strerror(errno)); return false; } -bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { +bool Module::WriteRuleMap(const RuleMap& rule_map, std::ostream& stream) { for (RuleMap::const_iterator it = rule_map.begin(); it != rule_map.end(); ++it) { if (it != rule_map.begin()) @@ -261,7 +357,7 @@ bool Module::AddressIsInModule(Address address) const { return false; } -bool Module::Write(std::ostream &stream, SymbolData symbol_data) { +bool Module::Write(std::ostream& stream, SymbolData symbol_data) { stream << "MODULE " << os_ << " " << architecture_ << " " << id_ << " " << name_ << "\n"; if (!stream.good()) @@ -271,33 +367,54 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) { stream << "INFO CODE_ID " << code_id_ << "\n"; } - if (symbol_data != ONLY_CFI) { - AssignSourceIds(); + if (symbol_data & SYMBOLS_AND_FILES) { + // Get all referenced inline origins. + set<InlineOrigin*, InlineOriginCompare> inline_origins; + CreateInlineOrigins(inline_origins); + AssignSourceIds(inline_origins); // Write out files. for (FileByNameMap::iterator file_it = files_.begin(); file_it != files_.end(); ++file_it) { - File *file = file_it->second; + File* file = file_it->second; if (file->source_id >= 0) { stream << "FILE " << file->source_id << " " << file->name << "\n"; if (!stream.good()) return ReportError(); } } + // Write out inline origins. + for (InlineOrigin* origin : inline_origins) { + stream << "INLINE_ORIGIN " << origin->id << " " << origin->name << "\n"; + if (!stream.good()) + return ReportError(); + } - // Write out functions and their lines. + // Write out functions and their inlines and lines. for (FunctionSet::const_iterator func_it = functions_.begin(); func_it != functions_.end(); ++func_it) { - Function *func = *func_it; + Function* func = *func_it; vector<Line>::iterator line_it = func->lines.begin(); for (auto range_it = func->ranges.cbegin(); range_it != func->ranges.cend(); ++range_it) { - stream << "FUNC " << hex - << (range_it->address - load_address_) << " " - << range_it->size << " " - << func->parameter_size << " " - << func->name << dec << "\n"; + stream << "FUNC " << (func->is_multiple ? "m " : "") << hex + << (range_it->address - load_address_) << " " << range_it->size + << " " << func->parameter_size << " " << func->name << dec + << "\n"; + + if (!stream.good()) + return ReportError(); + // Write out inlines. + auto write_inline = [&](unique_ptr<Inline>& in) { + stream << "INLINE "; + stream << in->inline_nest_level << " " << in->call_site_line << " " + << in->getCallSiteFileID() << " " << in->origin->id << hex; + for (const Range& r : in->ranges) + stream << " " << (r.address - load_address_) << " " << r.size; + stream << dec << "\n"; + }; + Module::Inline::InlineDFS(func->inlines, write_inline); if (!stream.good()) return ReportError(); @@ -322,19 +439,18 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) { // Write out 'PUBLIC' records. for (ExternSet::const_iterator extern_it = externs_.begin(); extern_it != externs_.end(); ++extern_it) { - Extern *ext = *extern_it; - stream << "PUBLIC " << hex - << (ext->address - load_address_) << " 0 " - << ext->name << dec << "\n"; + Extern* ext = extern_it->get(); + stream << "PUBLIC " << (ext->is_multiple ? "m " : "") << hex + << (ext->address - load_address_) << " 0 " << ext->name << dec + << "\n"; } } - if (symbol_data != NO_CFI) { + if (symbol_data & CFI) { // Write out 'STACK CFI INIT' and 'STACK CFI' records. - vector<StackFrameEntry *>::const_iterator frame_it; - for (frame_it = stack_frame_entries_.begin(); + for (auto frame_it = stack_frame_entries_.begin(); frame_it != stack_frame_entries_.end(); ++frame_it) { - StackFrameEntry *entry = *frame_it; + StackFrameEntry* entry = frame_it->get(); stream << "STACK CFI INIT " << hex << (entry->address - load_address_) << " " << entry->size << " " << dec; diff --git a/src/common/module.h b/src/common/module.h index 7309cedd..c1fd9f59 100644 --- a/src/common/module.h +++ b/src/common/module.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,13 +37,18 @@ #ifndef COMMON_LINUX_MODULE_H__ #define COMMON_LINUX_MODULE_H__ +#include <functional> #include <iostream> +#include <limits> #include <map> +#include <memory> #include <set> #include <string> #include <vector> +#include "common/string_view.h" #include "common/symbol_data.h" +#include "common/unordered.h" #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" @@ -62,8 +66,11 @@ class Module { public: // The type of addresses and sizes in a symbol table. typedef uint64_t Address; + static constexpr uint64_t kMaxAddress = std::numeric_limits<Address>::max(); struct File; struct Function; + struct InlineOrigin; + struct Inline; struct Line; struct Extern; @@ -74,7 +81,7 @@ class Module { // A source file. struct File { - explicit File(const string &name_input) : name(name_input), source_id(0) {} + explicit File(const string& name_input) : name(name_input), source_id(0) {} // The name of the source file. const string name; @@ -96,17 +103,17 @@ class Module { // A function. struct Function { - Function(const string &name_input, const Address &address_input) : + Function(StringView name_input, const Address& address_input) : name(name_input), address(address_input), parameter_size(0) {} // For sorting by address. (Not style-guide compliant, but it's // stupid not to put this in the struct.) - static bool CompareByAddress(const Function *x, const Function *y) { + static bool CompareByAddress(const Function* x, const Function* y) { return x->address < y->address; } // The function's name. - string name; + StringView name; // The start address and the address ranges covered by the function. const Address address; @@ -118,26 +125,127 @@ class Module { // Source lines belonging to this function, sorted by increasing // address. vector<Line> lines; + + // Inlined call sites belonging to this functions. + vector<std::unique_ptr<Inline>> inlines; + + // If this symbol has been folded with other symbols in the linked binary. + bool is_multiple = false; + }; + + struct InlineOrigin { + explicit InlineOrigin(StringView name) : id(-1), name(name) {} + + // A unique id for each InlineOrigin object. INLINE records use the id to + // refer to its INLINE_ORIGIN record. + int id; + + // The inlined function's name. + StringView name; + + File* file; + + int getFileID() const { return file ? file->source_id : -1; } + }; + + // A inlined call site. + struct Inline { + Inline(InlineOrigin* origin, + const vector<Range>& ranges, + int call_site_line, + int call_site_file_id, + int inline_nest_level, + vector<std::unique_ptr<Inline>> child_inlines) + : origin(origin), + ranges(ranges), + call_site_line(call_site_line), + call_site_file_id(call_site_file_id), + call_site_file(nullptr), + inline_nest_level(inline_nest_level), + child_inlines(std::move(child_inlines)) {} + + InlineOrigin* origin; + + // The list of addresses and sizes. + vector<Range> ranges; + + int call_site_line; + + // The id is only meanful inside a CU. It's only used for looking up real + // File* after scanning a CU. + int call_site_file_id; + + File* call_site_file; + + int inline_nest_level; + + // A list of inlines which are children of this inline. + vector<std::unique_ptr<Inline>> child_inlines; + + int getCallSiteFileID() const { + return call_site_file ? call_site_file->source_id : -1; + } + + static void InlineDFS( + vector<std::unique_ptr<Module::Inline>>& inlines, + std::function<void(std::unique_ptr<Module::Inline>&)> const& forEach) { + for (std::unique_ptr<Module::Inline>& in : inlines) { + forEach(in); + InlineDFS(in->child_inlines, forEach); + } + } + }; + + typedef map<uint64_t, InlineOrigin*> InlineOriginByOffset; + + class InlineOriginMap { + public: + // Add INLINE ORIGIN to the module. Return a pointer to origin . + InlineOrigin* GetOrCreateInlineOrigin(uint64_t offset, StringView name); + + // offset is the offset of a DW_TAG_subprogram. specification_offset is the + // value of its DW_AT_specification or equals to offset if + // DW_AT_specification doesn't exist in that DIE. + void SetReference(uint64_t offset, uint64_t specification_offset); + + ~InlineOriginMap() { + for (const auto& iter : inline_origins_) { + delete iter.second; + } + } + + private: + // A map from a DW_TAG_subprogram's offset to the DW_TAG_subprogram. + InlineOriginByOffset inline_origins_; + + // A map from a DW_TAG_subprogram's offset to the offset of its + // specification or abstract origin subprogram. The set of values in this + // map should always be the same set of keys in inline_origins_. + map<uint64_t, uint64_t> references_; }; + InlineOriginMap inline_origin_map; + // A source line. struct Line { // For sorting by address. (Not style-guide compliant, but it's // stupid not to put this in the struct.) - static bool CompareByAddress(const Module::Line &x, const Module::Line &y) { + static bool CompareByAddress(const Module::Line& x, const Module::Line& y) { return x.address < y.address; } Address address, size; // The address and size of the line's code. - File *file; // The source file. + File* file; // The source file. int number; // The source line number. }; // An exported symbol. struct Extern { - explicit Extern(const Address &address_input) : address(address_input) {} + explicit Extern(const Address& address_input) : address(address_input) {} const Address address; string name; + // If this symbol has been folded with other symbols in the linked binary. + bool is_multiple = false; }; // A map from register names to postfix expressions that recover @@ -170,25 +278,46 @@ class Module { }; struct FunctionCompare { - bool operator() (const Function *lhs, - const Function *rhs) const { + bool operator() (const Function* lhs, const Function* rhs) const { if (lhs->address == rhs->address) return lhs->name < rhs->name; return lhs->address < rhs->address; } }; + struct InlineOriginCompare { + bool operator()(const InlineOrigin* lhs, const InlineOrigin* rhs) const { + return lhs->name < rhs->name; + } + }; + struct ExternCompare { - bool operator() (const Extern *lhs, - const Extern *rhs) const { + // Defining is_transparent allows + // std::set<std::unique_ptr<Extern>, ExternCompare>::find() to be called + // with an Extern* and have set use the overloads below. + using is_transparent = void; + bool operator() (const std::unique_ptr<Extern>& lhs, + const std::unique_ptr<Extern>& rhs) const { + return lhs->address < rhs->address; + } + bool operator() (const Extern* lhs, const std::unique_ptr<Extern>& rhs) const { + return lhs->address < rhs->address; + } + bool operator() (const std::unique_ptr<Extern>& lhs, const Extern* rhs) const { return lhs->address < rhs->address; } }; // Create a new module with the given name, operating system, // architecture, and ID string. - Module(const string &name, const string &os, const string &architecture, - const string &id, const string &code_id = ""); + // NB: `enable_multiple_field` is temporary while transitioning to enabling + // writing the multiple field permanently. + Module(const string& name, + const string& os, + const string& architecture, + const string& id, + const string& code_id = "", + bool enable_multiple_field = false); ~Module(); // Set the module's load address to LOAD_ADDRESS; addresses given @@ -216,83 +345,90 @@ class Module { // Add FUNCTION to the module. FUNCTION's name must not be empty. // This module owns all Function objects added with this function: // destroying the module destroys them as well. - void AddFunction(Function *function); - - // Add all the functions in [BEGIN,END) to the module. - // This module owns all Function objects added with this function: - // destroying the module destroys them as well. - void AddFunctions(vector<Function *>::iterator begin, - vector<Function *>::iterator end); + // Return false if the function is duplicate and needs to be freed. + bool AddFunction(Function* function); // Add STACK_FRAME_ENTRY to the module. // This module owns all StackFrameEntry objects added with this // function: destroying the module destroys them as well. - void AddStackFrameEntry(StackFrameEntry *stack_frame_entry); + void AddStackFrameEntry(std::unique_ptr<StackFrameEntry> stack_frame_entry); // Add PUBLIC to the module. // This module owns all Extern objects added with this function: // destroying the module destroys them as well. - void AddExtern(Extern *ext); + void AddExtern(std::unique_ptr<Extern> ext); // If this module has a file named NAME, return a pointer to it. If // it has none, then create one and return a pointer to the new // file. This module owns all File objects created using these // functions; destroying the module destroys them as well. - File *FindFile(const string &name); - File *FindFile(const char *name); + File* FindFile(const string& name); + File* FindFile(const char* name); // If this module has a file named NAME, return a pointer to it. // Otherwise, return NULL. - File *FindExistingFile(const string &name); + File* FindExistingFile(const string& name); // Insert pointers to the functions added to this module at I in // VEC. The pointed-to Functions are still owned by this module. // (Since this is effectively a copy of the function list, this is // mostly useful for testing; other uses should probably get a more // appropriate interface.) - void GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i); + void GetFunctions(vector<Function*>* vec, vector<Function*>::iterator i); // Insert pointers to the externs added to this module at I in // VEC. The pointed-to Externs are still owned by this module. // (Since this is effectively a copy of the extern list, this is // mostly useful for testing; other uses should probably get a more // appropriate interface.) - void GetExterns(vector<Extern *> *vec, vector<Extern *>::iterator i); + void GetExterns(vector<Extern*>* vec, vector<Extern*>::iterator i); // Clear VEC and fill it with pointers to the Files added to this // module, sorted by name. The pointed-to Files are still owned by // this module. (Since this is effectively a copy of the file list, // this is mostly useful for testing; other uses should probably get // a more appropriate interface.) - void GetFiles(vector<File *> *vec); + void GetFiles(vector<File*>* vec); // Clear VEC and fill it with pointers to the StackFrameEntry // objects that have been added to this module. (Since this is // 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) const; + 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. // Set the source id numbers for all other files --- unused by the // source line data --- to -1. We do this before writing out the // symbol file, at which point we omit any unused files. - void AssignSourceIds(); + void AssignSourceIds(set<InlineOrigin*, InlineOriginCompare>& inline_origins); + + // This function should be called before AssignSourceIds() to get the set of + // valid InlineOrigins*. + void CreateInlineOrigins( + set<InlineOrigin*, InlineOriginCompare>& inline_origins); // Call AssignSourceIds, and write this module to STREAM in the // breakpad symbol format. Return true if all goes well, or false if // an error occurs. This method writes out: // - a header based on the values given to the constructor, - // If symbol_data is not ONLY_CFI then: + // If symbol_data is not CFI then: // - the source files added via FindFile, // - the functions added via AddFunctions, each with its lines, // - all public records, - // If symbol_data is not NO_CFI then: + // If symbol_data is CFI then: // - all CFI records. // Addresses in the output are all relative to the load address // established by SetLoadAddress. - bool Write(std::ostream &stream, SymbolData symbol_data); + bool Write(std::ostream& stream, SymbolData symbol_data); + + // Place the name in the global set of strings. Return a StringView points to + // a string inside the pool. + StringView AddStringToPool(const string& str) { + auto result = common_strings_.insert(str); + return *(result.first); + } string name() const { return name_; } string os() const { return os_; } @@ -308,7 +444,7 @@ class Module { // Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI' // records, without a final newline. Return true if all goes well; // if an error occurs, return false, and leave errno set. - static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream); + static bool WriteRuleMap(const RuleMap& rule_map, std::ostream& stream); // Returns true of the specified address resides with an specified address // range, or if no ranges have been specified. @@ -329,32 +465,43 @@ class Module { // Relation for maps whose keys are strings shared with some other // structure. struct CompareStringPtrs { - bool operator()(const string *x, const string *y) const { return *x < *y; } + bool operator()(const string* x, const string* y) const { return *x < *y; } }; // A map from filenames to File structures. The map's keys are // pointers to the Files' names. - typedef map<const string *, File *, CompareStringPtrs> FileByNameMap; + typedef map<const string*, File*, CompareStringPtrs> FileByNameMap; // A set containing Function structures, sorted by address. - typedef set<Function *, FunctionCompare> FunctionSet; + typedef set<Function*, FunctionCompare> FunctionSet; // A set containing Extern structures, sorted by address. - typedef set<Extern *, ExternCompare> ExternSet; + typedef set<std::unique_ptr<Extern>, ExternCompare> ExternSet; // The module owns all the files and functions that have been added // to it; destroying the module frees the Files and Functions these // point to. FileByNameMap files_; // This module's source files. FunctionSet functions_; // This module's functions. + // Used to quickly look up whether a function exists at a particular address. + unordered_set<Address> function_addresses_; // The module owns all the call frame info entries that have been // added to it. - vector<StackFrameEntry *> stack_frame_entries_; + vector<std::unique_ptr<StackFrameEntry>> stack_frame_entries_; // The module owns all the externs that have been added to it; // destroying the module frees the Externs these point to. ExternSet externs_; + + unordered_set<string> common_strings_; + + // Whether symbols sharing an address should be collapsed into a single entry + // and marked with an `m` in the output. See + // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=751 and docs + // at + // https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md#records-3 + bool enable_multiple_field_; }; } // namespace google_breakpad diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc index 37fee5dd..39727554 100644 --- a/src/common/module_unittest.cc +++ b/src/common/module_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,19 +36,22 @@ #include <string.h> #include <algorithm> +#include <memory> #include <sstream> #include <string> +#include <utility> #include "breakpad_googletest_includes.h" #include "common/module.h" #include "common/using_std_string.h" using google_breakpad::Module; +using google_breakpad::StringView; using std::stringstream; using std::vector; using testing::ContainerEq; -static Module::Function* generate_duplicate_function(const string &name) { +static Module::Function* generate_duplicate_function(StringView name) { const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cULL; const Module::Address DUP_SIZE = 0x200b26e605f99071ULL; const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99ULL; @@ -67,7 +69,7 @@ static Module::Function* generate_duplicate_function(const string &name) { #define MODULE_ID "id-string" #define MODULE_CODE_ID "code-id-string" -TEST(Write, Header) { +TEST(Module, WriteHeader) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); m.Write(s, ALL_SYMBOL_DATA); @@ -76,7 +78,7 @@ TEST(Write, Header) { contents.c_str()); } -TEST(Write, HeaderCodeId) { +TEST(Module, WriteHeaderCodeId) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, MODULE_CODE_ID); m.Write(s, ALL_SYMBOL_DATA); @@ -86,7 +88,7 @@ TEST(Write, HeaderCodeId) { contents.c_str()); } -TEST(Write, OneLineFunc) { +TEST(Module, WriteOneLineFunc) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); @@ -111,7 +113,7 @@ TEST(Write, OneLineFunc) { contents.c_str()); } -TEST(Write, RelativeLoadAddress) { +TEST(Module, WriteRelativeLoadAddress) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); @@ -137,7 +139,7 @@ TEST(Write, RelativeLoadAddress) { m.AddFunction(function); // Some stack information. - Module::StackFrameEntry* entry = new Module::StackFrameEntry(); + auto entry = std::make_unique<Module::StackFrameEntry>(); entry->address = 0x30f9e5c83323973dULL; entry->size = 0x49fc9ca7c7c13dc2ULL; entry->initial_rules[".cfa"] = "he was a handsome man"; @@ -145,7 +147,7 @@ TEST(Write, RelativeLoadAddress) { entry->rule_changes[0x30f9e5c83323973eULL]["how"] = "do you like your blueeyed boy"; entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; - m.AddStackFrameEntry(entry); + m.AddStackFrameEntry(std::move(entry)); // Set the load address. Doing this after adding all the data to // the module must work fine. @@ -169,7 +171,7 @@ TEST(Write, RelativeLoadAddress) { contents.c_str()); } -TEST(Write, OmitUnusedFiles) { +TEST(Module, WriteOmitUnusedFiles) { Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); // Create some source files. @@ -193,7 +195,8 @@ TEST(Write, OmitUnusedFiles) { function->lines.push_back(line2); m.AddFunction(function); - m.AssignSourceIds(); + std::set<Module::InlineOrigin*, Module::InlineOriginCompare> inline_origins; + m.AssignSourceIds(inline_origins); vector<Module::File*> vec; m.GetFiles(&vec); @@ -219,7 +222,7 @@ TEST(Write, OmitUnusedFiles) { contents.c_str()); } -TEST(Write, NoCFI) { +TEST(Module, WriteNoCFI) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); @@ -241,7 +244,7 @@ TEST(Write, NoCFI) { m.AddFunction(function); // Some stack information. - Module::StackFrameEntry* entry = new Module::StackFrameEntry(); + auto entry = std::make_unique<Module::StackFrameEntry>(); entry->address = 0x30f9e5c83323973dULL; entry->size = 0x49fc9ca7c7c13dc2ULL; entry->initial_rules[".cfa"] = "he was a handsome man"; @@ -249,13 +252,13 @@ TEST(Write, NoCFI) { entry->rule_changes[0x30f9e5c83323973eULL]["how"] = "do you like your blueeyed boy"; entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; - m.AddStackFrameEntry(entry); + m.AddStackFrameEntry(std::move(entry)); // Set the load address. Doing this after adding all the data to // the module must work fine. m.SetLoadAddress(0x2ab698b0b6407073ULL); - m.Write(s, NO_CFI); + m.Write(s, SYMBOLS_AND_FILES | INLINES); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "FILE 0 filename.cc\n" @@ -265,7 +268,7 @@ TEST(Write, NoCFI) { contents.c_str()); } -TEST(Construct, AddFunctions) { +TEST(Module, ConstructAddFunction) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); @@ -287,7 +290,8 @@ TEST(Construct, AddFunctions) { vec.push_back(function1); vec.push_back(function2); - m.AddFunctions(vec.begin(), vec.end()); + for (Module::Function* func: vec) + m.AddFunction(func); m.Write(s, ALL_SYMBOL_DATA); string contents = s.str(); @@ -306,27 +310,79 @@ TEST(Construct, AddFunctions) { EXPECT_EQ((size_t) 2, vec.size()); } -TEST(Construct, AddFrames) { +TEST(Module, WriteOutOfRangeAddresses) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Specify an allowed address range, representing a PT_LOAD segment in a + // module. + vector<Module::Range> address_ranges = { + Module::Range(0x2000ULL, 0x1000ULL), + }; + m.SetAddressRanges(address_ranges); + + // Add three stack frames (one lower, one in, and one higher than the allowed + // address range). Only the middle frame should be captured. + auto entry1 = std::make_unique<Module::StackFrameEntry>(); + entry1->address = 0x1000ULL; + entry1->size = 0x100ULL; + m.AddStackFrameEntry(std::move(entry1)); + auto entry2 = std::make_unique<Module::StackFrameEntry>(); + entry2->address = 0x2000ULL; + entry2->size = 0x100ULL; + m.AddStackFrameEntry(std::move(entry2)); + auto entry3 = std::make_unique<Module::StackFrameEntry>(); + entry3->address = 0x3000ULL; + entry3->size = 0x100ULL; + m.AddStackFrameEntry(std::move(entry3)); + + // Add a function outside the allowed range. + Module::File* file = m.FindFile("file_name.cc"); + Module::Function* function = new Module::Function( + "function_name", 0x4000ULL); + Module::Range range(0x4000ULL, 0x1000ULL); + function->ranges.push_back(range); + function->parameter_size = 0x100ULL; + Module::Line line = { 0x4000ULL, 0x100ULL, file, 67519080 }; + function->lines.push_back(line); + m.AddFunction(function); + + // Add an extern outside the allowed range. + auto extern1 = std::make_unique<Module::Extern>(0x5000ULL); + extern1->name = "_xyz"; + m.AddExtern(std::move(extern1)); + + m.Write(s, ALL_SYMBOL_DATA); + + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "STACK CFI INIT 2000 100 \n", + s.str().c_str()); + + // Cleanup - Prevent Memory Leak errors. + delete (function); +} + +TEST(Module, ConstructAddFrames) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); // First STACK CFI entry, with no initial rules or deltas. - Module::StackFrameEntry* entry1 = new Module::StackFrameEntry(); + auto entry1 = std::make_unique<Module::StackFrameEntry>(); entry1->address = 0xddb5f41285aa7757ULL; entry1->size = 0x1486493370dc5073ULL; - m.AddStackFrameEntry(entry1); + m.AddStackFrameEntry(std::move(entry1)); // Second STACK CFI entry, with initial rules but no deltas. - Module::StackFrameEntry* entry2 = new Module::StackFrameEntry(); + auto entry2 = std::make_unique<Module::StackFrameEntry>(); entry2->address = 0x8064f3af5e067e38ULL; entry2->size = 0x0de2a5ee55509407ULL; entry2->initial_rules[".cfa"] = "I think that I shall never see"; entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; - m.AddStackFrameEntry(entry2); + m.AddStackFrameEntry(std::move(entry2)); // Third STACK CFI entry, with initial rules and deltas. - Module::StackFrameEntry* entry3 = new Module::StackFrameEntry(); + auto entry3 = std::make_unique<Module::StackFrameEntry>(); entry3->address = 0x5e8d0db0a7075c6cULL; entry3->size = 0x1c7edb12a7aea229ULL; entry3->initial_rules[".cfa"] = "Whose woods are these"; @@ -338,7 +394,7 @@ TEST(Construct, AddFrames) { "his house is in"; entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; - m.AddStackFrameEntry(entry3); + m.AddStackFrameEntry(std::move(entry3)); // Check that Write writes STACK CFI records properly. m.Write(s, ALL_SYMBOL_DATA); @@ -393,7 +449,7 @@ TEST(Construct, AddFrames) { EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes)); } -TEST(Construct, UniqueFiles) { +TEST(Module, ConstructUniqueFiles) { Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); Module::File* file1 = m.FindFile("foo"); Module::File* file2 = m.FindFile(string("bar")); @@ -406,7 +462,7 @@ TEST(Construct, UniqueFiles) { EXPECT_TRUE(m.FindExistingFile("baz") == NULL); } -TEST(Construct, DuplicateFunctions) { +TEST(Module, ConstructDuplicateFunctions) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); @@ -415,7 +471,10 @@ TEST(Construct, DuplicateFunctions) { Module::Function* function2 = generate_duplicate_function("_without_form"); m.AddFunction(function1); - m.AddFunction(function2); + // If this succeeds, we'll have a double-free with the `delete` below. Avoid + // that. + ASSERT_FALSE(m.AddFunction(function2)); + delete function2; m.Write(s, ALL_SYMBOL_DATA); string contents = s.str(); @@ -425,7 +484,7 @@ TEST(Construct, DuplicateFunctions) { contents.c_str()); } -TEST(Construct, FunctionsWithSameAddress) { +TEST(Module, ConstructFunctionsWithSameAddress) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); @@ -446,20 +505,48 @@ TEST(Construct, FunctionsWithSameAddress) { contents.c_str()); } +// If multiple fields are enabled, only one function is included per address. +// The entry will be tagged with `m` to show that there are multiple symbols +// at that address. +// TODO(lgrey): Remove the non-multiple versions of these tests and remove the +// suffixes from the suffxed ones when removing `enable_multiple_field_`. +TEST(Module, ConstructFunctionsWithSameAddressMultiple) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true); + + // Two functions. + Module::Function* function1 = generate_duplicate_function("_without_form"); + Module::Function* function2 = generate_duplicate_function("_and_void"); + + m.AddFunction(function1); + // If this succeeds, we'll have a double-free with the `delete` below. Avoid + // that. + ASSERT_FALSE(m.AddFunction(function2)); + delete function2; + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ( + "MODULE os-name architecture id-string name with spaces\n" + "FUNC m d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" + " _without_form\n", + contents.c_str()); +} + // Externs should be written out as PUBLIC records, sorted by // address. -TEST(Construct, Externs) { +TEST(Module, ConstructExterns) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); // Two externs. - Module::Extern* extern1 = new Module::Extern(0xffff); + auto extern1 = std::make_unique<Module::Extern>(0xffff); extern1->name = "_abc"; - Module::Extern* extern2 = new Module::Extern(0xaaaa); + auto extern2 = std::make_unique<Module::Extern>(0xaaaa); extern2->name = "_xyz"; - m.AddExtern(extern1); - m.AddExtern(extern2); + m.AddExtern(std::move(extern1)); + m.AddExtern(std::move(extern2)); m.Write(s, ALL_SYMBOL_DATA); string contents = s.str(); @@ -473,18 +560,18 @@ TEST(Construct, Externs) { // Externs with the same address should only keep the first entry // added. -TEST(Construct, DuplicateExterns) { +TEST(Module, ConstructDuplicateExterns) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); // Two externs. - Module::Extern* extern1 = new Module::Extern(0xffff); + auto extern1 = std::make_unique<Module::Extern>(0xffff); extern1->name = "_xyz"; - Module::Extern* extern2 = new Module::Extern(0xffff); + auto extern2 = std::make_unique<Module::Extern>(0xffff); extern2->name = "_abc"; - m.AddExtern(extern1); - m.AddExtern(extern2); + m.AddExtern(std::move(extern1)); + m.AddExtern(std::move(extern2)); m.Write(s, ALL_SYMBOL_DATA); string contents = s.str(); @@ -494,21 +581,44 @@ TEST(Construct, DuplicateExterns) { "PUBLIC ffff 0 _xyz\n", contents.c_str()); } +// Externs with the same address have the `m` tag if the multiple field are +// enabled. +TEST(Module, ConstructDuplicateExternsMultiple) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true); + + // Two externs. + auto extern1 = std::make_unique<Module::Extern>(0xffff); + extern1->name = "_xyz"; + auto extern2 = std::make_unique<Module::Extern>(0xffff); + extern2->name = "_abc"; + + m.AddExtern(std::move(extern1)); + m.AddExtern(std::move(extern2)); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME + "\n" + "PUBLIC m ffff 0 _xyz\n", + contents.c_str()); +} // If there exists an extern and a function at the same address, only write // out the FUNC entry. -TEST(Construct, FunctionsAndExternsWithSameAddress) { +TEST(Module, ConstructFunctionsAndExternsWithSameAddress) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); // Two externs. - Module::Extern* extern1 = new Module::Extern(0xabc0); + auto extern1 = std::make_unique<Module::Extern>(0xabc0); extern1->name = "abc"; - Module::Extern* extern2 = new Module::Extern(0xfff0); + auto extern2 = std::make_unique<Module::Extern>(0xfff0); extern2->name = "xyz"; - m.AddExtern(extern1); - m.AddExtern(extern2); + m.AddExtern(std::move(extern1)); + m.AddExtern(std::move(extern2)); Module::Function* function = new Module::Function("_xyz", 0xfff0); Module::Range range(0xfff0, 0x10); @@ -527,24 +637,55 @@ TEST(Construct, FunctionsAndExternsWithSameAddress) { } // If there exists an extern and a function at the same address, only write +// out the FUNC entry, and mark it with `m` if the multiple field is enabled. +TEST(Module, ConstructFunctionsAndExternsWithSameAddressMultiple) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true); + + // Two externs. + auto extern1 = std::make_unique<Module::Extern>(0xabc0); + extern1->name = "abc"; + auto extern2 = std::make_unique<Module::Extern>(0xfff0); + extern2->name = "xyz"; + + m.AddExtern(std::move(extern1)); + m.AddExtern(std::move(extern2)); + + Module::Function* function = new Module::Function("_xyz", 0xfff0); + Module::Range range(0xfff0, 0x10); + function->ranges.push_back(range); + function->parameter_size = 0; + m.AddFunction(function); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME + "\n" + "FUNC m fff0 10 0 _xyz\n" + "PUBLIC abc0 0 abc\n", + contents.c_str()); +} + +// If there exists an extern and a function at the same address, only write // out the FUNC entry. For ARM THUMB, the extern that comes from the ELF // symbol section has bit 0 set. -TEST(Construct, FunctionsAndThumbExternsWithSameAddress) { +TEST(Module, ConstructFunctionsAndThumbExternsWithSameAddress) { stringstream s; Module m(MODULE_NAME, MODULE_OS, "arm", MODULE_ID); // Two THUMB externs. - Module::Extern* thumb_extern1 = new Module::Extern(0xabc1); + auto thumb_extern1 = std::make_unique<Module::Extern>(0xabc1); thumb_extern1->name = "thumb_abc"; - Module::Extern* thumb_extern2 = new Module::Extern(0xfff1); + auto thumb_extern2 = std::make_unique<Module::Extern>(0xfff1); thumb_extern2->name = "thumb_xyz"; - Module::Extern* arm_extern1 = new Module::Extern(0xcc00); + auto arm_extern1 = std::make_unique<Module::Extern>(0xcc00); arm_extern1->name = "arm_func"; - m.AddExtern(thumb_extern1); - m.AddExtern(thumb_extern2); - m.AddExtern(arm_extern1); + m.AddExtern(std::move(thumb_extern1)); + m.AddExtern(std::move(thumb_extern2)); + m.AddExtern(std::move(arm_extern1)); // The corresponding function from the DWARF debug data have the actual // address. @@ -564,53 +705,3 @@ TEST(Construct, FunctionsAndThumbExternsWithSameAddress) { "PUBLIC cc00 0 arm_func\n", contents.c_str()); } - -TEST(Write, OutOfRangeAddresses) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Specify an allowed address range, representing a PT_LOAD segment in a - // module. - vector<Module::Range> address_ranges = { - Module::Range(0x2000ULL, 0x1000ULL), - }; - m.SetAddressRanges(address_ranges); - - // Add three stack frames (one lower, one in, and one higher than the allowed - // address range). Only the middle frame should be captured. - Module::StackFrameEntry* entry1 = new Module::StackFrameEntry(); - entry1->address = 0x1000ULL; - entry1->size = 0x100ULL; - m.AddStackFrameEntry(entry1); - Module::StackFrameEntry* entry2 = new Module::StackFrameEntry(); - entry2->address = 0x2000ULL; - entry2->size = 0x100ULL; - m.AddStackFrameEntry(entry2); - Module::StackFrameEntry* entry3 = new Module::StackFrameEntry(); - entry3->address = 0x3000ULL; - entry3->size = 0x100ULL; - m.AddStackFrameEntry(entry3); - - // Add a function outside the allowed range. - Module::File* file = m.FindFile("file_name.cc"); - Module::Function* function = new Module::Function( - "function_name", 0x4000ULL); - Module::Range range(0x4000ULL, 0x1000ULL); - function->ranges.push_back(range); - function->parameter_size = 0x100ULL; - Module::Line line = { 0x4000ULL, 0x100ULL, file, 67519080 }; - function->lines.push_back(line); - m.AddFunction(function); - - // Add an extern outside the allowed range. - Module::Extern* extern1 = new Module::Extern(0x5000ULL); - extern1->name = "_xyz"; - m.AddExtern(extern1); - - m.Write(s, ALL_SYMBOL_DATA); - - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "STACK CFI INIT 2000 100 \n", - s.str().c_str()); - -} diff --git a/src/common/path_helper.cc b/src/common/path_helper.cc index 61a6e318..e51a1b68 100644 --- a/src/common/path_helper.cc +++ b/src/common/path_helper.cc @@ -1,5 +1,4 @@ -// Copyright 2017, Google Inc. -// All rights reserved. +// Copyright 2017 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/path_helper.h b/src/common/path_helper.h index 2166ba01..0c026c25 100644 --- a/src/common/path_helper.h +++ b/src/common/path_helper.h @@ -1,5 +1,4 @@ -// Copyright 2017, Google Inc. -// All rights reserved. +// Copyright 2017 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/safe_math.h b/src/common/safe_math.h new file mode 100644 index 00000000..3eab0d21 --- /dev/null +++ b/src/common/safe_math.h @@ -0,0 +1,81 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// safe_math.h: Helpful math functions. +#ifndef SAFE_MATH_H__ +#define SAFE_MATH_H__ + +#include <utility> + +namespace google_breakpad { + +// Adds `a` and `b`, returning a pair of: +// - The result after any truncation. +// - Whether an overflow/underflow occurred. +template <typename T> +std::pair<T, bool> AddWithOverflowCheck(T a, T b) { +#ifdef _WIN32 + // Since C++11, unsigned overflow is well-defined; do everything unsigned, + // assuming 2's complement. + if (std::is_unsigned<T>::value) { + T result = a + b; + // Since we're adding two values >= 0, having a smaller value implies + // overflow. + bool overflow = result < a; + return {result, overflow}; + } + + using TUnsigned = typename std::make_unsigned<T>::type; + T result = TUnsigned(a) + TUnsigned(b); + bool overflow; + if ((a >= 0) == (b >= 0)) { + if (a >= 0) { + overflow = result < a; + } else { + overflow = result > a; + } + } else { + // If signs are different, it's impossible for overflow to happen. + overflow = false; + } + return {result, overflow}; +#else + T result; + bool overflow = __builtin_add_overflow(a, b, &result); + return {result, overflow}; +#endif +} + +template <typename T> +T AddIgnoringOverflow(T a, T b) { + return AddWithOverflowCheck(a, b).first; +} + +} // namespace google_breakpad + +#endif // SAFE_MATH_H__ diff --git a/src/common/safe_math_unittest.cc b/src/common/safe_math_unittest.cc new file mode 100644 index 00000000..1908155d --- /dev/null +++ b/src/common/safe_math_unittest.cc @@ -0,0 +1,72 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// safe_math_unittest.cc: Unit tests for SafeMath + +#include "safe_math.h" +#include "breakpad_googletest_includes.h" + +namespace { + +using google_breakpad::AddIgnoringOverflow; +using google_breakpad::AddWithOverflowCheck; + +TEST(SafeMath, AddOverflowWorksAsIntended) { + EXPECT_EQ(AddWithOverflowCheck<uint8_t>(0, 0), + std::make_pair<uint8_t>(0, false)); + EXPECT_EQ(AddWithOverflowCheck<uint8_t>(0, 255), + std::make_pair<uint8_t>(255, false)); + EXPECT_EQ(AddWithOverflowCheck<uint8_t>(1, 255), + std::make_pair<uint8_t>(0, true)); + + EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, 127), + std::make_pair<int8_t>(-1, false)); + EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, -128), + std::make_pair<int8_t>(-1, false)); + EXPECT_EQ(AddWithOverflowCheck<int8_t>(1, -128), + std::make_pair<int8_t>(-127, false)); + EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, -1), + std::make_pair<int8_t>(126, false)); + + EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, -1), + std::make_pair<int8_t>(127, true)); + EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, -128), + std::make_pair<int8_t>(0, true)); + EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, 1), + std::make_pair<int8_t>(-128, true)); + EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, 127), + std::make_pair<int8_t>(-2, true)); +} + +TEST(SafeMath, AddIgnoringOverflowWorksAsIntended) { + EXPECT_EQ(AddIgnoringOverflow<uint8_t>(0, 0), 0); + EXPECT_EQ(AddIgnoringOverflow<uint8_t>(0, 255), 255); + EXPECT_EQ(AddIgnoringOverflow<uint8_t>(1, 255), 0); +} + +} // namespace diff --git a/src/common/scoped_ptr.h b/src/common/scoped_ptr.h index d137c186..d1110178 100644 --- a/src/common/scoped_ptr.h +++ b/src/common/scoped_ptr.h @@ -1,4 +1,4 @@ -// Copyright 2013 Google Inc. All Rights Reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/simple_string_dictionary.cc b/src/common/simple_string_dictionary.cc index e0a74cee..68288897 100644 --- a/src/common/simple_string_dictionary.cc +++ b/src/common/simple_string_dictionary.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/simple_string_dictionary.h b/src/common/simple_string_dictionary.h index 94849205..f7253a34 100644 --- a/src/common/simple_string_dictionary.h +++ b/src/common/simple_string_dictionary.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/simple_string_dictionary_unittest.cc b/src/common/simple_string_dictionary_unittest.cc index e7b8fd76..4f3f1f5c 100644 --- a/src/common/simple_string_dictionary_unittest.cc +++ b/src/common/simple_string_dictionary_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/solaris/dump_symbols.cc b/src/common/solaris/dump_symbols.cc index 168d0b28..8277fd66 100644 --- a/src/common/solaris/dump_symbols.cc +++ b/src/common/solaris/dump_symbols.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -97,7 +96,7 @@ struct LineInfo { // Information of a function. struct FuncInfo { // Name of the function. - const char *name; + const char* name; // Offset from the base of the loading address. GElf_Off rva_to_base; // Virtual address of the function. @@ -115,7 +114,7 @@ struct FuncInfo { // Information of a source file. struct SourceFileInfo { // Name of the source file. - const char *name; + const char* name; // Starting address of the source file. GElf_Addr addr; // Id of the source file. @@ -125,12 +124,12 @@ struct SourceFileInfo { }; struct CompareString { - bool operator()(const char *s1, const char *s2) const { + bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; -typedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap; +typedef std::map<const char*, struct SymbolEntry*, CompareString> SymbolMap; // Information of a symbol table. // This is the root of all types of symbol. @@ -141,16 +140,16 @@ struct SymbolInfo { }; // Stab section name. -const char *kStabName = ".stab"; +const char* kStabName = ".stab"; // Stab str section name. -const char *kStabStrName = ".stabstr"; +const char* kStabStrName = ".stabstr"; // Symtab section name. -const char *kSymtabName = ".symtab"; +const char* kSymtabName = ".symtab"; // Strtab section name. -const char *kStrtabName = ".strtab"; +const char* kStrtabName = ".strtab"; // Default buffer lenght for demangle. const int demangleLen = 20000; @@ -160,11 +159,11 @@ uint64_t stringOffset = 0; // Update the offset to the start of the string index of the next // object module for every N_ENDM stabs. -inline void RecalculateOffset(struct slist* cur_list, char *stabstr) { +inline void RecalculateOffset(struct slist* cur_list, char* stabstr) { while ((--cur_list)->n_strx == 0) ; stringOffset += cur_list->n_strx; - char *temp = stabstr + stringOffset; + char* temp = stabstr + stringOffset; while (*temp != '\0') { ++stringOffset; ++temp; @@ -174,10 +173,10 @@ inline void RecalculateOffset(struct slist* cur_list, char *stabstr) { } // Demangle using demangle library on Solaris. -std::string Demangle(const char *mangled) { +std::string Demangle(const char* mangled) { int status = 0; std::string str(mangled); - char *demangled = (char *)malloc(demangleLen); + char* demangled = (char*)malloc(demangleLen); if (!demangled) { fprintf(stderr, "no enough memory.\n"); @@ -197,7 +196,7 @@ out: return str; } -bool WriteFormat(int fd, const char *fmt, ...) { +bool WriteFormat(int fd, const char* fmt, ...) { va_list list; char buffer[4096]; ssize_t expected, written; @@ -209,27 +208,27 @@ bool WriteFormat(int fd, const char *fmt, ...) { return expected == written; } -bool IsValidElf(const GElf_Ehdr *elf_header) { +bool IsValidElf(const GElf_Ehdr* elf_header) { return memcmp(elf_header, ELFMAG, SELFMAG) == 0; } -static bool FindSectionByName(Elf *elf, const char *name, +static bool FindSectionByName(Elf* elf, const char* name, int shstrndx, - GElf_Shdr *shdr) { + GElf_Shdr* shdr) { assert(name != NULL); if (strlen(name) == 0) return false; - Elf_Scn *scn = NULL; + Elf_Scn* scn = NULL; while ((scn = elf_nextscn(elf, scn)) != NULL) { - if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) { + if (gelf_getshdr(scn, shdr) == (GElf_Shdr*)0) { fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0)); return false; } - const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name); + const char* section_name = elf_strptr(elf, shstrndx, shdr->sh_name); if (!section_name) { fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1)); continue; @@ -245,10 +244,10 @@ static bool FindSectionByName(Elf *elf, const char *name, // The parameter size is used for FPO-optimized code, and // this is all tied up with the debugging data for Windows x86. // Set it to 0 on Solaris. -int LoadStackParamSize(struct slist *list, - struct slist *list_end, - struct FuncInfo *func_info) { - struct slist *cur_list = list; +int LoadStackParamSize(struct slist* list, + struct slist* list_end, + struct FuncInfo* func_info) { + struct slist* cur_list = list; int step = 1; while (cur_list < list_end && cur_list->n_type == N_PSYM) { ++cur_list; @@ -259,10 +258,10 @@ int LoadStackParamSize(struct slist *list, return step; } -int LoadLineInfo(struct slist *list, - struct slist *list_end, - struct FuncInfo *func_info) { - struct slist *cur_list = list; +int LoadLineInfo(struct slist* list, + struct slist* list_end, + struct FuncInfo* func_info) { + struct slist* cur_list = list; do { // Skip non line information. while (cur_list < list_end && cur_list->n_type != N_SLINE) { @@ -288,12 +287,12 @@ int LoadLineInfo(struct slist *list, return cur_list - list; } -int LoadFuncSymbols(struct slist *list, - struct slist *list_end, - char *stabstr, +int LoadFuncSymbols(struct slist* list, + struct slist* list_end, + char* stabstr, GElf_Word base, - struct SourceFileInfo *source_file_info) { - struct slist *cur_list = list; + struct SourceFileInfo* source_file_info) { + struct slist* cur_list = list; assert(cur_list->n_type == N_SO); ++cur_list; @@ -342,17 +341,17 @@ int LoadFuncSymbols(struct slist *list, } // Compute size and rva information based on symbols loaded from stab section. -bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { - std::vector<struct SourceFileInfo> *sorted_files = +bool ComputeSizeAndRVA(struct SymbolInfo* symbols) { + std::vector<struct SourceFileInfo>* sorted_files = &(symbols->source_file_info); - SymbolMap *symbol_entries = &(symbols->symbol_entries); + SymbolMap* symbol_entries = &(symbols->symbol_entries); for (size_t i = 0; i < sorted_files->size(); ++i) { - struct SourceFileInfo &source_file = (*sorted_files)[i]; - std::vector<struct FuncInfo> *sorted_functions = &(source_file.func_info); + struct SourceFileInfo& source_file = (*sorted_files)[i]; + std::vector<struct FuncInfo>* sorted_functions = &(source_file.func_info); int func_size = sorted_functions->size(); for (size_t j = 0; j < func_size; ++j) { - struct FuncInfo &func_info = (*sorted_functions)[j]; + struct FuncInfo& func_info = (*sorted_functions)[j]; int line_count = func_info.line_info.size(); // Discard the ending part of the name. @@ -373,13 +372,13 @@ bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { // Compute function and line size. for (size_t k = 0; k < line_count; ++k) { - struct LineInfo &line_info = func_info.line_info[k]; + struct LineInfo& line_info = func_info.line_info[k]; line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base; if (k == line_count - 1) { line_info.size = func_info.size - line_info.rva_to_func; } else { - struct LineInfo &next_line = func_info.line_info[k + 1]; + struct LineInfo& next_line = func_info.line_info[k + 1]; line_info.size = next_line.rva_to_func - line_info.rva_to_func; } } // for each line. @@ -392,24 +391,23 @@ bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { return true; } -bool LoadAllSymbols(const GElf_Shdr *stab_section, - const GElf_Shdr *stabstr_section, +bool LoadAllSymbols(const GElf_Shdr* stab_section, + const GElf_Shdr* stabstr_section, GElf_Word base, - struct SymbolInfo *symbols) { + struct SymbolInfo* symbols) { if (stab_section == NULL || stabstr_section == NULL) return false; - char *stabstr = - reinterpret_cast<char *>(stabstr_section->sh_offset + base); - struct slist *lists = - reinterpret_cast<struct slist *>(stab_section->sh_offset + base); + char* stabstr = reinterpret_cast<char*>(stabstr_section->sh_offset + base); + struct slist* lists = + reinterpret_cast<struct slist*>(stab_section->sh_offset + base); int nstab = stab_section->sh_size / sizeof(struct slist); int source_id = 0; // First pass, load all symbols from the object file. for (int i = 0; i < nstab; ) { int step = 1; - struct slist *cur_list = lists + i; + struct slist* cur_list = lists + i; if (cur_list->n_type == N_SO) { // FUNC <address> <size> <param_stack_size> <function> struct SourceFileInfo source_file_info; @@ -431,12 +429,12 @@ bool LoadAllSymbols(const GElf_Shdr *stab_section, return ComputeSizeAndRVA(symbols); } -bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, - void *obj_base) { +bool LoadSymbols(Elf* elf, GElf_Ehdr* elf_header, struct SymbolInfo* symbols, + void* obj_base) { GElf_Word base = reinterpret_cast<GElf_Word>(obj_base); - const GElf_Shdr *sections = - reinterpret_cast<GElf_Shdr *>(elf_header->e_shoff + base); + const GElf_Shdr* sections = + reinterpret_cast<GElf_Shdr*>(elf_header->e_shoff + base); GElf_Shdr stab_section; if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx, &stab_section)) { @@ -462,11 +460,11 @@ bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, return false; } - Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset); + Elf_Sym* symbol = (Elf_Sym*)((char*)base + symtab_section.sh_offset); for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) { - struct SymbolEntry *symbol_entry = - (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry)); - const char *name = reinterpret_cast<char *>( + struct SymbolEntry* symbol_entry = + (struct SymbolEntry*)malloc(sizeof(struct SymbolEntry)); + const char* name = reinterpret_cast<char*>( strtab_section.sh_offset + (GElf_Word)base + symbol->st_name); symbol_entry->offset = symbol->st_value; symbol_entry->size = symbol->st_size; @@ -479,8 +477,8 @@ bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols); } -bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { - const char *arch_name = NULL; +bool WriteModuleInfo(int fd, GElf_Half arch, const std::string& obj_file) { + const char* arch_name = NULL; if (arch == EM_386) arch_name = "x86"; else if (arch == EM_X86_64) @@ -493,7 +491,7 @@ bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { } unsigned char identifier[16]; - google_breakpad::FileID file_id(obj_file.c_str()); + google_breakpad::elf::FileID file_id(obj_file.c_str()); if (file_id.ElfFileIdentifier(identifier)) { char identifier_str[40]; file_id.ConvertIdentifierToString(identifier, @@ -508,10 +506,10 @@ bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { return false; } -bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) { +bool WriteSourceFileInfo(int fd, const struct SymbolInfo& symbols) { for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { if (symbols.source_file_info[i].source_id != -1) { - const char *name = symbols.source_file_info[i].name; + const char* name = symbols.source_file_info[i].name; if (!WriteFormat(fd, "FILE %d %s\n", symbols.source_file_info[i].source_id, name)) return false; @@ -521,7 +519,7 @@ bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) { } bool WriteOneFunction(int fd, int source_id, - const struct FuncInfo &func_info){ + const struct FuncInfo& func_info){ // Discard the ending part of the name. std::string func_name(func_info.name); std::string::size_type last_colon = func_name.find_last_of(':'); @@ -539,7 +537,7 @@ bool WriteOneFunction(int fd, int source_id, func_info.stack_param_size, func_name.c_str())) { for (size_t i = 0; i < func_info.line_info.size(); ++i) { - const struct LineInfo &line_info = func_info.line_info[i]; + const struct LineInfo& line_info = func_info.line_info[i]; if (line_info.line_num == 0) return true; if (!WriteFormat(fd, "%llx %x %d %d\n", @@ -554,11 +552,11 @@ bool WriteOneFunction(int fd, int source_id, return false; } -bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) { +bool WriteFunctionInfo(int fd, const struct SymbolInfo& symbols) { for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { - const struct SourceFileInfo &file_info = symbols.source_file_info[i]; + const struct SourceFileInfo& file_info = symbols.source_file_info[i]; for (size_t j = 0; j < file_info.func_info.size(); ++j) { - const struct FuncInfo &func_info = file_info.func_info[j]; + const struct FuncInfo& func_info = file_info.func_info[j]; if (!WriteOneFunction(fd, file_info.source_id, func_info)) return false; } @@ -566,7 +564,7 @@ bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) { return true; } -bool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) { +bool DumpStabSymbols(int fd, const struct SymbolInfo& symbols) { return WriteSourceFileInfo(fd, symbols) && WriteFunctionInfo(fd, symbols); } @@ -604,13 +602,13 @@ class FDWrapper { // class MmapWrapper { public: - MmapWrapper(void *mapped_address, size_t mapped_size) : + MmapWrapper(void* mapped_address, size_t mapped_size) : base_(mapped_address), size_(mapped_size) { } ~MmapWrapper() { if (base_ != NULL) { assert(size_ > 0); - munmap((char *)base_, size_); + munmap((char*)base_, size_); } } void release() { @@ -619,7 +617,7 @@ class MmapWrapper { } private: - void *base_; + void* base_; size_t size_; }; @@ -629,14 +627,14 @@ namespace google_breakpad { class AutoElfEnder { public: - AutoElfEnder(Elf *elf) : elf_(elf) {} + AutoElfEnder(Elf* elf) : elf_(elf) {} ~AutoElfEnder() { if (elf_) elf_end(elf_); } private: - Elf *elf_; + Elf* elf_; }; -bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) { +bool DumpSymbols::WriteSymbolFile(const std::string& obj_file, int sym_fd) { if (elf_version(EV_CURRENT) == EV_NONE) { fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return false; @@ -649,16 +647,16 @@ bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) { struct stat st; if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) return false; - void *obj_base = mmap(NULL, st.st_size, + void* obj_base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, obj_fd, 0); if (obj_base == MAP_FAILED) return false; MmapWrapper map_wrapper(obj_base, st.st_size); GElf_Ehdr elf_header; - Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL); + Elf* elf = elf_begin(obj_fd, ELF_C_READ, NULL); AutoElfEnder elfEnder(elf); - if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr*)NULL) { fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1)); return false; } diff --git a/src/common/solaris/dump_symbols.h b/src/common/solaris/dump_symbols.h index 7f4baadc..9c986e4c 100644 --- a/src/common/solaris/dump_symbols.h +++ b/src/common/solaris/dump_symbols.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,7 +39,7 @@ namespace google_breakpad { class DumpSymbols { public: - bool WriteSymbolFile(const std::string &obj_file, + bool WriteSymbolFile(const std::string& obj_file, int sym_fd); }; diff --git a/src/common/solaris/file_id.cc b/src/common/solaris/file_id.cc index 643a1462..53d205b6 100644 --- a/src/common/solaris/file_id.cc +++ b/src/common/solaris/file_id.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -54,17 +53,17 @@ namespace google_breakpad { class AutoElfEnder { public: - AutoElfEnder(Elf *elf) : elf_(elf) {} + AutoElfEnder(Elf* elf) : elf_(elf) {} ~AutoElfEnder() { if (elf_) elf_end(elf_); } private: - Elf *elf_; + Elf* elf_; }; // Find the text section in elf object file. // Return the section start address and the size. -static bool FindElfTextSection(int fd, const void *elf_base, - const void **text_start, - int *text_size) { +static bool FindElfTextSection(int fd, const void* elf_base, + const void** text_start, + int* text_size) { assert(text_start); assert(text_size); @@ -78,10 +77,10 @@ static bool FindElfTextSection(int fd, const void *elf_base, GElf_Ehdr elf_header; lseek(fd, 0L, 0); - Elf *elf = elf_begin(fd, ELF_C_READ, NULL); + Elf* elf = elf_begin(fd, ELF_C_READ, NULL); AutoElfEnder elfEnder(elf); - if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr*)NULL) { print_message2(2, "failed to read elf header: %s\n", elf_errmsg(-1)); return false; } @@ -95,18 +94,18 @@ static bool FindElfTextSection(int fd, const void *elf_base, } static const char kTextSectionName[] = ".text"; - const GElf_Shdr *text_section = NULL; - Elf_Scn *scn = NULL; + const GElf_Shdr* text_section = NULL; + Elf_Scn* scn = NULL; GElf_Shdr shdr; while ((scn = elf_nextscn(elf, scn)) != NULL) { - if (gelf_getshdr(scn, &shdr) == (GElf_Shdr *)0) { + if (gelf_getshdr(scn, &shdr) == (GElf_Shdr*)0) { print_message2(2, "failed to read section header: %s\n", elf_errmsg(0)); return false; } if (shdr.sh_type == SHT_PROGBITS) { - const char *section_name = elf_strptr(elf, elf_header.e_shstrndx, + const char* section_name = elf_strptr(elf, elf_header.e_shstrndx, shdr.sh_name); if (!section_name) { print_message2(2, "Section name error: %s\n", elf_errmsg(-1)); @@ -120,7 +119,7 @@ static bool FindElfTextSection(int fd, const void *elf_base, } } if (text_section != NULL && text_section->sh_size > 0) { - *text_start = (char *)elf_base + text_section->sh_offset; + *text_start = (char*)elf_base + text_section->sh_offset; *text_size = text_section->sh_size; return true; } @@ -128,10 +127,6 @@ static bool FindElfTextSection(int fd, const void *elf_base, return false; } -FileID::FileID(const char *path) { - strcpy(path_, path); -} - class AutoCloser { public: AutoCloser(int fd) : fd_(fd) {} @@ -140,6 +135,12 @@ class AutoCloser { int fd_; }; +namespace elf { + +FileID::FileID(const char* path) { + strcpy(path_, path); +} + bool FileID::ElfFileIdentifier(unsigned char identifier[16]) { int fd = 0; if ((fd = open(path_, O_RDONLY)) < 0) @@ -150,29 +151,29 @@ bool FileID::ElfFileIdentifier(unsigned char identifier[16]) { if (fstat(fd, &st) != 0 || st.st_size <= 0) return false; - void *base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + void* base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (base == MAP_FAILED) return false; bool success = false; - const void *text_section = NULL; + const void* text_section = NULL; int text_size = 0; if (FindElfTextSection(fd, base, &text_section, &text_size)) { MD5Context md5; MD5Init(&md5); - MD5Update(&md5, (const unsigned char *)text_section, text_size); + MD5Update(&md5, (const unsigned char*)text_section, text_size); MD5Final(identifier, &md5); success = true; } - munmap((char *)base, st.st_size); + munmap((char*)base, st.st_size); return success; } // static bool FileID::ConvertIdentifierToString(const unsigned char identifier[16], - char *buffer, int buffer_length) { + char* buffer, int buffer_length) { if (buffer_length < 34) return false; @@ -194,4 +195,5 @@ bool FileID::ConvertIdentifierToString(const unsigned char identifier[16], return true; } +} // elf } // namespace google_breakpad diff --git a/src/common/solaris/file_id.h b/src/common/solaris/file_id.h index 375e8575..2e41f0ae 100644 --- a/src/common/solaris/file_id.h +++ b/src/common/solaris/file_id.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,6 +36,7 @@ #include <limits.h> namespace google_breakpad { +namespace elf { class FileID { public: @@ -61,6 +61,7 @@ class FileID { char path_[PATH_MAX]; }; +} // elf } // namespace google_breakpad #endif // COMMON_SOLARIS_FILE_ID_H__ diff --git a/src/common/solaris/guid_creator.cc b/src/common/solaris/guid_creator.cc index e9e6c6f5..4802f5a7 100644 --- a/src/common/solaris/guid_creator.cc +++ b/src/common/solaris/guid_creator.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -74,8 +73,8 @@ bool GUIDToString(const GUID *guid, char *buf, int buf_len) { assert(buf_len > kGUIDStringLength); int num = snprintf(buf, buf_len, kGUIDFormatString, guid->data1, guid->data2, guid->data3, - *reinterpret_cast<const uint32_t *>(&(guid->data4[0])), - *reinterpret_cast<const uint32_t *>(&(guid->data4[4]))); + *reinterpret_cast<const uint32_t*>(&(guid->data4[0])), + *reinterpret_cast<const uint32_t*>(&(guid->data4[4]))); if (num != kGUIDStringLength) return false; diff --git a/src/common/solaris/guid_creator.h b/src/common/solaris/guid_creator.h index 4aee3a1c..91ed0041 100644 --- a/src/common/solaris/guid_creator.h +++ b/src/common/solaris/guid_creator.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/solaris/message_output.h b/src/common/solaris/message_output.h index 3e3b1d46..9810dc57 100644 --- a/src/common/solaris/message_output.h +++ b/src/common/solaris/message_output.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/stabs_reader.cc b/src/common/stabs_reader.cc index 6019fc7e..30118830 100644 --- a/src/common/stabs_reader.cc +++ b/src/common/stabs_reader.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,7 +45,7 @@ using std::vector; namespace google_breakpad { -StabsReader::EntryIterator::EntryIterator(const ByteBuffer *buffer, +StabsReader::EntryIterator::EntryIterator(const ByteBuffer* buffer, bool big_endian, size_t value_size) : value_size_(value_size), cursor_(buffer, big_endian) { // Actually, we could handle weird sizes just fine, but they're @@ -65,10 +65,10 @@ void StabsReader::EntryIterator::Fetch() { entry_.at_end = !cursor_; } -StabsReader::StabsReader(const uint8_t *stab, size_t stab_size, - const uint8_t *stabstr, size_t stabstr_size, +StabsReader::StabsReader(const uint8_t* stab, size_t stab_size, + const uint8_t* stabstr, size_t stabstr_size, bool big_endian, size_t value_size, bool unitized, - StabsHandler *handler) + StabsHandler* handler) : entries_(stab, stab_size), strings_(stabstr, stabstr_size), iterator_(&entries_, big_endian, value_size), @@ -78,7 +78,7 @@ StabsReader::StabsReader(const uint8_t *stab, size_t stab_size, next_cu_string_offset_(0), current_source_file_(NULL) { } -const char *StabsReader::SymbolString() { +const char* StabsReader::SymbolString() { ptrdiff_t offset = string_offset_ + iterator_->name_offset; if (offset < 0 || (size_t) offset >= strings_.Size()) { handler_->Warning("symbol %d: name offset outside the string section\n", @@ -87,7 +87,7 @@ const char *StabsReader::SymbolString() { // taken from the string section. offset = 0; } - return reinterpret_cast<const char *>(strings_.start + offset); + return reinterpret_cast<const char*>(strings_.start + offset); } bool StabsReader::Process() { @@ -134,9 +134,9 @@ bool StabsReader::ProcessCompilationUnit() { // There may be an N_SO entry whose name ends with a slash, // indicating the directory in which the compilation occurred. // The build directory defaults to NULL. - const char *build_directory = NULL; + const char* build_directory = NULL; { - const char *name = SymbolString(); + const char* name = SymbolString(); if (name[0] && name[strlen(name) - 1] == '/') { build_directory = name; ++iterator_; @@ -148,7 +148,7 @@ bool StabsReader::ProcessCompilationUnit() { { if (iterator_->at_end || iterator_->type != N_SO) return true; - const char *name = SymbolString(); + const char* name = SymbolString(); if (name[0] == '\0') { // This seems to be a stray end-of-compilation-unit marker; // consume it, but don't report the end, since we didn't see a @@ -203,7 +203,7 @@ bool StabsReader::ProcessCompilationUnit() { uint64_t ending_address = 0; if (!iterator_->at_end) { assert(iterator_->type == N_SO); - const char *name = SymbolString(); + const char* name = SymbolString(); if (name[0] == '\0') { ending_address = iterator_->value; ++iterator_; @@ -225,8 +225,8 @@ bool StabsReader::ProcessFunction() { // The STABS string for an N_FUN entry is the name of the function, // followed by a colon, followed by type information for the // function. We want to pass the name alone to StartFunction. - const char *stab_string = SymbolString(); - const char *name_end = strchr(stab_string, ':'); + const char* stab_string = SymbolString(); + const char* name_end = strchr(stab_string, ':'); if (! name_end) name_end = stab_string + strlen(stab_string); string name(stab_string, name_end - stab_string); @@ -270,7 +270,7 @@ bool StabsReader::ProcessFunction() { if (!iterator_->at_end) { assert(iterator_->type == N_SO || iterator_->type == N_FUN); if (iterator_->type == N_FUN) { - const char *symbol_name = SymbolString(); + const char* symbol_name = SymbolString(); if (symbol_name[0] == '\0') { // An N_FUN entry with no name is a terminator for this function; // its value is the function's size. diff --git a/src/common/stabs_reader.h b/src/common/stabs_reader.h index 98ee2dd5..3f5f0a8f 100644 --- a/src/common/stabs_reader.h +++ b/src/common/stabs_reader.h @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -12,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -92,10 +92,10 @@ class StabsReader { // // Note that, in ELF, the .stabstr section should be found using the // 'sh_link' field of the .stab section header, not by name. - StabsReader(const uint8_t *stab, size_t stab_size, - const uint8_t *stabstr, size_t stabstr_size, + StabsReader(const uint8_t* stab, size_t stab_size, + const uint8_t* stabstr, size_t stabstr_size, bool big_endian, size_t value_size, bool unitized, - StabsHandler *handler); + StabsHandler* handler); // Process the STABS data, calling the handler's member functions to // report what we find. While the handler functions return true, @@ -149,17 +149,17 @@ class StabsReader { // Mac, they are 32 or 64 bits long. Oddly, the section header's entry // size for a Linux ELF .stab section varies according to the ELF class // from 12 to 20 even as the actual entries remain unchanged. - EntryIterator(const ByteBuffer *buffer, bool big_endian, size_t value_size); + EntryIterator(const ByteBuffer* buffer, bool big_endian, size_t value_size); // Move to the next entry. This function's behavior is undefined if // at_end() is true when it is called. - EntryIterator &operator++() { Fetch(); entry_.index++; return *this; } + EntryIterator& operator++() { Fetch(); entry_.index++; return *this; } // Dereferencing this iterator produces a reference to an Entry structure // that holds the current entry's values. The entry is owned by this // EntryIterator, and will be invalidated at the next call to operator++. - const Entry &operator*() const { return entry_; } - const Entry *operator->() const { return &entry_; } + const Entry& operator*() const { return entry_; } + const Entry* operator->() const { return &entry_; } private: // Read the STABS entry at cursor_, and set entry_ appropriately. @@ -178,12 +178,12 @@ class StabsReader { // A source line, saved to be reported later. struct Line { uint64_t address; - const char *filename; + const char* filename; int number; }; // Return the name of the current symbol. - const char *SymbolString(); + const char* SymbolString(); // Process a compilation unit starting at symbol_. Return true // to continue processing, or false to abort. @@ -210,7 +210,7 @@ class StabsReader { // StabsReader::StabsReader. bool unitized_; - StabsHandler *handler_; + StabsHandler* handler_; // The offset of the current compilation unit's strings within stabstr_. size_t string_offset_; @@ -220,7 +220,7 @@ class StabsReader { size_t next_cu_string_offset_; // The current source file name. - const char *current_source_file_; + const char* current_source_file_; // Mac OS X STABS place SLINE records before functions; we accumulate a // vector of these until we see the FUN record, and then report them @@ -261,7 +261,7 @@ class StabsHandler { // FILENAME values are different addresses, they represent different // file names. // - // Thus, it's safe to use (say) std::map<char *, ...>, which does + // Thus, it's safe to use (say) std::map<char*, ...>, which does // string address comparisons, not string content comparisons. // Since all the strings are in same array of characters --- the // .stabstr section --- comparing their addresses produces @@ -271,8 +271,8 @@ class StabsHandler { // named FILENAME, and whose base address is ADDRESS. If // BUILD_DIRECTORY is non-NULL, it is the name of the build // directory in which the compilation occurred. - virtual bool StartCompilationUnit(const char *filename, uint64_t address, - const char *build_directory) { + virtual bool StartCompilationUnit(const char* filename, uint64_t address, + const char* build_directory) { return true; } @@ -292,7 +292,7 @@ class StabsHandler { // StartFunction is the function name alone. // // In languages that use name mangling, like C++, NAME is mangled. - virtual bool StartFunction(const string &name, uint64_t address) { + virtual bool StartFunction(const string& name, uint64_t address) { return true; } @@ -305,19 +305,19 @@ class StabsHandler { // Report that the code at ADDRESS is attributable to line NUMBER of // the source file named FILENAME. The caller must infer the ending // address of the line. - virtual bool Line(uint64_t address, const char *filename, int number) { + virtual bool Line(uint64_t address, const char* filename, int number) { return true; } // Report that an exported function NAME is present at ADDRESS. // The size of the function is unknown. - virtual bool Extern(const string &name, uint64_t address) { + virtual bool Extern(const string& name, uint64_t address) { return true; } // Report a warning. FORMAT is a printf-like format string, // specifying how to format the subsequent arguments. - virtual void Warning(const char *format, ...) = 0; + virtual void Warning(const char* format, ...) = 0; }; } // namespace google_breakpad diff --git a/src/common/stabs_reader_unittest.cc b/src/common/stabs_reader_unittest.cc index a84da1c4..79888815 100644 --- a/src/common/stabs_reader_unittest.cc +++ b/src/common/stabs_reader_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -75,7 +74,7 @@ class StringAssembler: public Section { // Add the string S to this StringAssembler, and return the string's // offset within this compilation unit's strings. If S has been added // already, this returns the offset of its first instance. - size_t Add(const string &s) { + size_t Add(const string& s) { map<string, size_t>::iterator it = added_.find(s); if (it != added_.end()) return it->second; @@ -127,7 +126,7 @@ class StringAssembler: public Section { class StabsAssembler: public Section { public: // Create a StabsAssembler that uses StringAssembler for its strings. - StabsAssembler(StringAssembler *string_assembler) + StabsAssembler(StringAssembler* string_assembler) : Section(string_assembler->endianness()), string_assembler_(string_assembler), value_size_(0), @@ -137,7 +136,7 @@ class StabsAssembler: public Section { // Accessor and setter for value_size_. size_t value_size() const { return value_size_; } - StabsAssembler &set_value_size(size_t value_size) { + StabsAssembler& set_value_size(size_t value_size) { value_size_ = value_size; return *this; } @@ -147,7 +146,7 @@ class StabsAssembler: public Section { // its compilation unit's portion of the .stabstr section; this can be a // value generated by a StringAssembler. Return a reference to this // StabsAssembler. - StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, + StabsAssembler& Stab(uint8_t type, uint8_t other, Label descriptor, Label value, Label name) { D32(name); D8(type); @@ -159,15 +158,15 @@ class StabsAssembler: public Section { } // As above, but automatically add NAME to our StringAssembler. - StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, - Label value, const string &name) { + StabsAssembler& Stab(uint8_t type, uint8_t other, Label descriptor, + Label value, const string& name) { return Stab(type, other, descriptor, value, string_assembler_->Add(name)); } // Start a compilation unit named NAME, with an N_UNDF symbol to start // it, and its own portion of the string section. Return a reference to // this StabsAssembler. - StabsAssembler &StartCU(const string &name) { + StabsAssembler& StartCU(const string& name) { assert(!cu_header_); cu_header_ = new CUHeader; string_assembler_->StartCU(); @@ -180,7 +179,7 @@ class StabsAssembler: public Section { // Close off the current compilation unit. Return a reference to this // StabsAssembler. - StabsAssembler &EndCU() { + StabsAssembler& EndCU() { assert(cu_header_); cu_header_->final_entry_count = entry_count_; cu_header_->final_string_size = string_assembler_->EndCU(); @@ -201,7 +200,7 @@ class StabsAssembler: public Section { }; // The strings for our STABS entries. - StringAssembler *string_assembler_; + StringAssembler* string_assembler_; // The size of the 'value' field of stabs entries in this section. size_t value_size_; @@ -211,20 +210,20 @@ class StabsAssembler: public Section { // Header labels for this compilation unit, if we've started one but not // finished it. - CUHeader *cu_header_; + CUHeader* cu_header_; }; class MockStabsReaderHandler: public StabsHandler { public: MOCK_METHOD3(StartCompilationUnit, - bool(const char *, uint64_t, const char *)); + bool(const char*, uint64_t, const char*)); MOCK_METHOD1(EndCompilationUnit, bool(uint64_t)); - MOCK_METHOD2(StartFunction, bool(const string &, uint64_t)); + MOCK_METHOD2(StartFunction, bool(const string&, uint64_t)); MOCK_METHOD1(EndFunction, bool(uint64_t)); - MOCK_METHOD3(Line, bool(uint64_t, const char *, int)); - MOCK_METHOD2(Extern, bool(const string &, uint64_t)); - void Warning(const char *format, ...) { MockWarning(format); } - MOCK_METHOD1(MockWarning, void(const char *)); + MOCK_METHOD3(Line, bool(uint64_t, const char*, int)); + MOCK_METHOD2(Extern, bool(const string&, uint64_t)); + void Warning(const char* format, ...) { MockWarning(format); } + MOCK_METHOD1(MockWarning, void(const char*)); }; struct StabsFixture { @@ -243,9 +242,9 @@ struct StabsFixture { // Run the parser on the test input, passing whatever we find to HANDLER. StabsReader reader( - reinterpret_cast<const uint8_t *>(stabs_contents.data()), + reinterpret_cast<const uint8_t*>(stabs_contents.data()), stabs_contents.size(), - reinterpret_cast<const uint8_t *>(stabstr_contents.data()), + reinterpret_cast<const uint8_t*>(stabstr_contents.data()), stabstr_contents.size(), stabs.endianness() == kBigEndian, stabs.value_size(), unitized, &mock_handler); diff --git a/src/common/stabs_to_module.cc b/src/common/stabs_to_module.cc index 049a6cc6..3d026c22 100644 --- a/src/common/stabs_to_module.cc +++ b/src/common/stabs_to_module.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,6 +36,8 @@ #include <stdio.h> #include <algorithm> +#include <memory> +#include <utility> #include "common/stabs_to_module.h" #include "common/using_std_string.h" @@ -45,7 +46,7 @@ namespace google_breakpad { // Demangle using abi call. // Older GCC may not support it. -static string Demangle(const string &mangled) { +static string Demangle(const string& mangled) { int status = 0; char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); if (status == 0 && demangled != NULL) { @@ -58,7 +59,7 @@ static string Demangle(const string &mangled) { StabsToModule::~StabsToModule() { // Free any functions we've accumulated but not added to the module. - for (vector<Module::Function *>::const_iterator func_it = functions_.begin(); + for (vector<Module::Function*>::const_iterator func_it = functions_.begin(); func_it != functions_.end(); func_it++) delete *func_it; // Free any function that we're currently within. @@ -87,10 +88,11 @@ bool StabsToModule::EndCompilationUnit(uint64_t address) { return true; } -bool StabsToModule::StartFunction(const string &name, +bool StabsToModule::StartFunction(const string& name, uint64_t address) { assert(!current_function_); - Module::Function *f = new Module::Function(Demangle(name), address); + Module::Function* f = + new Module::Function(module_->AddStringToPool(Demangle(name)), address); Module::Range r(address, 0); // We compute this in StabsToModule::Finalize(). f->ranges.push_back(r); f->parameter_size = 0; // We don't provide this information. @@ -131,8 +133,8 @@ bool StabsToModule::Line(uint64_t address, const char *name, int number) { return true; } -bool StabsToModule::Extern(const string &name, uint64_t address) { - Module::Extern *ext = new Module::Extern(address); +bool StabsToModule::Extern(const string& name, uint64_t address) { + auto ext = std::make_unique<Module::Extern>(address); // Older libstdc++ demangle implementations can crash on unexpected // input, so be careful about what gets passed in. if (name.compare(0, 3, "__Z") == 0) { @@ -142,7 +144,7 @@ bool StabsToModule::Extern(const string &name, uint64_t address) { } else { ext->name = name; } - module_->AddExtern(ext); + module_->AddExtern(std::move(ext)); return true; } @@ -160,7 +162,7 @@ void StabsToModule::Finalize() { sort(functions_.begin(), functions_.end(), Module::Function::CompareByAddress); - for (vector<Module::Function *>::const_iterator func_it = functions_.begin(); + for (vector<Module::Function*>::const_iterator func_it = functions_.begin(); func_it != functions_.end(); func_it++) { Module::Function *f = *func_it; @@ -191,8 +193,11 @@ void StabsToModule::Finalize() { } } // Now that everything has a size, add our functions to the module, and - // dispose of our private list. - module_->AddFunctions(functions_.begin(), functions_.end()); + // dispose of our private list. Delete the functions that we fail to add, so + // they aren't leaked. + for (Module::Function* func: functions_) + if (!module_->AddFunction(func)) + delete func; functions_.clear(); } diff --git a/src/common/stabs_to_module.h b/src/common/stabs_to_module.h index 5e04fa79..99c61b0c 100644 --- a/src/common/stabs_to_module.h +++ b/src/common/stabs_to_module.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -76,10 +75,10 @@ class StabsToModule: public google_breakpad::StabsHandler { bool StartCompilationUnit(const char *name, uint64_t address, const char *build_directory); bool EndCompilationUnit(uint64_t address); - bool StartFunction(const string &name, uint64_t address); + bool StartFunction(const string& name, uint64_t address); bool EndFunction(uint64_t address); bool Line(uint64_t address, const char *name, int number); - bool Extern(const string &name, uint64_t address); + bool Extern(const string& name, uint64_t address); void Warning(const char *format, ...); // Do any final processing necessary to make module_ contain all the @@ -107,7 +106,7 @@ class StabsToModule: public google_breakpad::StabsHandler { // We could just stick them in module_ from the outset, but if // module_ already contains data gathered from other debugging // formats, that would complicate the size computation. - vector<Module::Function *> functions_; + vector<Module::Function*> functions_; // Boundary addresses. STABS doesn't necessarily supply sizes for // functions and lines, so we need to compute them ourselves by diff --git a/src/common/stabs_to_module_unittest.cc b/src/common/stabs_to_module_unittest.cc index aae00476..95bdb261 100644 --- a/src/common/stabs_to_module_unittest.cc +++ b/src/common/stabs_to_module_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -58,11 +57,11 @@ TEST(StabsToModule, SimpleCU) { Module::File *file = m.FindExistingFile("source-file-name"); ASSERT_TRUE(file != NULL); - vector<Module::Function *> functions; + vector<Module::Function*> functions; m.GetFunctions(&functions, functions.end()); ASSERT_EQ((size_t) 1, functions.size()); Module::Function *function = functions[0]; - EXPECT_STREQ("function", function->name.c_str()); + EXPECT_STREQ("function", function->name.str().c_str()); EXPECT_EQ(0xfde4abbed390c394LL, function->address); EXPECT_EQ(0x10U, function->ranges[0].size); EXPECT_EQ(0U, function->parameter_size); @@ -88,7 +87,7 @@ TEST(StabsToModule, Externs) { h.Finalize(); // Now check to see what has been added to the Module. - vector<Module::Extern *> externs; + vector<Module::Extern*> externs; m.GetExterns(&externs, externs.end()); ASSERT_EQ((size_t) 3, externs.size()); Module::Extern *extern1 = externs[0]; @@ -124,7 +123,7 @@ TEST(StabsToModule, DuplicateFunctionNames) { Module::File *file = m.FindExistingFile("compilation-unit"); ASSERT_TRUE(file != NULL); - vector<Module::Function *> functions; + vector<Module::Function*> functions; m.GetFunctions(&functions, functions.end()); ASSERT_EQ(1U, functions.size()); @@ -159,12 +158,12 @@ TEST(InferSizes, LineSize) { Module::File *file2 = m.FindExistingFile("source-file-name-2"); ASSERT_TRUE(file2 != NULL); - vector<Module::Function *> functions; + vector<Module::Function*> functions; m.GetFunctions(&functions, functions.end()); ASSERT_EQ((size_t) 1, functions.size()); Module::Function *function = functions[0]; - EXPECT_STREQ("function", function->name.c_str()); + EXPECT_STREQ("function", function->name.str().c_str()); EXPECT_EQ(0xb4513962eff94e92LL, function->address); EXPECT_EQ(0x1000100000000ULL, function->ranges[0].size); // inferred from CU end EXPECT_EQ(0U, function->parameter_size); @@ -204,17 +203,16 @@ TEST(FunctionNames, Mangled) { Module::File *file = m.FindExistingFile("compilation-unit"); ASSERT_TRUE(file != NULL); - vector<Module::Function *> functions; + vector<Module::Function*> functions; m.GetFunctions(&functions, functions.end()); ASSERT_EQ(1U, functions.size()); Module::Function *function = functions[0]; // This is GCC-specific, but we shouldn't be seeing STABS data anywhere // but Linux. - EXPECT_STREQ("std::vector<unsigned long long, " - "std::allocator<unsigned long long> >::" - "push_back(unsigned long long const&)", - function->name.c_str()); + EXPECT_THAT(function->name.str(), ::testing::ContainsRegex( + "std::vector<unsigned long long, std::allocator<unsigned long long>\\s?>::" + "push_back\\(unsigned long long const&\\)")); EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address); EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size EXPECT_EQ(0U, function->parameter_size); diff --git a/src/common/stdio_wrapper.h b/src/common/stdio_wrapper.h index a3dd50aa..32093bd4 100644 --- a/src/common/stdio_wrapper.h +++ b/src/common/stdio_wrapper.h @@ -1,5 +1,4 @@ -// Copyright (c) 2016, Google Inc. -// All rights reserved. +// Copyright 2016 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/string_conversion.cc b/src/common/string_conversion.cc index 11d60a36..213d6ed7 100644 --- a/src/common/string_conversion.cc +++ b/src/common/string_conversion.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,15 +37,15 @@ namespace google_breakpad { using std::vector; -void UTF8ToUTF16(const char *in, vector<uint16_t> *out) { +void UTF8ToUTF16(const char* in, vector<uint16_t>* out) { size_t source_length = strlen(in); - const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in); - const UTF8 *source_end_ptr = source_ptr + source_length; + const UTF8* source_ptr = reinterpret_cast<const UTF8*>(in); + const UTF8* source_end_ptr = source_ptr + source_length; // Erase the contents and zero fill to the expected size out->clear(); out->insert(out->begin(), source_length, 0); - uint16_t *target_ptr = &(*out)[0]; - uint16_t *target_end_ptr = target_ptr + out->capacity(); + uint16_t* target_ptr = &(*out)[0]; + uint16_t* target_end_ptr = target_ptr + out->capacity(); ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, &target_ptr, target_end_ptr, strictConversion); @@ -55,11 +54,11 @@ void UTF8ToUTF16(const char *in, vector<uint16_t> *out) { out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); } -int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) { - const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in); - const UTF8 *source_end_ptr = source_ptr + 1; - uint16_t *target_ptr = out; - uint16_t *target_end_ptr = target_ptr + 2; +int UTF8ToUTF16Char(const char* in, int in_length, uint16_t out[2]) { + const UTF8* source_ptr = reinterpret_cast<const UTF8*>(in); + const UTF8* source_end_ptr = source_ptr + 1; + uint16_t* target_ptr = out; + uint16_t* target_end_ptr = target_ptr + 2; out[0] = out[1] = 0; // Process one character at a time @@ -69,28 +68,28 @@ int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) { strictConversion); if (result == conversionOK) - return static_cast<int>(source_ptr - reinterpret_cast<const UTF8 *>(in)); + return static_cast<int>(source_ptr - reinterpret_cast<const UTF8*>(in)); // Add another character to the input stream and try again - source_ptr = reinterpret_cast<const UTF8 *>(in); + source_ptr = reinterpret_cast<const UTF8*>(in); ++source_end_ptr; - if (source_end_ptr > reinterpret_cast<const UTF8 *>(in) + in_length) + if (source_end_ptr > reinterpret_cast<const UTF8*>(in) + in_length) break; } return 0; } -void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out) { +void UTF32ToUTF16(const wchar_t* in, vector<uint16_t>* out) { size_t source_length = wcslen(in); - const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in); - const UTF32 *source_end_ptr = source_ptr + source_length; + const UTF32* source_ptr = reinterpret_cast<const UTF32*>(in); + const UTF32* source_end_ptr = source_ptr + source_length; // Erase the contents and zero fill to the expected size out->clear(); out->insert(out->begin(), source_length, 0); - uint16_t *target_ptr = &(*out)[0]; - uint16_t *target_end_ptr = target_ptr + out->capacity(); + uint16_t* target_ptr = &(*out)[0]; + uint16_t* target_end_ptr = target_ptr + out->capacity(); ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, &target_ptr, target_end_ptr, strictConversion); @@ -100,10 +99,10 @@ void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out) { } void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) { - const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(&in); - const UTF32 *source_end_ptr = source_ptr + 1; - uint16_t *target_ptr = out; - uint16_t *target_end_ptr = target_ptr + 2; + const UTF32* source_ptr = reinterpret_cast<const UTF32*>(&in); + const UTF32* source_end_ptr = source_ptr + 1; + uint16_t* target_ptr = out; + uint16_t* target_end_ptr = target_ptr + 2; out[0] = out[1] = 0; ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, &target_ptr, target_end_ptr, @@ -118,15 +117,15 @@ static inline uint16_t Swap(uint16_t value) { return (value >> 8) | static_cast<uint16_t>(value << 8); } -string UTF16ToUTF8(const vector<uint16_t> &in, bool swap) { - const UTF16 *source_ptr = &in[0]; +string UTF16ToUTF8(const vector<uint16_t>& in, bool swap) { + const UTF16* source_ptr = &in[0]; scoped_array<uint16_t> source_buffer; // If we're to swap, we need to make a local copy and swap each byte pair if (swap) { int idx = 0; source_buffer.reset(new uint16_t[in.size()]); - UTF16 *source_buffer_ptr = source_buffer.get(); + UTF16* source_buffer_ptr = source_buffer.get(); for (vector<uint16_t>::const_iterator it = in.begin(); it != in.end(); ++it, ++idx) source_buffer_ptr[idx] = Swap(*it); @@ -135,17 +134,17 @@ string UTF16ToUTF8(const vector<uint16_t> &in, bool swap) { } // The maximum expansion would be 4x the size of the input string. - const UTF16 *source_end_ptr = source_ptr + in.size(); + const UTF16* source_end_ptr = source_ptr + in.size(); size_t target_capacity = in.size() * 4; scoped_array<UTF8> target_buffer(new UTF8[target_capacity]); - UTF8 *target_ptr = target_buffer.get(); - UTF8 *target_end_ptr = target_ptr + target_capacity; + UTF8* target_ptr = target_buffer.get(); + UTF8* target_end_ptr = target_ptr + target_capacity; ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr, &target_ptr, target_end_ptr, strictConversion); if (result == conversionOK) { - const char *targetPtr = reinterpret_cast<const char *>(target_buffer.get()); + const char* targetPtr = reinterpret_cast<const char*>(target_buffer.get()); return targetPtr; } diff --git a/src/common/string_conversion.h b/src/common/string_conversion.h index b9ba96a2..c5f5a357 100644 --- a/src/common/string_conversion.h +++ b/src/common/string_conversion.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,24 +43,24 @@ using std::vector; // Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the // conversion failed, |out| will be zero length. -void UTF8ToUTF16(const char *in, vector<uint16_t> *out); +void UTF8ToUTF16(const char* in, vector<uint16_t>* out); // Convert at least one character (up to a maximum of |in_length|) from |in| // to UTF-16 into |out|. Return the number of characters consumed from |in|. // Any unused characters in |out| will be initialized to 0. No memory will // be allocated by this routine. -int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]); +int UTF8ToUTF16Char(const char* in, int in_length, uint16_t out[2]); // Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the // conversion failed, |out| will be zero length. -void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out); +void UTF32ToUTF16(const wchar_t* in, vector<uint16_t>* out); // Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be // initialized to 0. No memory will be allocated by this routine. void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]); // Convert |in| to UTF-8. If |swap| is true, swap bytes before converting. -string UTF16ToUTF8(const vector<uint16_t> &in, bool swap); +string UTF16ToUTF8(const vector<uint16_t>& in, bool swap); } // namespace google_breakpad diff --git a/src/common/string_conversion_unittest.cc b/src/common/string_conversion_unittest.cc index e9f9b55d..2e64a957 100644 --- a/src/common/string_conversion_unittest.cc +++ b/src/common/string_conversion_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2019, Google Inc. -// All rights reserved. +// Copyright 2019 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/string_view.h b/src/common/string_view.h new file mode 100644 index 00000000..a8e15922 --- /dev/null +++ b/src/common/string_view.h @@ -0,0 +1,113 @@ +// Copyright 2021 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_STRING_VIEW_H__ +#define COMMON_STRING_VIEW_H__ + +#include <cassert> +#include <cstring> +#include <ostream> +#include "common/using_std_string.h" + +namespace google_breakpad { + +// A StringView is a string reference to a string object, but not own the +// string object. It's a compatibile layer until we can use std::string_view in +// C++17. +class StringView { + private: + // The start of the string, in an external buffer. It doesn't have to be + // null-terminated. + const char* data_ = ""; + + size_t length_ = 0; + + public: + // Construct an empty StringView. + StringView() = default; + + // Disallow construct StringView from nullptr. + StringView(std::nullptr_t) = delete; + + // Construct a StringView from a cstring. + StringView(const char* str) : data_(str) { + assert(str); + length_ = strlen(str); + } + + // Construct a StringView from a cstring with fixed length. + StringView(const char* str, size_t length) : data_(str), length_(length) { + assert(str); + } + + // Construct a StringView from an std::string. + StringView(const string& str) : data_(str.data()), length_(str.length()) {} + + string str() const { return string(data_, length_); } + + const char* data() const { return data_; } + + bool empty() const { return length_ == 0; } + + size_t size() const { return length_; } + + int compare(StringView rhs) const { + size_t min_len = std::min(size(), rhs.size()); + int res = memcmp(data_, rhs.data(), min_len); + if (res != 0) + return res; + if (size() == rhs.size()) + return 0; + return size() < rhs.size() ? -1 : 1; + } +}; + +inline bool operator==(StringView lhs, StringView rhs) { + return lhs.compare(rhs) == 0; +} + +inline bool operator!=(StringView lhs, StringView rhs) { + return lhs.compare(rhs) != 0; +} + +inline bool operator<(StringView lhs, StringView rhs) { + return lhs.compare(rhs) < 0; +} + +inline bool operator>(StringView lhs, StringView rhs) { + return lhs.compare(rhs) > 0; +} + +inline std::ostream& operator<<(std::ostream& os, StringView s) { + os << s.str(); + return os; +} + +} // namespace google_breakpad + +#endif // COMMON_STRING_VIEW_H__ diff --git a/src/common/symbol_data.h b/src/common/symbol_data.h index 2cf15a85..19d6f3dd 100644 --- a/src/common/symbol_data.h +++ b/src/common/symbol_data.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -32,11 +31,27 @@ #ifndef COMMON_SYMBOL_DATA_H_ #define COMMON_SYMBOL_DATA_H_ +#include<type_traits> + // Control what data is used from the symbol file. enum SymbolData { - ALL_SYMBOL_DATA, - NO_CFI, - ONLY_CFI + NO_DATA = 0, + SYMBOLS_AND_FILES = 1, + CFI = 1 << 1, + INLINES = 1 << 2, + ALL_SYMBOL_DATA = INLINES | CFI | SYMBOLS_AND_FILES }; +inline SymbolData operator&(SymbolData data1, SymbolData data2) { + return static_cast<SymbolData>( + static_cast<std::underlying_type<SymbolData>::type>(data1) & + static_cast<std::underlying_type<SymbolData>::type>(data2)); +} + +inline SymbolData operator|(SymbolData data1, SymbolData data2) { + return static_cast<SymbolData>( + static_cast<std::underlying_type<SymbolData>::type>(data1) | + static_cast<std::underlying_type<SymbolData>::type>(data2)); +} + #endif // COMMON_SYMBOL_DATA_H_ diff --git a/src/common/test_assembler.cc b/src/common/test_assembler.cc index 1e783b45..91899663 100644 --- a/src/common/test_assembler.cc +++ b/src/common/test_assembler.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -46,7 +45,7 @@ using std::back_insert_iterator; Label::Label() : value_(new Binding()) { } Label::Label(uint64_t value) : value_(new Binding(value)) { } -Label::Label(const Label &label) { +Label::Label(const Label& label) { value_ = label.value_; value_->Acquire(); } @@ -54,12 +53,12 @@ Label::~Label() { if (value_->Release()) delete value_; } -Label &Label::operator=(uint64_t value) { +Label& Label::operator=(uint64_t value) { value_->Set(NULL, value); return *this; } -Label &Label::operator=(const Label &label) { +Label& Label::operator=(const Label& label) { value_->Set(label.value_, 0); return *this; } @@ -89,7 +88,7 @@ Label Label::operator-(uint64_t subtrahend) const { #define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x) #endif -uint64_t Label::operator-(const Label &label) const { +uint64_t Label::operator-(const Label& label) const { uint64_t offset; ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset)); return offset; @@ -101,8 +100,8 @@ uint64_t Label::Value() const { return v; }; -bool Label::IsKnownConstant(uint64_t *value_p) const { - Binding *base; +bool Label::IsKnownConstant(uint64_t* value_p) const { + Binding* base; uint64_t addend; value_->Get(&base, &addend); if (base != NULL) return false; @@ -110,9 +109,9 @@ bool Label::IsKnownConstant(uint64_t *value_p) const { return true; } -bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const +bool Label::IsKnownOffsetFrom(const Label& label, uint64_t* offset_p) const { - Binding *label_base, *this_base; + Binding* label_base, *this_base; uint64_t label_addend, this_addend; label.value_->Get(&label_base, &label_addend); value_->Get(&this_base, &this_addend); @@ -135,7 +134,7 @@ Label::Binding::~Binding() { delete base_; } -void Label::Binding::Set(Binding *binding, uint64_t addend) { +void Label::Binding::Set(Binding* binding, uint64_t addend) { if (!base_ && !binding) { // We're equating two constants. This could be okay. assert(addend_ == addend); @@ -183,13 +182,13 @@ void Label::Binding::Set(Binding *binding, uint64_t addend) { } } -void Label::Binding::Get(Binding **base, uint64_t *addend) { +void Label::Binding::Get(Binding** base, uint64_t* addend) { if (base_ && base_ != this) { // Recurse to find the end of our reference chain (the root of our // tree), and then rewrite every binding along the chain to refer // to it directly, adjusting addends appropriately. (This is why // this member function isn't this-const.) - Binding *final_base; + Binding* final_base; uint64_t final_addend; base_->Get(&final_base, &final_addend); if (final_base) final_base->Acquire(); @@ -218,14 +217,14 @@ static inline void InsertEndian(test_assembler::Endianness endianness, } } -Section &Section::Append(Endianness endianness, size_t size, uint64_t number) { +Section& Section::Append(Endianness endianness, size_t size, uint64_t number) { InsertEndian(endianness, size, number, back_insert_iterator<string>(contents_)); return *this; } -Section &Section::Append(Endianness endianness, size_t size, - const Label &label) { +Section& Section::Append(Endianness endianness, size_t size, + const Label& label) { // If this label's value is known, there's no reason to waste an // entry in references_ on it. uint64_t value; @@ -246,14 +245,14 @@ Section &Section::Append(Endianness endianness, size_t size, #define ENDIANNESS(e) ENDIANNESS_ ## e #define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ - Section &Section::e ## bits(uint ## bits ## _t v) { \ + Section& Section::e ## bits(uint ## bits ## _t v) { \ InsertEndian(ENDIANNESS(e), bits / 8, v, \ back_insert_iterator<string>(contents_)); \ return *this; \ } #define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \ - Section &Section::e ## bits(const Label &v) { \ + Section& Section::e ## bits(const Label& v) { \ return Append(ENDIANNESS(e), bits / 8, v); \ } @@ -272,13 +271,13 @@ DEFINE_SHORT_APPEND_ENDIAN(B, 32); DEFINE_SHORT_APPEND_ENDIAN(B, 64); #define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ - Section &Section::D ## bits(uint ## bits ## _t v) { \ + Section& Section::D ## bits(uint ## bits ## _t v) { \ InsertEndian(endianness_, bits / 8, v, \ back_insert_iterator<string>(contents_)); \ return *this; \ } #define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \ - Section &Section::D ## bits(const Label &v) { \ + Section& Section::D ## bits(const Label& v) { \ return Append(endianness_, bits / 8, v); \ } #define DEFINE_SHORT_APPEND_DEFAULT(bits) \ @@ -290,7 +289,7 @@ DEFINE_SHORT_APPEND_DEFAULT(16); DEFINE_SHORT_APPEND_DEFAULT(32); DEFINE_SHORT_APPEND_DEFAULT(64); -Section &Section::Append(const Section §ion) { +Section& Section::Append(const Section& section) { size_t base = contents_.size(); contents_.append(section.contents_); for (vector<Reference>::const_iterator it = section.references_.begin(); @@ -300,7 +299,7 @@ Section &Section::Append(const Section §ion) { return *this; } -Section &Section::LEB128(long long value) { +Section& Section::LEB128(long long value) { while (value < -0x40 || 0x3f < value) { contents_ += (value & 0x7f) | 0x80; if (value < 0) @@ -312,7 +311,7 @@ Section &Section::LEB128(long long value) { return *this; } -Section &Section::ULEB128(uint64_t value) { +Section& Section::ULEB128(uint64_t value) { while (value > 0x7f) { contents_ += (value & 0x7f) | 0x80; value = (value >> 7); @@ -321,7 +320,7 @@ Section &Section::ULEB128(uint64_t value) { return *this; } -Section &Section::Align(size_t alignment, uint8_t pad_byte) { +Section& Section::Align(size_t alignment, uint8_t pad_byte) { // ALIGNMENT must be a power of two. assert(((alignment - 1) & alignment) == 0); size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1); @@ -335,11 +334,11 @@ void Section::Clear() { references_.clear(); } -bool Section::GetContents(string *contents) { +bool Section::GetContents(string* contents) { // For each label reference, find the label's value, and patch it into // the section's contents. for (size_t i = 0; i < references_.size(); i++) { - Reference &r = references_[i]; + Reference& r = references_[i]; uint64_t value; if (!r.label.IsKnownConstant(&value)) { fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset); diff --git a/src/common/test_assembler.h b/src/common/test_assembler.h index 373dbeba..809c7b21 100644 --- a/src/common/test_assembler.h +++ b/src/common/test_assembler.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -111,7 +110,7 @@ class Label { public: Label(); // An undefined label. Label(uint64_t value); // A label with a fixed value - Label(const Label &value); // A label equal to another. + Label(const Label& value); // A label equal to another. ~Label(); // Return this label's value; it must be known. @@ -124,18 +123,18 @@ class Label { // former could fail if the label is not yet defined and the latter won't. uint64_t Value() const; - Label &operator=(uint64_t value); - Label &operator=(const Label &value); + Label& operator=(uint64_t value); + Label& operator=(const Label& value); Label operator+(uint64_t addend) const; Label operator-(uint64_t subtrahend) const; - uint64_t operator-(const Label &subtrahend) const; + uint64_t operator-(const Label& subtrahend) const; // We could also provide == and != that work on undefined, but // related, labels. // Return true if this label's value is known. If VALUE_P is given, // set *VALUE_P to the known value if returning true. - bool IsKnownConstant(uint64_t *value_p = NULL) const; + bool IsKnownConstant(uint64_t* value_p = NULL) const; // Return true if the offset from LABEL to this label is known. If // OFFSET_P is given, set *OFFSET_P to the offset when returning true. @@ -155,7 +154,7 @@ class Label { // l-m // -10 // m-l // 10 // m.Value() // error: m's value is not known - bool IsKnownOffsetFrom(const Label &label, uint64_t *offset_p = NULL) const; + bool IsKnownOffsetFrom(const Label& label, uint64_t* offset_p = NULL) const; private: // A label's value, or if that is not yet known, how the value is @@ -186,7 +185,7 @@ class Label { // Update every binding on this binding's chain to point directly // to BINDING, or to be a constant, with addends adjusted // appropriately. - void Set(Binding *binding, uint64_t value); + void Set(Binding* binding, uint64_t value); // Return what we know about the value of this binding. // - If this binding's value is a known constant, set BASE to @@ -198,7 +197,7 @@ class Label { // value. // - If this binding is unconstrained, set BASE to this, and leave // ADDEND unchanged. - void Get(Binding **base, uint64_t *addend); + void Get(Binding** base, uint64_t* addend); private: // There are three cases: @@ -220,7 +219,7 @@ class Label { // operations on bindings do path compression: they change every // binding on the chain to point directly to the final value, // adjusting addends as appropriate. - Binding *base_; + Binding* base_; uint64_t addend_; // The number of Labels and Bindings pointing to this binding. @@ -230,10 +229,10 @@ class Label { }; // This label's value. - Binding *value_; + Binding* value_; }; -inline Label operator+(uint64_t a, const Label &l) { return l + a; } +inline Label operator+(uint64_t a, const Label& l) { return l + a; } // Note that int-Label isn't defined, as negating a Label is not an // operation we support. @@ -288,18 +287,18 @@ class Section { // Append the SIZE bytes at DATA or the contents of STRING to the // end of this section. Return a reference to this section. - Section &Append(const uint8_t *data, size_t size) { - contents_.append(reinterpret_cast<const char *>(data), size); + Section& Append(const uint8_t* data, size_t size) { + contents_.append(reinterpret_cast<const char*>(data), size); return *this; }; - Section &Append(const string &data) { + Section& Append(const string& data) { contents_.append(data); return *this; }; // Append SIZE copies of BYTE to the end of this section. Return a // reference to this section. - Section &Append(size_t size, uint8_t byte) { + Section& Append(size_t size, uint8_t byte) { contents_.append(size, (char) byte); return *this; } @@ -307,8 +306,8 @@ class Section { // Append NUMBER to this section. ENDIANNESS is the endianness to // use to write the number. SIZE is the length of the number in // bytes. Return a reference to this section. - Section &Append(Endianness endianness, size_t size, uint64_t number); - Section &Append(Endianness endianness, size_t size, const Label &label); + Section& Append(Endianness endianness, size_t size, uint64_t number); + Section& Append(Endianness endianness, size_t size, const Label& label); // Append SECTION to the end of this section. The labels SECTION // refers to need not be defined yet. @@ -317,11 +316,11 @@ class Section { // SECTION. If placing SECTION within 'this' provides new // constraints on existing labels' values, then it's up to the // caller to fiddle with those labels as needed. - Section &Append(const Section §ion); + Section& Append(const Section& section); // Append the contents of DATA as a series of bytes terminated by // a NULL character. - Section &AppendCString(const string &data) { + Section& AppendCString(const string& data) { Append(data); contents_ += '\0'; return *this; @@ -329,7 +328,7 @@ class Section { // Append at most SIZE bytes from DATA; if DATA is less than SIZE bytes // long, pad with '\0' characters. - Section &AppendCString(const string &data, size_t size) { + Section& AppendCString(const string& data, size_t size) { contents_.append(data, 0, size); if (data.size() < size) Append(size - data.size(), 0); @@ -352,18 +351,18 @@ class Section { // the compiler will properly sign-extend a signed value before // passing it to the function, at which point the function's // behavior is the same either way. - Section &L8(uint8_t value) { contents_ += value; return *this; } - Section &B8(uint8_t value) { contents_ += value; return *this; } - Section &D8(uint8_t value) { contents_ += value; return *this; } + Section& L8(uint8_t value) { contents_ += value; return *this; } + Section& B8(uint8_t value) { contents_ += value; return *this; } + Section& D8(uint8_t value) { contents_ += value; return *this; } Section &L16(uint16_t), &L32(uint32_t), &L64(uint64_t), &B16(uint16_t), &B32(uint32_t), &B64(uint64_t), &D16(uint16_t), &D32(uint32_t), &D64(uint64_t); - Section &L8(const Label &label), &L16(const Label &label), - &L32(const Label &label), &L64(const Label &label), - &B8(const Label &label), &B16(const Label &label), - &B32(const Label &label), &B64(const Label &label), - &D8(const Label &label), &D16(const Label &label), - &D32(const Label &label), &D64(const Label &label); + Section &L8(const Label& label), &L16(const Label& label), + &L32(const Label& label), &L64(const Label& label), + &B8(const Label& label), &B16(const Label& label), + &B32(const Label& label), &B64(const Label& label), + &D8(const Label& label), &D16(const Label& label), + &D32(const Label& label), &D64(const Label& label); // Append VALUE in a signed LEB128 (Little-Endian Base 128) form. // @@ -383,7 +382,7 @@ class Section { // // Note that VALUE cannot be a Label (we would have to implement // relaxation). - Section &LEB128(long long value); + Section& LEB128(long long value); // Append VALUE in unsigned LEB128 (Little-Endian Base 128) form. // @@ -399,13 +398,13 @@ class Section { // // Note that VALUE cannot be a Label (we would have to implement // relaxation). - Section &ULEB128(uint64_t value); + Section& ULEB128(uint64_t value); // Jump to the next location aligned on an ALIGNMENT-byte boundary, // relative to the start of the section. Fill the gap with PAD_BYTE. // ALIGNMENT must be a power of two. Return a reference to this // section. - Section &Align(size_t alignment, uint8_t pad_byte = 0); + Section& Align(size_t alignment, uint8_t pad_byte = 0); // Clear the contents of this section. void Clear(); @@ -436,19 +435,19 @@ class Section { Label Here() const { return start_ + Size(); } // Set *LABEL to Here, and return a reference to this section. - Section &Mark(Label *label) { *label = Here(); return *this; } + Section& Mark(Label* label) { *label = Here(); return *this; } // If there are no undefined label references left in this // section, set CONTENTS to the contents of this section, as a // string, and clear this section. Return true on success, or false // if there were still undefined labels. - bool GetContents(string *contents); + bool GetContents(string* contents); private: // Used internally. A reference to a label's value. struct Reference { Reference(size_t set_offset, Endianness set_endianness, size_t set_size, - const Label &set_label) + const Label& set_label) : offset(set_offset), endianness(set_endianness), size(set_size), label(set_label) { } diff --git a/src/common/test_assembler_unittest.cc b/src/common/test_assembler_unittest.cc index 94b5a5ce..f16594f1 100644 --- a/src/common/test_assembler_unittest.cc +++ b/src/common/test_assembler_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -755,7 +754,7 @@ const uint8_t SectionFixture::data[] = { { \ static const uint8_t expected_bytes[] = b; \ ASSERT_EQ(sizeof(expected_bytes), s.size()); \ - ASSERT_TRUE(memcmp(s.data(), (const char *) expected_bytes, \ + ASSERT_TRUE(memcmp(s.data(), (const char*) expected_bytes, \ sizeof(expected_bytes)) == 0); \ } \ while(0) @@ -766,7 +765,7 @@ TEST_F(Append, Bytes) { section.Append(data, sizeof(data)); ASSERT_TRUE(section.GetContents(&contents)); ASSERT_EQ(sizeof(data), contents.size()); - EXPECT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data))); + EXPECT_TRUE(0 == memcmp(contents.data(), (const char*) data, sizeof(data))); } TEST_F(Append, BytesTwice) { @@ -774,9 +773,9 @@ TEST_F(Append, BytesTwice) { section.Append(data, sizeof(data)); ASSERT_TRUE(section.GetContents(&contents)); ASSERT_EQ(2 * sizeof(data), contents.size()); - ASSERT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data))); + ASSERT_TRUE(0 == memcmp(contents.data(), (const char*) data, sizeof(data))); ASSERT_TRUE(0 == memcmp(contents.data() + sizeof(data), - (const char *) data, sizeof(data))); + (const char*) data, sizeof(data))); } TEST_F(Append, String) { diff --git a/src/common/tests/auto_tempdir.h b/src/common/tests/auto_tempdir.h index 1df88db8..963c2dcf 100644 --- a/src/common/tests/auto_tempdir.h +++ b/src/common/tests/auto_tempdir.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/tests/file_utils.cc b/src/common/tests/file_utils.cc index 1c041777..814b2094 100644 --- a/src/common/tests/file_utils.cc +++ b/src/common/tests/file_utils.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -96,6 +95,10 @@ bool CopyFile(const char* from_path, const char* to_path) { return result; } +bool CopyFile(const std::string& from_path, const std::string& to_path) { + return CopyFile(from_path.c_str(), to_path.c_str()); +} + bool ReadFile(const char* path, void* buffer, ssize_t* buffer_size) { int fd = HANDLE_EINTR(open(path, O_RDONLY)); if (fd == -1) { diff --git a/src/common/tests/file_utils.h b/src/common/tests/file_utils.h index c98a9bfa..b96029d0 100644 --- a/src/common/tests/file_utils.h +++ b/src/common/tests/file_utils.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -33,9 +32,12 @@ #ifndef COMMON_TESTS_FILE_UTILS_H_ #define COMMON_TESTS_FILE_UTILS_H_ +#include <string> + namespace google_breakpad { // Copies a file from |from_path| to |to_path|. Returns true on success. +bool CopyFile(const std::string& from_path, const std::string& to_path); bool CopyFile(const char* from_path, const char* to_path); // Reads the content of a file at |path| into |buffer|. |buffer_size| specifies diff --git a/src/common/unordered.h b/src/common/unordered.h index c9cbd585..7606f170 100644 --- a/src/common/unordered.h +++ b/src/common/unordered.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -46,17 +45,11 @@ struct unordered_map : public __gnu_cxx::hash_map<T, U, H> {}; template <class T, class H = __gnu_cxx::hash<T> > struct unordered_set : public __gnu_cxx::hash_set<T, H> {}; -#elif defined(_LIBCPP_VERSION) // c++11 +#else #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_ diff --git a/src/common/using_std_string.h b/src/common/using_std_string.h index 13c1da59..0f11db7b 100644 --- a/src/common/using_std_string.h +++ b/src/common/using_std_string.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -55,6 +54,7 @@ #ifdef HAS_GLOBAL_STRING typedef ::string google_breakpad_string; #else +#include <string> using std::string; typedef std::string google_breakpad_string; #endif diff --git a/src/common/windows/common_windows.gyp b/src/common/windows/common_windows.gyp deleted file mode 100644 index 5f7594b1..00000000 --- a/src/common/windows/common_windows.gyp +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2013 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': [ - '../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'dia_sdk', - 'type': 'none', - 'all_dependent_settings': { - 'include_dirs': [ - '<(DEPTH)', - '$(VSInstallDir)/DIA SDK/include', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalDependencies': [ - 'diaguids.lib', - 'imagehlp.lib', - ], - }, - }, - 'configurations': { - 'x86_Base': { - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalLibraryDirectories': - ['$(VSInstallDir)/DIA SDK/lib'], - }, - }, - }, - 'x64_Base': { - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalLibraryDirectories': - ['$(VSInstallDir)/DIA SDK/lib/amd64'], - }, - }, - }, - }, - }, - }, - { - 'target_name': 'common_windows_lib', - 'type': 'static_library', - 'sources': [ - 'dia_util.cc', - 'dia_util.h', - 'guid_string.cc', - 'guid_string.h', - 'http_upload.cc', - 'http_upload.h', - 'module_info.h', - 'omap.cc', - 'omap.h', - 'omap_internal.h', - 'pdb_source_line_writer.cc', - 'pdb_source_line_writer.h', - 'pe_source_line_writer.cc', - 'pe_source_line_writer.h', - 'pe_util.h', - 'pe_util.cc', - 'string_utils.cc', - 'string_utils-inl.h', - 'symbol_collector_client.cc', - 'symbol_collector_client.h', - ], - 'dependencies': [ - 'dia_sdk', - ], - }, - { - 'target_name': 'common_windows_unittests', - 'type': 'executable', - 'sources': [ - 'omap_unittest.cc', - ], - 'dependencies': [ - '<(DEPTH)/client/windows/unittests/testing.gyp:gmock', - '<(DEPTH)/client/windows/unittests/testing.gyp:gtest', - 'common_windows_lib', - ], - }, - ], -} diff --git a/src/common/windows/dia_util.cc b/src/common/windows/dia_util.cc index ed8cb5b6..dcfe0ef9 100644 --- a/src/common/windows/dia_util.cc +++ b/src/common/windows/dia_util.cc @@ -1,92 +1,92 @@ -// Copyright 2013 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 "common/windows/dia_util.h"
-
-#include <atlbase.h>
-
-namespace google_breakpad {
-
-bool FindDebugStream(const wchar_t* name,
- IDiaSession* session,
- IDiaEnumDebugStreamData** debug_stream) {
- CComPtr<IDiaEnumDebugStreams> enum_debug_streams;
- if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) {
- fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n");
- return false;
- }
-
- CComPtr<IDiaEnumDebugStreamData> temp_debug_stream;
- ULONG fetched = 0;
- while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) &&
- fetched == 1) {
- CComBSTR stream_name;
- if (FAILED(temp_debug_stream->get_name(&stream_name))) {
- fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n");
- return false;
- }
-
- // Found the stream?
- if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) {
- *debug_stream = temp_debug_stream.Detach();
- return true;
- }
-
- temp_debug_stream.Release();
- }
-
- // No table was found.
- return false;
-}
-
-bool FindTable(REFIID iid, IDiaSession* session, void** table) {
- // Get the table enumerator.
- CComPtr<IDiaEnumTables> enum_tables;
- if (FAILED(session->getEnumTables(&enum_tables))) {
- fprintf(stderr, "IDiaSession::getEnumTables failed\n");
- return false;
- }
-
- // Iterate through the tables.
- CComPtr<IDiaTable> temp_table;
- ULONG fetched = 0;
- while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) &&
- fetched == 1) {
- void* temp = NULL;
- if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) {
- *table = temp;
- return true;
- }
- temp_table.Release();
- }
-
- // The table was not found.
- return false;
-}
-
+// Copyright 2013 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/windows/dia_util.h" + +#include <atlbase.h> + +namespace google_breakpad { + +bool FindDebugStream(const wchar_t* name, + IDiaSession* session, + IDiaEnumDebugStreamData** debug_stream) { + CComPtr<IDiaEnumDebugStreams> enum_debug_streams; + if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) { + fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n"); + return false; + } + + CComPtr<IDiaEnumDebugStreamData> temp_debug_stream; + ULONG fetched = 0; + while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) && + fetched == 1) { + CComBSTR stream_name; + if (FAILED(temp_debug_stream->get_name(&stream_name))) { + fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n"); + return false; + } + + // Found the stream? + if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) { + *debug_stream = temp_debug_stream.Detach(); + return true; + } + + temp_debug_stream.Release(); + } + + // No table was found. + return false; +} + +bool FindTable(REFIID iid, IDiaSession* session, void** table) { + // Get the table enumerator. + CComPtr<IDiaEnumTables> enum_tables; + if (FAILED(session->getEnumTables(&enum_tables))) { + fprintf(stderr, "IDiaSession::getEnumTables failed\n"); + return false; + } + + // Iterate through the tables. + CComPtr<IDiaTable> temp_table; + ULONG fetched = 0; + while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) && + fetched == 1) { + void* temp = NULL; + if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) { + *table = temp; + return true; + } + temp_table.Release(); + } + + // The table was not found. + return false; +} + } // namespace google_breakpad
\ No newline at end of file diff --git a/src/common/windows/dia_util.h b/src/common/windows/dia_util.h index b9e0df2d..16ed8380 100644 --- a/src/common/windows/dia_util.h +++ b/src/common/windows/dia_util.h @@ -1,4 +1,4 @@ -// Copyright 2013 Google Inc. All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/windows/guid_string.cc b/src/common/windows/guid_string.cc index b7f877e6..be9eb8a3 100644 --- a/src/common/windows/guid_string.cc +++ b/src/common/windows/guid_string.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/windows/guid_string.h b/src/common/windows/guid_string.h index 48a5c1d3..ee3d1006 100644 --- a/src/common/windows/guid_string.h +++ b/src/common/windows/guid_string.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/windows/http_upload.cc b/src/common/windows/http_upload.cc index b0cc9078..088a5e54 100644 --- a/src/common/windows/http_upload.cc +++ b/src/common/windows/http_upload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -65,7 +64,7 @@ namespace { HINTERNET handle_; }; - wstring UTF8ToWide(const string &utf8) { + wstring UTF8ToWide(const string& utf8) { if (utf8.length() == 0) { return wstring(); } @@ -85,7 +84,7 @@ namespace { return result; } - string WideToMBCP(const wstring &wide, unsigned int cp) { + string WideToMBCP(const wstring& wide, unsigned int cp) { if (wide.length() == 0) { return string(); } @@ -107,7 +106,7 @@ namespace { return result; } - bool GetFileContents(const wstring &filename, vector<char> *contents) { + bool GetFileContents(const wstring& filename, vector<char>* contents) { bool rv = false; // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a // wchar_t* filename, so use _wfopen directly in that case. For VC8 and @@ -141,10 +140,10 @@ namespace { return rv; } - bool CheckParameters(const map<wstring, wstring> ¶meters) { + bool CheckParameters(const map<wstring, wstring>& parameters) { for (map<wstring, wstring>::const_iterator pos = parameters.begin(); pos != parameters.end(); ++pos) { - const wstring &str = pos->first; + const wstring& str = pos->first; if (str.size() == 0) { return false; // disallow empty parameter names } @@ -159,7 +158,7 @@ namespace { } // Converts a UTF16 string to UTF8. - string WideToUTF8(const wstring &wide) { + string WideToUTF8(const wstring& wide) { return WideToMBCP(wide, CP_UTF8); } @@ -262,7 +261,7 @@ namespace { NULL, // password INTERNET_SERVICE_HTTP, 0, // flags - NULL)); // context + 0)); // context if (!connection.get()) { return false; } @@ -276,7 +275,7 @@ namespace { NULL, // referer NULL, // agent type http_open_flags, - NULL)); // context + 0)); // context if (!request.get()) { return false; } @@ -305,7 +304,7 @@ namespace { } if (!HttpSendRequest(request.get(), NULL, 0, - const_cast<char *>(request_body.data()), + const_cast<char*>(request_body.data()), static_cast<DWORD>(request_body.size()))) { return false; } @@ -351,16 +350,16 @@ namespace { return wstring(temp); } - wstring GenerateMultipartPostRequestHeader(const wstring &boundary) { + wstring GenerateMultipartPostRequestHeader(const wstring& boundary) { wstring header = L"Content-Type: multipart/form-data; boundary="; header += boundary; return header; } - bool AppendFileToRequestBody( - const wstring& file_part_name, - const wstring& filename, - string* request_body) { + bool AppendFileToRequestBody(const wstring& file_part_name, + const wstring& filename, + string* request_body, + bool set_content_type = true) { string file_part_name_utf8 = WideToUTF8(file_part_name); if (file_part_name_utf8.empty()) { return false; @@ -371,11 +370,17 @@ namespace { return false; } - request_body->append("Content-Disposition: form-data; " - "name=\"" + file_part_name_utf8 + "\"; " - "filename=\"" + filename_utf8 + "\"\r\n"); - request_body->append("Content-Type: application/octet-stream\r\n"); - request_body->append("\r\n"); + if (set_content_type) { + request_body->append( + "Content-Disposition: form-data; " + "name=\"" + + file_part_name_utf8 + + "\"; " + "filename=\"" + + filename_utf8 + "\"\r\n"); + request_body->append("Content-Type: application/octet-stream\r\n"); + request_body->append("\r\n"); + } vector<char> contents; if (!GetFileContents(filename, &contents)) { @@ -385,14 +390,13 @@ namespace { if (!contents.empty()) { request_body->append(&(contents[0]), contents.size()); } - request_body->append("\r\n"); return true; } - bool GenerateRequestBody(const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - const wstring &boundary, + bool GenerateRequestBody(const map<wstring, wstring>& parameters, + const map<wstring, wstring>& files, + const wstring& boundary, string *request_body) { string boundary_str = WideToUTF8(boundary); if (boundary_str.empty()) { @@ -432,7 +436,11 @@ namespace google_breakpad { wstring* response_body, int* response_code) { string request_body; - if (!AppendFileToRequestBody(L"symbol_file", path, &request_body)) { + // Turn off content-type in the body. If content-type is set then binary + // files uploaded to GCS end up with the it prepended to the file + // contents. + if (!AppendFileToRequestBody(L"symbol_file", path, &request_body, + /*set_content_type=*/false)) { return false; } diff --git a/src/common/windows/http_upload.h b/src/common/windows/http_upload.h index 57e526e3..e117840e 100644 --- a/src/common/windows/http_upload.h +++ b/src/common/windows/http_upload.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -114,8 +113,8 @@ class HTTPUpload { // No instances of this class should be created. // Disallow all constructors, destructors, and operator=. HTTPUpload(); - explicit HTTPUpload(const HTTPUpload &); - void operator=(const HTTPUpload &); + explicit HTTPUpload(const HTTPUpload&); + void operator=(const HTTPUpload&); ~HTTPUpload(); }; diff --git a/src/common/windows/module_info.h b/src/common/windows/module_info.h index 3dccc808..ade32c11 100644 --- a/src/common/windows/module_info.h +++ b/src/common/windows/module_info.h @@ -1,75 +1,74 @@ -// Copyright (c) 2019, 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_WINDOWS_MODULE_INFO_H_
-#define COMMON_WINDOWS_MODULE_INFO_H_
-
-#include <string>
-
-namespace google_breakpad {
-
-using std::wstring;
-// A structure that carries information that identifies a module.
-struct PDBModuleInfo {
-public:
- // The basename of the pe/pdb file from which information was loaded.
- wstring debug_file;
-
- // The module's identifier. For recent pe/pdb files, the identifier consists
- // of the pe/pdb's guid, in uppercase hexadecimal form without any dashes
- // or separators, followed immediately by the pe/pdb's age, also in
- // uppercase hexadecimal form. For older pe/pdb files which have no guid,
- // the identifier is the pe/pdb's 32-bit signature value, in zero-padded
- // hexadecimal form, followed immediately by the pe/pdb's age, in lowercase
- // hexadecimal form.
- wstring debug_identifier;
-
- // A string identifying the cpu that the pe/pdb is associated with.
- // Currently, this may be "x86" or "unknown".
- wstring cpu;
-};
-
-// A structure that carries information that identifies a PE file,
-// either an EXE or a DLL.
-struct PEModuleInfo {
- // The basename of the PE file.
- wstring code_file;
-
- // The PE file's code identifier, which consists of its timestamp
- // and file size concatenated together into a single hex string.
- // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and
- // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp
- // documentation.) This is not well documented, if it's documented
- // at all, but it's what symstore does and what DbgHelp supports.
- wstring code_identifier;
-};
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_MODULE_INFO_H_
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_WINDOWS_MODULE_INFO_H_ +#define COMMON_WINDOWS_MODULE_INFO_H_ + +#include <string> + +namespace google_breakpad { + +using std::wstring; +// A structure that carries information that identifies a module. +struct PDBModuleInfo { +public: + // The basename of the pe/pdb file from which information was loaded. + wstring debug_file; + + // The module's identifier. For recent pe/pdb files, the identifier consists + // of the pe/pdb's guid, in uppercase hexadecimal form without any dashes + // or separators, followed immediately by the pe/pdb's age, also in + // uppercase hexadecimal form. For older pe/pdb files which have no guid, + // the identifier is the pe/pdb's 32-bit signature value, in zero-padded + // hexadecimal form, followed immediately by the pe/pdb's age, in lowercase + // hexadecimal form. + wstring debug_identifier; + + // A string identifying the cpu that the pe/pdb is associated with. + // Currently, this may be "x86" or "unknown". + wstring cpu; +}; + +// A structure that carries information that identifies a PE file, +// either an EXE or a DLL. +struct PEModuleInfo { + // The basename of the PE file. + wstring code_file; + + // The PE file's code identifier, which consists of its timestamp + // and file size concatenated together into a single hex string. + // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and + // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp + // documentation.) This is not well documented, if it's documented + // at all, but it's what symstore does and what DbgHelp supports. + wstring code_identifier; +}; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_MODULE_INFO_H_ diff --git a/src/common/windows/omap.cc b/src/common/windows/omap.cc index ba3ce86b..ad916997 100644 --- a/src/common/windows/omap.cc +++ b/src/common/windows/omap.cc @@ -1,4 +1,4 @@ -// Copyright 2013 Google Inc. All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -449,11 +449,11 @@ void BuildEndpointIndexMap(ImageMap* image_map) { } } -void BuildSubsequentRVAMap(const OmapData &omap_data, - std::map<DWORD, DWORD> *subsequent) { +void BuildSubsequentRVAMap(const OmapData& omap_data, + std::map<DWORD, DWORD>* subsequent) { assert(subsequent->empty()); - const OmapFromTable &orig2tran = - reinterpret_cast<const OmapFromTable &>(omap_data.omap_from); + const OmapFromTable& orig2tran = + reinterpret_cast<const OmapFromTable&>(omap_data.omap_from); if (orig2tran.empty()) return; diff --git a/src/common/windows/omap.h b/src/common/windows/omap.h index bc293afb..51601fa9 100644 --- a/src/common/windows/omap.h +++ b/src/common/windows/omap.h @@ -1,4 +1,4 @@ -// Copyright 2013 Google Inc. All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/windows/omap_internal.h b/src/common/windows/omap_internal.h index 2a4713d9..cd20d9fb 100644 --- a/src/common/windows/omap_internal.h +++ b/src/common/windows/omap_internal.h @@ -1,4 +1,4 @@ -// Copyright 2013 Google Inc. All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/common/windows/omap_unittest.cc b/src/common/windows/omap_unittest.cc index 7fe66bd4..841e5391 100644 --- a/src/common/windows/omap_unittest.cc +++ b/src/common/windows/omap_unittest.cc @@ -1,329 +1,329 @@ -// Copyright 2013 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.
-
-// Unittests for OMAP related functions.
-
-#include "common/windows/omap.h"
-
-#include "breakpad_googletest_includes.h"
-
-namespace google_breakpad {
-
-// Equality operators for ContainerEq. These must be outside of the anonymous
-// namespace in order for them to be found.
-bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
- return mr1.rva_original == mr2.rva_original &&
- mr1.rva_transformed == mr2.rva_transformed &&
- mr1.length == mr2.length &&
- mr1.injected == mr2.injected &&
- mr1.removed == mr2.removed;
-}
-bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
- return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
-}
-
-// Pretty printers for more meaningful error messages. Also need to be outside
-// the anonymous namespace.
-std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
- os << "MappedRange(rva_original=" << mr.rva_original
- << ", rva_transformed=" << mr.rva_transformed
- << ", length=" << mr.length
- << ", injected=" << mr.injected
- << ", removed=" << mr.removed << ")";
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
- os << "EndpointIndex(endpoint=" << ei.endpoint
- << ", index=" << ei.index << ")";
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
- os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
- return os;
-}
-
-namespace {
-
-OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
- OMAP o = { rva, rvaTo };
- return o;
-}
-
-MappedRange CreateMappedRange(DWORD rva_original,
- DWORD rva_transformed,
- DWORD length,
- DWORD injected,
- DWORD removed) {
- MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
- return mr;
-}
-
-EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
- EndpointIndex ei = { endpoint, index };
- return ei;
-}
-
-// (C is removed)
-// Original : A B C D E F G H
-// Transformed: A B D F E * H1 G1 G2 H2
-// (* is injected, G is copied, H is split)
-// A is implied.
-
-// Layout of the original image.
-const AddressRange B(100, 15);
-const AddressRange C(B.end(), 10);
-const AddressRange D(C.end(), 25);
-const AddressRange E(D.end(), 10);
-const AddressRange F(E.end(), 40);
-const AddressRange G(F.end(), 3);
-const AddressRange H(G.end(), 7);
-
-// Layout of the transformed image.
-const AddressRange Bt(100, 15);
-const AddressRange Dt(Bt.end(), 20); // D is shortened.
-const AddressRange Ft(Dt.end(), F.length);
-const AddressRange Et(Ft.end(), E.length);
-const AddressRange injected(Et.end(), 5);
-const AddressRange H1t(injected.end(), 4); // H is split.
-const AddressRange G1t(H1t.end(), G.length); // G is copied.
-const AddressRange G2t(G1t.end(), G.length); // G is copied.
-const AddressRange H2t(G2t.end(), 3); // H is split.
-
-class BuildImageMapTest : public testing::Test {
- public:
- static const DWORD kInvalidAddress = 0xFFFFFFFF;
-
- void InitOmapData() {
- omap_data.length_original = H.end();
-
- // Build the OMAPTO vector (from transformed to original).
- omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
- omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
- omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
- omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
- omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
- omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
- omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
- omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
- omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
- omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
-
- // Build the OMAPFROM vector (from original to transformed).
- omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
- omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
- omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
- omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
- omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
- omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
- }
-
- OmapData omap_data;
-};
-
-} // namespace
-
-TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
- ASSERT_EQ(0u, omap_data.omap_from.size());
- ASSERT_EQ(0u, omap_data.omap_to.size());
- ASSERT_EQ(0u, omap_data.length_original);
-
- ImageMap image_map;
- BuildImageMap(omap_data, &image_map);
- EXPECT_EQ(0u, image_map.mapping.size());
- EXPECT_EQ(0u, image_map.endpoint_index_map.size());
-}
-
-TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
- InitOmapData();
- ASSERT_LE(0u, omap_data.omap_from.size());
- ASSERT_LE(0u, omap_data.omap_to.size());
- ASSERT_LE(0u, omap_data.length_original);
-
- ImageMap image_map;
- BuildImageMap(omap_data, &image_map);
- EXPECT_LE(9u, image_map.mapping.size());
- EXPECT_LE(9u, image_map.endpoint_index_map.size());
-
- Mapping mapping;
- mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
- // C is removed, and it originally comes immediately after B.
- mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
- // D is shortened by a length of 5.
- mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
- // The injected content comes immediately after E in the transformed image.
- mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
- 0));
- mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
- // G is copied so creates two entries.
- mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
- mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
- // H is split, so create two entries.
- mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
- mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
- 0, 0));
- EXPECT_THAT(mapping,
- testing::ContainerEq(image_map.mapping));
-
- EndpointIndexMap endpoint_index_map;
- endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
- endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
- endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
- endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
- endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
- // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
- endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
- // H is split so we expect 2 endpoints to show up attributed to it.
- endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
- endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
- endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
- EXPECT_THAT(endpoint_index_map,
- testing::ContainerEq(image_map.endpoint_index_map));
-}
-
-namespace {
-
-class MapAddressRangeTest : public BuildImageMapTest {
- public:
- typedef BuildImageMapTest Super;
- virtual void SetUp() {
- Super::SetUp();
- InitOmapData();
- BuildImageMap(omap_data, &image_map);
- }
-
- ImageMap image_map;
-
- private:
- using BuildImageMapTest::InitOmapData;
- using BuildImageMapTest::omap_data;
-};
-
-} // namespace
-
-TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
- ImageMap im;
- AddressRangeVector mapped_ranges;
- AddressRange ar(0, 1024);
- MapAddressRange(im, ar, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_EQ(ar, mapped_ranges[0]);
-}
-
-TEST_F(MapAddressRangeTest, MapOutOfImage) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
- EXPECT_EQ(0u, mapped_ranges.size());
-}
-
-TEST_F(MapAddressRangeTest, MapIdentity) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, B, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
-}
-
-TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
- AddressRangeVector mapped_ranges;
-
- AddressRange DEF(D.rva, F.end() - D.rva);
- MapAddressRange(image_map, DEF, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
-}
-
-TEST_F(MapAddressRangeTest, MapEmptySingle) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
-}
-
-TEST_F(MapAddressRangeTest, MapEmptyCopied) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
- EXPECT_EQ(2u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
- AddressRange(G2t.rva, 0)));
-}
-
-TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, G, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(
- AddressRange(G1t.rva, G2t.end() - G1t.rva)));
-}
-
-TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, H, &mapped_ranges);
- EXPECT_EQ(2u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
-}
-
-TEST_F(MapAddressRangeTest, MapInjected) {
- AddressRangeVector mapped_ranges;
-
- AddressRange EFGH(E.rva, H.end() - E.rva);
- MapAddressRange(image_map, EFGH, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
-}
-
-TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, C, &mapped_ranges);
- EXPECT_EQ(0u, mapped_ranges.size());
-}
-
-TEST_F(MapAddressRangeTest, MapRemovedPartly) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, D, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
-}
-
-TEST_F(MapAddressRangeTest, MapFull) {
- AddressRangeVector mapped_ranges;
-
- AddressRange AH(0, H.end());
- MapAddressRange(image_map, AH, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange AHt(0, H2t.end());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
-}
-
-} // namespace google_breakpad
+// Copyright 2013 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Unittests for OMAP related functions. + +#include "common/windows/omap.h" + +#include "breakpad_googletest_includes.h" + +namespace google_breakpad { + +// Equality operators for ContainerEq. These must be outside of the anonymous +// namespace in order for them to be found. +bool operator==(const MappedRange& mr1, const MappedRange& mr2) { + return mr1.rva_original == mr2.rva_original && + mr1.rva_transformed == mr2.rva_transformed && + mr1.length == mr2.length && + mr1.injected == mr2.injected && + mr1.removed == mr2.removed; +} +bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) { + return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index; +} + +// Pretty printers for more meaningful error messages. Also need to be outside +// the anonymous namespace. +std::ostream& operator<<(std::ostream& os, const MappedRange& mr) { + os << "MappedRange(rva_original=" << mr.rva_original + << ", rva_transformed=" << mr.rva_transformed + << ", length=" << mr.length + << ", injected=" << mr.injected + << ", removed=" << mr.removed << ")"; + return os; +} +std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) { + os << "EndpointIndex(endpoint=" << ei.endpoint + << ", index=" << ei.index << ")"; + return os; +} +std::ostream& operator<<(std::ostream& os, const AddressRange& ar) { + os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")"; + return os; +} + +namespace { + +OMAP CreateOmap(DWORD rva, DWORD rvaTo) { + OMAP o = { rva, rvaTo }; + return o; +} + +MappedRange CreateMappedRange(DWORD rva_original, + DWORD rva_transformed, + DWORD length, + DWORD injected, + DWORD removed) { + MappedRange mr = { rva_original, rva_transformed, length, injected, removed }; + return mr; +} + +EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) { + EndpointIndex ei = { endpoint, index }; + return ei; +} + +// (C is removed) +// Original : A B C D E F G H +// Transformed: A B D F E * H1 G1 G2 H2 +// (* is injected, G is copied, H is split) +// A is implied. + +// Layout of the original image. +const AddressRange B(100, 15); +const AddressRange C(B.end(), 10); +const AddressRange D(C.end(), 25); +const AddressRange E(D.end(), 10); +const AddressRange F(E.end(), 40); +const AddressRange G(F.end(), 3); +const AddressRange H(G.end(), 7); + +// Layout of the transformed image. +const AddressRange Bt(100, 15); +const AddressRange Dt(Bt.end(), 20); // D is shortened. +const AddressRange Ft(Dt.end(), F.length); +const AddressRange Et(Ft.end(), E.length); +const AddressRange injected(Et.end(), 5); +const AddressRange H1t(injected.end(), 4); // H is split. +const AddressRange G1t(H1t.end(), G.length); // G is copied. +const AddressRange G2t(G1t.end(), G.length); // G is copied. +const AddressRange H2t(G2t.end(), 3); // H is split. + +class BuildImageMapTest : public testing::Test { + public: + static const DWORD kInvalidAddress = 0xFFFFFFFF; + + void InitOmapData() { + omap_data.length_original = H.end(); + + // Build the OMAPTO vector (from transformed to original). + omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva)); + omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva)); + omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva)); + omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva)); + omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress)); + omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva)); + omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva)); + omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva)); + omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length)); + omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress)); + + // Build the OMAPFROM vector (from original to transformed). + omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva)); + omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress)); + omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva)); + omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva)); + omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva)); + omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress)); + } + + OmapData omap_data; +}; + +} // namespace + +TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) { + ASSERT_EQ(0u, omap_data.omap_from.size()); + ASSERT_EQ(0u, omap_data.omap_to.size()); + ASSERT_EQ(0u, omap_data.length_original); + + ImageMap image_map; + BuildImageMap(omap_data, &image_map); + EXPECT_EQ(0u, image_map.mapping.size()); + EXPECT_EQ(0u, image_map.endpoint_index_map.size()); +} + +TEST_F(BuildImageMapTest, ImageMapIsCorrect) { + InitOmapData(); + ASSERT_LE(0u, omap_data.omap_from.size()); + ASSERT_LE(0u, omap_data.omap_to.size()); + ASSERT_LE(0u, omap_data.length_original); + + ImageMap image_map; + BuildImageMap(omap_data, &image_map); + EXPECT_LE(9u, image_map.mapping.size()); + EXPECT_LE(9u, image_map.endpoint_index_map.size()); + + Mapping mapping; + mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0)); + // C is removed, and it originally comes immediately after B. + mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length)); + // D is shortened by a length of 5. + mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5)); + // The injected content comes immediately after E in the transformed image. + mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length, + 0)); + mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0)); + // G is copied so creates two entries. + mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0)); + mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0)); + // H is split, so create two entries. + mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0)); + mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length, + 0, 0)); + EXPECT_THAT(mapping, + testing::ContainerEq(image_map.mapping)); + + EndpointIndexMap endpoint_index_map; + endpoint_index_map.push_back(CreateEndpointIndex(0, 0)); + endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1)); + endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2)); + endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3)); + endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4)); + // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7. + endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5)); + // H is split so we expect 2 endpoints to show up attributed to it. + endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7)); + endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8)); + endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9)); + EXPECT_THAT(endpoint_index_map, + testing::ContainerEq(image_map.endpoint_index_map)); +} + +namespace { + +class MapAddressRangeTest : public BuildImageMapTest { + public: + typedef BuildImageMapTest Super; + virtual void SetUp() { + Super::SetUp(); + InitOmapData(); + BuildImageMap(omap_data, &image_map); + } + + ImageMap image_map; + + private: + using BuildImageMapTest::InitOmapData; + using BuildImageMapTest::omap_data; +}; + +} // namespace + +TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) { + ImageMap im; + AddressRangeVector mapped_ranges; + AddressRange ar(0, 1024); + MapAddressRange(im, ar, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_EQ(ar, mapped_ranges[0]); +} + +TEST_F(MapAddressRangeTest, MapOutOfImage) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges); + EXPECT_EQ(0u, mapped_ranges.size()); +} + +TEST_F(MapAddressRangeTest, MapIdentity) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, B, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(B)); +} + +TEST_F(MapAddressRangeTest, MapReorderedContiguous) { + AddressRangeVector mapped_ranges; + + AddressRange DEF(D.rva, F.end() - D.rva); + MapAddressRange(image_map, DEF, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange DFEt(Dt.rva, Et.end() - Dt.rva); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt)); +} + +TEST_F(MapAddressRangeTest, MapEmptySingle) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0))); +} + +TEST_F(MapAddressRangeTest, MapEmptyCopied) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges); + EXPECT_EQ(2u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0), + AddressRange(G2t.rva, 0))); +} + +TEST_F(MapAddressRangeTest, MapCopiedContiguous) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, G, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre( + AddressRange(G1t.rva, G2t.end() - G1t.rva))); +} + +TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, H, &mapped_ranges); + EXPECT_EQ(2u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t)); +} + +TEST_F(MapAddressRangeTest, MapInjected) { + AddressRangeVector mapped_ranges; + + AddressRange EFGH(E.rva, H.end() - E.rva); + MapAddressRange(image_map, EFGH, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt)); +} + +TEST_F(MapAddressRangeTest, MapRemovedEntirely) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, C, &mapped_ranges); + EXPECT_EQ(0u, mapped_ranges.size()); +} + +TEST_F(MapAddressRangeTest, MapRemovedPartly) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, D, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt)); +} + +TEST_F(MapAddressRangeTest, MapFull) { + AddressRangeVector mapped_ranges; + + AddressRange AH(0, H.end()); + MapAddressRange(image_map, AH, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange AHt(0, H2t.end()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt)); +} + +} // namespace google_breakpad diff --git a/src/common/windows/pdb_source_line_writer.cc b/src/common/windows/pdb_source_line_writer.cc index 4030a2e9..800c316f 100644 --- a/src/common/windows/pdb_source_line_writer.cc +++ b/src/common/windows/pdb_source_line_writer.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,6 +39,7 @@ #include <algorithm> #include <limits> #include <map> +#include <memory> #include <set> #include <utility> @@ -58,6 +58,8 @@ namespace google_breakpad { namespace { +using std::set; +using std::unique_ptr; using std::vector; // The symbol (among possibly many) selected to represent an rva. @@ -120,7 +122,7 @@ bool SymbolsMatch(IDiaSymbol* a, IDiaSymbol* b) { return a_section == b_section && a_offset == b_offset; } -bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) { +bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource>& data_source) { if (SUCCEEDED(data_source.CoCreateInstance(CLSID_DiaSource))) { return true; } @@ -134,7 +136,7 @@ bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) { // We can try loading the DLL corresponding to the #included DIA SDK, but // the DIA headers don't provide a version. Lets try to figure out which DIA // version we're compiling against by comparing CLSIDs. - const wchar_t *msdia_dll = nullptr; + const wchar_t* msdia_dll = nullptr; if (CLSID_DiaSource == _uuidof(DiaSource100)) { msdia_dll = L"msdia100.dll"; } else if (CLSID_DiaSource == _uuidof(DiaSource110)) { @@ -147,23 +149,261 @@ bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) { if (msdia_dll && SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, - reinterpret_cast<void **>(&data_source)))) { + reinterpret_cast<void**>(&data_source)))) { return true; } return false; } +const DWORD kUndecorateOptions = UNDNAME_NO_MS_KEYWORDS | + UNDNAME_NO_FUNCTION_RETURNS | + UNDNAME_NO_ALLOCATION_MODEL | + UNDNAME_NO_ALLOCATION_LANGUAGE | + UNDNAME_NO_THISTYPE | + UNDNAME_NO_ACCESS_SPECIFIERS | + UNDNAME_NO_THROW_SIGNATURES | + UNDNAME_NO_MEMBER_TYPE | + UNDNAME_NO_RETURN_UDT_MODEL | + UNDNAME_NO_ECSU; + +#define arraysize(f) (sizeof(f) / sizeof(*f)) + +void StripLlvmSuffixAndUndecorate(BSTR* name) { + // LLVM sometimes puts a suffix on symbols to give them a globally unique + // name. The suffix is either some string preceded by a period (like in the + // Itanium ABI; also on Windows this is safe since periods are otherwise + // never part of mangled names), or a dollar sign followed by a 32-char hex + // string (this should go away in future LLVM versions). Strip such suffixes + // and try demangling again. + // + // + // Example symbol names with such suffixes: + // + // ?foo@@YAXXZ$5520c83448162c04f2b239db4b5a2c61 + // ?foo@@YAXXZ.llvm.13040715209719948753 + + if (**name != L'?') + return; // The name is already demangled. + + for (size_t i = 0, len = wcslen(*name); i < len; i++) { + wchar_t c = (*name)[i]; + + if (c == L'.' || (c == L'$' && len - i == 32 + 1)) { + (*name)[i] = L'\0'; + wchar_t undecorated[1024]; + DWORD res = UnDecorateSymbolNameW(*name, undecorated, + arraysize(undecorated), + kUndecorateOptions); + if (res == 0 || undecorated[0] == L'?') { + // Demangling failed; restore the symbol name and return. + (*name)[i] = c; + return; + } + + SysFreeString(*name); + *name = SysAllocString(undecorated); + return; + } + } +} + +// Prints the error message related to the error code as seen in +// Microsoft's MSVS documentation for loadDataFromPdb and loadDataForExe. +void PrintOpenError(HRESULT hr, const char* fn_name, const wchar_t* file) { + switch (hr) { + case E_PDB_NOT_FOUND: + fprintf(stderr, "%s: Failed to open %ws, or the file has an " + "invalid format.\n", fn_name, file); + break; + case E_PDB_FORMAT: + fprintf(stderr, "%s: Attempted to access %ws with an obsolete " + "format.\n", fn_name, file); + break; + case E_PDB_INVALID_SIG: + fprintf(stderr, "%s: Signature does not match for %ws.\n", fn_name, + file); + break; + case E_PDB_INVALID_AGE: + fprintf(stderr, "%s: Age does not match for %ws.\n", fn_name, file); + break; + case E_INVALIDARG: + fprintf(stderr, "%s: Invalid parameter for %ws.\n", fn_name, file); + break; + case E_UNEXPECTED: + fprintf(stderr, "%s: Data source has already been prepared for %ws.\n", + fn_name, file); + break; + default: + fprintf(stderr, "%s: Unexpected error 0x%lx, file: %ws.\n", + fn_name, hr, file); + break; + } +} + } // namespace -PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) { +PDBSourceLineWriter::Inline::Inline(int inline_nest_level) + : inline_nest_level_(inline_nest_level) {} + +void PDBSourceLineWriter::Inline::SetOriginId(int origin_id) { + origin_id_ = origin_id; +} + +void PDBSourceLineWriter::Inline::ExtendRanges(const Line& line) { + if (ranges_.empty()) { + ranges_[line.rva] = line.length; + return; + } + auto iter = ranges_.lower_bound(line.rva); + // There is no overlap if this function is called with inlinee lines from + // the same callsite. + if (iter == ranges_.begin()) { + return; + } + if (line.rva + line.length == iter->first) { + // If they are connected, merge their ranges into one. + DWORD length = line.length + iter->second; + ranges_.erase(iter); + ranges_[line.rva] = length; + } else { + --iter; + if (iter->first + iter->second == line.rva) { + ranges_[iter->first] = iter->second + line.length; + } else { + ranges_[line.rva] = line.length; + } + } +} + +void PDBSourceLineWriter::Inline::SetCallSiteLine(DWORD call_site_line) { + call_site_line_ = call_site_line; } +void PDBSourceLineWriter::Inline::SetCallSiteFileId(DWORD call_site_file_id) { + call_site_file_id_ = call_site_file_id; +} + +void PDBSourceLineWriter::Inline::SetChildInlines( + vector<unique_ptr<Inline>> child_inlines) { + child_inlines_ = std::move(child_inlines); +} + +void PDBSourceLineWriter::Inline::Print(FILE* output) const { + // Ignore INLINE record that doesn't have any range. + if (ranges_.empty()) + return; + fprintf(output, "INLINE %d %lu %lu %d", inline_nest_level_, call_site_line_, + call_site_file_id_, origin_id_); + for (const auto& r : ranges_) { + fprintf(output, " %lx %lx", r.first, r.second); + } + fprintf(output, "\n"); + for (const unique_ptr<Inline>& in : child_inlines_) { + in->Print(output); + } +} + +const PDBSourceLineWriter::Line* PDBSourceLineWriter::Lines::GetLine( + DWORD rva) const { + auto iter = line_map_.find(rva); + if (iter == line_map_.end()) { + // If not found exact rva, check if it's within any range. + iter = line_map_.lower_bound(rva); + if (iter == line_map_.begin()) + return nullptr; + --iter; + auto l = iter->second; + // This happens when there is no top level lines cover this rva (e.g. empty + // lines found for the function). Then we don't know the call site line + // number for this inlined function. + if (rva >= l.rva + l.length) + return nullptr; + } + return &iter->second; +} + +DWORD PDBSourceLineWriter::Lines::GetLineNum(DWORD rva) const { + const Line* line = GetLine(rva); + return line ? line->line_num : 0; +} + +DWORD PDBSourceLineWriter::Lines::GetFileId(DWORD rva) const { + const Line* line = GetLine(rva); + return line ? line->file_id : 0; +} + +void PDBSourceLineWriter::Lines::AddLine(const Line& line) { + if (line_map_.empty()) { + line_map_[line.rva] = line; + return; + } + + // Given an existing line in line_map_, remove it from line_map_ if it + // overlaps with the line and add a new line for the non-overlap range. Return + // true if there is an overlap. + auto intercept = [&](Line old_line) { + DWORD end = old_line.rva + old_line.length; + // No overlap. + if (old_line.rva >= line.rva + line.length || line.rva >= end) + return false; + // old_line is within the line. + if (old_line.rva >= line.rva && end <= line.rva + line.length) { + line_map_.erase(old_line.rva); + return true; + } + // Then there is a overlap. + if (old_line.rva < line.rva) { + old_line.length -= end - line.rva; + if (end > line.rva + line.length) { + Line new_line = old_line; + new_line.rva = line.rva + line.length; + new_line.length = end - new_line.rva; + line_map_[new_line.rva] = new_line; + } + } else { + line_map_.erase(old_line.rva); + old_line.length -= line.rva + line.length - old_line.rva; + old_line.rva = line.rva + line.length; + } + line_map_[old_line.rva] = old_line; + return true; + }; + + bool is_intercept; + // Use a loop in cases that there are multiple lines within the given line. + do { + auto iter = line_map_.lower_bound(line.rva); + if (iter == line_map_.end()) { + if (!line_map_.empty()) { + --iter; + intercept(iter->second); + } + break; + } + is_intercept = false; + if (iter != line_map_.begin()) { + // Check if the given line overlaps a line with smaller in the map. + auto prev = line_map_.lower_bound(line.rva); + --prev; + is_intercept = intercept(prev->second); + } + // Check if the given line overlaps a line with greater or equal rva in the + // map. Using operator |= here since it's possible that there are multiple + // lines with greater rva in the map overlap with the given line. + is_intercept |= intercept(iter->second); + } while (is_intercept); + line_map_[line.rva] = line; +} + +PDBSourceLineWriter::PDBSourceLineWriter(bool handle_inline) + : output_(NULL), handle_inline_(handle_inline) {} + PDBSourceLineWriter::~PDBSourceLineWriter() { Close(); } -bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) { +bool PDBSourceLineWriter::SetCodeFile(const wstring& exe_file) { if (code_file_.empty()) { code_file_ = exe_file; return true; @@ -173,7 +413,7 @@ bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) { return exe_file == code_file_; } -bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { +bool PDBSourceLineWriter::Open(const wstring& file, FileFormat format) { Close(); code_file_.clear(); @@ -192,25 +432,32 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { return false; } + HRESULT from_pdb_result; + HRESULT for_exe_result; + const wchar_t* file_name = file.c_str(); switch (format) { case PDB_FILE: - if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { - fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str()); + from_pdb_result = data_source->loadDataFromPdb(file_name); + if (FAILED(from_pdb_result)) { + PrintOpenError(from_pdb_result, "loadDataFromPdb", file_name); return false; } break; case EXE_FILE: - if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { - fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str()); + for_exe_result = data_source->loadDataForExe(file_name, NULL, NULL); + if (FAILED(for_exe_result)) { + PrintOpenError(for_exe_result, "loadDataForExe", file_name); return false; } code_file_ = file; break; case ANY_FILE: - if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { - if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { - fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n", - file.c_str()); + from_pdb_result = data_source->loadDataFromPdb(file_name); + if (FAILED(from_pdb_result)) { + for_exe_result = data_source->loadDataForExe(file_name, NULL, NULL); + if (FAILED(for_exe_result)) { + PrintOpenError(from_pdb_result, "loadDataFromPdb", file_name); + PrintOpenError(for_exe_result, "loadDataForExe", file_name); return false; } code_file_ = file; @@ -228,52 +475,65 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { return true; } -bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) { - // The line number format is: - // <rva> <line number> <source file id> - CComPtr<IDiaLineNumber> line; - ULONG count; +bool PDBSourceLineWriter::GetLine(IDiaLineNumber* dia_line, Line* line) const { + if (FAILED(dia_line->get_relativeVirtualAddress(&line->rva))) { + fprintf(stderr, "failed to get line rva\n"); + return false; + } - while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) { - DWORD rva; - if (FAILED(line->get_relativeVirtualAddress(&rva))) { - fprintf(stderr, "failed to get line rva\n"); - return false; - } + if (FAILED(dia_line->get_length(&line->length))) { + fprintf(stderr, "failed to get line code length\n"); + return false; + } - DWORD length; - if (FAILED(line->get_length(&length))) { - fprintf(stderr, "failed to get line code length\n"); - return false; - } + DWORD dia_source_id; + if (FAILED(dia_line->get_sourceFileId(&dia_source_id))) { + fprintf(stderr, "failed to get line source file id\n"); + return false; + } + // duplicate file names are coalesced to share one ID + line->file_id = GetRealFileID(dia_source_id); - DWORD dia_source_id; - if (FAILED(line->get_sourceFileId(&dia_source_id))) { - fprintf(stderr, "failed to get line source file id\n"); - return false; - } - // duplicate file names are coalesced to share one ID - DWORD source_id = GetRealFileID(dia_source_id); + if (FAILED(dia_line->get_lineNumber(&line->line_num))) { + fprintf(stderr, "failed to get line number\n"); + return false; + } + return true; +} - DWORD line_num; - if (FAILED(line->get_lineNumber(&line_num))) { - fprintf(stderr, "failed to get line number\n"); +bool PDBSourceLineWriter::GetLines(IDiaEnumLineNumbers* lines, + Lines* line_list) const { + CComPtr<IDiaLineNumber> line; + ULONG count; + + while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) { + Line l; + if (!GetLine(line, &l)) return false; - } + // Silently ignore zero-length lines. + if (l.length != 0) + line_list->AddLine(l); + line.Release(); + } + return true; +} +void PDBSourceLineWriter::PrintLines(const Lines& lines) const { + // The line number format is: + // <rva> <line number> <source file id> + for (const auto& kv : lines.GetLineMap()) { + const Line& l = kv.second; AddressRangeVector ranges; - MapAddressRange(image_map_, AddressRange(rva, length), &ranges); - for (size_t i = 0; i < ranges.size(); ++i) { - fprintf(output_, "%lx %lx %lu %lu\n", ranges[i].rva, ranges[i].length, - line_num, source_id); + MapAddressRange(image_map_, AddressRange(l.rva, l.length), &ranges); + for (auto& range : ranges) { + fprintf(output_, "%lx %lx %lu %lu\n", range.rva, range.length, l.line_num, + l.file_id); } - line.Release(); } - return true; } -bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function, - IDiaSymbol *block, +bool PDBSourceLineWriter::PrintFunction(IDiaSymbol* function, + IDiaSymbol* block, bool has_multiple_symbols) { // The function format is: // FUNC <address> <length> <param_stack_size> <function> @@ -320,9 +580,20 @@ bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function, return false; } - if (!PrintLines(lines)) { + // Get top level lines first, which later may be split into multiple smaller + // lines if any inline exists in their ranges if we want to handle inline. + Lines line_list; + if (!GetLines(lines, &line_list)) { return false; } + if (handle_inline_) { + vector<unique_ptr<Inline>> inlines; + if (!GetInlines(block, &line_list, 0, &inlines)) { + return false; + } + PrintInlines(inlines); + } + PrintLines(line_list); return true; } @@ -340,6 +611,10 @@ bool PDBSourceLineWriter::PrintSourceFiles() { return false; } + // Print a dummy file with id equals 0 to represent unknown file, because + // inline records might have unknown call site. + fwprintf(output_, L"FILE %d unknown file\n", 0); + CComPtr<IDiaSymbol> compiland; ULONG count; while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { @@ -503,6 +778,97 @@ bool PDBSourceLineWriter::PrintFunctions() { return true; } +void PDBSourceLineWriter::PrintInlineOrigins() const { + struct OriginCompare { + bool operator()(const InlineOrigin lhs, const InlineOrigin rhs) const { + return lhs.id < rhs.id; + } + }; + set<InlineOrigin, OriginCompare> origins; + // Sort by origin id. + for (auto const& origin : inline_origins_) + origins.insert(origin.second); + for (auto o : origins) { + fprintf(output_, "INLINE_ORIGIN %d %ls\n", o.id, o.name.c_str()); + } +} + +bool PDBSourceLineWriter::GetInlines(IDiaSymbol* block, + Lines* line_list, + int inline_nest_level, + vector<unique_ptr<Inline>>* inlines) { + CComPtr<IDiaEnumSymbols> inline_callsites; + if (FAILED(block->findChildrenEx(SymTagInlineSite, nullptr, nsNone, + &inline_callsites))) { + return false; + } + ULONG count; + CComPtr<IDiaSymbol> callsite; + while (SUCCEEDED(inline_callsites->Next(1, &callsite, &count)) && + count == 1) { + unique_ptr<Inline> new_inline(new Inline(inline_nest_level)); + CComPtr<IDiaEnumLineNumbers> lines; + // All inlinee lines have the same file id. + DWORD file_id = 0; + DWORD call_site_line = 0; + if (FAILED(session_->findInlineeLines(callsite, &lines))) { + return false; + } + CComPtr<IDiaLineNumber> dia_line; + while (SUCCEEDED(lines->Next(1, &dia_line, &count)) && count == 1) { + Line line; + if (!GetLine(dia_line, &line)) { + return false; + } + // Silently ignore zero-length lines. + if (line.length != 0) { + // Use the first line num and file id at rva as this inline's call site + // line number, because after adding lines it may be changed to inner + // line number and inner file id. + if (call_site_line == 0) + call_site_line = line_list->GetLineNum(line.rva); + if (file_id == 0) + file_id = line_list->GetFileId(line.rva); + line_list->AddLine(line); + new_inline->ExtendRanges(line); + } + dia_line.Release(); + } + BSTR name; + callsite->get_name(&name); + if (SysStringLen(name) == 0) { + name = SysAllocString(L"<name omitted>"); + } + auto iter = inline_origins_.find(name); + if (iter == inline_origins_.end()) { + InlineOrigin origin; + origin.id = inline_origins_.size(); + origin.name = name; + inline_origins_[name] = origin; + } + new_inline->SetOriginId(inline_origins_[name].id); + new_inline->SetCallSiteLine(call_site_line); + new_inline->SetCallSiteFileId(file_id); + // Go to next level. + vector<unique_ptr<Inline>> child_inlines; + if (!GetInlines(callsite, line_list, inline_nest_level + 1, + &child_inlines)) { + return false; + } + new_inline->SetChildInlines(std::move(child_inlines)); + inlines->push_back(std::move(new_inline)); + callsite.Release(); + } + return true; +} + +void PDBSourceLineWriter::PrintInlines( + const vector<unique_ptr<Inline>>& inlines) const { + for (const unique_ptr<Inline>& in : inlines) { + in->Print(output_); + } +} + #undef max bool PDBSourceLineWriter::PrintFrameDataUsingPDB() { @@ -673,13 +1039,11 @@ bool PDBSourceLineWriter::PrintFrameData() { PDBModuleInfo info; if (GetModuleInfo(&info) && info.cpu == L"x86_64") { return PrintFrameDataUsingEXE(); - } else { - return PrintFrameDataUsingPDB(); } - return false; + return PrintFrameDataUsingPDB(); } -bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol, +bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol* symbol, bool has_multiple_symbols) { BOOL is_code; if (FAILED(symbol->get_code(&is_code))) { @@ -781,9 +1145,9 @@ bool PDBSourceLineWriter::PrintPEInfo() { // and scanf families, which are not as strict about input and in some cases // don't provide a good way for the caller to determine if a conversion was // successful. -static bool wcstol_positive_strict(wchar_t *string, int *result) { +static bool wcstol_positive_strict(wchar_t* string, int* result) { int value = 0; - for (wchar_t *c = string; *c != '\0'; ++c) { + for (wchar_t* c = string; *c != '\0'; ++c) { int last_value = value; value *= 10; // Detect overflow. @@ -821,7 +1185,7 @@ bool PDBSourceLineWriter::FindPEFile() { wstring file(symbols_file); // Look for an EXE or DLL file. - const wchar_t *extensions[] = { L"exe", L"dll" }; + const wchar_t* extensions[] = { L"exe", L"dll" }; for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) { size_t dot_pos = file.find_last_of(L"."); if (dot_pos != wstring::npos) { @@ -839,23 +1203,13 @@ bool PDBSourceLineWriter::FindPEFile() { } // static -bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, - BSTR *name, - int *stack_param_size) { +bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol* function, + BSTR* name, + int* stack_param_size) { *stack_param_size = -1; - const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS | - UNDNAME_NO_FUNCTION_RETURNS | - UNDNAME_NO_ALLOCATION_MODEL | - UNDNAME_NO_ALLOCATION_LANGUAGE | - UNDNAME_NO_THISTYPE | - UNDNAME_NO_ACCESS_SPECIFIERS | - UNDNAME_NO_THROW_SIGNATURES | - UNDNAME_NO_MEMBER_TYPE | - UNDNAME_NO_RETURN_UDT_MODEL | - UNDNAME_NO_ECSU; // Use get_undecoratedNameEx to get readable C++ names with arguments. - if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) { + if (function->get_undecoratedNameEx(kUndecorateOptions, name) != S_OK) { if (function->get_name(name) != S_OK) { fprintf(stderr, "failed to get function name\n"); return false; @@ -879,15 +1233,17 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, // all of the parameter and return type information may not be included in // the name string. } else { + StripLlvmSuffixAndUndecorate(name); + // C++ uses a bogus "void" argument for functions and methods that don't // take any parameters. Take it out of the undecorated name because it's // ugly and unnecessary. - const wchar_t *replace_string = L"(void)"; + const wchar_t* replace_string = L"(void)"; const size_t replace_length = wcslen(replace_string); - const wchar_t *replacement_string = L"()"; + const wchar_t* replacement_string = L"()"; size_t length = wcslen(*name); if (length >= replace_length) { - wchar_t *name_end = *name + length - replace_length; + wchar_t* name_end = *name + length - replace_length; if (wcscmp(name_end, replace_string) == 0) { WindowsStringUtils::safe_wcscpy(name_end, replace_length, replacement_string); @@ -903,7 +1259,7 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, // whether the undecorated name contains any ':' or '(' characters. if (!wcschr(*name, ':') && !wcschr(*name, '(') && (*name[0] == '_' || *name[0] == '@')) { - wchar_t *last_at = wcsrchr(*name + 1, '@'); + wchar_t* last_at = wcsrchr(*name + 1, '@'); if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) { // If this function adheres to the fastcall convention, it accepts up // to the first 8 bytes of parameters in registers (%ecx and %edx). @@ -935,7 +1291,7 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, } // static -int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) { +int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol* function) { // This implementation is highly x86-specific. // Gather the symbols corresponding to data. @@ -1050,7 +1406,7 @@ next_child: return param_size; } -bool PDBSourceLineWriter::WriteSymbols(FILE *symbol_file) { +bool PDBSourceLineWriter::WriteSymbols(FILE* symbol_file) { output_ = symbol_file; // Load the OMAP information, and disable auto-translation of addresses in @@ -1063,10 +1419,8 @@ bool PDBSourceLineWriter::WriteSymbols(FILE *symbol_file) { bool ret = PrintPDBInfo(); // This is not a critical piece of the symbol file. PrintPEInfo(); - ret = ret && - PrintSourceFiles() && - PrintFunctions() && - PrintFrameData(); + ret = ret && PrintSourceFiles() && PrintFunctions() && PrintFrameData(); + PrintInlineOrigins(); output_ = NULL; return ret; @@ -1078,7 +1432,7 @@ void PDBSourceLineWriter::Close() { } } -bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) { +bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo* info) { if (!info) { return false; } @@ -1143,7 +1497,7 @@ bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) { return true; } -bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) { +bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo* info) { if (!info) { return false; } @@ -1156,7 +1510,7 @@ bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) { return ReadPEInfo(code_file_, info); } -bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) { +bool PDBSourceLineWriter::UsesGUID(bool* uses_guid) { if (!uses_guid) return false; diff --git a/src/common/windows/pdb_source_line_writer.h b/src/common/windows/pdb_source_line_writer.h index c0adf29f..8c74e2ca 100644 --- a/src/common/windows/pdb_source_line_writer.h +++ b/src/common/windows/pdb_source_line_writer.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -35,8 +34,11 @@ #include <atlcomcli.h> +#include <map> +#include <memory> #include <string> #include <unordered_map> +#include <vector> #include "common/windows/module_info.h" #include "common/windows/omap.h" @@ -47,6 +49,8 @@ struct IDiaSymbol; namespace google_breakpad { +using std::map; +using std::vector; using std::wstring; using std::unordered_map; @@ -58,14 +62,14 @@ class PDBSourceLineWriter { ANY_FILE // try PDB_FILE and then EXE_FILE }; - explicit PDBSourceLineWriter(); + explicit PDBSourceLineWriter(bool handle_inline = false); ~PDBSourceLineWriter(); // Opens the given file. For executable files, the corresponding pdb // file must be available; Open will be if it is not. // If there is already a pdb file open, it is automatically closed. // Returns true on success. - bool Open(const wstring &file, FileFormat format); + bool Open(const wstring& file, FileFormat format); // Closes the current pdb file and its associated resources. void Close(); @@ -77,7 +81,7 @@ class PDBSourceLineWriter { // file and it must be called after Open() and before WriteMap(). // If Open() was called for an executable file, then it is an error to call // SetCodeFile() with a different file path and it will return false. - bool SetCodeFile(const wstring &exe_file); + bool SetCodeFile(const wstring& exe_file); // Writes a Breakpad symbol file from the current pdb file to |symbol_file|. // Returns true on success. @@ -99,9 +103,110 @@ class PDBSourceLineWriter { bool UsesGUID(bool *uses_guid); private: - // Outputs the line/address pairs for each line in the enumerator. + // InlineOrigin represents INLINE_ORIGIN record in a symbol file. It's an + // inlined function. + struct InlineOrigin { + // The unique id for an InlineOrigin. + int id; + // The name of the inlined function. + wstring name; + }; + + // Line represents LINE record in a symbol file. It represents a source code + // line. + struct Line { + // The relative address of a line. + DWORD rva; + // The number bytes this line has. + DWORD length; + // The source line number. + DWORD line_num; + // The source file id where the source line is located at. + DWORD file_id; + }; + + // Inline represents INLINE record in a symbol file. + class Inline { + public: + explicit Inline(int inline_nest_level); + + void SetOriginId(int origin_id); + + // Adding inlinee line's range into ranges. If line is adjacent with any + // existing lines, extend the range. Otherwise, add line as a new range. + void ExtendRanges(const Line& line); + + void SetCallSiteLine(DWORD call_site_line); + + void SetCallSiteFileId(DWORD call_site_file_id); + + void SetChildInlines(std::vector<std::unique_ptr<Inline>> child_inlines); + + void Print(FILE* output) const; + + private: + // The nest level of this inline record. + int inline_nest_level_; + // The source line number at where this inlined function is called. + DWORD call_site_line_ = 0; + // The call site file id at where this inlined function is called. + DWORD call_site_file_id_ = 0; + // The id used for referring to an InlineOrigin. + int origin_id_ = 0; + // A map from rva to length. This is the address ranges covered by this + // Inline. + map<DWORD, DWORD> ranges_; + // The list of direct Inlines inlined inside this Inline. + vector<std::unique_ptr<Inline>> child_inlines_; + }; + + // Lines represents a map of lines inside a function with rva as the key. + // AddLine function adds a line into the map and ensures that there is no + // overlap between any two lines in the map. + class Lines { + public: + const map<DWORD, Line>& GetLineMap() const { return line_map_; } + + // Finds the line from line_map_ that contains the given rva returns its + // line_num. If not found, return 0. + DWORD GetLineNum(DWORD rva) const; + + // Finds the line from line_map_ that contains the given rva returns its + // file_id. If not found, return 0. + DWORD GetFileId(DWORD rva) const; + + // Add the `line` into line_map_. If the `line` overlaps with existing + // lines, truncate the existing lines and add the given line. It ensures + // that all lines in line_map_ do not overlap with each other. For example, + // suppose there is a line A in the map and we call AddLine with Line B. + // Line A: rva: 100, length: 20, line_num: 10, file_id: 1 + // Line B: rva: 105, length: 10, line_num: 4, file_id: 2 + // After calling AddLine with Line B, we will have the following lines: + // Line 1: rva: 100, length: 5, line_num: 10, file_id: 1 + // Line 2: rva: 105, length: 10, line_num: 4, file_id: 2 + // Line 3: rva: 115, length: 5, line_num: 10, file_id: 1 + void AddLine(const Line& line); + + private: + // Finds the line from line_map_ that contains the given rva. If not found, + // return nullptr. + const Line* GetLine(DWORD rva) const; + // The key is rva. AddLine function ensures that any two lines in the map do + // not overlap. + map<DWORD, Line> line_map_; + }; + + // Construct Line from IDiaLineNumber. The output Line is stored at line. + // Return true on success. + bool GetLine(IDiaLineNumber* dia_line, Line* line) const; + + // Construct Lines from IDiaEnumLineNumbers. The list of Lines are stored at + // line_list. // Returns true on success. - bool PrintLines(IDiaEnumLineNumbers *lines); + bool GetLines(IDiaEnumLineNumbers* lines, Lines* line_list) const; + + // Outputs the line/address pairs for each line in the enumerator. + void PrintLines(const Lines& lines) const; // Outputs a function address and name, followed by its source line list. // block can be the same object as function, or it can be a reference to a @@ -118,6 +223,25 @@ class PDBSourceLineWriter { // Returns true on success. bool PrintSourceFiles(); + // Output all inline origins. + void PrintInlineOrigins() const; + + // Retrieve inlines inside the given block. It also adds inlinee lines to + // `line_list` since inner lines are more precise source location. If the + // block has children wih SymTagInlineSite Tag, it will recursively (DFS) call + // itself with each child as first argument. Returns true on success. + // `block`: the IDiaSymbol that may have inline sites. + // `line_list`: the list of lines inside current function. + // `inline_nest_level`: the nest level of block's Inlines. + // `inlines`: the vector to store the list of inlines for the block. + bool GetInlines(IDiaSymbol* block, + Lines* line_list, + int inline_nest_level, + vector<std::unique_ptr<Inline>>* inlines); + + // Outputs all inlines. + void PrintInlines(const vector<std::unique_ptr<Inline>>& inlines) const; + // Outputs all of the frame information necessary to construct stack // backtraces in the absence of frame pointers. For x86 data stored in // .pdb files. Returns true on success. @@ -150,17 +274,17 @@ class PDBSourceLineWriter { // Returns true if this filename has already been seen, // and an ID is stored for it, or false if it has not. - bool FileIDIsCached(const wstring &file) { + bool FileIDIsCached(const wstring& file) { return unique_files_.find(file) != unique_files_.end(); } // Cache this filename and ID for later reuse. - void CacheFileID(const wstring &file, DWORD id) { + void CacheFileID(const wstring& file, DWORD id) { unique_files_[file] = id; } // Store this ID in the cache as a duplicate for this filename. - void StoreDuplicateFileID(const wstring &file, DWORD id) { + void StoreDuplicateFileID(const wstring& file, DWORD id) { unordered_map<wstring, DWORD>::iterator iter = unique_files_.find(file); if (iter != unique_files_.end()) { // map this id to the previously seen one @@ -172,8 +296,8 @@ class PDBSourceLineWriter { // reference it. There may be multiple files with identical filenames // but different unique IDs. The cache attempts to coalesce these into // one ID per unique filename. - DWORD GetRealFileID(DWORD id) { - unordered_map<DWORD, DWORD>::iterator iter = file_ids_.find(id); + DWORD GetRealFileID(DWORD id) const { + unordered_map<DWORD, DWORD>::const_iterator iter = file_ids_.find(id); if (iter == file_ids_.end()) return id; return iter->second; @@ -213,9 +337,15 @@ class PDBSourceLineWriter { // This maps unique filenames to file IDs. unordered_map<wstring, DWORD> unique_files_; + // The INLINE_ORIGINS records. The key is the function name. + std::map<wstring, InlineOrigin> inline_origins_; + // This is used for calculating post-transform symbol addresses and lengths. ImageMap image_map_; + // If we should output INLINE/INLINE_ORIGIN records + bool handle_inline_; + // Disallow copy ctor and operator= PDBSourceLineWriter(const PDBSourceLineWriter&); void operator=(const PDBSourceLineWriter&); diff --git a/src/common/windows/pe_source_line_writer.cc b/src/common/windows/pe_source_line_writer.cc index cb6cc713..a568e0c7 100644 --- a/src/common/windows/pe_source_line_writer.cc +++ b/src/common/windows/pe_source_line_writer.cc @@ -1,77 +1,76 @@ -// Copyright (c) 2019, 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 "common/windows/pe_source_line_writer.h"
-
-#include "common/windows/pe_util.h"
-
-namespace google_breakpad {
-PESourceLineWriter::PESourceLineWriter(const wstring& pe_file) :
- pe_file_(pe_file) {
-}
-
-PESourceLineWriter::~PESourceLineWriter() {
-}
-
-bool PESourceLineWriter::WriteSymbols(FILE* symbol_file) {
- PDBModuleInfo module_info;
- if (!GetModuleInfo(&module_info)) {
- return false;
- }
- // Hard-code "windows" for the OS because that's the only thing that makes
- // sense for PDB files. (This might not be strictly correct for Windows CE
- // support, but we don't care about that at the moment.)
- fprintf(symbol_file, "MODULE windows %ws %ws %ws\n",
- module_info.cpu.c_str(), module_info.debug_identifier.c_str(),
- module_info.debug_file.c_str());
-
- PEModuleInfo pe_info;
- if (!GetPEInfo(&pe_info)) {
- return false;
- }
- fprintf(symbol_file, "INFO CODE_ID %ws %ws\n",
- pe_info.code_identifier.c_str(),
- pe_info.code_file.c_str());
-
- if (!PrintPEFrameData(pe_file_, symbol_file)) {
- return false;
- }
-
- return true;
-}
-
-bool PESourceLineWriter::GetModuleInfo(PDBModuleInfo* info) {
- return ReadModuleInfo(pe_file_, info);
-}
-
-bool PESourceLineWriter::GetPEInfo(PEModuleInfo* info) {
- return ReadPEInfo(pe_file_, info);
-}
-
-} // namespace google_breakpad
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/windows/pe_source_line_writer.h" + +#include "common/windows/pe_util.h" + +namespace google_breakpad { +PESourceLineWriter::PESourceLineWriter(const wstring& pe_file) : + pe_file_(pe_file) { +} + +PESourceLineWriter::~PESourceLineWriter() { +} + +bool PESourceLineWriter::WriteSymbols(FILE* symbol_file) { + PDBModuleInfo module_info; + if (!GetModuleInfo(&module_info)) { + return false; + } + // Hard-code "windows" for the OS because that's the only thing that makes + // sense for PDB files. (This might not be strictly correct for Windows CE + // support, but we don't care about that at the moment.) + fprintf(symbol_file, "MODULE windows %ws %ws %ws\n", + module_info.cpu.c_str(), module_info.debug_identifier.c_str(), + module_info.debug_file.c_str()); + + PEModuleInfo pe_info; + if (!GetPEInfo(&pe_info)) { + return false; + } + fprintf(symbol_file, "INFO CODE_ID %ws %ws\n", + pe_info.code_identifier.c_str(), + pe_info.code_file.c_str()); + + if (!PrintPEFrameData(pe_file_, symbol_file)) { + return false; + } + + return true; +} + +bool PESourceLineWriter::GetModuleInfo(PDBModuleInfo* info) { + return ReadModuleInfo(pe_file_, info); +} + +bool PESourceLineWriter::GetPEInfo(PEModuleInfo* info) { + return ReadPEInfo(pe_file_, info); +} + +} // namespace google_breakpad diff --git a/src/common/windows/pe_source_line_writer.h b/src/common/windows/pe_source_line_writer.h index 2bf1d4fd..a3748145 100644 --- a/src/common/windows/pe_source_line_writer.h +++ b/src/common/windows/pe_source_line_writer.h @@ -1,69 +1,68 @@ -// Copyright (c) 2019, 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_WINDOWS_PE_SOURCE_LINE_WRITER_H_
-#define COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
-
-#include <string>
-
-#include "common/basictypes.h"
-#include "common/windows/module_info.h"
-
-namespace google_breakpad {
-
-using std::wstring;
-
-// PESourceLineWriter uses a pe file produced by Visual C++ to output
-// a line/address map for use with BasicSourceLineResolver.
-// NOTE: Only supports PE32+ format, ie. a 64bit PE file.
-class PESourceLineWriter {
-public:
- explicit PESourceLineWriter(const wstring& pe_file);
- ~PESourceLineWriter();
-
- // Writes Breakpad symbols from the pe file to |symbol_file|.
- // Returns true on success.
- bool WriteSymbols(FILE* symbol_file);
-
- // Retrieves information about the module. Returns true on success.
- bool GetModuleInfo(PDBModuleInfo* info);
-
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_ +#define COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_ + +#include <string> + +#include "common/basictypes.h" +#include "common/windows/module_info.h" + +namespace google_breakpad { + +using std::wstring; + +// PESourceLineWriter uses a pe file produced by Visual C++ to output +// a line/address map for use with BasicSourceLineResolver. +// NOTE: Only supports PE32+ format, ie. a 64bit PE file. +class PESourceLineWriter { +public: + explicit PESourceLineWriter(const wstring& pe_file); + ~PESourceLineWriter(); + + // Writes Breakpad symbols from the pe file to |symbol_file|. + // Returns true on success. + bool WriteSymbols(FILE* symbol_file); + + // Retrieves information about the module. Returns true on success. + bool GetModuleInfo(PDBModuleInfo* info); + // Retrieves information about the module's PE file. Returns - // true on success.
- bool GetPEInfo(PEModuleInfo* info);
-
-private:
- const wstring pe_file_;
-
- DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter);
-};
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
+ // true on success. + bool GetPEInfo(PEModuleInfo* info); + +private: + const wstring pe_file_; + + DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter); +}; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_ diff --git a/src/common/windows/pe_util.cc b/src/common/windows/pe_util.cc index 6fa63fa3..1df93105 100644 --- a/src/common/windows/pe_util.cc +++ b/src/common/windows/pe_util.cc @@ -1,407 +1,411 @@ -// Copyright (c) 2019, 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 "pe_util.h"
-
-#include <windows.h>
-#include <winnt.h>
-#include <atlbase.h>
-#include <ImageHlp.h>
-
-#include <functional>
-
-#include "common/windows/string_utils-inl.h"
-#include "common/windows/guid_string.h"
-
-namespace {
-
-/*
- * Not defined in WinNT.h for some reason. Definitions taken from:
- * http://uninformed.org/index.cgi?v=4&a=1&p=13
- *
- */
-typedef unsigned char UBYTE;
-
-#if !defined(_WIN64)
-#define UNW_FLAG_EHANDLER 0x01
-#define UNW_FLAG_UHANDLER 0x02
-#define UNW_FLAG_CHAININFO 0x04
-#endif
-
-union UnwindCode {
- struct {
- UBYTE offset_in_prolog;
- UBYTE unwind_operation_code : 4;
- UBYTE operation_info : 4;
- };
- USHORT frame_offset;
-};
-
-enum UnwindOperationCodes {
- UWOP_PUSH_NONVOL = 0, /* info == register number */
- UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
- UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
- UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
- UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
- UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
- // XXX: these are missing from MSDN!
- // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
- UWOP_SAVE_XMM,
- UWOP_SAVE_XMM_FAR,
- UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
- UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
- UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
-};
-
-// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
-// Note: some fields removed as we don't use them.
-struct UnwindInfo {
- UBYTE version : 3;
- UBYTE flags : 5;
- UBYTE size_of_prolog;
- UBYTE count_of_codes;
- UBYTE frame_register : 4;
- UBYTE frame_offset : 4;
- UnwindCode unwind_code[1];
-};
-
-struct CV_INFO_PDB70 {
- ULONG cv_signature;
- GUID signature;
- ULONG age;
- CHAR pdb_filename[ANYSIZE_ARRAY];
-};
-
-#define CV_SIGNATURE_RSDS 'SDSR'
-
-// A helper class to scope a PLOADED_IMAGE.
-class AutoImage {
-public:
- explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
- ~AutoImage() {
- if (img_)
- ImageUnload(img_);
- }
-
- operator PLOADED_IMAGE() { return img_; }
- PLOADED_IMAGE operator->() { return img_; }
-
-private:
- PLOADED_IMAGE img_;
-};
-} // namespace
-
-namespace google_breakpad {
-
-using std::unique_ptr;
-using google_breakpad::GUIDString;
-
-bool ReadModuleInfo(const wstring & pe_file, PDBModuleInfo * info) {
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to load %s\n", img_file.c_str());
- return false;
- }
-
- info->cpu = FileHeaderMachineToCpuString(
- img->FileHeader->FileHeader.Machine);
-
- PIMAGE_OPTIONAL_HEADER64 optional_header =
- &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
-
- // Search debug directories for a guid signature & age
- DWORD debug_rva = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
- DWORD debug_size = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
- PIMAGE_DEBUG_DIRECTORY debug_directories =
- static_cast<PIMAGE_DEBUG_DIRECTORY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- debug_rva,
- &img->LastRvaSection));
-
- for (DWORD i = 0; i < debug_size / sizeof(*debug_directories); i++) {
- if (debug_directories[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW ||
- debug_directories[i].SizeOfData < sizeof(CV_INFO_PDB70)) {
- continue;
- }
-
- struct CV_INFO_PDB70* cv_info = static_cast<CV_INFO_PDB70*>(ImageRvaToVa(
- img->FileHeader,
- img->MappedAddress,
- debug_directories[i].AddressOfRawData,
- &img->LastRvaSection));
- if (cv_info->cv_signature != CV_SIGNATURE_RSDS) {
- continue;
- }
-
- info->debug_identifier = GenerateDebugIdentifier(cv_info->age,
- cv_info->signature);
-
- // This code assumes that the pdb_filename is stored as ASCII without
- // multibyte characters, but it's not clear if that's true.
- size_t debug_file_length = strnlen_s(cv_info->pdb_filename, MAX_PATH);
- if (debug_file_length < 0 || debug_file_length >= MAX_PATH) {
- fprintf(stderr, "PE debug directory is corrupt.\n");
- return false;
- }
- std::string debug_file(cv_info->pdb_filename, debug_file_length);
- if (!WindowsStringUtils::safe_mbstowcs(debug_file, &info->debug_file)) {
- fprintf(stderr, "PDB filename '%s' contains unrecognized characters.\n",
- debug_file.c_str());
- return false;
- }
- info->debug_file = WindowsStringUtils::GetBaseName(info->debug_file);
-
- return true;
- }
-
- fprintf(stderr, "Image is missing debug information.\n");
- return false;
-}
-
-bool ReadPEInfo(const wstring & pe_file, PEModuleInfo * info) {
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to open PE file: %S\n", pe_file.c_str());
- return false;
- }
-
- info->code_file = WindowsStringUtils::GetBaseName(pe_file);
-
- // The date and time that the file was created by the linker.
- DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp;
- // The size of the file in bytes, including all headers.
- DWORD SizeOfImage = 0;
- PIMAGE_OPTIONAL_HEADER64 opt =
- &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader;
- if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- // 64-bit PE file.
- SizeOfImage = opt->SizeOfImage;
- }
- else {
- // 32-bit PE file.
- SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage;
- }
- wchar_t code_identifier[32];
- swprintf(code_identifier,
- sizeof(code_identifier) / sizeof(code_identifier[0]),
- L"%08X%X", TimeDateStamp, SizeOfImage);
- info->code_identifier = code_identifier;
-
- return true;
-}
-
-bool PrintPEFrameData(const wstring & pe_file, FILE * out_file)
-{
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to load %s\n", img_file.c_str());
- return false;
- }
- PIMAGE_OPTIONAL_HEADER64 optional_header =
- &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
- if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- fprintf(stderr, "Not a PE32+ image\n");
- return false;
- }
-
- // Read Exception Directory
- DWORD exception_rva = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
- DWORD exception_size = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
- PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
- static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- exception_rva,
- &img->LastRvaSection));
- for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
- DWORD unwind_rva = funcs[i].UnwindInfoAddress;
- // handle chaining
- while (unwind_rva & 0x1) {
- unwind_rva ^= 0x1;
- PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
- static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- unwind_rva,
- &img->LastRvaSection));
- unwind_rva = chained_func->UnwindInfoAddress;
- }
-
- UnwindInfo *unwind_info = static_cast<UnwindInfo *>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- unwind_rva,
- &img->LastRvaSection));
-
- DWORD stack_size = 8; // minimal stack size is 8 for RIP
- DWORD rip_offset = 8;
- do {
- for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
- UnwindCode *unwind_code = &unwind_info->unwind_code[c];
- switch (unwind_code->unwind_operation_code) {
- case UWOP_PUSH_NONVOL: {
- stack_size += 8;
- break;
- }
- case UWOP_ALLOC_LARGE: {
- if (unwind_code->operation_info == 0) {
- c++;
- if (c < unwind_info->count_of_codes)
- stack_size += (unwind_code + 1)->frame_offset * 8;
- }
- else {
- c += 2;
- if (c < unwind_info->count_of_codes)
- stack_size += (unwind_code + 1)->frame_offset |
- ((unwind_code + 2)->frame_offset << 16);
- }
- break;
- }
- case UWOP_ALLOC_SMALL: {
- stack_size += unwind_code->operation_info * 8 + 8;
- break;
- }
- case UWOP_SET_FPREG:
- case UWOP_SAVE_XMM:
- case UWOP_SAVE_XMM_FAR:
- break;
- case UWOP_SAVE_NONVOL:
- case UWOP_SAVE_XMM128: {
- c++; // skip slot with offset
- break;
- }
- case UWOP_SAVE_NONVOL_FAR:
- case UWOP_SAVE_XMM128_FAR: {
- c += 2; // skip 2 slots with offset
- break;
- }
- case UWOP_PUSH_MACHFRAME: {
- if (unwind_code->operation_info) {
- stack_size += 88;
- }
- else {
- stack_size += 80;
- }
- rip_offset += 80;
- break;
- }
- }
- }
- if (unwind_info->flags & UNW_FLAG_CHAININFO) {
- PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
- reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- (unwind_info->unwind_code +
- ((unwind_info->count_of_codes + 1) & ~1)));
-
- unwind_info = static_cast<UnwindInfo *>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- chained_func->UnwindInfoAddress,
- &img->LastRvaSection));
- }
- else {
- unwind_info = NULL;
- }
- } while (unwind_info);
- fprintf(out_file, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n",
- funcs[i].BeginAddress,
- funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
- fprintf(out_file, "STACK CFI %lx .cfa: $rsp %lu +\n",
- funcs[i].BeginAddress, stack_size);
- }
-
- return true;
-}
-
-wstring GenerateDebugIdentifier(DWORD age, GUID signature)
-{
- // Use the same format that the MS symbol server uses in filesystem
- // hierarchies.
- wchar_t age_string[9];
- swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
- L"%x", age);
-
- // remove when VC++7.1 is no longer supported
- age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
-
- wstring debug_identifier = GUIDString::GUIDToSymbolServerWString(&signature);
- debug_identifier.append(age_string);
-
- return debug_identifier;
-}
-
-wstring GenerateDebugIdentifier(DWORD age, DWORD signature)
-{
- // Use the same format that the MS symbol server uses in filesystem
- // hierarchies.
- wchar_t identifier_string[17];
- swprintf(identifier_string,
- sizeof(identifier_string) / sizeof(identifier_string[0]),
- L"%08X%x", signature, age);
-
- // remove when VC++7.1 is no longer supported
- identifier_string[sizeof(identifier_string) /
- sizeof(identifier_string[0]) - 1] = L'\0';
-
- return wstring(identifier_string);
-}
-
-} // namespace google_breakpad
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "pe_util.h" + +#include <windows.h> +#include <winnt.h> +#include <atlbase.h> +#include <ImageHlp.h> + +#include <functional> +#include <memory> + +#include "common/windows/string_utils-inl.h" +#include "common/windows/guid_string.h" + +namespace { + +/* + * Not defined in WinNT.h prior to SDK 10.0.20348.0 for some reason. + * Definitions taken from: http://uninformed.org/index.cgi?v=4&a=1&p=13 + * + */ +typedef unsigned char UBYTE; + +#if !defined(UNW_FLAG_EHANDLER) +#define UNW_FLAG_EHANDLER 0x01 +#endif +#if !defined(UNW_FLAG_UHANDLER) +#define UNW_FLAG_UHANDLER 0x02 +#endif +#if !defined(UNW_FLAG_CHAININFO) +#define UNW_FLAG_CHAININFO 0x04 +#endif + +union UnwindCode { + struct { + UBYTE offset_in_prolog; + UBYTE unwind_operation_code : 4; + UBYTE operation_info : 4; + }; + USHORT frame_offset; +}; + +enum UnwindOperationCodes { + UWOP_PUSH_NONVOL = 0, /* info == register number */ + UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */ + UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */ + UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */ + UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */ + UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */ + // XXX: these are missing from MSDN! + // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm + UWOP_SAVE_XMM, + UWOP_SAVE_XMM_FAR, + UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */ + UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */ + UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */ +}; + +// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx +// Note: some fields removed as we don't use them. +struct UnwindInfo { + UBYTE version : 3; + UBYTE flags : 5; + UBYTE size_of_prolog; + UBYTE count_of_codes; + UBYTE frame_register : 4; + UBYTE frame_offset : 4; + UnwindCode unwind_code[1]; +}; + +struct CV_INFO_PDB70 { + ULONG cv_signature; + GUID signature; + ULONG age; + CHAR pdb_filename[ANYSIZE_ARRAY]; +}; + +#define CV_SIGNATURE_RSDS 'SDSR' + +// A helper class to scope a PLOADED_IMAGE. +class AutoImage { +public: + explicit AutoImage(PLOADED_IMAGE img) : img_(img) {} + ~AutoImage() { + if (img_) + ImageUnload(img_); + } + + operator PLOADED_IMAGE() { return img_; } + PLOADED_IMAGE operator->() { return img_; } + +private: + PLOADED_IMAGE img_; +}; +} // namespace + +namespace google_breakpad { + +using std::unique_ptr; +using google_breakpad::GUIDString; + +bool ReadModuleInfo(const wstring & pe_file, PDBModuleInfo * info) { + // Convert wchar to native charset because ImageLoad only takes + // a PSTR as input. + string img_file; + if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) { + fprintf(stderr, "Image path '%S' contains unrecognized characters.\n", + pe_file.c_str()); + return false; + } + + AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL)); + if (!img) { + fprintf(stderr, "Failed to load %s\n", img_file.c_str()); + return false; + } + + info->cpu = FileHeaderMachineToCpuString( + img->FileHeader->FileHeader.Machine); + + PIMAGE_OPTIONAL_HEADER64 optional_header = + &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader; + + // Search debug directories for a guid signature & age + DWORD debug_rva = optional_header-> + DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + DWORD debug_size = optional_header-> + DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + PIMAGE_DEBUG_DIRECTORY debug_directories = + static_cast<PIMAGE_DEBUG_DIRECTORY>( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + debug_rva, + &img->LastRvaSection)); + + for (DWORD i = 0; i < debug_size / sizeof(*debug_directories); i++) { + if (debug_directories[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW || + debug_directories[i].SizeOfData < sizeof(CV_INFO_PDB70)) { + continue; + } + + struct CV_INFO_PDB70* cv_info = static_cast<CV_INFO_PDB70*>(ImageRvaToVa( + img->FileHeader, + img->MappedAddress, + debug_directories[i].AddressOfRawData, + &img->LastRvaSection)); + if (cv_info->cv_signature != CV_SIGNATURE_RSDS) { + continue; + } + + info->debug_identifier = GenerateDebugIdentifier(cv_info->age, + cv_info->signature); + + // This code assumes that the pdb_filename is stored as ASCII without + // multibyte characters, but it's not clear if that's true. + size_t debug_file_length = strnlen_s(cv_info->pdb_filename, MAX_PATH); + if (debug_file_length < 0 || debug_file_length >= MAX_PATH) { + fprintf(stderr, "PE debug directory is corrupt.\n"); + return false; + } + std::string debug_file(cv_info->pdb_filename, debug_file_length); + if (!WindowsStringUtils::safe_mbstowcs(debug_file, &info->debug_file)) { + fprintf(stderr, "PDB filename '%s' contains unrecognized characters.\n", + debug_file.c_str()); + return false; + } + info->debug_file = WindowsStringUtils::GetBaseName(info->debug_file); + + return true; + } + + fprintf(stderr, "Image is missing debug information.\n"); + return false; +} + +bool ReadPEInfo(const wstring & pe_file, PEModuleInfo * info) { + // Convert wchar to native charset because ImageLoad only takes + // a PSTR as input. + string img_file; + if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) { + fprintf(stderr, "Image path '%S' contains unrecognized characters.\n", + pe_file.c_str()); + return false; + } + + AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL)); + if (!img) { + fprintf(stderr, "Failed to open PE file: %S\n", pe_file.c_str()); + return false; + } + + info->code_file = WindowsStringUtils::GetBaseName(pe_file); + + // The date and time that the file was created by the linker. + DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp; + // The size of the file in bytes, including all headers. + DWORD SizeOfImage = 0; + PIMAGE_OPTIONAL_HEADER64 opt = + &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader; + if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // 64-bit PE file. + SizeOfImage = opt->SizeOfImage; + } + else { + // 32-bit PE file. + SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage; + } + wchar_t code_identifier[32]; + swprintf(code_identifier, + sizeof(code_identifier) / sizeof(code_identifier[0]), + L"%08X%X", TimeDateStamp, SizeOfImage); + info->code_identifier = code_identifier; + + return true; +} + +bool PrintPEFrameData(const wstring & pe_file, FILE * out_file) +{ + // Convert wchar to native charset because ImageLoad only takes + // a PSTR as input. + string img_file; + if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) { + fprintf(stderr, "Image path '%S' contains unrecognized characters.\n", + pe_file.c_str()); + return false; + } + + AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL)); + if (!img) { + fprintf(stderr, "Failed to load %s\n", img_file.c_str()); + return false; + } + PIMAGE_OPTIONAL_HEADER64 optional_header = + &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader; + if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + fprintf(stderr, "Not a PE32+ image\n"); + return false; + } + + // Read Exception Directory + DWORD exception_rva = optional_header-> + DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; + DWORD exception_size = optional_header-> + DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; + PIMAGE_RUNTIME_FUNCTION_ENTRY funcs = + static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + exception_rva, + &img->LastRvaSection)); + for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) { + DWORD unwind_rva = funcs[i].UnwindInfoAddress; + // handle chaining + while (unwind_rva & 0x1) { + unwind_rva ^= 0x1; + PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = + static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + unwind_rva, + &img->LastRvaSection)); + unwind_rva = chained_func->UnwindInfoAddress; + } + + UnwindInfo *unwind_info = static_cast<UnwindInfo*>( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + unwind_rva, + &img->LastRvaSection)); + + DWORD stack_size = 8; // minimal stack size is 8 for RIP + DWORD rip_offset = 8; + do { + for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) { + UnwindCode *unwind_code = &unwind_info->unwind_code[c]; + switch (unwind_code->unwind_operation_code) { + case UWOP_PUSH_NONVOL: { + stack_size += 8; + break; + } + case UWOP_ALLOC_LARGE: { + if (unwind_code->operation_info == 0) { + c++; + if (c < unwind_info->count_of_codes) + stack_size += (unwind_code + 1)->frame_offset * 8; + } + else { + c += 2; + if (c < unwind_info->count_of_codes) + stack_size += (unwind_code + 1)->frame_offset | + ((unwind_code + 2)->frame_offset << 16); + } + break; + } + case UWOP_ALLOC_SMALL: { + stack_size += unwind_code->operation_info * 8 + 8; + break; + } + case UWOP_SET_FPREG: + case UWOP_SAVE_XMM: + case UWOP_SAVE_XMM_FAR: + break; + case UWOP_SAVE_NONVOL: + case UWOP_SAVE_XMM128: { + c++; // skip slot with offset + break; + } + case UWOP_SAVE_NONVOL_FAR: + case UWOP_SAVE_XMM128_FAR: { + c += 2; // skip 2 slots with offset + break; + } + case UWOP_PUSH_MACHFRAME: { + if (unwind_code->operation_info) { + stack_size += 88; + } + else { + stack_size += 80; + } + rip_offset += 80; + break; + } + } + } + if (unwind_info->flags & UNW_FLAG_CHAININFO) { + PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = + reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( + (unwind_info->unwind_code + + ((unwind_info->count_of_codes + 1) & ~1))); + + unwind_info = static_cast<UnwindInfo*>( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + chained_func->UnwindInfoAddress, + &img->LastRvaSection)); + } + else { + unwind_info = NULL; + } + } while (unwind_info); + fprintf(out_file, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n", + funcs[i].BeginAddress, + funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset); + fprintf(out_file, "STACK CFI %lx .cfa: $rsp %lu +\n", + funcs[i].BeginAddress, stack_size); + } + + return true; +} + +wstring GenerateDebugIdentifier(DWORD age, GUID signature) +{ + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + wchar_t age_string[9]; + swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]), + L"%x", age); + + // remove when VC++7.1 is no longer supported + age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0'; + + wstring debug_identifier = GUIDString::GUIDToSymbolServerWString(&signature); + debug_identifier.append(age_string); + + return debug_identifier; +} + +wstring GenerateDebugIdentifier(DWORD age, DWORD signature) +{ + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + wchar_t identifier_string[17]; + swprintf(identifier_string, + sizeof(identifier_string) / sizeof(identifier_string[0]), + L"%08X%x", signature, age); + + // remove when VC++7.1 is no longer supported + identifier_string[sizeof(identifier_string) / + sizeof(identifier_string[0]) - 1] = L'\0'; + + return wstring(identifier_string); +} + +} // namespace google_breakpad diff --git a/src/common/windows/pe_util.h b/src/common/windows/pe_util.h index 634ba293..6c6b364f 100644 --- a/src/common/windows/pe_util.h +++ b/src/common/windows/pe_util.h @@ -1,78 +1,77 @@ -// Copyright (c) 2019, 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_WINDOWS_PE_UTIL_H_
-#define COMMON_WINDOWS_PE_UTIL_H_
-
-#include <windows.h>
-
-#include "common/windows/module_info.h"
-
-namespace google_breakpad {
-
-using std::wstring;
-
-// Reads |pe_file| and populates |info|. Returns true on success.
-// Only supports PE32+ format, ie. a 64bit PE file.
-// Will fail if |pe_file| does not contain a valid CodeView record.
-bool ReadModuleInfo(const wstring& pe_file, PDBModuleInfo* info);
-
-// Reads |pe_file| and populates |info|. Returns true on success.
-bool ReadPEInfo(const wstring& pe_file, PEModuleInfo* info);
-
-// Reads |pe_file| and prints frame data (aka. unwind info) to |out_file|.
-// Only supports PE32+ format, ie. a 64bit PE file.
-bool PrintPEFrameData(const wstring& pe_file, FILE* out_file);
-
-// Combines a GUID |signature| and DWORD |age| to create a Breakpad debug
-// identifier.
-wstring GenerateDebugIdentifier(DWORD age, GUID signature);
-
-// Combines a DWORD |signature| and DWORD |age| to create a Breakpad debug
-// identifier.
-wstring GenerateDebugIdentifier(DWORD age, DWORD signature);
-
-// Converts |machine| enum value to the corresponding string used by Breakpad.
-// The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h.
-constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) {
- switch (machine) {
- case IMAGE_FILE_MACHINE_I386: {
- return L"x86";
- }
- case IMAGE_FILE_MACHINE_IA64:
- case IMAGE_FILE_MACHINE_AMD64: {
- return L"x86_64";
- }
- default: { return L"unknown"; }
- }
-}
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_PE_UTIL_H_
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_WINDOWS_PE_UTIL_H_ +#define COMMON_WINDOWS_PE_UTIL_H_ + +#include <windows.h> + +#include "common/windows/module_info.h" + +namespace google_breakpad { + +using std::wstring; + +// Reads |pe_file| and populates |info|. Returns true on success. +// Only supports PE32+ format, ie. a 64bit PE file. +// Will fail if |pe_file| does not contain a valid CodeView record. +bool ReadModuleInfo(const wstring& pe_file, PDBModuleInfo* info); + +// Reads |pe_file| and populates |info|. Returns true on success. +bool ReadPEInfo(const wstring& pe_file, PEModuleInfo* info); + +// Reads |pe_file| and prints frame data (aka. unwind info) to |out_file|. +// Only supports PE32+ format, ie. a 64bit PE file. +bool PrintPEFrameData(const wstring& pe_file, FILE* out_file); + +// Combines a GUID |signature| and DWORD |age| to create a Breakpad debug +// identifier. +wstring GenerateDebugIdentifier(DWORD age, GUID signature); + +// Combines a DWORD |signature| and DWORD |age| to create a Breakpad debug +// identifier. +wstring GenerateDebugIdentifier(DWORD age, DWORD signature); + +// Converts |machine| enum value to the corresponding string used by Breakpad. +// The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h. +constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) { + switch (machine) { + case IMAGE_FILE_MACHINE_I386: { + return L"x86"; + } + case IMAGE_FILE_MACHINE_IA64: + case IMAGE_FILE_MACHINE_AMD64: { + return L"x86_64"; + } + default: { return L"unknown"; } + } +} + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_PE_UTIL_H_ diff --git a/src/common/windows/string_utils-inl.h b/src/common/windows/string_utils-inl.h index 9b636072..c6f5e0ac 100644 --- a/src/common/windows/string_utils-inl.h +++ b/src/common/windows/string_utils-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -72,26 +71,26 @@ class WindowsStringUtils { // Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does // not fail if source is longer than destination_size. The destination // buffer is always 0-terminated. - static void safe_wcscpy(wchar_t *destination, size_t destination_size, - const wchar_t *source); + static void safe_wcscpy(wchar_t* destination, size_t destination_size, + const wchar_t* source); // Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot // be passed directly, and pre-MSVC8, this will not fail if source or count // are longer than destination_size. The destination buffer is always // 0-terminated. - static void safe_wcsncpy(wchar_t *destination, size_t destination_size, - const wchar_t *source, size_t count); + static void safe_wcsncpy(wchar_t* destination, size_t destination_size, + const wchar_t* source, size_t count); // Performs multi-byte to wide character conversion on C++ strings, using // mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8). Returns false on failure, // without setting wcs. - static bool safe_mbstowcs(const string &mbs, wstring *wcs); + static bool safe_mbstowcs(const string& mbs, wstring* wcs); // The inverse of safe_mbstowcs. - static bool safe_wcstombs(const wstring &wcs, string *mbs); + static bool safe_wcstombs(const wstring& wcs, string* mbs); // Returns the base name of a file, e.g. strips off the path. - static wstring GetBaseName(const wstring &filename); + static wstring GetBaseName(const wstring& filename); private: // Disallow instantiation and other object-based operations. @@ -102,9 +101,9 @@ class WindowsStringUtils { }; // static -inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination, +inline void WindowsStringUtils::safe_wcscpy(wchar_t* destination, size_t destination_size, - const wchar_t *source) { + const wchar_t* source) { #if _MSC_VER >= 1400 // MSVC 2005/8 wcscpy_s(destination, destination_size, source); #else // _MSC_VER >= 1400 @@ -118,9 +117,9 @@ inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination, } // static -inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination, +inline void WindowsStringUtils::safe_wcsncpy(wchar_t* destination, size_t destination_size, - const wchar_t *source, + const wchar_t* source, size_t count) { #if _MSC_VER >= 1400 // MSVC 2005/8 wcsncpy_s(destination, destination_size, source, count); diff --git a/src/common/windows/string_utils.cc b/src/common/windows/string_utils.cc index 27280003..01dca193 100644 --- a/src/common/windows/string_utils.cc +++ b/src/common/windows/string_utils.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -35,7 +34,7 @@ namespace google_breakpad { // static -wstring WindowsStringUtils::GetBaseName(const wstring &filename) { +wstring WindowsStringUtils::GetBaseName(const wstring& filename) { wstring base_name(filename); size_t slash_pos = base_name.find_last_of(L"/\\"); if (slash_pos != wstring::npos) { @@ -45,7 +44,7 @@ wstring WindowsStringUtils::GetBaseName(const wstring &filename) { } // static -bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) { +bool WindowsStringUtils::safe_mbstowcs(const string& mbs, wstring* wcs) { assert(wcs); // First, determine the length of the destination buffer. @@ -88,7 +87,7 @@ bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) { } // static -bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) { +bool WindowsStringUtils::safe_wcstombs(const wstring& wcs, string* mbs) { assert(mbs); // First, determine the length of the destination buffer. diff --git a/src/common/windows/sym_upload_v2_protocol.cc b/src/common/windows/sym_upload_v2_protocol.cc new file mode 100644 index 00000000..f2dc660c --- /dev/null +++ b/src/common/windows/sym_upload_v2_protocol.cc @@ -0,0 +1,118 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/windows/sym_upload_v2_protocol.h" + +#include <cstdio> + +#include "common/windows/http_upload.h" +#include "common/windows/symbol_collector_client.h" + +using google_breakpad::CompleteUploadResult; +using google_breakpad::HTTPUpload; +using google_breakpad::SymbolCollectorClient; +using google_breakpad::SymbolStatus; +using google_breakpad::UploadUrlResponse; +using std::wstring; + +namespace google_breakpad { + +static bool SymUploadV2ProtocolSend(const wchar_t* api_url, + const wchar_t* api_key, + int* timeout_ms, + const wstring& debug_file, + const wstring& debug_id, + const wstring& symbol_filename, + const wstring& symbol_type, + const wstring& product_name, + bool force) { + wstring url(api_url); + wstring key(api_key); + + if (!force) { + SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus( + url, key, timeout_ms, debug_file, debug_id); + if (symbolStatus == SymbolStatus::Found) { + wprintf( + L"Symbol file already exists, upload aborted." + L" Use \"-f\" to overwrite.\n"); + return true; + } else if (symbolStatus == SymbolStatus::Unknown) { + wprintf(L"Failed to get check for existing symbol.\n"); + return false; + } + } + + UploadUrlResponse uploadUrlResponse; + if (!SymbolCollectorClient::CreateUploadUrl(url, key, timeout_ms, + &uploadUrlResponse)) { + wprintf(L"Failed to create upload URL.\n"); + return false; + } + + wstring signed_url = uploadUrlResponse.upload_url; + wstring upload_key = uploadUrlResponse.upload_key; + wstring response; + int response_code; + bool success = HTTPUpload::SendPutRequest( + signed_url, symbol_filename, timeout_ms, &response, &response_code); + if (!success) { + wprintf(L"Failed to send symbol file.\n"); + wprintf(L"Response code: %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } else if (response_code == 0) { + wprintf(L"Failed to send symbol file: No response code\n"); + return false; + } else if (response_code != 200) { + wprintf(L"Failed to send symbol file: Response code %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } + + CompleteUploadResult completeUploadResult = + SymbolCollectorClient::CompleteUpload(url, key, timeout_ms, upload_key, + debug_file, debug_id, symbol_type, + product_name); + if (completeUploadResult == CompleteUploadResult::Error) { + wprintf(L"Failed to complete upload.\n"); + return false; + } else if (completeUploadResult == CompleteUploadResult::DuplicateData) { + wprintf( + L"Uploaded file checksum matched existing file checksum," + L" no change necessary.\n"); + } else { + wprintf(L"Successfully sent the symbol file.\n"); + } + + return true; +} + +} // namespace google_breakpad diff --git a/src/common/windows/sym_upload_v2_protocol.h b/src/common/windows/sym_upload_v2_protocol.h new file mode 100644 index 00000000..19e6f87a --- /dev/null +++ b/src/common/windows/sym_upload_v2_protocol.h @@ -0,0 +1,66 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_ +#define COMMON_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_ + +#include <string> + +namespace google_breakpad { + +// Sends file at |symbol_filename| using the sym-upload-v2 protocol to +// |api_url| using key |api_key|, and using identifiers |debug_file| and +// |debug_id|. |timeout_ms| is the number of milliseconds to wait before +// terminating the upload attempt. |symbol_type| is the type of the symbol +// file, which is one of: +// "BREAKPAD" +// "ELF" +// "PE" +// "MACHO" +// "DEBUG_ONLY" +// "DWP" +// "DSYM" +// "PDB" +// "SOURCE_MAP" +// If |product_name| is non-empty then it will be sent as part of the symbol +// metadata. +// If |force| is set then it will overwrite an existing file with the +// same |debug_file| and |debug_id| in the store. +bool SymUploadV2ProtocolSend(const wchar_t* api_url, + const wchar_t* api_key, + int* timeout_ms, + const std::wstring& debug_file, + const std::wstring& debug_id, + const std::wstring& symbol_filename, + const std::wstring& symbol_type, + const std::wstring& product_name, + bool force); + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_
\ No newline at end of file diff --git a/src/common/windows/symbol_collector_client.cc b/src/common/windows/symbol_collector_client.cc index 30c663ed..187b100e 100644 --- a/src/common/windows/symbol_collector_client.cc +++ b/src/common/windows/symbol_collector_client.cc @@ -12,6 +12,7 @@ namespace google_breakpad { bool SymbolCollectorClient::CreateUploadUrl( wstring& api_url, wstring& api_key, + int* timeout_ms, UploadUrlResponse *uploadUrlResponse) { wstring url = api_url + L"/v1/uploads:create" @@ -23,7 +24,7 @@ namespace google_breakpad { url, L"", L"", - NULL, + timeout_ms, &response, &response_code)) { wprintf(L"Failed to create upload url.\n"); @@ -66,17 +67,35 @@ namespace google_breakpad { CompleteUploadResult SymbolCollectorClient::CompleteUpload( wstring& api_url, wstring& api_key, + int* timeout_ms, const wstring& upload_key, const wstring& debug_file, - const wstring& debug_id) { + const wstring& debug_id, + const wstring& type, + const wstring& product_name) { wstring url = api_url + L"/v1/uploads/" + upload_key + L":complete" L"?key=" + api_key; wstring body = L"{ symbol_id: {" - L"debug_file: \"" + debug_file + L"\", " - L"debug_id: \"" + debug_id + L"\" " - L"} }"; + L"debug_file: \"" + + debug_file + + L"\", " + L"debug_id: \"" + + debug_id + + L"\" " + L"}, "; + if (!product_name.empty()) { + body += + L"metadata: {" + L"product_name: \"" + + product_name + + L"\"" + L"},"; + } + body += L"symbol_upload_type: \"" + type + + L"\", " + L"use_async_processing: true }"; wstring response; int response_code; @@ -84,7 +103,7 @@ namespace google_breakpad { url, body, L"application/json", - NULL, + timeout_ms, &response, &response_code)) { wprintf(L"Failed to complete upload.\n"); @@ -116,6 +135,7 @@ namespace google_breakpad { SymbolStatus SymbolCollectorClient::CheckSymbolStatus( wstring& api_url, wstring& api_key, + int* timeout_ms, const wstring& debug_file, const wstring& debug_id) { wstring response; @@ -126,7 +146,7 @@ namespace google_breakpad { if (!HTTPUpload::SendGetRequest( url, - NULL, + timeout_ms, &response, &response_code)) { wprintf(L"Failed to check symbol status.\n"); diff --git a/src/common/windows/symbol_collector_client.h b/src/common/windows/symbol_collector_client.h index 30e0cb32..4e9bf3b6 100644 --- a/src/common/windows/symbol_collector_client.h +++ b/src/common/windows/symbol_collector_client.h @@ -1,5 +1,4 @@ -// Copyright (c) 2019, Google Inc. -// All rights reserved. +// Copyright 2019 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -64,22 +63,26 @@ namespace google_breakpad { static bool CreateUploadUrl( wstring& api_url, wstring& api_key, + int* timeout_ms, UploadUrlResponse *uploadUrlResponse); // Notify the API that symbol file upload is finished and its contents // are ready to be read and/or used for further processing. - static CompleteUploadResult CompleteUpload( - wstring& api_url, - wstring& api_key, - const wstring& upload_key, - const wstring& debug_file, - const wstring& debug_id); + static CompleteUploadResult CompleteUpload(wstring& api_url, + wstring& api_key, + int* timeout_ms, + const wstring& upload_key, + const wstring& debug_file, + const wstring& debug_id, + const wstring& type, + const wstring& product_name); // Returns whether or not a symbol file corresponding to the debug_file/ // debug_id pair is already present in symbol storage. static SymbolStatus CheckSymbolStatus( wstring& api_url, wstring& api_key, + int* timeout_ms, const wstring& debug_file, const wstring& debug_id); }; diff --git a/src/config.h.in b/src/config.h.in index 0553a24b..8fd7b0aa 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -6,8 +6,8 @@ /* Define to 1 if you have the <a.out.h> header file. */ #undef HAVE_A_OUT_H -/* define if the compiler supports basic C++11 syntax */ -#undef HAVE_CXX11 +/* define if the compiler supports basic C++17 syntax */ +#undef HAVE_CXX17 /* Define to 1 if you have the `getcontext' function. */ #undef HAVE_GETCONTEXT @@ -18,15 +18,24 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if you have the <memory.h> header file. */ -#undef HAVE_MEMORY_H +/* Define to 1 if you have the `rustc_demangle' library (-lrustc_demangle). */ +#undef HAVE_LIBRUSTC_DEMANGLE + +/* Define to 1 if you have the `memfd_create' function. */ +#undef HAVE_MEMFD_CREATE /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD +/* Define to 1 if you have the <rustc_demangle.h> header file. */ +#undef HAVE_RUSTC_DEMANGLE_H + /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the <stdio.h> header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H @@ -36,6 +45,9 @@ /* Define to 1 if you have the <string.h> header file. */ #undef HAVE_STRING_H +/* Define to 1 if you have the <sys/mman.h> header file. */ +#undef HAVE_SYS_MMAN_H + /* Define to 1 if you have the <sys/random.h> header file. */ #undef HAVE_SYS_RANDOM_H @@ -76,17 +88,14 @@ your system. */ #undef PTHREAD_CREATE_JOINABLE -/* Define to 1 if you have the ANSI C header files. */ +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION -/* Enable large inode numbers on Mac OS X 10.5. */ -#ifndef _DARWIN_USE_64_BIT_INODE -# define _DARWIN_USE_64_BIT_INODE 1 -#endif - /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS diff --git a/src/google_breakpad/common/breakpad_types.h b/src/google_breakpad/common/breakpad_types.h index d8828043..efd94e9d 100644 --- a/src/google_breakpad/common/breakpad_types.h +++ b/src/google_breakpad/common/breakpad_types.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_cpu_amd64.h b/src/google_breakpad/common/minidump_cpu_amd64.h index 4256706d..308f21ec 100644 --- a/src/google_breakpad/common/minidump_cpu_amd64.h +++ b/src/google_breakpad/common/minidump_cpu_amd64.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_cpu_arm.h b/src/google_breakpad/common/minidump_cpu_arm.h index 6a711383..2ac0623e 100644 --- a/src/google_breakpad/common/minidump_cpu_arm.h +++ b/src/google_breakpad/common/minidump_cpu_arm.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2009, Google Inc. - * All rights reserved. +/* Copyright 2009 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_cpu_arm64.h b/src/google_breakpad/common/minidump_cpu_arm64.h index 0411bebb..96f26332 100644 --- a/src/google_breakpad/common/minidump_cpu_arm64.h +++ b/src/google_breakpad/common/minidump_cpu_arm64.h @@ -1,5 +1,4 @@ -/* Copyright 2013 Google Inc. - * All rights reserved. +/* Copyright 2013 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_cpu_mips.h b/src/google_breakpad/common/minidump_cpu_mips.h index f4e2b589..91b700af 100644 --- a/src/google_breakpad/common/minidump_cpu_mips.h +++ b/src/google_breakpad/common/minidump_cpu_mips.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2013, Google Inc. - * All rights reserved. +/* Copyright 2013 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_cpu_ppc.h b/src/google_breakpad/common/minidump_cpu_ppc.h index b24cc424..17a71af7 100644 --- a/src/google_breakpad/common/minidump_cpu_ppc.h +++ b/src/google_breakpad/common/minidump_cpu_ppc.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_cpu_ppc64.h b/src/google_breakpad/common/minidump_cpu_ppc64.h index 61f41938..75638b5d 100644 --- a/src/google_breakpad/common/minidump_cpu_ppc64.h +++ b/src/google_breakpad/common/minidump_cpu_ppc64.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2008, Google Inc. - * All rights reserved. +/* Copyright 2008 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_cpu_riscv.h b/src/google_breakpad/common/minidump_cpu_riscv.h new file mode 100644 index 00000000..94d06117 --- /dev/null +++ b/src/google_breakpad/common/minidump_cpu_riscv.h @@ -0,0 +1,168 @@ +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on RISCV and RISCV64. These files may be read on any platform + * provided that the alignments of these structures on the processing system + * are identical to the alignments of these structures on the producing + * system. For this reason, precise-sized types are used. The structures + * defined by this file have been laid out to minimize alignment problems by + * ensuring that all members are aligned on their natural boundaries. + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Iacopo Colonnelli + */ + +/* + * RISCV and RISCV64 support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV_H__ + +#include "google_breakpad/common/breakpad_types.h" + +#define MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT 32 +#if defined(__riscv) +# if __riscv_flen == 32 +typedef uint32_t riscv_fpr_size; +# elif __riscv_flen == 64 +typedef uint64_t riscv_fpr_size; +# elif __riscv_flen == 128 +typedef uint128_struct riscv_fpr_size; +# else +# error "Unexpected __riscv_flen" +# endif +#else +typedef uint32_t riscv_fpr_size; +#endif + +#define MD_CONTEXT_RISCV_GPR_COUNT 32 + +typedef struct { + /* 32 floating point registers, f0 .. f31. */ + riscv_fpr_size regs[MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT]; + uint32_t fpcsr; +} MDFloatingSaveAreaRISCV; + +enum MDRISCVRegisterNumbers { + MD_CONTEXT_RISCV_REG_PC = 0, + MD_CONTEXT_RISCV_REG_RA = 1, + MD_CONTEXT_RISCV_REG_SP = 2, +}; + +/* For (MDRawContextRISCV).context_flags. These values indicate the type of + * context stored in the structure. */ +#define MD_CONTEXT_RISCV 0x00800000 +#define MD_CONTEXT_RISCV_INTEGER (MD_CONTEXT_RISCV | 0x00000001) +#define MD_CONTEXT_RISCV_FLOATING_POINT (MD_CONTEXT_RISCV | 0x00000004) +#define MD_CONTEXT_RISCV_FULL (MD_CONTEXT_RISCV_INTEGER | \ + MD_CONTEXT_RISCV_FLOATING_POINT) + +typedef struct { + /* Determines which fields of this struct are populated */ + uint32_t context_flags; + + uint32_t pc; + uint32_t ra; + uint32_t sp; + uint32_t gp; + uint32_t tp; + uint32_t t0; + uint32_t t1; + uint32_t t2; + uint32_t s0; + uint32_t s1; + uint32_t a0; + uint32_t a1; + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + uint32_t s2; + uint32_t s3; + uint32_t s4; + uint32_t s5; + uint32_t s6; + uint32_t s7; + uint32_t s8; + uint32_t s9; + uint32_t s10; + uint32_t s11; + uint32_t t3; + uint32_t t4; + uint32_t t5; + uint32_t t6; + + MDFloatingSaveAreaRISCV float_save; +} MDRawContextRISCV; + +/* For (MDRawContextRISCV64).context_flags. These values indicate the type of + * context stored in the structure. */ +#define MD_CONTEXT_RISCV64 0x08000000 +#define MD_CONTEXT_RISCV64_INTEGER (MD_CONTEXT_RISCV64 | 0x00000001) +#define MD_CONTEXT_RISCV64_FLOATING_POINT (MD_CONTEXT_RISCV64 | 0x00000004) +#define MD_CONTEXT_RISCV64_FULL (MD_CONTEXT_RISCV64_INTEGER | \ + MD_CONTEXT_RISCV64_FLOATING_POINT) + +typedef struct { + /* Determines which fields of this struct are populated */ + uint32_t context_flags; + + uint64_t pc; + uint64_t ra; + uint64_t sp; + uint64_t gp; + uint64_t tp; + uint64_t t0; + uint64_t t1; + uint64_t t2; + uint64_t s0; + uint64_t s1; + uint64_t a0; + uint64_t a1; + uint64_t a2; + uint64_t a3; + uint64_t a4; + uint64_t a5; + uint64_t a6; + uint64_t a7; + uint64_t s2; + uint64_t s3; + uint64_t s4; + uint64_t s5; + uint64_t s6; + uint64_t s7; + uint64_t s8; + uint64_t s9; + uint64_t s10; + uint64_t s11; + uint64_t t3; + uint64_t t4; + uint64_t t5; + uint64_t t6; + + MDFloatingSaveAreaRISCV float_save; +} MDRawContextRISCV64; + + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV_H__ */ diff --git a/src/google_breakpad/common/minidump_cpu_sparc.h b/src/google_breakpad/common/minidump_cpu_sparc.h index 95c08b17..6452588a 100644 --- a/src/google_breakpad/common/minidump_cpu_sparc.h +++ b/src/google_breakpad/common/minidump_cpu_sparc.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_cpu_x86.h b/src/google_breakpad/common/minidump_cpu_x86.h index e09cb7cb..add1e225 100644 --- a/src/google_breakpad/common/minidump_cpu_x86.h +++ b/src/google_breakpad/common/minidump_cpu_x86.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_exception_fuchsia.h b/src/google_breakpad/common/minidump_exception_fuchsia.h index f26a8a2a..169094b2 100644 --- a/src/google_breakpad/common/minidump_exception_fuchsia.h +++ b/src/google_breakpad/common/minidump_exception_fuchsia.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2019, Google Inc. - * All rights reserved. +/* Copyright 2019 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_exception_linux.h b/src/google_breakpad/common/minidump_exception_linux.h index 6138d5d7..354cdd6b 100644 --- a/src/google_breakpad/common/minidump_exception_linux.h +++ b/src/google_breakpad/common/minidump_exception_linux.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_exception_mac.h b/src/google_breakpad/common/minidump_exception_mac.h index fadbf4ef..acfafaa0 100644 --- a/src/google_breakpad/common/minidump_exception_mac.h +++ b/src/google_breakpad/common/minidump_exception_mac.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * @@ -66,9 +65,15 @@ typedef enum { MD_EXCEPTION_MAC_MACH_SYSCALL = 8, /* EXC_MACH_SYSCALL */ MD_EXCEPTION_MAC_RPC_ALERT = 9, + /* EXC_RESOURCE */ + MD_EXCEPTION_MAC_RESOURCE = 11, + /* EXC_GUARD */ + MD_EXCEPTION_MAC_GUARD = 12, /* EXC_RPC_ALERT */ - MD_EXCEPTION_MAC_SIMULATED = 0x43507378 + MD_EXCEPTION_MAC_SIMULATED = 0x43507378, /* Fake exception code used by Crashpad's SimulateCrash ('CPsx'). */ + MD_NS_EXCEPTION_SIMULATED = 0x43506E78 + /* Fake exception code used by Crashpad's uncaught exceptions ('CPnx'). */ } MDExceptionMac; /* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X diff --git a/src/google_breakpad/common/minidump_exception_ps3.h b/src/google_breakpad/common/minidump_exception_ps3.h index adff5a6b..dd87d7a7 100644 --- a/src/google_breakpad/common/minidump_exception_ps3.h +++ b/src/google_breakpad/common/minidump_exception_ps3.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2013, Google Inc. - * All rights reserved. +/* Copyright 2013 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_exception_solaris.h b/src/google_breakpad/common/minidump_exception_solaris.h index f18ddf42..16641919 100644 --- a/src/google_breakpad/common/minidump_exception_solaris.h +++ b/src/google_breakpad/common/minidump_exception_solaris.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/google_breakpad/common/minidump_exception_win32.h b/src/google_breakpad/common/minidump_exception_win32.h index 4b5d57c8..0431a3fa 100644 --- a/src/google_breakpad/common/minidump_exception_win32.h +++ b/src/google_breakpad/common/minidump_exception_win32.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * @@ -2266,4 +2265,77 @@ typedef enum { MD_IN_PAGE_ERROR_WIN_EXEC = 8 } MDInPageErrorTypeWin; +// These constants are defined in winnt.h and are used with the +// STATUS_STACK_BUFFER_OVERRUN exception as exception subcodes. +typedef enum { + MD_FAST_FAIL_LEGACY_GS_VIOLATION = 0, + MD_FAST_FAIL_VTGUARD_CHECK_FAILURE = 1, + MD_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE = 2, + MD_FAST_FAIL_CORRUPT_LIST_ENTRY = 3, + MD_FAST_FAIL_INCORRECT_STACK = 4, + MD_FAST_FAIL_INVALID_ARG = 5, + MD_FAST_FAIL_GS_COOKIE_INIT = 6, + MD_FAST_FAIL_FATAL_APP_EXIT = 7, + MD_FAST_FAIL_RANGE_CHECK_FAILURE = 8, + MD_FAST_FAIL_UNSAFE_REGISTRY_ACCESS = 9, + MD_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE = 10, + MD_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE = 11, + MD_FAST_FAIL_INVALID_FIBER_SWITCH = 12, + MD_FAST_FAIL_INVALID_SET_OF_CONTEXT = 13, + MD_FAST_FAIL_INVALID_REFERENCE_COUNT = 14, + MD_FAST_FAIL_INVALID_JUMP_BUFFER = 18, + MD_FAST_FAIL_MRDATA_MODIFIED = 19, + MD_FAST_FAIL_CERTIFICATION_FAILURE = 20, + MD_FAST_FAIL_INVALID_EXCEPTION_CHAIN = 21, + MD_FAST_FAIL_CRYPTO_LIBRARY = 22, + MD_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT = 23, + MD_FAST_FAIL_INVALID_IMAGE_BASE = 24, + MD_FAST_FAIL_DLOAD_PROTECTION_FAILURE = 25, + MD_FAST_FAIL_UNSAFE_EXTENSION_CALL = 26, + MD_FAST_FAIL_DEPRECATED_SERVICE_INVOKED = 27, + MD_FAST_FAIL_INVALID_BUFFER_ACCESS = 28, + MD_FAST_FAIL_INVALID_BALANCED_TREE = 29, + MD_FAST_FAIL_INVALID_NEXT_THREAD = 30, + MD_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED = 31, + MD_FAST_FAIL_APCS_DISABLED = 32, + MD_FAST_FAIL_INVALID_IDLE_STATE = 33, + MD_FAST_FAIL_MRDATA_PROTECTION_FAILURE = 34, + MD_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION = 35, + MD_FAST_FAIL_INVALID_LOCK_STATE = 36, + MD_FAST_FAIL_GUARD_JUMPTABLE = 37, + MD_FAST_FAIL_INVALID_LONGJUMP_TARGET = 38, + MD_FAST_FAIL_INVALID_DISPATCH_CONTEXT = 39, + MD_FAST_FAIL_INVALID_THREAD = 40, + MD_FAST_FAIL_INVALID_SYSCALL_NUMBER = 41, + MD_FAST_FAIL_INVALID_FILE_OPERATION = 42, + MD_FAST_FAIL_LPAC_ACCESS_DENIED = 43, + MD_FAST_FAIL_GUARD_SS_FAILURE = 44, + MD_FAST_FAIL_LOADER_CONTINUITY_FAILURE = 45, + MD_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE = 46, + MD_FAST_FAIL_INVALID_CONTROL_STACK = 47, + MD_FAST_FAIL_SET_CONTEXT_DENIED = 48, + MD_FAST_FAIL_INVALID_IAT = 49, + MD_FAST_FAIL_HEAP_METADATA_CORRUPTION = 50, + MD_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION = 51, + MD_FAST_FAIL_LOW_LABEL_ACCESS_DENIED = 52, + MD_FAST_FAIL_ENCLAVE_CALL_FAILURE = 53, + MD_FAST_FAIL_UNHANDLED_LSS_EXCEPTON = 54, + MD_FAST_FAIL_ADMINLESS_ACCESS_DENIED = 55, + MD_FAST_FAIL_UNEXPECTED_CALL = 56, + MD_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS = 57, + MD_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR = 58, + MD_FAST_FAIL_FLAGS_CORRUPTION = 59, + MD_FAST_FAIL_VEH_CORRUPTION = 60, + MD_FAST_FAIL_ETW_CORRUPTION = 61, + MD_FAST_FAIL_RIO_ABORT = 62, + MD_FAST_FAIL_INVALID_PFN = 63, + MD_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG = 64, + MD_FAST_FAIL_CAST_GUARD = 65, + MD_FAST_FAIL_HOST_VISIBILITY_CHANGE = 66, + MD_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST = 67, + MD_FAST_FAIL_PATCH_CALLBACK_FAILED = 68, + MD_FAST_FAIL_NTDLL_PATCH_FAILED = 69, + MD_FAST_FAIL_INVALID_FLS_DATA = 70 +} MDFastFailSubcodeTypeWin; + #endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */ diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h index 6eceddbb..1526afce 100644 --- a/src/google_breakpad/common/minidump_format.h +++ b/src/google_breakpad/common/minidump_format.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2006, Google Inc. - * All rights reserved. +/* Copyright 2006 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * @@ -118,6 +117,7 @@ typedef struct { #include "minidump_cpu_mips.h" #include "minidump_cpu_ppc.h" #include "minidump_cpu_ppc64.h" +#include "minidump_cpu_riscv.h" #include "minidump_cpu_sparc.h" #include "minidump_cpu_x86.h" @@ -239,6 +239,15 @@ typedef struct { MDRVA rva; } MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */ +/* An MDRVA64 is an 64-bit offset into the minidump file. The beginning of the + * MDRawHeader is at offset 0. */ +typedef uint64_t MDRVA64; /* RVA64 */ + +typedef struct { + uint64_t data_size; + MDRVA64 rva; +} MDLocationDescriptor64; /* MINIDUMP_LOCATION_DESCRIPTOR64 */ + typedef struct { /* The base address of the memory range on the host that produced the @@ -332,6 +341,7 @@ typedef enum { MD_JAVASCRIPT_DATA_STREAM = 20, MD_SYSTEM_MEMORY_INFO_STREAM = 21, MD_PROCESS_VM_COUNTERS_STREAM = 22, + MD_THREAD_NAME_LIST_STREAM = 24, /* MDRawThreadNameList */ MD_LAST_RESERVED_STREAM = 0x0000ffff, /* Breakpad extension types. 0x4767 = "Gg" */ @@ -382,6 +392,20 @@ typedef struct { static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList, threads[0]); +#pragma pack(push, 4) +typedef struct { + uint32_t thread_id; + MDRVA64 thread_name_rva; /* MDString */ +} MDRawThreadName; /* MINIDUMP_THREAD_NAME */ + +typedef struct { + uint32_t number_of_thread_names; + MDRawThreadName thread_names[1]; +} MDRawThreadNameList; /* MINIDUMP_THREAD_NAME_LIST */ +#pragma pack(pop) + +static const size_t MDRawThreadNameList_minsize = + offsetof(MDRawThreadNameList, thread_names[0]); typedef struct { uint64_t base_of_image; @@ -529,7 +553,7 @@ static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList, memory_ranges[0]); -#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15 +#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15u typedef struct { uint32_t exception_code; /* Windows: MDExceptionCodeWin, @@ -660,6 +684,8 @@ typedef enum { MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */ MD_CPU_ARCHITECTURE_ARM64_OLD = 0x8003, /* Breakpad-defined value for ARM64 */ MD_CPU_ARCHITECTURE_MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */ + MD_CPU_ARCHITECTURE_RISCV = 0x8005, /* Breakpad-defined value for RISCV */ + MD_CPU_ARCHITECTURE_RISCV64 = 0x8006, /* Breakpad-defined value for RISCV64 */ MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ } MDCPUArchitecture; @@ -1071,9 +1097,22 @@ typedef struct { } MDRawSimpleStringDictionary; typedef struct { + MDRVA name; + uint16_t type; + uint16_t reserved; + MDRVA value; +} MDRawCrashpadAnnotation; + +typedef struct { + uint32_t count; + MDLocationDescriptor objects[0]; /* MDRawCrashpadAnnotation */ +} MDRawCrashpadAnnotationList; + +typedef struct { uint32_t version; MDLocationDescriptor list_annotations; MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */ + MDLocationDescriptor annotation_objects; /* MDRawCrashpadAnnotationList */ } MDRawModuleCrashpadInfo; typedef struct { @@ -1092,6 +1131,8 @@ typedef struct { MDGUID client_id; MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */ MDLocationDescriptor module_list; /* MDRawModuleCrashpadInfoList */ + uint32_t reserved; + uint64_t address_mask; } MDRawCrashpadInfo; #if defined(_MSC_VER) diff --git a/src/google_breakpad/common/minidump_size.h b/src/google_breakpad/common/minidump_size.h index fae57923..f9abdc36 100644 --- a/src/google_breakpad/common/minidump_size.h +++ b/src/google_breakpad/common/minidump_size.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/basic_source_line_resolver.h b/src/google_breakpad/processor/basic_source_line_resolver.h index 91fb7841..e86b28d2 100644 --- a/src/google_breakpad/processor/basic_source_line_resolver.h +++ b/src/google_breakpad/processor/basic_source_line_resolver.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,6 +39,7 @@ #include <map> #include <string> +#include <vector> #include "common/using_std_string.h" #include "google_breakpad/processor/source_line_resolver_base.h" @@ -84,15 +84,50 @@ class BasicSourceLineResolver : public SourceLineResolverBase { // Helper class, containing useful methods for parsing of Breakpad symbol files. class SymbolParseHelper { public: + using MemAddr = SourceLineResolverInterface::MemAddr; + // Parses a |file_line| declaration. Returns true on success. // Format: FILE <id> <filename>. // Notice, that this method modifies the input |file_line| which is why it // can't be const. On success, <id>, and <filename> are stored in |*index|, // and |*filename|. No allocation is done, |*filename| simply points inside // |file_line|. - static bool ParseFile(char *file_line, // in - long *index, // out - char **filename); // out + static bool ParseFile(char* file_line, // in + long* index, // out + char** filename); // out + + // Parses a |inline_origin_line| declaration. Returns true on success. + // Old Format: INLINE_ORIGIN <origin_id> <file_id> <name>. + // New Format: INLINE_ORIGIN <origin_id> <name>. + // Notice, that this method modifies the input |inline_origin_line| which is + // why it can't be const. On success, <has_file_id>, <origin_id>, <file_id> + // and <name> are stored in |*has_file_id*|, |*origin_id|, |*file_id|, and + // |*name|. No allocation is done, |*name| simply points inside + // |inline_origin_line|. + static bool ParseInlineOrigin(char* inline_origin_line, // in + bool* has_file_id, // out + long* origin_id, // out + long* file_id, // out + char** name); // out + + // Parses a |inline| declaration. Returns true on success. + // Old Format: INLINE <inline_nest_level> <call_site_line> <origin_id> + // [<address> <size>]+ + // New Format: INLINE <inline_nest_level> <call_site_line> <call_site_file_id> + // <origin_id> [<address> <size>]+ + // Notice, that this method modifies the input |inline| + // which is why it can't be const. On success, <has_call_site_file_id>, + // <inline_nest_level>, <call_site_line> and <origin_id> are stored in + // |*has_call_site_file_id*|, |*inline_nest_level|, |*call_site_line|, and + // |*origin_id|, and all pairs of (<address>, <size>) are added into ranges. + static bool ParseInline( + char* inline_line, // in + bool* has_call_site_file_id, // out + long* inline_nest_level, // out + long* call_site_line, // out + long* call_site_file_id, // out + long* origin_id, // out + std::vector<std::pair<MemAddr, MemAddr>>* ranges); // out // Parses a |function_line| declaration. Returns true on success. // Format: FUNC [<multiple>] <address> <size> <stack_param_size> <name>. @@ -101,12 +136,12 @@ class SymbolParseHelper { // <stack_param_size>, and <name> are stored in |*is_multiple|, |*address|, // |*size|, |*stack_param_size|, and |*name|. No allocation is done, |*name| // simply points inside |function_line|. - static bool ParseFunction(char *function_line, // in - bool *is_multiple, // out - uint64_t *address, // out - uint64_t *size, // out - long *stack_param_size, // out - char **name); // out + static bool ParseFunction(char* function_line, // in + bool* is_multiple, // out + uint64_t* address, // out + uint64_t* size, // out + long* stack_param_size, // out + char** name); // out // Parses a |line| declaration. Returns true on success. // Format: <address> <size> <line number> <source file id> @@ -114,11 +149,11 @@ class SymbolParseHelper { // it can't be const. On success, <address>, <size>, <line number>, and // <source file id> are stored in |*address|, |*size|, |*line_number|, and // |*source_file|. - static bool ParseLine(char *line_line, // in - uint64_t *address, // out - uint64_t *size, // out - long *line_number, // out - long *source_file); // out + static bool ParseLine(char* line_line, // in + uint64_t* address, // out + uint64_t* size, // out + long* line_number, // out + long* source_file); // out // Parses a |public_line| declaration. Returns true on success. // Format: PUBLIC [<multiple>] <address> <stack_param_size> <name> @@ -127,15 +162,15 @@ class SymbolParseHelper { // <stack_param_size>, <name> are stored in |*is_multiple|, |*address|, // |*stack_param_size|, and |*name|. No allocation is done, |*name| simply // points inside |public_line|. - static bool ParsePublicSymbol(char *public_line, // in - bool *is_multiple, // out - uint64_t *address, // out - long *stack_param_size, // out - char **name); // out + static bool ParsePublicSymbol(char* public_line, // in + bool* is_multiple, // out + uint64_t* address, // out + long* stack_param_size, // out + char** name); // out private: // Used for success checks after strtoull and strtol. - static bool IsValidAfterNumber(char *after_number); + static bool IsValidAfterNumber(char* after_number); // Only allow static methods. SymbolParseHelper(); diff --git a/src/google_breakpad/processor/call_stack.h b/src/google_breakpad/processor/call_stack.h index c5914231..9bf062f8 100644 --- a/src/google_breakpad/processor/call_stack.h +++ b/src/google_breakpad/processor/call_stack.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/code_module.h b/src/google_breakpad/processor/code_module.h index 29b8d9c9..76bbfab8 100644 --- a/src/google_breakpad/processor/code_module.h +++ b/src/google_breakpad/processor/code_module.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/code_modules.h b/src/google_breakpad/processor/code_modules.h index 74f113c1..7538328b 100644 --- a/src/google_breakpad/processor/code_modules.h +++ b/src/google_breakpad/processor/code_modules.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/dump_context.h b/src/google_breakpad/processor/dump_context.h index df80bf7e..7a1c643e 100644 --- a/src/google_breakpad/processor/dump_context.h +++ b/src/google_breakpad/processor/dump_context.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014 Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -54,14 +53,16 @@ class DumpContext : public DumpObject { // Returns raw CPU-specific context data for the named CPU type. If the // context data does not match the CPU type or does not exist, returns NULL. - const MDRawContextAMD64* GetContextAMD64() const; - const MDRawContextARM* GetContextARM() const; - const MDRawContextARM64* GetContextARM64() const; - const MDRawContextMIPS* GetContextMIPS() const; - const MDRawContextPPC* GetContextPPC() const; - const MDRawContextPPC64* GetContextPPC64() const; - const MDRawContextSPARC* GetContextSPARC() const; - const MDRawContextX86* GetContextX86() const; + const MDRawContextAMD64* GetContextAMD64() const; + const MDRawContextARM* GetContextARM() const; + const MDRawContextARM64* GetContextARM64() const; + const MDRawContextMIPS* GetContextMIPS() const; + const MDRawContextPPC* GetContextPPC() const; + const MDRawContextPPC64* GetContextPPC64() const; + const MDRawContextSPARC* GetContextSPARC() const; + const MDRawContextX86* GetContextX86() const; + const MDRawContextRISCV* GetContextRISCV() const; + const MDRawContextRISCV64* GetContextRISCV64() const; // A convenience method to get the instruction pointer out of the // MDRawContext, since it varies per-CPU architecture. @@ -87,6 +88,8 @@ class DumpContext : public DumpObject { void SetContextARM(MDRawContextARM* arm); void SetContextARM64(MDRawContextARM64* arm64); void SetContextMIPS(MDRawContextMIPS* ctx_mips); + void SetContextRISCV(MDRawContextRISCV* riscv); + void SetContextRISCV64(MDRawContextRISCV64* riscv64); // Free the CPU-specific context structure. void FreeContext(); @@ -94,17 +97,19 @@ class DumpContext : public DumpObject { private: // The CPU-specific context structure. union { - MDRawContextBase* base; - MDRawContextX86* x86; - MDRawContextPPC* ppc; - MDRawContextPPC64* ppc64; - MDRawContextAMD64* amd64; + MDRawContextBase* base; + MDRawContextX86* x86; + MDRawContextPPC* ppc; + MDRawContextPPC64* ppc64; + MDRawContextAMD64* amd64; // on Solaris SPARC, sparc is defined as a numeric constant, // so variables can NOT be named as sparc - MDRawContextSPARC* ctx_sparc; - MDRawContextARM* arm; - MDRawContextARM64* arm64; - MDRawContextMIPS* ctx_mips; + MDRawContextSPARC* ctx_sparc; + MDRawContextARM* arm; + MDRawContextARM64* arm64; + MDRawContextMIPS* ctx_mips; + MDRawContextRISCV* riscv; + MDRawContextRISCV64* riscv64; } context_; // Store this separately because of the weirdo AMD64 context diff --git a/src/google_breakpad/processor/dump_object.h b/src/google_breakpad/processor/dump_object.h index 112f687f..0b1f4884 100644 --- a/src/google_breakpad/processor/dump_object.h +++ b/src/google_breakpad/processor/dump_object.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014 Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/exception_record.h b/src/google_breakpad/processor/exception_record.h index eac6c90a..aa2b0de3 100644 --- a/src/google_breakpad/processor/exception_record.h +++ b/src/google_breakpad/processor/exception_record.h @@ -1,5 +1,4 @@ -// Copyright (c) 2019 Google Inc. -// All rights reserved. +// Copyright 2019 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/exploitability.h b/src/google_breakpad/processor/exploitability.h index 014413c9..0b51ba13 100644 --- a/src/google_breakpad/processor/exploitability.h +++ b/src/google_breakpad/processor/exploitability.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/fast_source_line_resolver.h b/src/google_breakpad/processor/fast_source_line_resolver.h index fdf91077..11cec75e 100644 --- a/src/google_breakpad/processor/fast_source_line_resolver.h +++ b/src/google_breakpad/processor/fast_source_line_resolver.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -79,6 +78,8 @@ class FastSourceLineResolver : public SourceLineResolverBase { // SourceLineResolverBase. struct Line; struct Function; + struct Inline; + struct InlineOrigin; struct PublicSymbol; class Module; diff --git a/src/google_breakpad/processor/memory_region.h b/src/google_breakpad/processor/memory_region.h index 30f88df4..378fcc39 100644 --- a/src/google_breakpad/processor/memory_region.h +++ b/src/google_breakpad/processor/memory_region.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/microdump.h b/src/google_breakpad/processor/microdump.h index 02ebdcd7..7c2f3e66 100644 --- a/src/google_breakpad/processor/microdump.h +++ b/src/google_breakpad/processor/microdump.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014 Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/microdump_processor.h b/src/google_breakpad/processor/microdump_processor.h index 60d14a54..abf468f4 100644 --- a/src/google_breakpad/processor/microdump_processor.h +++ b/src/google_breakpad/processor/microdump_processor.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h index d712cb66..934a0e3e 100644 --- a/src/google_breakpad/processor/minidump.h +++ b/src/google_breakpad/processor/minidump.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -291,7 +290,7 @@ class MinidumpThread : public MinidumpObject { // so a special getter is provided to retrieve this data from the // MDRawThread structure. Returns false if the thread ID cannot be // determined. - virtual bool GetThreadID(uint32_t *thread_id) const; + virtual bool GetThreadID(uint32_t* thread_id) const; // Print a human-readable representation of the object to stdout. void Print(); @@ -370,6 +369,86 @@ class MinidumpThreadList : public MinidumpStream { DISALLOW_COPY_AND_ASSIGN(MinidumpThreadList); }; +// MinidumpThreadName contains the name of a thread. +class MinidumpThreadName : public MinidumpObject { + public: + virtual ~MinidumpThreadName(); + + const MDRawThreadName* thread_name() const { + return valid_ ? &thread_name_ : NULL; + } + + // Gets the thread ID. + virtual bool GetThreadID(uint32_t* thread_id) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + // Returns the name of the thread. + virtual std::string GetThreadName() const; + + protected: + explicit MinidumpThreadName(Minidump* minidump); + + private: + // These objects are managed by MinidumpThreadNameList. + friend class MinidumpThreadNameList; + + // This works like MinidumpStream::Read, but is driven by + // MinidumpThreadNameList. No size checking is done, because + // MinidumpThreadNameList handles that directly. + bool Read(); + + // Reads indirectly-referenced data, including the thread name. + bool ReadAuxiliaryData(); + + // True after a successful Read. This is different from valid_, which is not + // set true until ReadAuxiliaryData also completes successfully. + // thread_name_valid_ is only used by ReadAuxiliaryData and the functions it + // calls to determine whether the object is ready for auxiliary data to be + // read. + bool thread_name_valid_; + + MDRawThreadName thread_name_; + + // Cached thread name. + const string* name_; +}; + +// MinidumpThreadNameList contains all of the names of the threads (as +// MinidumpThreadNames) in a process. +class MinidumpThreadNameList : public MinidumpStream { + public: + virtual ~MinidumpThreadNameList(); + + virtual unsigned int thread_name_count() const { + return valid_ ? thread_name_count_ : 0; + } + + // Sequential access to thread names. + virtual MinidumpThreadName* GetThreadNameAtIndex(unsigned int index) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpThreadNameList(Minidump* aMinidump); + + private: + friend class Minidump; + + typedef vector<MinidumpThreadName> MinidumpThreadNames; + + static const uint32_t kStreamType = MD_THREAD_NAME_LIST_STREAM; + + bool Read(uint32_t aExpectedSize) override; + + // The list of thread names. + MinidumpThreadNames* thread_names_; + uint32_t thread_name_count_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpThreadNameList); +}; // MinidumpModule wraps MDRawModule, which contains information about loaded // code modules. Access is provided to various data referenced indirectly @@ -549,9 +628,9 @@ class MinidumpModuleList : public MinidumpStream, static uint32_t max_modules_; // Access to modules using addresses as the key. - RangeMap<uint64_t, unsigned int> *range_map_; + RangeMap<uint64_t, unsigned int>* range_map_; - MinidumpModules *modules_; + MinidumpModules* modules_; uint32_t module_count_; DISALLOW_COPY_AND_ASSIGN(MinidumpModuleList); @@ -606,16 +685,16 @@ class MinidumpMemoryList : public MinidumpStream { static uint32_t max_regions_; // Access to memory regions using addresses as the key. - RangeMap<uint64_t, unsigned int> *range_map_; + RangeMap<uint64_t, unsigned int>* range_map_; // The list of descriptors. This is maintained separately from the list // of regions, because MemoryRegion doesn't own its MemoryDescriptor, it // maintains a pointer to it. descriptors_ provides the storage for this // purpose. - MemoryDescriptors *descriptors_; + MemoryDescriptors* descriptors_; // The list of regions. - MemoryRegions *regions_; + MemoryRegions* regions_; uint32_t region_count_; DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryList); @@ -640,7 +719,7 @@ class MinidumpException : public MinidumpStream { // so a special getter is provided to retrieve this data from the // MDRawExceptionStream structure. Returns false if the thread ID cannot // be determined. - bool GetThreadID(uint32_t *thread_id) const; + bool GetThreadID(uint32_t* thread_id) const; MinidumpContext* GetContext(); @@ -862,9 +941,9 @@ class MinidumpUnloadedModuleList : public MinidumpStream, static uint32_t max_modules_; // Access to module indices using addresses as the key. - RangeMap<uint64_t, unsigned int> *range_map_; + RangeMap<uint64_t, unsigned int>* range_map_; - MinidumpUnloadedModules *unloaded_modules_; + MinidumpUnloadedModules* unloaded_modules_; uint32_t module_count_; DISALLOW_COPY_AND_ASSIGN(MinidumpUnloadedModuleList); @@ -919,8 +998,8 @@ class MinidumpBreakpadInfo : public MinidumpStream { // treatment, so special getters are provided to retrieve this data from // the MDRawBreakpadInfo structure. The getters return false if the thread // IDs cannot be determined. - bool GetDumpThreadID(uint32_t *thread_id) const; - bool GetRequestingThreadID(uint32_t *thread_id) const; + bool GetDumpThreadID(uint32_t* thread_id) const; + bool GetRequestingThreadID(uint32_t* thread_id) const; // Print a human-readable representation of the object to stdout. void Print(); @@ -1003,7 +1082,7 @@ class MinidumpMemoryInfoList : public MinidumpStream { bool Read(uint32_t expected_size) override; // Access to memory info using addresses as the key. - RangeMap<uint64_t, unsigned int> *range_map_; + RangeMap<uint64_t, unsigned int>* range_map_; MinidumpMemoryInfos* infos_; uint32_t info_count_; @@ -1056,7 +1135,7 @@ class MinidumpLinuxMaps : public MinidumpObject { friend class MinidumpLinuxMapsList; // This caller owns the pointer. - explicit MinidumpLinuxMaps(Minidump *minidump); + explicit MinidumpLinuxMaps(Minidump* minidump); // The memory region struct that this class wraps. MappedMemoryRegion region_; @@ -1075,9 +1154,9 @@ class MinidumpLinuxMapsList : public MinidumpStream { unsigned int get_maps_count() const { return valid_ ? maps_count_ : 0; } // Get mapping at the given memory address. The caller owns the pointer. - const MinidumpLinuxMaps *GetLinuxMapsForAddress(uint64_t address) const; + const MinidumpLinuxMaps* GetLinuxMapsForAddress(uint64_t address) const; // Get mapping at the given index. The caller owns the pointer. - const MinidumpLinuxMaps *GetLinuxMapsAtIndex(unsigned int index) const; + const MinidumpLinuxMaps* GetLinuxMapsAtIndex(unsigned int index) const; // Print the contents of /proc/self/maps to stdout. void Print() const; @@ -1085,12 +1164,12 @@ class MinidumpLinuxMapsList : public MinidumpStream { private: friend class Minidump; - typedef vector<MinidumpLinuxMaps *> MinidumpLinuxMappings; + typedef vector<MinidumpLinuxMaps*> MinidumpLinuxMappings; static const uint32_t kStreamType = MD_LINUX_MAPS; // The caller owns the pointer. - explicit MinidumpLinuxMapsList(Minidump *minidump); + explicit MinidumpLinuxMapsList(Minidump* minidump); // Read and load the contents of the process mapping data. // The stream should have data in the form of /proc/self/maps. @@ -1098,7 +1177,7 @@ class MinidumpLinuxMapsList : public MinidumpStream { bool Read(uint32_t expected_size) override; // The list of individual mappings. - MinidumpLinuxMappings *maps_; + MinidumpLinuxMappings* maps_; // The number of mappings. uint32_t maps_count_; @@ -1110,10 +1189,21 @@ class MinidumpLinuxMapsList : public MinidumpStream { // at the time the minidump was generated. class MinidumpCrashpadInfo : public MinidumpStream { public: + struct AnnotationObject { + uint16_t type; + std::string name; + std::vector<uint8_t> value; + }; + const MDRawCrashpadInfo* crashpad_info() const { return valid_ ? &crashpad_info_ : NULL; } + const std::vector<std::vector<AnnotationObject>>* + GetModuleCrashpadInfoAnnotationObjects() const { + return valid_ ? &module_crashpad_info_annotation_objects_ : NULL; + } + // Print a human-readable representation of the object to stdout. void Print(); @@ -1132,6 +1222,9 @@ class MinidumpCrashpadInfo : public MinidumpStream { std::vector<std::vector<std::string>> module_crashpad_info_list_annotations_; std::vector<std::map<std::string, std::string>> module_crashpad_info_simple_annotations_; + std::vector<std::vector<AnnotationObject>> + module_crashpad_info_annotation_objects_; + std::map<std::string, std::string> simple_annotations_; }; @@ -1188,6 +1281,7 @@ class Minidump { // to avoid exposing an ugly API (GetStream needs to accept a garbage // parameter). virtual MinidumpThreadList* GetThreadList(); + virtual MinidumpThreadNameList* GetThreadNameList(); virtual MinidumpModuleList* GetModuleList(); virtual MinidumpMemoryList* GetMemoryList(); virtual MinidumpException* GetException(); @@ -1200,7 +1294,7 @@ class Minidump { MinidumpCrashpadInfo* GetCrashpadInfo(); // The next method also calls GetStream, but is exclusive for Linux dumps. - virtual MinidumpLinuxMapsList *GetLinuxMapsList(); + virtual MinidumpLinuxMapsList* GetLinuxMapsList(); // The next set of methods are provided for users who wish to access // data in minidump files directly, while leveraging the rest of @@ -1240,6 +1334,10 @@ class Minidump { off_t offset, std::map<std::string, std::string>* simple_string_dictionary); + bool ReadCrashpadAnnotationsList( + off_t offset, + std::vector<MinidumpCrashpadInfo::AnnotationObject>* annotations_list); + // SeekToStreamType positions the file at the beginning of a stream // identified by stream_type, and informs the caller of the stream's // length by setting *stream_length. Because stream_map maps each stream diff --git a/src/google_breakpad/processor/minidump_processor.h b/src/google_breakpad/processor/minidump_processor.h index 387115ef..137ef444 100644 --- a/src/google_breakpad/processor/minidump_processor.h +++ b/src/google_breakpad/processor/minidump_processor.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -70,7 +69,7 @@ class MinidumpProcessor { ~MinidumpProcessor(); // Processes the minidump file and fills process_state with the result. - ProcessResult Process(const string &minidump_file, + ProcessResult Process(const string& minidump_file, ProcessState* process_state); // Processes the minidump structure and fills process_state with the @@ -102,8 +101,10 @@ class MinidumpProcessor { // exception, if this information is available. This will be a code // address when the crash was caused by problems such as illegal // instructions or divisions by zero, or a data address when the crash - // was caused by a memory access violation. - static string GetCrashReason(Minidump* dump, uint64_t* address); + // was caused by a memory access violation. If enable_objdump is set, this + // may use disassembly to compute the faulting address. + static string GetCrashReason(Minidump* dump, uint64_t* address, + bool enable_objdump); // This function returns true if the passed-in error code is // something unrecoverable(i.e. retry should not happen). For diff --git a/src/google_breakpad/processor/proc_maps_linux.h b/src/google_breakpad/processor/proc_maps_linux.h index 3045daa5..b99414c3 100644 --- a/src/google_breakpad/processor/proc_maps_linux.h +++ b/src/google_breakpad/processor/proc_maps_linux.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 2013 Google LLC // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/src/google_breakpad/processor/process_result.h b/src/google_breakpad/processor/process_result.h index 15c7213e..780060d9 100644 --- a/src/google_breakpad/processor/process_result.h +++ b/src/google_breakpad/processor/process_result.h @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -56,9 +55,13 @@ enum ProcessResult { PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS, // There was more than one // requesting thread. - PROCESS_SYMBOL_SUPPLIER_INTERRUPTED // The dump processing was + PROCESS_SYMBOL_SUPPLIER_INTERRUPTED, // The dump processing was // interrupted by the // SymbolSupplier(not fatal). + + PROCESS_ERROR_GETTING_THREAD_NAME, // There was an error getting one + // thread's name from the dump. + }; } // namespace google_breakpad diff --git a/src/google_breakpad/processor/process_state.h b/src/google_breakpad/processor/process_state.h index 9bc44c45..3fe6a5c2 100644 --- a/src/google_breakpad/processor/process_state.h +++ b/src/google_breakpad/processor/process_state.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -111,6 +110,7 @@ class ProcessState { const vector<MemoryRegion*>* thread_memory_regions() const { return &thread_memory_regions_; } + const vector<string>* thread_names() const { return &thread_names_; } const SystemInfo* system_info() const { return &system_info_; } const CodeModules* modules() const { return modules_; } const CodeModules* unloaded_modules() const { return unloaded_modules_; } @@ -176,6 +176,12 @@ class ProcessState { vector<CallStack*> threads_; vector<MemoryRegion*> thread_memory_regions_; + // Names of each thread at the time of the crash, one for each entry in + // threads_. Note that a thread's name might be empty if there was no + // corresponding ThreadNamesStream in the minidump, or if a particular thread + // ID was not present in the THREAD_NAME_LIST. + vector<string> thread_names_; + // OS and CPU information. SystemInfo system_info_; diff --git a/src/google_breakpad/processor/source_line_resolver_base.h b/src/google_breakpad/processor/source_line_resolver_base.h index c720b0c3..4c64bfc9 100644 --- a/src/google_breakpad/processor/source_line_resolver_base.h +++ b/src/google_breakpad/processor/source_line_resolver_base.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -41,6 +40,7 @@ #ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__ #define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__ +#include <deque> #include <map> #include <set> #include <string> @@ -64,36 +64,40 @@ class SourceLineResolverBase : public SourceLineResolverInterface { // LoadMap() method. // Place dynamically allocated heap buffer in symbol_data. Caller has the // ownership of the buffer, and should call delete [] to free the buffer. - static bool ReadSymbolFile(const string &file_name, - char **symbol_data, - size_t *symbol_data_size); + static bool ReadSymbolFile(const string& file_name, + char** symbol_data, + size_t* symbol_data_size); protected: // Users are not allowed create SourceLineResolverBase instance directly. - SourceLineResolverBase(ModuleFactory *module_factory); + SourceLineResolverBase(ModuleFactory* module_factory); virtual ~SourceLineResolverBase(); // Virtual methods inherited from SourceLineResolverInterface. - virtual bool LoadModule(const CodeModule *module, const string &map_file); - virtual bool LoadModuleUsingMapBuffer(const CodeModule *module, - const string &map_buffer); - virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module, - char *memory_buffer, + virtual bool LoadModule(const CodeModule* module, const string& map_file); + virtual bool LoadModuleUsingMapBuffer(const CodeModule* module, + const string& map_buffer); + virtual bool LoadModuleUsingMemoryBuffer(const CodeModule* module, + char* memory_buffer, size_t memory_buffer_size); virtual bool ShouldDeleteMemoryBufferAfterLoadModule(); - virtual void UnloadModule(const CodeModule *module); - virtual bool HasModule(const CodeModule *module); - virtual bool IsModuleCorrupt(const CodeModule *module); - virtual void FillSourceLineInfo(StackFrame *frame); - virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame); - virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame); + virtual void UnloadModule(const CodeModule* module); + virtual bool HasModule(const CodeModule* module); + virtual bool IsModuleCorrupt(const CodeModule* module); + virtual void FillSourceLineInfo( + StackFrame* frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames); + virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame); + virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame); // Nested structs and classes. + struct InlineOrigin; + struct Inline; struct Line; struct Function; struct PublicSymbol; struct CompareString { - bool operator()(const string &s1, const string &s2) const; + bool operator()(const string& s1, const string& s2) const; }; // Module is an interface for an in-memory symbol file. class Module; @@ -101,18 +105,18 @@ class SourceLineResolverBase : public SourceLineResolverInterface { // All of the modules that are loaded. typedef map<string, Module*, CompareString> ModuleMap; - ModuleMap *modules_; + ModuleMap* modules_; // The loaded modules that were detecting to be corrupt during load. typedef set<string, CompareString> ModuleSet; - ModuleSet *corrupt_modules_; + ModuleSet* corrupt_modules_; // All of heap-allocated buffers that are owned locally by resolver. typedef std::map<string, char*, CompareString> MemoryMap; - MemoryMap *memory_buffers_; + MemoryMap* memory_buffers_; // Creates a concrete module at run-time. - ModuleFactory *module_factory_; + ModuleFactory* module_factory_; private: // ModuleFactory needs to have access to protected type Module. diff --git a/src/google_breakpad/processor/source_line_resolver_interface.h b/src/google_breakpad/processor/source_line_resolver_interface.h index a694bf2e..9f1f50c9 100644 --- a/src/google_breakpad/processor/source_line_resolver_interface.h +++ b/src/google_breakpad/processor/source_line_resolver_interface.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -34,7 +33,10 @@ #ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ #define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ +#include <deque> +#include <memory> #include <string> +#include <vector> #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" @@ -58,11 +60,11 @@ class SourceLineResolverInterface { // and debug_identifier members populated. // // map_file should contain line/address mappings for this module. - virtual bool LoadModule(const CodeModule *module, - const string &map_file) = 0; + virtual bool LoadModule(const CodeModule* module, + const string& map_file) = 0; // Same as above, but takes the contents of a pre-read map buffer - virtual bool LoadModuleUsingMapBuffer(const CodeModule *module, - const string &map_buffer) = 0; + virtual bool LoadModuleUsingMapBuffer(const CodeModule* module, + const string& map_buffer) = 0; // Add an interface to load symbol using C-String data instead of string. // This is useful in the optimization design for avoiding unnecessary copying @@ -70,8 +72,8 @@ class SourceLineResolverInterface { // LoadModuleUsingMemoryBuffer() does NOT take ownership of memory_buffer. // LoadModuleUsingMemoryBuffer() null terminates the passed in buffer, if // the last character is not a null terminator. - virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module, - char *memory_buffer, + virtual bool LoadModuleUsingMemoryBuffer(const CodeModule* module, + char* memory_buffer, size_t memory_buffer_size) = 0; // Return true if the memory buffer should be deleted immediately after @@ -81,31 +83,35 @@ class SourceLineResolverInterface { // Request that the specified module be unloaded from this resolver. // A resolver may choose to ignore such a request. - virtual void UnloadModule(const CodeModule *module) = 0; + virtual void UnloadModule(const CodeModule* module) = 0; // Returns true if the module has been loaded. - virtual bool HasModule(const CodeModule *module) = 0; + virtual bool HasModule(const CodeModule* module) = 0; // Returns true if the module has been loaded and it is corrupt. - virtual bool IsModuleCorrupt(const CodeModule *module) = 0; + virtual bool IsModuleCorrupt(const CodeModule* module) = 0; // Fills in the function_base, function_name, source_file_name, // and source_line fields of the StackFrame. The instruction and - // module_name fields must already be filled in. - virtual void FillSourceLineInfo(StackFrame *frame) = 0; + // module_name fields must already be filled in. If inlined_frames is not + // nullptr, it will try to construct inlined frames by adding them into + // inlined_frames in an order from outermost frame to inner most frame. + virtual void FillSourceLineInfo( + StackFrame* frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames) = 0; // If Windows stack walking information is available covering // FRAME's instruction address, return a WindowsFrameInfo structure // describing it. If the information is not available, returns NULL. // A NULL return value does not indicate an error. The caller takes // ownership of any returned WindowsFrameInfo object. - virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) = 0; + virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame) = 0; // If CFI stack walking information is available covering ADDRESS, // return a CFIFrameInfo structure describing it. If the information // is not available, return NULL. The caller takes ownership of any // returned CFIFrameInfo object. - virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) = 0; + virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) = 0; protected: // SourceLineResolverInterface cannot be instantiated except by subclasses diff --git a/src/google_breakpad/processor/stack_frame.h b/src/google_breakpad/processor/stack_frame.h index 1491d788..eebe06e6 100644 --- a/src/google_breakpad/processor/stack_frame.h +++ b/src/google_breakpad/processor/stack_frame.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -50,8 +49,12 @@ struct StackFrame { FRAME_TRUST_CFI_SCAN, // Found while scanning stack using call frame info FRAME_TRUST_FP, // Derived from frame pointer FRAME_TRUST_CFI, // Derived from call frame info - FRAME_TRUST_PREWALKED, // Explicitly provided by some external stack walker. - FRAME_TRUST_CONTEXT // Given as instruction pointer in a context + // Explicitly provided by some external stack walker. + FRAME_TRUST_PREWALKED, + FRAME_TRUST_CONTEXT, // Given as instruction pointer in a context + FRAME_TRUST_INLINE, // Found by inline records in symbol files. + // Derived from leaf function by simulating a return. + FRAME_TRUST_LEAF, }; StackFrame() @@ -60,9 +63,10 @@ struct StackFrame { function_name(), function_base(), source_file_name(), - source_line(), + source_line(0), source_line_base(), - trust(FRAME_TRUST_NONE) {} + trust(FRAME_TRUST_NONE), + is_multiple(false) {} virtual ~StackFrame() {} // Return a string describing how this stack frame was found @@ -81,7 +85,11 @@ struct StackFrame { return "previous frame's frame pointer"; case StackFrame::FRAME_TRUST_SCAN: return "stack scanning"; - default: + case StackFrame::FRAME_TRUST_INLINE: + return "inline record"; + case StackFrame::FRAME_TRUST_LEAF: + return "simulating a return from leaf function"; + default: return "unknown"; } } @@ -137,6 +145,12 @@ struct StackFrame { // Amount of trust the stack walker has in the instruction pointer // of this frame. FrameTrust trust; + + // True if the frame corresponds to multiple functions, for example as the + // result of identical code folding by the linker. In that case the function + // name, filename, etc. information above represents the state of an arbitrary + // one of these functions. + bool is_multiple; }; } // namespace google_breakpad diff --git a/src/google_breakpad/processor/stack_frame_cpu.h b/src/google_breakpad/processor/stack_frame_cpu.h index dc5d8ae6..91f1d0cb 100644 --- a/src/google_breakpad/processor/stack_frame_cpu.h +++ b/src/google_breakpad/processor/stack_frame_cpu.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -251,7 +250,10 @@ struct StackFrameARM : public StackFrame { // Return the ContextValidity flag for register rN. static ContextValidity RegisterValidFlag(int n) { - return ContextValidity(1 << n); + if (0 <= n && n <= 15) { + return ContextValidity(1 << n); + } + return CONTEXT_VALID_NONE; } // Register state. This is only fully valid for the topmost frame in a @@ -400,6 +402,118 @@ struct StackFrameMIPS : public StackFrame { int context_validity; }; +struct StackFrameRISCV : public StackFrame { + + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_PC = 1 << 0, + CONTEXT_VALID_RA = 1 << 1, + CONTEXT_VALID_SP = 1 << 2, + CONTEXT_VALID_GP = 1 << 3, + CONTEXT_VALID_TP = 1 << 4, + CONTEXT_VALID_T0 = 1 << 5, + CONTEXT_VALID_T1 = 1 << 6, + CONTEXT_VALID_T2 = 1 << 7, + CONTEXT_VALID_S0 = 1 << 8, + CONTEXT_VALID_S1 = 1 << 9, + CONTEXT_VALID_A0 = 1 << 10, + CONTEXT_VALID_A1 = 1 << 11, + CONTEXT_VALID_A2 = 1 << 12, + CONTEXT_VALID_A3 = 1 << 13, + CONTEXT_VALID_A4 = 1 << 14, + CONTEXT_VALID_A5 = 1 << 15, + CONTEXT_VALID_A6 = 1 << 16, + CONTEXT_VALID_A7 = 1 << 17, + CONTEXT_VALID_S2 = 1 << 18, + CONTEXT_VALID_S3 = 1 << 19, + CONTEXT_VALID_S4 = 1 << 20, + CONTEXT_VALID_S5 = 1 << 21, + CONTEXT_VALID_S6 = 1 << 22, + CONTEXT_VALID_S7 = 1 << 23, + CONTEXT_VALID_S8 = 1 << 24, + CONTEXT_VALID_S9 = 1 << 25, + CONTEXT_VALID_S10 = 1 << 26, + CONTEXT_VALID_S11 = 1 << 27, + CONTEXT_VALID_T3 = 1 << 28, + CONTEXT_VALID_T4 = 1 << 29, + CONTEXT_VALID_T5 = 1 << 30, + CONTEXT_VALID_T6 = 1 << 31, + CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE + }; + + StackFrameRISCV() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, which registers are present depends on what + // debugging information were available. Refer to 'context_validity' below. + MDRawContextRISCV context; + + // For each register in context whose value has been recovered, + // the corresponding CONTEXT_VALID_ bit in 'context_validity' is set. + // + // context_validity's type should actually be ContextValidity, but + // type int is used instead because the bitwise inclusive or operator + // yields an int when applied to enum values, and C++ doesn't + // silently convert from ints to enums. + int context_validity; +}; + +struct StackFrameRISCV64 : public StackFrame { + + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_PC = 1 << 0, + CONTEXT_VALID_RA = 1 << 1, + CONTEXT_VALID_SP = 1 << 2, + CONTEXT_VALID_GP = 1 << 3, + CONTEXT_VALID_TP = 1 << 4, + CONTEXT_VALID_T0 = 1 << 5, + CONTEXT_VALID_T1 = 1 << 6, + CONTEXT_VALID_T2 = 1 << 7, + CONTEXT_VALID_S0 = 1 << 8, + CONTEXT_VALID_S1 = 1 << 9, + CONTEXT_VALID_A0 = 1 << 10, + CONTEXT_VALID_A1 = 1 << 11, + CONTEXT_VALID_A2 = 1 << 12, + CONTEXT_VALID_A3 = 1 << 13, + CONTEXT_VALID_A4 = 1 << 14, + CONTEXT_VALID_A5 = 1 << 15, + CONTEXT_VALID_A6 = 1 << 16, + CONTEXT_VALID_A7 = 1 << 17, + CONTEXT_VALID_S2 = 1 << 18, + CONTEXT_VALID_S3 = 1 << 19, + CONTEXT_VALID_S4 = 1 << 20, + CONTEXT_VALID_S5 = 1 << 21, + CONTEXT_VALID_S6 = 1 << 22, + CONTEXT_VALID_S7 = 1 << 23, + CONTEXT_VALID_S8 = 1 << 24, + CONTEXT_VALID_S9 = 1 << 25, + CONTEXT_VALID_S10 = 1 << 26, + CONTEXT_VALID_S11 = 1 << 27, + CONTEXT_VALID_T3 = 1 << 28, + CONTEXT_VALID_T4 = 1 << 29, + CONTEXT_VALID_T5 = 1 << 30, + CONTEXT_VALID_T6 = 1 << 31, + CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE + }; + + StackFrameRISCV64() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, which registers are present depends on what + // debugging information were available. Refer to 'context_validity' below. + MDRawContextRISCV64 context; + + // For each register in context whose value has been recovered, + // the corresponding CONTEXT_VALID_ bit in 'context_validity' is set. + // + // context_validity's type should actually be ContextValidity, but + // type int is used instead because the bitwise inclusive or operator + // yields an int when applied to enum values, and C++ doesn't + // silently convert from ints to enums. + int context_validity; +}; + } // namespace google_breakpad #endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__ diff --git a/src/google_breakpad/processor/stack_frame_symbolizer.h b/src/google_breakpad/processor/stack_frame_symbolizer.h index 0bbaae0a..ed342ce6 100644 --- a/src/google_breakpad/processor/stack_frame_symbolizer.h +++ b/src/google_breakpad/processor/stack_frame_symbolizer.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2012 Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -35,8 +34,11 @@ #ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__ #define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__ +#include <deque> +#include <memory> #include <set> #include <string> +#include <vector> #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" @@ -79,7 +81,8 @@ class StackFrameSymbolizer { const CodeModules* modules, const CodeModules* unloaded_modules, const SystemInfo* system_info, - StackFrame* stack_frame); + StackFrame* stack_frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames); virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame); diff --git a/src/google_breakpad/processor/stackwalker.h b/src/google_breakpad/processor/stackwalker.h index 0c458d50..e5d88c80 100644 --- a/src/google_breakpad/processor/stackwalker.h +++ b/src/google_breakpad/processor/stackwalker.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -176,8 +175,12 @@ class Stackwalker { if (!memory_->GetMemoryAtAddress(location, &ip)) break; - if (modules_ && modules_->GetModuleForAddress(ip) && - InstructionAddressSeemsValid(ip)) { + // The return address points to the instruction after a call. If the + // caller was a no return function, this might point past the end of the + // function. Subtract one from the instruction pointer so it points into + // the call instruction instead. + if (modules_ && modules_->GetModuleForAddress(ip - 1) && + InstructionAddressSeemsValid(ip - 1)) { *ip_found = ip; *location_found = location; return true; diff --git a/src/google_breakpad/processor/symbol_supplier.h b/src/google_breakpad/processor/symbol_supplier.h index a042081f..b1c23535 100644 --- a/src/google_breakpad/processor/symbol_supplier.h +++ b/src/google_breakpad/processor/symbol_supplier.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -63,35 +62,35 @@ class SymbolSupplier { // to help locate the symbol file. system_info may be NULL or its // fields may be empty if these values are unknown. symbol_file // must be a pointer to a valid string - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file) = 0; + virtual SymbolResult GetSymbolFile(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file) = 0; // Same as above, except also places symbol data into symbol_data. // If symbol_data is NULL, the data is not returned. // TODO(nealsid) Once we have symbol data caching behavior implemented // investigate making all symbol suppliers implement all methods, // and make this pure virtual - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data) = 0; + virtual SymbolResult GetSymbolFile(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + string* symbol_data) = 0; // Same as above, except allocates data buffer on heap and then places the // symbol data into the buffer as C-string. // SymbolSupplier is responsible for deleting the data buffer. After the call // to GetCStringSymbolData(), the caller should call FreeSymbolData(const - // Module *module) once the data buffer is no longer needed. + // Module* module) once the data buffer is no longer needed. // If symbol_data is not NULL, symbol supplier won't return FOUND unless it // returns a valid buffer in symbol_data, e.g., returns INTERRUPT on memory // allocation failure. - virtual SymbolResult GetCStringSymbolData(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size) = 0; + virtual SymbolResult GetCStringSymbolData(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + char** symbol_data, + size_t* symbol_data_size) = 0; // Frees the data buffer allocated for the module in GetCStringSymbolData. - virtual void FreeSymbolData(const CodeModule *module) = 0; + virtual void FreeSymbolData(const CodeModule* module) = 0; }; } // namespace google_breakpad diff --git a/src/google_breakpad/processor/system_info.h b/src/google_breakpad/processor/system_info.h index 8d2f60be..01c48182 100644 --- a/src/google_breakpad/processor/system_info.h +++ b/src/google_breakpad/processor/system_info.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/address_map-inl.h b/src/processor/address_map-inl.h index 251c4478..e1b944d1 100644 --- a/src/processor/address_map-inl.h +++ b/src/processor/address_map-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,8 +44,8 @@ namespace google_breakpad { template<typename AddressType, typename EntryType> -bool AddressMap<AddressType, EntryType>::Store(const AddressType &address, - const EntryType &entry) { +bool AddressMap<AddressType, EntryType>::Store(const AddressType& address, + const EntryType& entry) { // Ensure that the specified address doesn't conflict with something already // in the map. if (map_.find(address) != map_.end()) { @@ -61,8 +60,8 @@ bool AddressMap<AddressType, EntryType>::Store(const AddressType &address, template<typename AddressType, typename EntryType> bool AddressMap<AddressType, EntryType>::Retrieve( - const AddressType &address, - EntryType *entry, AddressType *entry_address) const { + const AddressType& address, + EntryType* entry, AddressType* entry_address) const { BPLOG_IF(ERROR, !entry) << "AddressMap::Retrieve requires |entry|"; assert(entry); diff --git a/src/processor/address_map.h b/src/processor/address_map.h index 2972cbb9..8a4f7ba8 100644 --- a/src/processor/address_map.h +++ b/src/processor/address_map.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -53,15 +52,15 @@ class AddressMap { // Inserts an entry into the map. Returns false without storing the entry // if an entry is already stored in the map at the same address as specified // by the address argument. - bool Store(const AddressType &address, const EntryType &entry); + bool Store(const AddressType& address, const EntryType& entry); // Locates the entry stored at the highest address less than or equal to // the address argument. If there is no such range, returns false. The // entry is returned in entry, which is a required argument. If // entry_address is not NULL, it will be set to the address that the entry // was stored at. - bool Retrieve(const AddressType &address, - EntryType *entry, AddressType *entry_address) const; + bool Retrieve(const AddressType& address, + EntryType* entry, AddressType* entry_address) const; // Empties the address map, restoring it to the same state as when it was // initially created. diff --git a/src/processor/address_map_unittest.cc b/src/processor/address_map_unittest.cc index 9b4095b1..1bf0d718 100644 --- a/src/processor/address_map_unittest.cc +++ b/src/processor/address_map_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -189,7 +188,7 @@ static bool RunTests() { } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { BPLOG_INIT(&argc, &argv); return RunTests() ? 0 : 1; diff --git a/src/processor/basic_code_module.h b/src/processor/basic_code_module.h index 35d66a60..9da62d92 100644 --- a/src/processor/basic_code_module.h +++ b/src/processor/basic_code_module.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -66,11 +65,11 @@ class BasicCodeModule : public CodeModule { is_unloaded_(that->is_unloaded()) {} BasicCodeModule(uint64_t base_address, uint64_t size, - const string &code_file, - const string &code_identifier, - const string &debug_file, - const string &debug_identifier, - const string &version, + const string& code_file, + const string& code_identifier, + const string& debug_file, + const string& debug_identifier, + const string& version, const bool is_unloaded = false) : base_address_(base_address), size_(size), @@ -112,8 +111,8 @@ class BasicCodeModule : public CodeModule { bool is_unloaded_; // Disallow copy constructor and assignment operator. - BasicCodeModule(const BasicCodeModule &that); - void operator=(const BasicCodeModule &that); + BasicCodeModule(const BasicCodeModule& that); + void operator=(const BasicCodeModule& that); }; } // namespace google_breakpad diff --git a/src/processor/basic_code_modules.cc b/src/processor/basic_code_modules.cc index f71aeb74..57021d47 100644 --- a/src/processor/basic_code_modules.cc +++ b/src/processor/basic_code_modules.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/basic_code_modules.h b/src/processor/basic_code_modules.h index 45ebc53b..e9d58f6b 100644 --- a/src/processor/basic_code_modules.h +++ b/src/processor/basic_code_modules.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -88,8 +87,8 @@ class BasicCodeModules : public CodeModules { private: // Disallow copy constructor and assignment operator. - BasicCodeModules(const BasicCodeModules &that); - void operator=(const BasicCodeModules &that); + BasicCodeModules(const BasicCodeModules& that); + void operator=(const BasicCodeModules& that); }; } // namespace google_breakpad diff --git a/src/processor/basic_source_line_resolver.cc b/src/processor/basic_source_line_resolver.cc index c4aa949c..07aba6bc 100644 --- a/src/processor/basic_source_line_resolver.cc +++ b/src/processor/basic_source_line_resolver.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,6 +39,7 @@ #include <limits> #include <map> +#include <memory> #include <utility> #include <vector> @@ -49,9 +49,11 @@ #include "processor/tokenize.h" +using std::deque; +using std::make_pair; using std::map; +using std::unique_ptr; using std::vector; -using std::make_pair; namespace google_breakpad { @@ -69,11 +71,11 @@ namespace { // field, and max_tokens is the maximum number of tokens including the optional // field. Refer to the documentation for Tokenize for descriptions of the other // arguments. -bool TokenizeWithOptionalField(char *line, - const char *optional_field, - const char *separators, +bool TokenizeWithOptionalField(char* line, + const char* optional_field, + const char* separators, int max_tokens, - vector<char*> *tokens) { + vector<char*>* tokens) { // First tokenize assuming the optional field is not present. If we then see // the optional field, additionally tokenize the last token into two tokens. if (!Tokenize(line, separators, max_tokens - 1, tokens)) { @@ -98,7 +100,7 @@ bool TokenizeWithOptionalField(char *line, } // namespace -static const char *kWhitespace = " \r\n"; +static const char* kWhitespace = " \r\n"; static const int kMaxErrorsPrinted = 5; static const int kMaxErrorsBeforeBailing = 100; @@ -107,9 +109,9 @@ BasicSourceLineResolver::BasicSourceLineResolver() : // static void BasicSourceLineResolver::Module::LogParseError( - const string &message, + const string& message, int line_number, - int *num_errors) { + int* num_errors) { if (++(*num_errors) <= kMaxErrorsPrinted) { if (line_number > 0) { BPLOG(ERROR) << "Line " << line_number << ": " << message; @@ -120,12 +122,13 @@ void BasicSourceLineResolver::Module::LogParseError( } bool BasicSourceLineResolver::Module::LoadMapFromMemory( - char *memory_buffer, + char* memory_buffer, size_t memory_buffer_size) { linked_ptr<Function> cur_func; int line_number = 0; int num_errors = 0; - char *save_ptr; + int inline_num_errors = 0; + char* save_ptr; // If the length is 0, we can still pretend we have a symbol file. This is // for scenarios that want to test symbol lookup, but don't necessarily care @@ -160,7 +163,7 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory( &num_errors); } - char *buffer; + char* buffer; buffer = strtok_r(memory_buffer, "\r\n", &save_ptr); while (buffer != NULL) { @@ -202,12 +205,23 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory( // Ignore these as well, they're similarly just for housekeeping. // // INFO CODE_ID <code id> <filename> + } else if (strncmp(buffer, "INLINE ", 7) == 0) { + linked_ptr<Inline> in = ParseInline(buffer); + if (!in.get()) + LogParseError("ParseInline failed", line_number, &inline_num_errors); + else + cur_func->AppendInline(in); + } else if (strncmp(buffer, "INLINE_ORIGIN ", 14) == 0) { + if (!ParseInlineOrigin(buffer)) { + LogParseError("ParseInlineOrigin failed", line_number, + &inline_num_errors); + } } else { if (!cur_func.get()) { LogParseError("Found source line data without a function", line_number, &num_errors); } else { - Line *line = ParseLine(buffer); + Line* line = ParseLine(buffer); if (!line) { LogParseError("ParseLine failed", line_number, &num_errors); } else { @@ -225,7 +239,67 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory( return true; } -void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { +void BasicSourceLineResolver::Module::ConstructInlineFrames( + StackFrame* frame, + MemAddr address, + const ContainedRangeMap<uint64_t, linked_ptr<Inline>>& inline_map, + deque<unique_ptr<StackFrame>>* inlined_frames) const { + vector<const linked_ptr<Inline>*> inlines; + if (!inline_map.RetrieveRanges(address, inlines)) { + return; + } + + for (const linked_ptr<Inline>* const in : inlines) { + unique_ptr<StackFrame> new_frame = + unique_ptr<StackFrame>(new StackFrame(*frame)); + auto origin = inline_origins_.find(in->get()->origin_id); + if (origin != inline_origins_.end()) { + new_frame->function_name = origin->second->name; + } else { + new_frame->function_name = "<name omitted>"; + } + + // Store call site file and line in current frame, which will be updated + // later. + new_frame->source_line = in->get()->call_site_line; + if (in->get()->has_call_site_file_id) { + auto file = files_.find(in->get()->call_site_file_id); + if (file != files_.end()) { + new_frame->source_file_name = file->second; + } + } + + // Use the starting address of the inlined range as inlined function base. + new_frame->function_base = new_frame->module->base_address(); + for (const auto& range : in->get()->inline_ranges) { + if (address >= range.first && address < range.first + range.second) { + new_frame->function_base += range.first; + break; + } + } + new_frame->trust = StackFrame::FRAME_TRUST_INLINE; + + // The inlines vector has an order from innermost entry to outermost entry. + // By push_back, we will have inlined_frames with the same order. + inlined_frames->push_back(std::move(new_frame)); + } + + // Update the source file and source line for each inlined frame. + if (!inlined_frames->empty()) { + string parent_frame_source_file_name = frame->source_file_name; + int parent_frame_source_line = frame->source_line; + frame->source_file_name = inlined_frames->back()->source_file_name; + frame->source_line = inlined_frames->back()->source_line; + for (unique_ptr<StackFrame>& inlined_frame : *inlined_frames) { + std::swap(inlined_frame->source_file_name, parent_frame_source_file_name); + std::swap(inlined_frame->source_line, parent_frame_source_line); + } + } +} + +void BasicSourceLineResolver::Module::LookupAddress( + StackFrame* frame, + deque<unique_ptr<StackFrame>>* inlined_frames) const { MemAddr address = frame->instruction - frame->module->base_address(); // First, look for a FUNC record that covers address. Use @@ -244,6 +318,7 @@ void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { address >= function_base && address - function_base < function_size) { frame->function_name = func->name; frame->function_base = frame->module->base_address() + function_base; + frame->is_multiple = func->is_multiple; linked_ptr<Line> line; MemAddr line_base; @@ -256,16 +331,22 @@ void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { frame->source_line = line->line; frame->source_line_base = frame->module->base_address() + line_base; } + + // Check if this is inlined function call. + if (inlined_frames) { + ConstructInlineFrames(frame, address, func->inlines, inlined_frames); + } } else if (public_symbols_.Retrieve(address, &public_symbol, &public_address) && (!func.get() || public_address > function_base)) { frame->function_name = public_symbol->name; frame->function_base = frame->module->base_address() + public_address; + frame->is_multiple = public_symbol->is_multiple; } } -WindowsFrameInfo *BasicSourceLineResolver::Module::FindWindowsFrameInfo( - const StackFrame *frame) const { +WindowsFrameInfo* BasicSourceLineResolver::Module::FindWindowsFrameInfo( + const StackFrame* frame) const { MemAddr address = frame->instruction - frame->module->base_address(); scoped_ptr<WindowsFrameInfo> result(new WindowsFrameInfo()); @@ -313,8 +394,8 @@ WindowsFrameInfo *BasicSourceLineResolver::Module::FindWindowsFrameInfo( return NULL; } -CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo( - const StackFrame *frame) const { +CFIFrameInfo* BasicSourceLineResolver::Module::FindCFIFrameInfo( + const StackFrame* frame) const { MemAddr address = frame->instruction - frame->module->base_address(); MemAddr initial_base, initial_size; string initial_rules; @@ -347,9 +428,9 @@ CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo( return rules.release(); } -bool BasicSourceLineResolver::Module::ParseFile(char *file_line) { +bool BasicSourceLineResolver::Module::ParseFile(char* file_line) { long index; - char *filename; + char* filename; if (SymbolParseHelper::ParseFile(file_line, &index, &filename)) { files_.insert(make_pair(index, string(filename))); return true; @@ -357,13 +438,48 @@ bool BasicSourceLineResolver::Module::ParseFile(char *file_line) { return false; } +bool BasicSourceLineResolver::Module::ParseInlineOrigin( + char* inline_origin_line) { + bool has_file_id; + long origin_id; + long source_file_id; + char* origin_name; + if (SymbolParseHelper::ParseInlineOrigin(inline_origin_line, &has_file_id, + &origin_id, &source_file_id, + &origin_name)) { + inline_origins_.insert(make_pair( + origin_id, + new InlineOrigin(has_file_id, source_file_id, origin_name))); + return true; + } + return false; +} + +linked_ptr<BasicSourceLineResolver::Inline> +BasicSourceLineResolver::Module::ParseInline(char* inline_line) { + bool has_call_site_file_id; + long inline_nest_level; + long call_site_line; + long call_site_file_id; + long origin_id; + vector<std::pair<MemAddr, MemAddr>> ranges; + if (SymbolParseHelper::ParseInline(inline_line, &has_call_site_file_id, + &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)) { + return linked_ptr<Inline>(new Inline(has_call_site_file_id, + inline_nest_level, call_site_line, + call_site_file_id, origin_id, ranges)); + } + return linked_ptr<Inline>(); +} + BasicSourceLineResolver::Function* -BasicSourceLineResolver::Module::ParseFunction(char *function_line) { +BasicSourceLineResolver::Module::ParseFunction(char* function_line) { bool is_multiple; uint64_t address; uint64_t size; long stack_param_size; - char *name; + char* name; if (SymbolParseHelper::ParseFunction(function_line, &is_multiple, &address, &size, &stack_param_size, &name)) { return new Function(name, address, size, stack_param_size, is_multiple); @@ -372,7 +488,7 @@ BasicSourceLineResolver::Module::ParseFunction(char *function_line) { } BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine( - char *line_line) { + char* line_line) { uint64_t address; uint64_t size; long line_number; @@ -385,11 +501,11 @@ BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine( return NULL; } -bool BasicSourceLineResolver::Module::ParsePublicSymbol(char *public_line) { +bool BasicSourceLineResolver::Module::ParsePublicSymbol(char* public_line) { bool is_multiple; uint64_t address; long stack_param_size; - char *name; + char* name; if (SymbolParseHelper::ParsePublicSymbol(public_line, &is_multiple, &address, &stack_param_size, &name)) { @@ -411,7 +527,7 @@ bool BasicSourceLineResolver::Module::ParsePublicSymbol(char *public_line) { return false; } -bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) { +bool BasicSourceLineResolver::Module::ParseStackInfo(char* stack_info_line) { // Skip "STACK " prefix. stack_info_line += 6; @@ -419,7 +535,7 @@ bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) { // information this is. while (*stack_info_line == ' ') stack_info_line++; - const char *platform = stack_info_line; + const char* platform = stack_info_line; while (!strchr(kWhitespace, *stack_info_line)) stack_info_line++; *stack_info_line++ = '\0'; @@ -468,23 +584,23 @@ bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) { } bool BasicSourceLineResolver::Module::ParseCFIFrameInfo( - char *stack_info_line) { - char *cursor; + char* stack_info_line) { + char* cursor; // Is this an INIT record or a delta record? - char *init_or_address = strtok_r(stack_info_line, " \r\n", &cursor); + char* init_or_address = strtok_r(stack_info_line, " \r\n", &cursor); if (!init_or_address) return false; if (strcmp(init_or_address, "INIT") == 0) { // This record has the form "STACK INIT <address> <size> <rules...>". - char *address_field = strtok_r(NULL, " \r\n", &cursor); + char* address_field = strtok_r(NULL, " \r\n", &cursor); if (!address_field) return false; - char *size_field = strtok_r(NULL, " \r\n", &cursor); + char* size_field = strtok_r(NULL, " \r\n", &cursor); if (!size_field) return false; - char *initial_rules = strtok_r(NULL, "\r\n", &cursor); + char* initial_rules = strtok_r(NULL, "\r\n", &cursor); if (!initial_rules) return false; MemAddr address = strtoul(address_field, NULL, 16); @@ -494,17 +610,30 @@ bool BasicSourceLineResolver::Module::ParseCFIFrameInfo( } // This record has the form "STACK <address> <rules...>". - char *address_field = init_or_address; - char *delta_rules = strtok_r(NULL, "\r\n", &cursor); + char* address_field = init_or_address; + char* delta_rules = strtok_r(NULL, "\r\n", &cursor); if (!delta_rules) return false; MemAddr address = strtoul(address_field, NULL, 16); cfi_delta_rules_[address] = delta_rules; return true; } +bool BasicSourceLineResolver::Function::AppendInline(linked_ptr<Inline> in) { + // This happends if in's parent wasn't added due to a malformed INLINE record. + if (in->inline_nest_level > last_added_inline_nest_level + 1) + return false; + + last_added_inline_nest_level = in->inline_nest_level; + + // Store all ranges into current level of inlines. + for (auto range : in->inline_ranges) + inlines.StoreRange(range.first, range.second, in); + return true; +} + // static -bool SymbolParseHelper::ParseFile(char *file_line, long *index, - char **filename) { +bool SymbolParseHelper::ParseFile(char* file_line, long* index, + char** filename) { // FILE <id> <filename> assert(strncmp(file_line, "FILE ", 5) == 0); file_line += 5; // skip prefix @@ -514,7 +643,7 @@ bool SymbolParseHelper::ParseFile(char *file_line, long *index, return false; } - char *after_number; + char* after_number; *index = strtol(tokens[0], &after_number, 10); if (!IsValidAfterNumber(after_number) || *index < 0 || *index == std::numeric_limits<long>::max()) { @@ -530,9 +659,149 @@ bool SymbolParseHelper::ParseFile(char *file_line, long *index, } // static -bool SymbolParseHelper::ParseFunction(char *function_line, bool *is_multiple, - uint64_t *address, uint64_t *size, - long *stack_param_size, char **name) { +bool SymbolParseHelper::ParseInlineOrigin(char* inline_origin_line, + bool* has_file_id, + long* origin_id, + long* file_id, + char** name) { + // Old INLINE_ORIGIN format: + // INLINE_ORIGIN <origin_id> <file_id> <name> + // New INLINE_ORIGIN format: + // INLINE_ORIGIN <origin_id> <name> + assert(strncmp(inline_origin_line, "INLINE_ORIGIN ", 14) == 0); + inline_origin_line += 14; // skip prefix + vector<char*> tokens; + // Split the line into two parts so that the first token is "<origin_id>", and + // second token is either "<file_id> <name>"" or "<name>"" depending on the + // format version. + if (!Tokenize(inline_origin_line, kWhitespace, 2, &tokens)) { + return false; + } + + char* after_number; + *origin_id = strtol(tokens[0], &after_number, 10); + if (!IsValidAfterNumber(after_number) || *origin_id < 0 || + *origin_id == std::numeric_limits<long>::max()) { + return false; + } + + // If the field after origin_id is a number, then it's old format. + char* remaining_line = tokens[1]; + *has_file_id = true; + for (size_t i = 0; + i < strlen(remaining_line) && remaining_line[i] != ' ' && *has_file_id; + ++i) { + // If the file id is -1, it might be an artificial function that doesn't + // have file id. So, we consider -1 as a valid special case. + if (remaining_line[i] == '-' && i == 0) { + continue; + } + *has_file_id = isdigit(remaining_line[i]); + } + + if (*has_file_id) { + // If it's old format, split "<file_id> <name>" to {"<field_id>", "<name>"}. + if (!Tokenize(remaining_line, kWhitespace, 2, &tokens)) { + return false; + } + *file_id = strtol(tokens[0], &after_number, 10); + // If the file id is -1, it might be an artificial function that doesn't + // have file id. So, we consider -1 as a valid special case. + if (!IsValidAfterNumber(after_number) || *file_id < -1 || + *file_id == std::numeric_limits<long>::max()) { + return false; + } + } + + *name = tokens[1]; + if (!*name) { + return false; + } + + return true; +} + +// static +bool SymbolParseHelper::ParseInline( + char* inline_line, + bool* has_call_site_file_id, + long* inline_nest_level, + long* call_site_line, + long* call_site_file_id, + long* origin_id, + vector<std::pair<MemAddr, MemAddr>>* ranges) { + // Old INLINE format: + // INLINE <inline_nest_level> <call_site_line> <origin_id> [<address> <size>]+ + // New INLINE format: + // INLINE <inline_nest_level> <call_site_line> <call_site_file_id> <origin_id> + // [<address> <size>]+ + assert(strncmp(inline_line, "INLINE ", 7) == 0); + inline_line += 7; // skip prefix + + vector<char*> tokens; + // Increase max_tokens if necessary. + Tokenize(inline_line, kWhitespace, 512, &tokens); + + // Determine the version of INLINE record by parity of the vector length. + *has_call_site_file_id = tokens.size() % 2 == 0; + + // The length of the vector should be at least 5. + if (tokens.size() < 5) { + return false; + } + + char* after_number; + size_t next_idx = 0; + + *inline_nest_level = strtol(tokens[next_idx++], &after_number, 10); + if (!IsValidAfterNumber(after_number) || *inline_nest_level < 0 || + *inline_nest_level == std::numeric_limits<long>::max()) { + return false; + } + + *call_site_line = strtol(tokens[next_idx++], &after_number, 10); + if (!IsValidAfterNumber(after_number) || *call_site_line < 0 || + *call_site_line == std::numeric_limits<long>::max()) { + return false; + } + + if (*has_call_site_file_id) { + *call_site_file_id = strtol(tokens[next_idx++], &after_number, 10); + // If the file id is -1, it might be an artificial function that doesn't + // have file id. So, we consider -1 as a valid special case. + if (!IsValidAfterNumber(after_number) || *call_site_file_id < -1 || + *call_site_file_id == std::numeric_limits<long>::max()) { + return false; + } + } + + *origin_id = strtol(tokens[next_idx++], &after_number, 10); + if (!IsValidAfterNumber(after_number) || *origin_id < 0 || + *origin_id == std::numeric_limits<long>::max()) { + return false; + } + + while (next_idx < tokens.size()) { + MemAddr address = strtoull(tokens[next_idx++], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + address == std::numeric_limits<unsigned long long>::max()) { + return false; + } + MemAddr size = strtoull(tokens[next_idx++], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + size == std::numeric_limits<unsigned long long>::max()) { + return false; + } + ranges->push_back({address, size}); + } + + return true; +} + +// static +bool SymbolParseHelper::ParseFunction(char* function_line, bool* is_multiple, + uint64_t* address, uint64_t* size, + long* stack_param_size, char** name) { // FUNC [<multiple>] <address> <size> <stack_param_size> <name> assert(strncmp(function_line, "FUNC ", 5) == 0); function_line += 5; // skip prefix @@ -545,7 +814,7 @@ bool SymbolParseHelper::ParseFunction(char *function_line, bool *is_multiple, *is_multiple = strcmp(tokens[0], "m") == 0; int next_token = *is_multiple ? 1 : 0; - char *after_number; + char* after_number; *address = strtoull(tokens[next_token++], &after_number, 16); if (!IsValidAfterNumber(after_number) || *address == std::numeric_limits<unsigned long long>::max()) { @@ -568,16 +837,16 @@ bool SymbolParseHelper::ParseFunction(char *function_line, bool *is_multiple, } // static -bool SymbolParseHelper::ParseLine(char *line_line, uint64_t *address, - uint64_t *size, long *line_number, - long *source_file) { +bool SymbolParseHelper::ParseLine(char* line_line, uint64_t* address, + uint64_t* size, long* line_number, + long* source_file) { // <address> <size> <line number> <source file id> vector<char*> tokens; if (!Tokenize(line_line, kWhitespace, 4, &tokens)) { return false; } - char *after_number; + char* after_number; *address = strtoull(tokens[0], &after_number, 16); if (!IsValidAfterNumber(after_number) || *address == std::numeric_limits<unsigned long long>::max()) { @@ -613,10 +882,10 @@ bool SymbolParseHelper::ParseLine(char *line_line, uint64_t *address, } // static -bool SymbolParseHelper::ParsePublicSymbol(char *public_line, bool *is_multiple, - uint64_t *address, - long *stack_param_size, - char **name) { +bool SymbolParseHelper::ParsePublicSymbol(char* public_line, bool* is_multiple, + uint64_t* address, + long* stack_param_size, + char** name) { // PUBLIC [<multiple>] <address> <stack_param_size> <name> assert(strncmp(public_line, "PUBLIC ", 7) == 0); public_line += 7; // skip prefix @@ -629,7 +898,7 @@ bool SymbolParseHelper::ParsePublicSymbol(char *public_line, bool *is_multiple, *is_multiple = strcmp(tokens[0], "m") == 0; int next_token = *is_multiple ? 1 : 0; - char *after_number; + char* after_number; *address = strtoull(tokens[next_token++], &after_number, 16); if (!IsValidAfterNumber(after_number) || *address == std::numeric_limits<unsigned long long>::max()) { @@ -647,7 +916,7 @@ bool SymbolParseHelper::ParsePublicSymbol(char *public_line, bool *is_multiple, } // static -bool SymbolParseHelper::IsValidAfterNumber(char *after_number) { +bool SymbolParseHelper::IsValidAfterNumber(char* after_number) { if (after_number != NULL && strchr(kWhitespace, *after_number) != NULL) { return true; } diff --git a/src/processor/basic_source_line_resolver_types.h b/src/processor/basic_source_line_resolver_types.h index 89eb57e8..3c8b01c7 100644 --- a/src/processor/basic_source_line_resolver_types.h +++ b/src/processor/basic_source_line_resolver_types.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -57,25 +56,37 @@ namespace google_breakpad { struct BasicSourceLineResolver::Function : public SourceLineResolverBase::Function { - Function(const string &function_name, + Function(const string& function_name, MemAddr function_address, MemAddr code_size, int set_parameter_size, - bool is_mutiple) : Base(function_name, - function_address, - code_size, - set_parameter_size, - is_mutiple), - lines() { } - RangeMap< MemAddr, linked_ptr<Line> > lines; + bool is_mutiple) + : Base(function_name, + function_address, + code_size, + set_parameter_size, + is_mutiple), + inlines(true), + last_added_inline_nest_level(0) {} + + // Append inline into corresponding RangeMap. + // This function assumes it's called in the order of reading INLINE records. + bool AppendInline(linked_ptr<Inline> in); + + ContainedRangeMap<MemAddr, linked_ptr<Inline>> inlines; + RangeMap<MemAddr, linked_ptr<Line>> lines; + private: typedef SourceLineResolverBase::Function Base; + + // The last added inline_nest_level from INLINE record. + int last_added_inline_nest_level; }; class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module { public: - explicit Module(const string &name) : name_(name), is_corrupt_(false) { } + explicit Module(const string& name) : name_(name), is_corrupt_(false) { } virtual ~Module() { } // Loads a map from the given buffer in char* type. @@ -83,7 +94,7 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module { // The passed in |memory buffer| is of size |memory_buffer_size|. If it is // not null terminated, LoadMapFromMemory() will null terminate it by // modifying the passed in buffer. - virtual bool LoadMapFromMemory(char *memory_buffer, + virtual bool LoadMapFromMemory(char* memory_buffer, size_t memory_buffer_size); // Tells whether the loaded symbol data is corrupt. Return value is @@ -92,20 +103,32 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module { // Looks up the given relative address, and fills the StackFrame struct // with the result. - virtual void LookupAddress(StackFrame *frame) const; + virtual void LookupAddress( + StackFrame* frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frame) const; + + // Construct inlined frames for |frame| and store them in |inline_frames|. + // |frame|'s source line and source file name may be updated if an inlined + // frame is found inside |frame|. As a result, the innermost inlined frame + // will be the first one in |inline_frames|. + virtual void ConstructInlineFrames( + StackFrame* frame, + MemAddr address, + const ContainedRangeMap<uint64_t, linked_ptr<Inline>>& inline_map, + std::deque<std::unique_ptr<StackFrame>>* inline_frames) const; // If Windows stack walking information is available covering ADDRESS, // return a WindowsFrameInfo structure describing it. If the information // is not available, returns NULL. A NULL return value does not indicate // an error. The caller takes ownership of any returned WindowsFrameInfo // object. - virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) const; + virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame) const; // If CFI stack walking information is available covering ADDRESS, // return a CFIFrameInfo structure describing it. If the information // is not available, return NULL. The caller takes ownership of any // returned CFIFrameInfo object. - virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const; + virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const; private: // Friend declarations. @@ -118,32 +141,39 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module { // Logs parse errors. |*num_errors| is increased every time LogParseError is // called. static void LogParseError( - const string &message, + const string& message, int line_number, - int *num_errors); + int* num_errors); // Parses a file declaration - bool ParseFile(char *file_line); + bool ParseFile(char* file_line); + + // Parses an inline origin declaration. + bool ParseInlineOrigin(char* inline_origin_line); + + // Parses an inline declaration. + linked_ptr<Inline> ParseInline(char* inline_line); // Parses a function declaration, returning a new Function object. - Function* ParseFunction(char *function_line); + Function* ParseFunction(char* function_line); // Parses a line declaration, returning a new Line object. - Line* ParseLine(char *line_line); + Line* ParseLine(char* line_line); // Parses a PUBLIC symbol declaration, storing it in public_symbols_. // Returns false if an error occurs. - bool ParsePublicSymbol(char *public_line); + bool ParsePublicSymbol(char* public_line); // Parses a STACK WIN or STACK CFI frame info declaration, storing // it in the appropriate table. - bool ParseStackInfo(char *stack_info_line); + bool ParseStackInfo(char* stack_info_line); // Parses a STACK CFI record, storing it in cfi_frame_info_. - bool ParseCFIFrameInfo(char *stack_info_line); + bool ParseCFIFrameInfo(char* stack_info_line); string name_; FileMap files_; + std::map<int, linked_ptr<InlineOrigin>> inline_origins_; RangeMap< MemAddr, linked_ptr<Function> > functions_; AddressMap< MemAddr, linked_ptr<PublicSymbol> > public_symbols_; bool is_corrupt_; diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc index 90c34172..fba4e9a6 100644 --- a/src/processor/basic_source_line_resolver_unittest.cc +++ b/src/processor/basic_source_line_resolver_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,7 +51,6 @@ using google_breakpad::CodeModule; using google_breakpad::MemoryRegion; using google_breakpad::StackFrame; using google_breakpad::WindowsFrameInfo; -using google_breakpad::linked_ptr; using google_breakpad::scoped_ptr; using google_breakpad::SymbolParseHelper; @@ -83,26 +81,26 @@ class TestCodeModule : public CodeModule { class MockMemoryRegion: public MemoryRegion { uint64_t GetBase() const { return 0x10000; } uint32_t GetSize() const { return 0x01000; } - bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { *value = address & 0xff; return true; } - bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { *value = address & 0xffff; return true; } - bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { switch (address) { - case 0x10008: *value = 0x98ecadc3; break; // saved %ebx - case 0x1000c: *value = 0x878f7524; break; // saved %esi - case 0x10010: *value = 0x6312f9a5; break; // saved %edi - case 0x10014: *value = 0x10038; break; // caller's %ebp - case 0x10018: *value = 0xf6438648; break; // return address - default: *value = 0xdeadbeef; break; // junk + case 0x10008: *value = 0x98ecadc3; break; // saved %ebx + case 0x1000c: *value = 0x878f7524; break; // saved %esi + case 0x10010: *value = 0x6312f9a5; break; // saved %edi + case 0x10014: *value = 0x10038; break; // caller's %ebp + case 0x10018: *value = 0xf6438648; break; // return address + default: *value = 0xdeadbeef; break; // junk } return true; } - bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { *value = address; return true; } @@ -116,9 +114,9 @@ class MockMemoryRegion: public MemoryRegion { // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and // ".cfa". static bool VerifyRegisters( - const char *file, int line, - const CFIFrameInfo::RegisterValueMap<uint32_t> &expected, - const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) { + const char* file, int line, + const CFIFrameInfo::RegisterValueMap<uint32_t>& expected, + const CFIFrameInfo::RegisterValueMap<uint32_t>& actual) { CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a; a = actual.find(".cfa"); if (a == actual.end()) @@ -148,7 +146,7 @@ static bool VerifyRegisters( } -static bool VerifyEmpty(const StackFrame &frame) { +static bool VerifyEmpty(const StackFrame& frame) { if (frame.function_name.empty() && frame.source_file_name.empty() && frame.source_line == 0) @@ -156,7 +154,7 @@ static bool VerifyEmpty(const StackFrame &frame) { return false; } -static void ClearSourceLineInfo(StackFrame *frame) { +static void ClearSourceLineInfo(StackFrame* frame) { frame->function_name.clear(); frame->module = NULL; frame->source_file_name.clear(); @@ -164,7 +162,7 @@ static void ClearSourceLineInfo(StackFrame *frame) { } class TestBasicSourceLineResolver : public ::testing::Test { -public: + public: void SetUp() { testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") + "/src/processor/testdata"; @@ -189,16 +187,17 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve) scoped_ptr<CFIFrameInfo> cfi_frame_info; frame.instruction = 0x1000; frame.module = NULL; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_FALSE(frame.module); ASSERT_TRUE(frame.function_name.empty()); ASSERT_EQ(frame.function_base, 0U); ASSERT_TRUE(frame.source_file_name.empty()); ASSERT_EQ(frame.source_line, 0); ASSERT_EQ(frame.source_line_base, 0U); + EXPECT_EQ(frame.is_multiple, false); frame.module = &module1; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Function1_1"); ASSERT_TRUE(frame.module); ASSERT_EQ(frame.module->code_file(), "module1"); @@ -206,6 +205,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve) ASSERT_EQ(frame.source_file_name, "file1_1.cc"); ASSERT_EQ(frame.source_line, 44); ASSERT_EQ(frame.source_line_base, 0x1000U); + EXPECT_EQ(frame.is_multiple, true); windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); ASSERT_TRUE(windows_frame_info.get()); ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA); @@ -216,13 +216,13 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve) ClearSourceLineInfo(&frame); frame.instruction = 0x800; frame.module = &module1; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_TRUE(VerifyEmpty(frame)); windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); ASSERT_FALSE(windows_frame_info.get()); frame.instruction = 0x1280; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Function1_3"); ASSERT_TRUE(frame.source_file_name.empty()); ASSERT_EQ(frame.source_line, 0); @@ -233,7 +233,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve) ASSERT_TRUE(windows_frame_info->program_string.empty()); frame.instruction = 0x1380; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Function1_4"); ASSERT_TRUE(frame.source_file_name.empty()); ASSERT_EQ(frame.source_line, 0); @@ -342,17 +342,18 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve) frame.instruction = 0x2900; frame.module = &module1; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, string("PublicSymbol")); + EXPECT_EQ(frame.is_multiple, true); frame.instruction = 0x4000; frame.module = &module1; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, string("LargeFunction")); frame.instruction = 0x2181; frame.module = &module2; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Function2_2"); ASSERT_EQ(frame.function_base, 0x2170U); ASSERT_TRUE(frame.module); @@ -360,24 +361,26 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve) ASSERT_EQ(frame.source_file_name, "file2_2.cc"); ASSERT_EQ(frame.source_line, 21); ASSERT_EQ(frame.source_line_base, 0x2180U); + EXPECT_EQ(frame.is_multiple, false); windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); ASSERT_TRUE(windows_frame_info.get()); ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA); ASSERT_EQ(windows_frame_info->prolog_size, 1U); frame.instruction = 0x216f; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Public2_1"); + EXPECT_EQ(frame.is_multiple, false); ClearSourceLineInfo(&frame); frame.instruction = 0x219f; frame.module = &module2; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_TRUE(frame.function_name.empty()); frame.instruction = 0x21a0; frame.module = &module2; - resolver.FillSourceLineInfo(&frame); + resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Public2_2"); } @@ -413,11 +416,101 @@ TEST_F(TestBasicSourceLineResolver, TestUnload) ASSERT_TRUE(resolver.HasModule(&module1)); } +TEST_F(TestBasicSourceLineResolver, TestLoadAndResolveOldInlines) { + TestCodeModule module("linux_inline"); + ASSERT_TRUE(resolver.LoadModule( + &module, testdata_dir + + "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/" + "linux_inline.old.sym")); + ASSERT_TRUE(resolver.HasModule(&module)); + StackFrame frame; + std::deque<std::unique_ptr<StackFrame>> inlined_frames; + frame.instruction = 0x161b6; + frame.module = &module; + // main frame. + resolver.FillSourceLineInfo(&frame, &inlined_frames); + ASSERT_EQ(frame.function_name, "main"); + ASSERT_EQ(frame.function_base, 0x15b30U); + ASSERT_EQ(frame.source_file_name, "linux_inline.cpp"); + ASSERT_EQ(frame.source_line, 42); + ASSERT_EQ(frame.source_line_base, 0x161b6U); + EXPECT_EQ(frame.is_multiple, false); + + ASSERT_EQ(inlined_frames.size(), 3UL); + + // Inlined frames inside main frame. + ASSERT_EQ(inlined_frames[2]->function_name, "foo()"); + ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U); + ASSERT_EQ(inlined_frames[2]->source_file_name, "linux_inline.cpp"); + ASSERT_EQ(inlined_frames[2]->source_line, 39); + ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE); + + ASSERT_EQ(inlined_frames[1]->function_name, "bar()"); + ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U); + ASSERT_EQ(inlined_frames[1]->source_file_name, "linux_inline.cpp"); + ASSERT_EQ(inlined_frames[1]->source_line, 32); + ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE); + + ASSERT_EQ(inlined_frames[0]->function_name, "func()"); + ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U); + ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp"); + ASSERT_EQ(inlined_frames[0]->source_line, 27); + ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE); +} + +TEST_F(TestBasicSourceLineResolver, TestLoadAndResolveNewInlines) { + TestCodeModule module("linux_inline"); + ASSERT_TRUE(resolver.LoadModule( + &module, testdata_dir + + "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/" + "linux_inline.new.sym")); + ASSERT_TRUE(resolver.HasModule(&module)); + StackFrame frame; + std::deque<std::unique_ptr<StackFrame>> inlined_frames; + frame.instruction = 0x161b6; + frame.module = &module; + // main frame. + resolver.FillSourceLineInfo(&frame, &inlined_frames); + ASSERT_EQ(frame.function_name, "main"); + ASSERT_EQ(frame.function_base, 0x15b30U); + ASSERT_EQ(frame.source_file_name, "a.cpp"); + ASSERT_EQ(frame.source_line, 42); + ASSERT_EQ(frame.source_line_base, 0x161b6U); + EXPECT_EQ(frame.is_multiple, false); + + ASSERT_EQ(inlined_frames.size(), 3UL); + + // Inlined frames inside main frame. + ASSERT_EQ(inlined_frames[2]->function_name, "foo()"); + ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U); + ASSERT_EQ(inlined_frames[2]->source_file_name, "b.cpp"); + ASSERT_EQ(inlined_frames[2]->source_line, 39); + ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE); + + ASSERT_EQ(inlined_frames[1]->function_name, "bar()"); + ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U); + ASSERT_EQ(inlined_frames[1]->source_file_name, "c.cpp"); + ASSERT_EQ(inlined_frames[1]->source_line, 32); + ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE); + + ASSERT_EQ(inlined_frames[0]->function_name, "func()"); + ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U); + ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp"); + ASSERT_EQ(inlined_frames[0]->source_line, 27); + ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE); +} + // Test parsing of valid FILE lines. The format is: // FILE <id> <filename> TEST(SymbolParseHelper, ParseFileValid) { long index; - char *filename; + char* filename; char kTestLine[] = "FILE 1 file name"; ASSERT_TRUE(SymbolParseHelper::ParseFile(kTestLine, &index, &filename)); @@ -435,7 +528,7 @@ TEST(SymbolParseHelper, ParseFileValid) { // FILE <id> <filename> TEST(SymbolParseHelper, ParseFileInvalid) { long index; - char *filename; + char* filename; // Test missing file name. char kTestLine[] = "FILE 1 "; @@ -461,7 +554,7 @@ TEST(SymbolParseHelper, ParseFunctionValid) { uint64_t address; uint64_t size; long stack_param_size; - char *name; + char* name; char kTestLine[] = "FUNC 1 2 3 function name"; ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine, &multiple, &address, @@ -513,7 +606,7 @@ TEST(SymbolParseHelper, ParseFunctionInvalid) { uint64_t address; uint64_t size; long stack_param_size; - char *name; + char* name; // Test missing function name. char kTestLine[] = "FUNC 1 2 3 "; @@ -649,7 +742,7 @@ TEST(SymbolParseHelper, ParsePublicSymbolValid) { bool multiple; uint64_t address; long stack_param_size; - char *name; + char* name; char kTestLine[] = "PUBLIC 1 2 3"; ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine, &multiple, @@ -697,7 +790,7 @@ TEST(SymbolParseHelper, ParsePublicSymbolInvalid) { bool multiple; uint64_t address; long stack_param_size; - char *name; + char* name; // Test missing source function name. char kTestLine[] = "PUBLIC 1 2 "; @@ -736,9 +829,179 @@ TEST(SymbolParseHelper, ParsePublicSymbolInvalid) { &name)); } +// Test parsing of valid INLINE_ORIGIN lines. +// The old format: +// INLINE_ORIGIN <origin_id> <file_id> <name> +// The new format: +// INLINE_ORIGIN <origin_id> <name> +TEST(SymbolParseHelper, ParseInlineOriginValid) { + bool has_file_id; + long origin_id; + long file_id; + char* name; + // Test for old format. + char kTestLine[] = "INLINE_ORIGIN 1 1 function name"; + ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin( + kTestLine, &has_file_id, &origin_id, &file_id, &name)); + EXPECT_EQ(true, has_file_id); + EXPECT_EQ(1, origin_id); + EXPECT_EQ(1, file_id); + EXPECT_EQ("function name", string(name)); + + // -1 is a file id, which is used when the function is artifical. + char kTestLine1[] = "INLINE_ORIGIN 0 -1 function name"; + ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin( + kTestLine1, &has_file_id, &origin_id, &file_id, &name)); + EXPECT_EQ(true, has_file_id); + EXPECT_EQ(0, origin_id); + EXPECT_EQ(-1, file_id); + EXPECT_EQ("function name", string(name)); + + // Test for new format. + char kTestLine2[] = "INLINE_ORIGIN 0 function name"; + ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin( + kTestLine2, &has_file_id, &origin_id, &file_id, &name)); + EXPECT_EQ(false, has_file_id); + EXPECT_EQ(0, origin_id); + EXPECT_EQ("function name", string(name)); + + char kTestLine3[] = "INLINE_ORIGIN 0 function"; + ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin( + kTestLine3, &has_file_id, &origin_id, &file_id, &name)); + EXPECT_EQ(false, has_file_id); + EXPECT_EQ(0, origin_id); + EXPECT_EQ("function", string(name)); +} + +// Test parsing of valid INLINE ORIGIN lines. The format is: +// INLINE_ORIGIN <origin_id> <file_id> <name> +TEST(SymbolParseHelper, ParseInlineOriginInvalid) { + bool has_file_id; + long origin_id; + long file_id; + char* name; + + // Test missing function name. + char kTestLine[] = "INLINE_ORIGIN 1 1"; + ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin( + kTestLine, &has_file_id, &origin_id, &file_id, &name)); + + // Test bad origin id. + char kTestLine1[] = "INLINE_ORIGIN x1 1 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin( + kTestLine1, &has_file_id, &origin_id, &file_id, &name)); + + // Test large origin id. + char kTestLine2[] = "INLINE_ORIGIN 123123123123123123123123 1 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin( + kTestLine2, &has_file_id, &origin_id, &file_id, &name)); + + // Test negative origin id. + char kTestLine3[] = "INLINE_ORIGIN -1 1 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin( + kTestLine3, &has_file_id, &origin_id, &file_id, &name)); +} + +// Test parsing of valid INLINE lines. +// The old format: +// INLINE <inline_nest_level> <call_site_line> <origin_id> [<address> <size>]+ +// The new format: +// INLINE <inline_nest_level> <call_site_line> <call_site_file_id> <origin_id> +// [<address> <size>]+ +TEST(SymbolParseHelper, ParseInlineValid) { + bool has_call_site_file_id; + long inline_nest_level; + long call_site_line; + long call_site_file_id; + long origin_id; + std::vector<std::pair<uint64_t, uint64_t>> ranges; + + // Test for old format. + char kTestLine[] = "INLINE 0 1 2 3 4"; + ASSERT_TRUE(SymbolParseHelper::ParseInline( + kTestLine, &has_call_site_file_id, &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)); + EXPECT_EQ(false, has_call_site_file_id); + EXPECT_EQ(0, inline_nest_level); + EXPECT_EQ(1, call_site_line); + EXPECT_EQ(2, origin_id); + EXPECT_EQ(0x3ULL, ranges[0].first); + EXPECT_EQ(0x4ULL, ranges[0].second); + ranges.clear(); + + // Test hex and discontinuous ranges. + char kTestLine1[] = "INLINE 0 1 2 a b 1a 1b"; + ASSERT_TRUE(SymbolParseHelper::ParseInline( + kTestLine1, &has_call_site_file_id, &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)); + EXPECT_EQ(false, has_call_site_file_id); + EXPECT_EQ(0, inline_nest_level); + EXPECT_EQ(1, call_site_line); + EXPECT_EQ(2, origin_id); + EXPECT_EQ(0xaULL, ranges[0].first); + EXPECT_EQ(0xbULL, ranges[0].second); + EXPECT_EQ(0x1aULL, ranges[1].first); + EXPECT_EQ(0x1bULL, ranges[1].second); + + // Test for new format. + char kTestLine2[] = "INLINE 0 1 2 3 a b 1a 1b"; + ASSERT_TRUE(SymbolParseHelper::ParseInline( + kTestLine2, &has_call_site_file_id, &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)); + EXPECT_EQ(true, has_call_site_file_id); + EXPECT_EQ(0, inline_nest_level); + EXPECT_EQ(1, call_site_line); + EXPECT_EQ(2, call_site_file_id); + EXPECT_EQ(3, origin_id); + EXPECT_EQ(0xaULL, ranges[0].first); + EXPECT_EQ(0xbULL, ranges[0].second); + EXPECT_EQ(0x1aULL, ranges[1].first); + EXPECT_EQ(0x1bULL, ranges[1].second); +} + +// Test parsing of Invalid INLINE lines. +TEST(SymbolParseHelper, ParseInlineInvalid) { + bool has_call_site_file_id; + long inline_nest_level; + long call_site_line; + long call_site_file_id; + long origin_id; + std::vector<std::pair<uint64_t, uint64_t>> ranges; + + // Test negative inline_nest_level. + char kTestLine[] = "INLINE -1 1 2 3 4"; + ASSERT_FALSE(SymbolParseHelper::ParseInline( + kTestLine, &has_call_site_file_id, &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)); + + // Test negative call_site_line. + char kTestLine1[] = "INLINE 0 -1 2 3 4"; + ASSERT_FALSE(SymbolParseHelper::ParseInline( + kTestLine1, &has_call_site_file_id, &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)); + + // Test negative origin_id. + char kTestLine2[] = "INLINE 0 1 -2 3 4"; + ASSERT_FALSE(SymbolParseHelper::ParseInline( + kTestLine2, &has_call_site_file_id, &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)); + + // Test missing ranges. + char kTestLine3[] = "INLINE 0 1 -2"; + ASSERT_FALSE(SymbolParseHelper::ParseInline( + kTestLine3, &has_call_site_file_id, &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)); + + // Test missing size for range. + char kTestLine4[] = "INLINE 0 1 -2 3"; + ASSERT_FALSE(SymbolParseHelper::ParseInline( + kTestLine4, &has_call_site_file_id, &inline_nest_level, &call_site_line, + &call_site_file_id, &origin_id, &ranges)); +} + } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/src/processor/call_stack.cc b/src/processor/call_stack.cc index 925f0846..87ffd1ae 100644 --- a/src/processor/call_stack.cc +++ b/src/processor/call_stack.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -43,7 +42,7 @@ CallStack::~CallStack() { } void CallStack::Clear() { - for (vector<StackFrame *>::const_iterator iterator = frames_.begin(); + for (vector<StackFrame*>::const_iterator iterator = frames_.begin(); iterator != frames_.end(); ++iterator) { delete *iterator; diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-inl.h index 7e7af0af..acfc4f79 100644 --- a/src/processor/cfi_frame_info-inl.h +++ b/src/processor/cfi_frame_info-inl.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,12 +41,12 @@ namespace google_breakpad { template <typename RegisterType, class RawContextType> bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters( - const MemoryRegion &memory, - const CFIFrameInfo &cfi_frame_info, - const RawContextType &callee_context, + const MemoryRegion& memory, + const CFIFrameInfo& cfi_frame_info, + const RawContextType& callee_context, int callee_validity, - RawContextType *caller_context, - int *caller_validity) const { + RawContextType* caller_context, + int* caller_validity) const { typedef CFIFrameInfo::RegisterValueMap<RegisterType> ValueMap; ValueMap callee_registers; ValueMap caller_registers; @@ -56,7 +55,7 @@ bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters( // Populate callee_registers with register values from callee_context. for (size_t i = 0; i < map_size_; i++) { - const RegisterSet &r = register_map_[i]; + const RegisterSet& r = register_map_[i]; if (callee_validity & r.validity_flag) callee_registers[r.name] = callee_context.*r.context_member; } @@ -71,7 +70,7 @@ bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters( memset(caller_context, 0xda, sizeof(*caller_context)); *caller_validity = 0; for (size_t i = 0; i < map_size_; i++) { - const RegisterSet &r = register_map_[i]; + const RegisterSet& r = register_map_[i]; typename ValueMap::const_iterator caller_entry; // Did the rules provide a value for this register by its name? diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc index 0c4af7ba..5216a44e 100644 --- a/src/processor/cfi_frame_info.cc +++ b/src/processor/cfi_frame_info.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -48,9 +47,9 @@ namespace google_breakpad { #endif template<typename V> -bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> ®isters, - const MemoryRegion &memory, - RegisterValueMap<V> *caller_registers) const { +bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V>& registers, + const MemoryRegion& memory, + RegisterValueMap<V>* caller_registers) const { // If there are not rules for both .ra and .cfa in effect at this address, // don't use this CFI data for stack walking. if (cfa_rule_.empty() || ra_rule_.empty()) @@ -81,7 +80,7 @@ bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> ®isters, working = registers; working[".cfa"] = cfa; if (!evaluator.EvaluateForValue(it->second, &value)) - return false; + continue; (*caller_registers)[it->first] = value; } @@ -93,13 +92,13 @@ bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> ®isters, // Explicit instantiations for 32-bit and 64-bit architectures. template bool CFIFrameInfo::FindCallerRegs<uint32_t>( - const RegisterValueMap<uint32_t> ®isters, - const MemoryRegion &memory, - RegisterValueMap<uint32_t> *caller_registers) const; + const RegisterValueMap<uint32_t>& registers, + const MemoryRegion& memory, + RegisterValueMap<uint32_t>* caller_registers) const; template bool CFIFrameInfo::FindCallerRegs<uint64_t>( - const RegisterValueMap<uint64_t> ®isters, - const MemoryRegion &memory, - RegisterValueMap<uint64_t> *caller_registers) const; + const RegisterValueMap<uint64_t>& registers, + const MemoryRegion& memory, + RegisterValueMap<uint64_t>* caller_registers) const; string CFIFrameInfo::Serialize() const { std::ostringstream stream; @@ -123,7 +122,7 @@ string CFIFrameInfo::Serialize() const { return stream.str(); } -bool CFIRuleParser::Parse(const string &rule_set) { +bool CFIRuleParser::Parse(const string& rule_set) { size_t rule_set_len = rule_set.size(); scoped_array<char> working_copy(new char[rule_set_len + 1]); memcpy(working_copy.get(), rule_set.data(), rule_set_len); @@ -132,9 +131,9 @@ bool CFIRuleParser::Parse(const string &rule_set) { name_.clear(); expression_.clear(); - char *cursor; + char* cursor; static const char token_breaks[] = " \t\r\n"; - char *token = strtok_r(working_copy.get(), token_breaks, &cursor); + char* token = strtok_r(working_copy.get(), token_breaks, &cursor); for (;;) { // End of rule set? @@ -170,16 +169,16 @@ bool CFIRuleParser::Report() { return true; } -void CFIFrameInfoParseHandler::CFARule(const string &expression) { +void CFIFrameInfoParseHandler::CFARule(const string& expression) { frame_info_->SetCFARule(expression); } -void CFIFrameInfoParseHandler::RARule(const string &expression) { +void CFIFrameInfoParseHandler::RARule(const string& expression) { frame_info_->SetRARule(expression); } -void CFIFrameInfoParseHandler::RegisterRule(const string &name, - const string &expression) { +void CFIFrameInfoParseHandler::RegisterRule(const string& name, + const string& expression) { frame_info_->SetRegisterRule(name, expression); } diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h index 90a1b3d7..08f1eb72 100644 --- a/src/processor/cfi_frame_info.h +++ b/src/processor/cfi_frame_info.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -72,9 +71,9 @@ class CFIFrameInfo { // Set the expression for computing a call frame address, return // address, or register's value. At least the CFA rule and the RA // rule must be set before calling FindCallerRegs. - void SetCFARule(const string &expression) { cfa_rule_ = expression; } - void SetRARule(const string &expression) { ra_rule_ = expression; } - void SetRegisterRule(const string ®ister_name, const string &expression) { + void SetCFARule(const string& expression) { cfa_rule_ = expression; } + void SetRARule(const string& expression) { ra_rule_ = expression; } + void SetRegisterRule(const string& register_name, const string& expression) { register_rules_[register_name] = expression; } @@ -96,9 +95,9 @@ class CFIFrameInfo { // These may be helpful in computing the caller's PC and stack // pointer, if their values are not explicitly specified. template<typename ValueType> - bool FindCallerRegs(const RegisterValueMap<ValueType> ®isters, - const MemoryRegion &memory, - RegisterValueMap<ValueType> *caller_registers) const; + bool FindCallerRegs(const RegisterValueMap<ValueType>& registers, + const MemoryRegion& memory, + RegisterValueMap<ValueType>* caller_registers) const; // Serialize the rules in this object into a string in the format // of STACK CFI records. @@ -148,28 +147,28 @@ class CFIRuleParser { virtual ~Handler() { } // The input specifies EXPRESSION as the CFA/RA computation rule. - virtual void CFARule(const string &expression) = 0; - virtual void RARule(const string &expression) = 0; + virtual void CFARule(const string& expression) = 0; + virtual void RARule(const string& expression) = 0; // The input specifies EXPRESSION as the recovery rule for register NAME. - virtual void RegisterRule(const string &name, const string &expression) = 0; + virtual void RegisterRule(const string& name, const string& expression) = 0; }; // Construct a parser which feeds its results to HANDLER. - CFIRuleParser(Handler *handler) : handler_(handler) { } + CFIRuleParser(Handler* handler) : handler_(handler) { } // Parse RULE_SET as a set of CFA computation and RA/register // recovery rules, as appearing in STACK CFI records. Report the // results of parsing by making the appropriate calls to handler_. // Return true if parsing was successful, false otherwise. - bool Parse(const string &rule_set); + bool Parse(const string& rule_set); private: // Report any accumulated rule to handler_ bool Report(); // The handler to which the parser reports its findings. - Handler *handler_; + Handler* handler_; // Working data. string name_, expression_; @@ -180,15 +179,15 @@ class CFIRuleParser { class CFIFrameInfoParseHandler: public CFIRuleParser::Handler { public: // Populate FRAME_INFO with the results of parsing. - CFIFrameInfoParseHandler(CFIFrameInfo *frame_info) + CFIFrameInfoParseHandler(CFIFrameInfo* frame_info) : frame_info_(frame_info) { } - void CFARule(const string &expression); - void RARule(const string &expression); - void RegisterRule(const string &name, const string &expression); + void CFARule(const string& expression); + void RARule(const string& expression); + void RegisterRule(const string& name, const string& expression); private: - CFIFrameInfo *frame_info_; + CFIFrameInfo* frame_info_; }; // A utility class template for simple 'STACK CFI'-driven stack walkers. @@ -212,14 +211,14 @@ class SimpleCFIWalker { // A structure describing one architecture register. struct RegisterSet { // The register name, as it appears in STACK CFI rules. - const char *name; + const char* name; // An alternate name that the register's value might be found // under in a register value dictionary, or NULL. When generating // names, prefer NAME to this value. It's common to list ".cfa" as // an alternative name for the stack pointer, and ".ra" as an // alternative name for the instruction pointer. - const char *alternate_name; + const char* alternate_name; // True if the callee is expected to preserve the value of this // register. If this flag is true for some register R, and the STACK @@ -240,7 +239,7 @@ class SimpleCFIWalker { // architecture's register set. REGISTER_MAP is an array of // RegisterSet structures; MAP_SIZE is the number of elements in the // array. - SimpleCFIWalker(const RegisterSet *register_map, size_t map_size) + SimpleCFIWalker(const RegisterSet* register_map, size_t map_size) : register_map_(register_map), map_size_(map_size) { } // Compute the calling frame's raw context given the callee's raw @@ -256,15 +255,15 @@ class SimpleCFIWalker { // fill in CALLER_CONTEXT with the caller's register values, and set // CALLER_VALIDITY to indicate which registers are valid in // CALLER_CONTEXT. Return true on success, or false on failure. - bool FindCallerRegisters(const MemoryRegion &memory, - const CFIFrameInfo &cfi_frame_info, - const RawContextType &callee_context, + bool FindCallerRegisters(const MemoryRegion& memory, + const CFIFrameInfo& cfi_frame_info, + const RawContextType& callee_context, int callee_validity, - RawContextType *caller_context, - int *caller_validity) const; + RawContextType* caller_context, + int* caller_validity) const; private: - const RegisterSet *register_map_; + const RegisterSet* register_map_; size_t map_size_; }; diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc index 542b2849..85f970a5 100644 --- a/src/processor/cfi_frame_info_unittest.cc +++ b/src/processor/cfi_frame_info_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -56,10 +55,10 @@ class MockMemoryRegion: public MemoryRegion { public: MOCK_CONST_METHOD0(GetBase, uint64_t()); MOCK_CONST_METHOD0(GetSize, uint32_t()); - MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint8_t *)); - MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint16_t *)); - MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint32_t *)); - MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint64_t *)); + MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint8_t*)); + MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint16_t*)); + MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint32_t*)); + MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint64_t*)); MOCK_CONST_METHOD0(Print, void()); }; @@ -70,10 +69,10 @@ struct CFIFixture { void ExpectNoMemoryReferences() { EXPECT_CALL(memory, GetBase()).Times(0); EXPECT_CALL(memory, GetSize()).Times(0); - EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint8_t *>())).Times(0); - EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint16_t *>())).Times(0); - EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint32_t *>())).Times(0); - EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint64_t *>())).Times(0); + EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint8_t*>())).Times(0); + EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint16_t*>())).Times(0); + EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint32_t*>())).Times(0); + EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint64_t*>())).Times(0); } CFIFrameInfo cfi; @@ -254,8 +253,9 @@ TEST_F(Scope, RegsLackRA) { cfi.SetCFARule("42740329"); cfi.SetRARule("27045204"); cfi.SetRegisterRule("$r1", ".ra"); - ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory, - &caller_registers)); + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, + &caller_registers)); + ASSERT_EQ(caller_registers.end(), caller_registers.find("$r1")); } // Register rules can see the current frame's register values. @@ -292,9 +292,9 @@ TEST_F(Scope, SeparateTempsRA) { class MockCFIRuleParserHandler: public CFIRuleParser::Handler { public: - MOCK_METHOD1(CFARule, void(const string &)); - MOCK_METHOD1(RARule, void(const string &)); - MOCK_METHOD2(RegisterRule, void(const string &, const string &)); + MOCK_METHOD1(CFARule, void(const string&)); + MOCK_METHOD1(RARule, void(const string&)); + MOCK_METHOD2(RegisterRule, void(const string&, const string&)); }; // A fixture class for testing CFIRuleParser. @@ -439,6 +439,7 @@ TEST_F(ParseHandler, RegisterRules) { handler.RARule("reg-for-ra"); handler.RegisterRule("reg1", "reg-for-reg1"); handler.RegisterRule("reg2", "reg-for-reg2"); + handler.RegisterRule("reg3", "reg3"); registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL; registers["reg-for-ra"] = 0x6301b475b8b91c02ULL; registers["reg-for-reg1"] = 0x06cde8e2ff062481ULL; @@ -449,6 +450,7 @@ TEST_F(ParseHandler, RegisterRules) { ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]); ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers["reg1"]); ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers["reg2"]); + ASSERT_EQ(caller_registers.end(), caller_registers.find("reg3")); } struct SimpleCFIWalkerFixture { @@ -509,12 +511,12 @@ TEST_F(SimpleWalker, Walk) { // Saved r0. EXPECT_CALL(memory, - GetMemoryAtAddress(stack_top, A<uint64_t *>())) + GetMemoryAtAddress(stack_top, A<uint64_t*>())) .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xdc1975eba8602302ULL), Return(true))); // Saved return address. EXPECT_CALL(memory, - GetMemoryAtAddress(stack_top + 16, A<uint64_t *>())) + GetMemoryAtAddress(stack_top + 16, A<uint64_t*>())) .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xba5ad6d9acce28deULL), Return(true))); diff --git a/src/processor/contained_range_map-inl.h b/src/processor/contained_range_map-inl.h index 4c0ad41f..e085dcb4 100644 --- a/src/processor/contained_range_map-inl.h +++ b/src/processor/contained_range_map-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -55,7 +54,7 @@ ContainedRangeMap<AddressType, EntryType>::~ContainedRangeMap() { template<typename AddressType, typename EntryType> bool ContainedRangeMap<AddressType, EntryType>::StoreRange( - const AddressType &base, const AddressType &size, const EntryType &entry) { + const AddressType& base, const AddressType& size, const EntryType& entry) { AddressType high = base + size - 1; // Check for undersize or overflow. @@ -84,10 +83,12 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange( // range's, it violates the containment rules, and an attempt to store // it must fail. iterator_base->first contains the key, which was the // containing child's high address. - if (iterator_base->second->base_ == base && iterator_base->first == high) { + if (!allow_equal_range_ && iterator_base->second->base_ == base && + iterator_base->first == high) { // TODO(nealsid): See the TODO above on why this is commented out. -// BPLOG(INFO) << "StoreRange failed, identical range is already " -// "present: " << HexString(base) << "+" << HexString(size); + // BPLOG(INFO) << "StoreRange failed, identical range is already " + // "present: " << HexString(base) << "+" << + // HexString(size); return false; } @@ -125,7 +126,7 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange( // Optimization: if the iterators are equal, no child ranges would be // moved. Create the new child range with a NULL map to conserve space // in leaf nodes, of which there will be many. - AddressToRangeMap *child_map = NULL; + AddressToRangeMap* child_map = NULL; if (iterator_base != iterator_high) { // The children of this range that are contained by the new range must @@ -141,15 +142,17 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange( // the new child range contains were formerly children of this range but // are now this range's grandchildren. Ownership of these is transferred // to the new child range. - map_->insert(MapValue(high, - new ContainedRangeMap(base, entry, child_map))); + ContainedRangeMap* new_child = + new ContainedRangeMap(base, entry, child_map, allow_equal_range_); + + map_->insert(MapValue(high, new_child)); return true; } template<typename AddressType, typename EntryType> bool ContainedRangeMap<AddressType, EntryType>::RetrieveRange( - const AddressType &address, EntryType *entry) const { + const AddressType& address, EntryType* entry) const { BPLOG_IF(ERROR, !entry) << "ContainedRangeMap::RetrieveRange requires " "|entry|"; assert(entry); @@ -177,6 +180,20 @@ bool ContainedRangeMap<AddressType, EntryType>::RetrieveRange( return true; } +template <typename AddressType, typename EntryType> +bool ContainedRangeMap<AddressType, EntryType>::RetrieveRanges( + const AddressType& address, + std::vector<const EntryType*>& entries) const { + // If nothing was ever stored, then there's nothing to retrieve. + if (!map_) + return false; + MapIterator iterator = map_->lower_bound(address); + if (iterator == map_->end() || address < iterator->second->base_) + return false; + iterator->second->RetrieveRanges(address, entries); + entries.push_back(&iterator->second->entry_); + return true; +} template<typename AddressType, typename EntryType> void ContainedRangeMap<AddressType, EntryType>::Clear() { diff --git a/src/processor/contained_range_map.h b/src/processor/contained_range_map.h index 1015ae8c..24a3bb41 100644 --- a/src/processor/contained_range_map.h +++ b/src/processor/contained_range_map.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -62,6 +61,7 @@ #include <map> +#include <vector> namespace google_breakpad { @@ -75,7 +75,8 @@ class ContainedRangeMap { // The default constructor creates a ContainedRangeMap with no geometry // and no entry, and as such is only suitable for the root node of a // ContainedRangeMap tree. - ContainedRangeMap() : base_(), entry_(), map_(NULL) {} + explicit ContainedRangeMap(bool allow_equal_range = false) + : base_(), entry_(), map_(NULL), allow_equal_range_(allow_equal_range) {} ~ContainedRangeMap(); @@ -86,16 +87,21 @@ class ContainedRangeMap { // grandchildren of this ContainedRangeMap. Returns false for a // parameter error, or if the ContainedRangeMap hierarchy guarantees // would be violated. - bool StoreRange(const AddressType &base, - const AddressType &size, - const EntryType &entry); + bool StoreRange(const AddressType& base, + const AddressType& size, + const EntryType& entry); // Retrieves the most specific (smallest) descendant range encompassing // the specified address. This method will only return entries held by // child ranges, and not the entry contained by |this|. This is necessary // to support a sparsely-populated root range. If no descendant range // encompasses the address, returns false. - bool RetrieveRange(const AddressType &address, EntryType *entry) const; + bool RetrieveRange(const AddressType& address, EntryType* entries) const; + + // Retrieves the vector of entries encompassing the specified address from the + // innermost entry to the outermost entry. + bool RetrieveRanges(const AddressType& address, + std::vector<const EntryType*>& entries) const; // Removes all children. Note that Clear only removes descendants, // leaving the node on which it is called intact. Because the only @@ -110,7 +116,7 @@ class ContainedRangeMap { // AddressToRangeMap stores pointers. This makes reparenting simpler in // StoreRange, because it doesn't need to copy entire objects. - typedef std::map<AddressType, ContainedRangeMap *> AddressToRangeMap; + typedef std::map<AddressType, ContainedRangeMap*> AddressToRangeMap; typedef typename AddressToRangeMap::const_iterator MapConstIterator; typedef typename AddressToRangeMap::iterator MapIterator; typedef typename AddressToRangeMap::value_type MapValue; @@ -118,9 +124,14 @@ class ContainedRangeMap { // Creates a new ContainedRangeMap with the specified base address, entry, // and initial child map, which may be NULL. This is only used internally // by ContainedRangeMap when it creates a new child. - ContainedRangeMap(const AddressType &base, const EntryType &entry, - AddressToRangeMap *map) - : base_(base), entry_(entry), map_(map) {} + ContainedRangeMap(const AddressType& base, + const EntryType& entry, + AddressToRangeMap* map, + bool allow_equal_range) + : base_(base), + entry_(entry), + map_(map), + allow_equal_range_(allow_equal_range) {} // The base address of this range. The high address does not need to // be stored, because it is used as the key to an object in its parent's @@ -140,7 +151,13 @@ class ContainedRangeMap { // The map containing child ranges, keyed by each child range's high // address. This is a pointer to avoid allocating map structures for // leaf nodes, where they are not needed. - AddressToRangeMap *map_; + AddressToRangeMap* map_; + + // Whether or not we allow storing an entry into a range that equals to + // existing range in the map. Default is false. + // If this is true, the newly added range will become a child of existing + // innermost range which has same base and size. + bool allow_equal_range_; }; diff --git a/src/processor/contained_range_map_unittest.cc b/src/processor/contained_range_map_unittest.cc index e5910da0..670bb189 100644 --- a/src/processor/contained_range_map_unittest.cc +++ b/src/processor/contained_range_map_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -51,9 +50,82 @@ namespace { using google_breakpad::ContainedRangeMap; +// The first is the querying address, the second is the entries vector result. +using EntriesTestPair = std::pair<unsigned, std::vector<int>>; +using EntriesTestPairVec = std::vector<EntriesTestPair>; +static bool RunTestsWithRetrieveRange( + const ContainedRangeMap<unsigned int, int>& crm, + const int* test_data, + unsigned int test_length) { + // Now, do the RetrieveRange tests. This further validates that the + // objects were stored properly and that retrieval returns the correct + // object. + // If GENERATE_TEST_DATA is defined, instead of the retrieval tests, a + // new test_data array will be printed. Exercise caution when doing this. + // Be sure to verify the results manually! +#ifdef GENERATE_TEST_DATA + printf(" const int test_data[] = {\n"); +#endif // GENERATE_TEST_DATA -static bool RunTests() { + for (unsigned int address = 0; address < test_length; ++address) { + int value; + if (!crm.RetrieveRange(address, &value)) + value = 0; + +#ifndef GENERATE_TEST_DATA + // Don't use ASSERT inside the loop because it won't show the failed + // |address|, and the line number will always be the same. That makes + // it difficult to figure out which test failed. + if (value != test_data[address]) { + fprintf(stderr, "FAIL: retrieve %d expected %d observed %d @ %s:%d\n", + address, test_data[address], value, __FILE__, __LINE__); + return false; + } +#else // !GENERATE_TEST_DATA + printf(" %d%c%s // %d\n", value, address == test_high - 1 ? ' ' : ',', + value < 10 ? " " : "", address); +#endif // !GENERATE_TEST_DATA + } + +#ifdef GENERATE_TEST_DATA + printf(" };\n"); +#endif // GENERATE_TEST_DATA + + return true; +} + +static bool RunTestsWithRetrieveRangeVector( + const ContainedRangeMap<unsigned int, int>& crm, + const EntriesTestPairVec& entries_tests) { + for (const EntriesTestPair& entries_test : entries_tests) { + std::vector<const int*> entries; + crm.RetrieveRanges(entries_test.first, entries); + if (entries.size() != entries_test.second.size()) { + fprintf(stderr, + "FAIL: retrieving entries at address %u has size %zu " + "expected to have size %zu " + "@ %s: %d\n", + entries_test.first, entries.size(), entries_test.second.size(), + __FILE__, __LINE__); + return false; + } + for (size_t i = 0; i < entries.size(); ++i) { + if (*entries[i] != entries_test.second[i]) { + fprintf(stderr, + "FAIL: retrieving entries at address %u entries[%zu] is %d " + "expected %d" + "@ %s: %d\n", + entries_test.first, i, *entries[i], entries_test.second[i], + __FILE__, __LINE__); + return false; + } + } + } + return true; +} + +static bool RunTestsWithNoEqualRange() { ContainedRangeMap<unsigned int, int> crm; // First, do the StoreRange tests. This validates the containment @@ -211,52 +283,96 @@ static bool RunTests() { 0, // 98 0 // 99 }; - unsigned int test_high = sizeof(test_data) / sizeof(int); + unsigned int test_length = sizeof(test_data) / sizeof(int); + return RunTestsWithRetrieveRange(crm, test_data, test_length); +} - // Now, do the RetrieveRange tests. This further validates that the - // objects were stored properly and that retrieval returns the correct - // object. - // If GENERATE_TEST_DATA is defined, instead of the retrieval tests, a - // new test_data array will be printed. Exercise caution when doing this. - // Be sure to verify the results manually! -#ifdef GENERATE_TEST_DATA - printf(" const int test_data[] = {\n"); -#endif // GENERATE_TEST_DATA +static bool RunTestsWithEqualRange() { + ContainedRangeMap<unsigned int, int> crm(true); - for (unsigned int address = 0; address < test_high; ++address) { - int value; - if (!crm.RetrieveRange(address, &value)) - value = 0; + // First, do the StoreRange tests. This validates the containment + // rules. + ASSERT_TRUE (crm.StoreRange(1, 3, 1)); + ASSERT_TRUE (crm.StoreRange(1, 3, 2)); // exactly equal to 1 + ASSERT_TRUE (crm.StoreRange(1, 3, 3)); // exactly equal to 1, 2 + ASSERT_TRUE (crm.StoreRange(1, 3, 4)); // exactly equal to 1, 2, 3 + ASSERT_FALSE(crm.StoreRange(0, 3, 5)); // partial overlap. + ASSERT_FALSE(crm.StoreRange(2, 3, 6)); // partial overlap. -#ifndef GENERATE_TEST_DATA - // Don't use ASSERT inside the loop because it won't show the failed - // |address|, and the line number will always be the same. That makes - // it difficult to figure out which test failed. - if (value != test_data[address]) { - fprintf(stderr, "FAIL: retrieve %d expected %d observed %d @ %s:%d\n", - address, test_data[address], value, __FILE__, __LINE__); - return false; - } -#else // !GENERATE_TEST_DATA - printf(" %d%c%s // %d\n", value, - address == test_high - 1 ? ' ' : ',', - value < 10 ? " " : "", - address); -#endif // !GENERATE_TEST_DATA - } + ASSERT_TRUE (crm.StoreRange(5, 3, 7)); + ASSERT_TRUE (crm.StoreRange(5, 3, 8)); // exactly equal to 7 + ASSERT_TRUE (crm.StoreRange(5, 3, 9)); // exactly equal to 7, 8 + ASSERT_TRUE (crm.StoreRange(5, 4, 10)); // encompasses 7, 8, 9 + ASSERT_TRUE (crm.StoreRange(5, 5, 11)); // encompasses 7, 8, 9, 10 -#ifdef GENERATE_TEST_DATA - printf(" };\n"); -#endif // GENERATE_TEST_DATA + ASSERT_TRUE (crm.StoreRange(10, 3, 12)); + ASSERT_TRUE (crm.StoreRange(10, 3, 13)); // exactly equal to 12 + ASSERT_TRUE (crm.StoreRange(11, 2, 14)); // encompasses by 12 + ASSERT_TRUE (crm.StoreRange(11, 1, 15)); // encompasses by 12, 13 - return true; + ASSERT_TRUE (crm.StoreRange(14, 3, 16)); + ASSERT_TRUE (crm.StoreRange(14, 3, 17)); // exactly equal to 14 + ASSERT_TRUE (crm.StoreRange(14, 1, 18)); // encompasses by 14, 15 + ASSERT_TRUE (crm.StoreRange(14, 2, 19)); // encompasses by 14, 15 and encompasses 16 + ASSERT_TRUE (crm.StoreRange(14, 1, 20)); // exactly equal to 18 + ASSERT_TRUE (crm.StoreRange(14, 2, 21)); // exactly equal to 19 + + // Each element in test_data contains the expected result when calling + // RetrieveRange on an address. + const int test_data[] = { + 0, // 0 + 4, // 1 + 4, // 2 + 4, // 3 + 0, // 4 + 9, // 5 + 9, // 6 + 9, // 7 + 10, // 8 + 11, // 9 + 13, // 10 + 15, // 11 + 14, // 12 + 0, // 13 + 20, // 14 + 21, // 15 + 17, // 16 + 0, // 17 + }; + unsigned int test_length = sizeof(test_data) / sizeof(int); + EntriesTestPairVec entries_tests = { + {0, {}}, + {1, {4, 3, 2, 1}}, + {2, {4, 3, 2, 1}}, + {3, {4, 3, 2, 1}}, + {4, {}}, + {5, {9, 8, 7, 10, 11}}, + {6, {9, 8, 7, 10, 11}}, + {7, {9, 8, 7, 10, 11}}, + {8, {10, 11}}, + {9, {11}}, + {10, {13, 12}}, + {11, {15, 14, 13, 12}}, + {12, {14, 13, 12}}, + {13, {}}, + {14, {20, 18, 21, 19, 17, 16}}, + {15, {21, 19, 17, 16}}, + {16, {17, 16}}, + {17, {}}, + }; + return RunTestsWithRetrieveRange(crm, test_data, test_length) && + RunTestsWithRetrieveRangeVector(crm, entries_tests); +} + +static bool RunTests() { + return RunTestsWithNoEqualRange() && RunTestsWithEqualRange(); } } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { BPLOG_INIT(&argc, &argv); return RunTests() ? 0 : 1; diff --git a/src/processor/convert_old_arm64_context.cc b/src/processor/convert_old_arm64_context.cc index d4b749e7..8347064a 100644 --- a/src/processor/convert_old_arm64_context.cc +++ b/src/processor/convert_old_arm64_context.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2018, Google Inc. -// All rights reserved. +// Copyright 2018 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/convert_old_arm64_context.h b/src/processor/convert_old_arm64_context.h index 8c0dfe90..241b9259 100644 --- a/src/processor/convert_old_arm64_context.h +++ b/src/processor/convert_old_arm64_context.h @@ -1,5 +1,4 @@ -// Copyright (c) 2018, Google Inc. -// All rights reserved. +// Copyright 2018 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/disassembler_objdump.cc b/src/processor/disassembler_objdump.cc new file mode 100644 index 00000000..dfe10d58 --- /dev/null +++ b/src/processor/disassembler_objdump.cc @@ -0,0 +1,520 @@ +// Copyright (c) 2022, Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// disassembler_objdump.: Disassembler that invokes objdump for disassembly. +// +// Author: Mark Brand + +#include "processor/disassembler_objdump.h" + +#ifdef __linux__ +#include <unistd.h> +#include <fstream> +#include <iostream> +#include <iterator> +#include <regex> +#include <sstream> +#include <vector> + +#include "processor/logging.h" + +namespace google_breakpad { +namespace { +const size_t kMaxX86InstructionLength = 15; + +// Small RAII wrapper for temporary files. +// +// Example: +// ScopedTmpFile tmp("/tmp/tmpfile-XXXX"); +// if (tmp.Create()) { +// std::cerr << tmp.path() << std::endl; +// } +class ScopedTmpFile { + public: + // Initialize the ScopedTmpFile object - this does not create the temporary + // file yet. + ScopedTmpFile(const char* path_format); + ~ScopedTmpFile(); + + // Creates the temporary file, returns true on success. + bool Create(); + + // Writes bytes to the temporary file, returns true on success. + bool Write(const uint8_t* bytes, unsigned int bytes_len); + + // Returns the path of the temporary file. + string path() const { return path_; } + + private: + int fd_; + string path_; +}; + +ScopedTmpFile::ScopedTmpFile(const char* path_format) : path_(path_format) {} + +ScopedTmpFile::~ScopedTmpFile() { + if (fd_) { + close(fd_); + unlink(path_.c_str()); + } +} + +bool ScopedTmpFile::Create() { + fd_ = mkstemp(path_.data()); + if (fd_ < 0) { + unlink(path_.c_str()); + fd_ = 0; + path_ = ""; + return false; + } + + return true; +} + +bool ScopedTmpFile::Write(const uint8_t* bytes, unsigned int bytes_len) { + if (fd_) { + do { + ssize_t result = write(fd_, bytes, bytes_len); + if (result < 0) { + break; + } + + bytes += result; + bytes_len -= result; + } while (bytes_len); + } + + return bytes_len == 0; +} + +bool IsInstructionPrefix(const string& token) { + if (token == "lock" || token == "rep" || token == "repz" || + token == "repnz") { + return true; + } + return false; +} + +bool IsOperandSize(const string& token) { + if (token == "BYTE" || token == "WORD" || token == "DWORD" || + token == "QWORD" || token == "PTR") { + return true; + } + return false; +} + +bool GetSegmentAddressX86(const DumpContext& context, string segment_name, + uint64_t& address) { + if (segment_name == "ds") { + address = context.GetContextX86()->ds; + } else if (segment_name == "es") { + address = context.GetContextX86()->es; + } else if (segment_name == "fs") { + address = context.GetContextX86()->fs; + } else if (segment_name == "gs") { + address = context.GetContextX86()->gs; + } else { + BPLOG(ERROR) << "Unsupported segment register: " << segment_name; + return false; + } + + return true; +} + +bool GetSegmentAddressAMD64(const DumpContext& context, string segment_name, + uint64_t& address) { + if (segment_name == "ds") { + address = 0; + } else if (segment_name == "es") { + address = 0; + } else { + BPLOG(ERROR) << "Unsupported segment register: " << segment_name; + return false; + } + + return true; +} + +bool GetSegmentAddress(const DumpContext& context, string segment_name, + uint64_t& address) { + if (context.GetContextCPU() == MD_CONTEXT_X86) { + return GetSegmentAddressX86(context, segment_name, address); + } else if (context.GetContextCPU() == MD_CONTEXT_AMD64) { + return GetSegmentAddressAMD64(context, segment_name, address); + } else { + BPLOG(ERROR) << "Unsupported architecture for GetSegmentAddress\n"; + return false; + } +} + +bool GetRegisterValueX86(const DumpContext& context, string register_name, + uint64_t& value) { + if (register_name == "eax") { + value = context.GetContextX86()->eax; + } else if (register_name == "ebx") { + value = context.GetContextX86()->ebx; + } else if (register_name == "ecx") { + value = context.GetContextX86()->ecx; + } else if (register_name == "edx") { + value = context.GetContextX86()->edx; + } else if (register_name == "edi") { + value = context.GetContextX86()->edi; + } else if (register_name == "esi") { + value = context.GetContextX86()->esi; + } else if (register_name == "ebp") { + value = context.GetContextX86()->ebp; + } else if (register_name == "esp") { + value = context.GetContextX86()->esp; + } else if (register_name == "eip") { + value = context.GetContextX86()->eip; + } else { + BPLOG(ERROR) << "Unsupported register: " << register_name; + return false; + } + + return true; +} + +bool GetRegisterValueAMD64(const DumpContext& context, string register_name, + uint64_t& value) { + if (register_name == "rax") { + value = context.GetContextAMD64()->rax; + } else if (register_name == "rbx") { + value = context.GetContextAMD64()->rbx; + } else if (register_name == "rcx") { + value = context.GetContextAMD64()->rcx; + } else if (register_name == "rdx") { + value = context.GetContextAMD64()->rdx; + } else if (register_name == "rdi") { + value = context.GetContextAMD64()->rdi; + } else if (register_name == "rsi") { + value = context.GetContextAMD64()->rsi; + } else if (register_name == "rbp") { + value = context.GetContextAMD64()->rbp; + } else if (register_name == "rsp") { + value = context.GetContextAMD64()->rsp; + } else if (register_name == "r8") { + value = context.GetContextAMD64()->r8; + } else if (register_name == "r9") { + value = context.GetContextAMD64()->r9; + } else if (register_name == "r10") { + value = context.GetContextAMD64()->r10; + } else if (register_name == "r11") { + value = context.GetContextAMD64()->r11; + } else if (register_name == "r12") { + value = context.GetContextAMD64()->r12; + } else if (register_name == "r13") { + value = context.GetContextAMD64()->r13; + } else if (register_name == "r14") { + value = context.GetContextAMD64()->r14; + } else if (register_name == "r15") { + value = context.GetContextAMD64()->r15; + } else if (register_name == "rip") { + value = context.GetContextAMD64()->rip; + } else { + BPLOG(ERROR) << "Unsupported register: " << register_name; + return false; + } + + return true; +} + +// Lookup the value of `register_name` in `context`, store it into `value` on +// success. +// Support for non-full-size registers not implemented, since we're only using +// this to evaluate address expressions. +bool GetRegisterValue(const DumpContext& context, string register_name, + uint64_t& value) { + if (context.GetContextCPU() == MD_CONTEXT_X86) { + return GetRegisterValueX86(context, register_name, value); + } else if (context.GetContextCPU() == MD_CONTEXT_AMD64) { + return GetRegisterValueAMD64(context, register_name, value); + } else { + BPLOG(ERROR) << "Unsupported architecture for GetRegisterValue\n"; + return false; + } +} +} // namespace + +// static +bool DisassemblerObjdump::DisassembleInstruction(uint32_t cpu, + const uint8_t* raw_bytes, + unsigned int raw_bytes_len, + string& instruction) { + // Always initialize outputs + instruction = ""; + + if (!raw_bytes || raw_bytes_len == 0) { + // There's no need to perform any operation in this case, as there's + // clearly no instruction there. + return false; + } + + string architecture; + if (cpu == MD_CONTEXT_X86) { + architecture = "i386"; + } else if (cpu == MD_CONTEXT_AMD64) { + architecture = "i386:x86-64"; + } else { + BPLOG(ERROR) << "Unsupported architecture."; + return false; + } + + // Create two temporary files, one for the raw instruction bytes to pass to + // objdump, and one for the output, and write the bytes to the input file. + ScopedTmpFile raw_bytes_file("/tmp/breakpad_mem_region-raw_bytes-XXXXXX"); + ScopedTmpFile disassembly_file("/tmp/breakpad_mem_region-disassembly-XXXXXX"); + if (!raw_bytes_file.Create() || !disassembly_file.Create() || + !raw_bytes_file.Write(raw_bytes, raw_bytes_len)) { + BPLOG(ERROR) << "Failed creating temporary files."; + return false; + } + + char cmd[1024] = {0}; + snprintf(cmd, 1024, + "objdump -D --no-show-raw-insn -b binary -M intel -m %s %s > %s", + architecture.c_str(), raw_bytes_file.path().c_str(), + disassembly_file.path().c_str()); + if (system(cmd)) { + BPLOG(ERROR) << "Failed to call objdump."; + return false; + } + + // Pipe each output line into the string until the string contains the first + // instruction from objdump. + std::ifstream objdump_stream(disassembly_file.path()); + + // Match the instruction line, from: + // 0: lock cmpxchg DWORD PTR [esi+0x10],eax + // extract the string "lock cmpxchg DWORD PTR [esi+0x10],eax" + std::regex instruction_regex( + "^\\s+[0-9a-f]+:\\s+" // " 0:" + "((?:\\s*\\S*)+)$"); // "lock cmpxchg..." + + std::string line; + std::smatch match; + do { + if (!getline(objdump_stream, line)) { + BPLOG(INFO) << "Failed to find instruction in objdump output."; + return false; + } + } while (!std::regex_match(line, match, instruction_regex)); + + instruction = match[1].str(); + + return true; +} + +// static +bool DisassemblerObjdump::TokenizeInstruction(const string& instruction, + string& operation, string& dest, + string& src) { + // Always initialize outputs. + operation = ""; + dest = ""; + src = ""; + + // Split the instruction into tokens by either whitespace or comma. + std::regex token_regex("((?:[^\\s,]+)|,)(?:\\s)*"); + std::sregex_iterator tokens_begin(instruction.begin(), instruction.end(), + token_regex); + + bool found_comma = false; + for (auto tokens_iter = tokens_begin; tokens_iter != std::sregex_iterator(); + ++tokens_iter) { + auto token = (*tokens_iter)[1].str(); + if (operation.size() == 0) { + if (IsInstructionPrefix(token)) + continue; + operation = token; + } else if (dest.size() == 0) { + if (IsOperandSize(token)) + continue; + dest = token; + } else if (!found_comma) { + if (token == ",") { + found_comma = true; + } else { + BPLOG(ERROR) << "Failed to parse operands from objdump output, expected" + " comma but found \"" + << token << "\""; + return false; + } + } else if (src.size() == 0) { + if (IsOperandSize(token)) + continue; + src = token; + } else { + if (token == ",") { + BPLOG(ERROR) << "Failed to parse operands from objdump output, found " + "unexpected comma after last operand."; + return false; + } else { + // We just ignore other junk after the last operand unless it's a + // comma, which would indicate we're probably still in the middle + // of the operands and something has gone wrong + } + } + } + + if (found_comma && src.size() == 0) { + BPLOG(ERROR) << "Failed to parse operands from objdump output, found comma " + "but no src operand."; + return false; + } + + return true; +} + +// static +bool DisassemblerObjdump::CalculateAddress(const DumpContext& context, + const string& expression, + uint64_t& address) { + address = 0; + + // Extract the components of the expression. + // fs:[esi+edi*4+0x80] -> ["fs", "esi", "edi", "4", "-", "0x80"] + std::regex expression_regex( + "^(?:(\\ws):)?" // "fs:" + "\\[(\\w+)" // "[esi" + "(?:\\+(\\w+)(?:\\*(\\d+)))?" // "+edi*4" + "(?:([\\+-])(0x[0-9a-f]+))?" // "-0x80" + "\\]$"); // "]" + + std::smatch match; + if (!std::regex_match(expression, match, expression_regex) || + match.size() != 7) { + return false; + } + + string segment_name = match[1].str(); + string register_name = match[2].str(); + string index_name = match[3].str(); + string index_stride = match[4].str(); + string offset_sign = match[5].str(); + string offset = match[6].str(); + + uint64_t segment_address = 0; + uint64_t register_value = 0; + uint64_t index_value = 0; + uint64_t index_stride_value = 1; + uint64_t offset_value = 0; + + if (segment_name.size() && + !GetSegmentAddress(context, segment_name, segment_address)) { + return false; + } + + if (!GetRegisterValue(context, register_name, register_value)) { + return false; + } + + if (index_name.size() && + !GetRegisterValue(context, index_name, index_value)) { + return false; + } + + if (index_stride.size()) { + index_stride_value = strtoull(index_stride.c_str(), nullptr, 0); + } + + if (offset.size()) { + offset_value = strtoull(offset.c_str(), nullptr, 0); + } + + address = + segment_address + register_value + (index_value * index_stride_value); + if (offset_sign == "+") { + address += offset_value; + } else if (offset_sign == "-") { + address -= offset_value; + } + + return true; +} + +DisassemblerObjdump::DisassemblerObjdump(const uint32_t cpu, + const MemoryRegion* memory_region, + uint64_t address) { + if (address < memory_region->GetBase() || + memory_region->GetBase() + memory_region->GetSize() <= address) { + return; + } + + uint8_t ip_bytes[kMaxX86InstructionLength] = {0}; + size_t ip_bytes_length; + for (ip_bytes_length = 0; ip_bytes_length < kMaxX86InstructionLength; + ++ip_bytes_length) { + // We have to read byte-by-byte here, since we still want to try and + // disassemble an instruction even if we don't have enough bytes. + if (!memory_region->GetMemoryAtAddress(address + ip_bytes_length, + &ip_bytes[ip_bytes_length])) { + break; + } + } + + string instruction; + if (!DisassembleInstruction(cpu, ip_bytes, kMaxX86InstructionLength, + instruction)) { + return; + } + + if (!TokenizeInstruction(instruction, operation_, dest_, src_)) { + return; + } +} + +bool DisassemblerObjdump::CalculateSrcAddress(const DumpContext& context, + uint64_t& address) { + return CalculateAddress(context, src_, address); +} + +bool DisassemblerObjdump::CalculateDestAddress(const DumpContext& context, + uint64_t& address) { + return CalculateAddress(context, dest_, address); +} +} // namespace google_breakpad + +#else // __linux__ +namespace google_breakpad { +DisassemblerObjdump::DisassemblerObjdump(const uint32_t cpu, + const MemoryRegion* memory_region, + uint64_t address) {} + +bool DisassemblerObjdump::CalculateSrcAddress(const DumpContext& context, + uint64_t& address) { + return false; +} + +bool DisassemblerObjdump::CalculateDestAddress(const DumpContext& context, + uint64_t& address) { + return false; +} +} // namespace google_breakpad + +#endif // __linux__ diff --git a/src/processor/disassembler_objdump.h b/src/processor/disassembler_objdump.h new file mode 100644 index 00000000..7db1e111 --- /dev/null +++ b/src/processor/disassembler_objdump.h @@ -0,0 +1,142 @@ +// Copyright (c) 2022, Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// disassembler_objdump.h: Disassembler that invokes objdump for disassembly. +// +// Author: Mark Brand + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_OBJDUMP_H_ +#define GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_OBJDUMP_H_ + +#include <string> + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/dump_context.h" +#include "google_breakpad/processor/memory_region.h" + +namespace google_breakpad { + +// Uses objdump to disassemble a single instruction. +// +// Currently supports disassembly for x86 and x86_64 on linux hosts only; on +// unsupported platform or for unsupported architectures disassembly will fail. +// +// If disassembly is successful, then this allows extracting the instruction +// opcode, source and destination operands, and computing the source and +// destination addresses for instructions that operate on memory. +// +// Example: +// DisassemblerObjdump disassembler(context->GetContextCPU(), memory_region, +// instruction_ptr); +// if (disassembler.IsValid()) { +// uint64_t src_address = 0; +// std::cerr << disassembler.operation() << " " << disassembler.src() +// << ", " << disassembler.dest() << std::endl; +// if (disassembler.CalculateSrcAddress(*context, src_address)) { +// std::cerr << "[src_address = " << std::hex << src_address << "]\n"; +// } +// } +class DisassemblerObjdump { + public: + // Construct an ObjdumpDisassembler for the provided `cpu` type, where this is + // one of MD_CONTEXT_X86 or MD_CONTEXT_AMD64. Provided that `address` is + // within `memory_region`, and the memory referenced is a valid instruction, + // this will then be initialized with the disassembly for that instruction. + DisassemblerObjdump(uint32_t cpu, + const MemoryRegion* memory_region, + uint64_t address); + ~DisassemblerObjdump() = default; + + // If the source operand of the instruction is a memory operand, compute the + // address referred to by the operand, and store this in `address`. On success + // returns true, otherwise (if computation fails, or if the source operand is + // not a memory operand) returns false and sets `address` to 0. + bool CalculateSrcAddress(const DumpContext& context, uint64_t& address); + + // If the destination operand of the instruction is a memory operand, compute + // the address referred to by the operand, and store this in `address`. On + // success returns true, otherwise (if computation fails, or if the source + // operand is not a memory operand) returns false and sets `address` to 0. + bool CalculateDestAddress(const DumpContext& context, uint64_t& address); + + // If the instruction was disassembled successfully, this will be true. + bool IsValid() const { return operation_.size() != 0; } + + // Returns the operation part of the disassembly, without any prefixes: + // "pop" eax + // lock "xchg" eax, edx + const string& operation() const { return operation_; } + + // Returns the destination operand of the disassembly, without memory operand + // size prefixes: + // mov DWORD PTR "[rax + 16]", edx + const string& dest() const { return dest_; } + + // Returns the source operand of the disassembly, without memory operand + // size prefixes: + // mov rax, QWORD PTR "[rdx]" + const string& src() const { return src_; } + + private: + friend class DisassemblerObjdumpForTest; + + // Writes out the provided `raw_bytes` to a temporary file, and executes objdump + // to disassemble according to `cpu`, which must be either MD_CONTEXT_X86 or + // MD_CONTEXT_AMD64. Once objdump has completed, parses out the instruction + // string from the first instruction in the output and stores it in + // `instruction`. + static bool DisassembleInstruction(uint32_t cpu, const uint8_t* raw_bytes, + unsigned int raw_bytes_len, + string& instruction); + + // Splits an `instruction` into three parts, the "main" `operation` and + // the `dest` and `src` operands. + // Example: + // instruction = "lock cmpxchg QWORD PTR [rdi], rsi" + // operation = "cmpxchg", dest = "[rdi]", src = "rsi" + static bool TokenizeInstruction(const string& instruction, string& operation, + string& dest, string& src); + + // Compute the address referenced by `expression` in `context`. + // Supports memory operands in the form + // (segment:)[base_reg(+index_reg*index_stride)(+-offset)] + // Returns false if evaluation fails, or if the operand is not a supported + // memory operand. + static bool CalculateAddress(const DumpContext& context, + const string& expression, + uint64_t& address); + + // The parsed components of the disassembly for the instruction. + string operation_ = ""; + string dest_ = ""; + string src_ = ""; +}; +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_OBJDUMP_H_
\ No newline at end of file diff --git a/src/processor/disassembler_objdump_unittest.cc b/src/processor/disassembler_objdump_unittest.cc new file mode 100644 index 00000000..4b4ce6c3 --- /dev/null +++ b/src/processor/disassembler_objdump_unittest.cc @@ -0,0 +1,464 @@ +// Copyright (c) 2022, Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <unistd.h> +#include <vector> + +#include "breakpad_googletest_includes.h" + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_cpu_amd64.h" +#include "google_breakpad/common/minidump_cpu_x86.h" +#include "google_breakpad/processor/dump_context.h" +#include "google_breakpad/processor/memory_region.h" +#include "processor/disassembler_objdump.h" + +namespace google_breakpad { +class DisassemblerObjdumpForTest : public DisassemblerObjdump { + public: + using DisassemblerObjdump::CalculateAddress; + using DisassemblerObjdump::DisassembleInstruction; + using DisassemblerObjdump::TokenizeInstruction; +}; + +class TestMemoryRegion : public MemoryRegion { + public: + TestMemoryRegion(uint64_t base, std::vector<uint8_t> bytes); + ~TestMemoryRegion() override = default; + + uint64_t GetBase() const override; + uint32_t GetSize() const override; + + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const override; + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const override; + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const override; + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const override; + + void Print() const override; + + private: + uint64_t base_; + std::vector<uint8_t> bytes_; +}; + +TestMemoryRegion::TestMemoryRegion(uint64_t address, std::vector<uint8_t> bytes) + : base_(address), bytes_(bytes) {} + +uint64_t TestMemoryRegion::GetBase() const { + return base_; +} + +uint32_t TestMemoryRegion::GetSize() const { + return static_cast<uint32_t>(bytes_.size()); +} + +bool TestMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint8_t* value) const { + if (address < GetBase() || + address + sizeof(uint8_t) > GetBase() + GetSize()) { + return false; + } + + memcpy(value, &bytes_[address - GetBase()], sizeof(uint8_t)); + return true; +} + +// We don't use the following functions, so no need to implement. +bool TestMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint16_t* value) const { + return false; +} + +bool TestMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint32_t* value) const { + return false; +} + +bool TestMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint64_t* value) const { + return false; +} + +void TestMemoryRegion::Print() const {} + +const uint32_t kX86TestDs = 0x01000000; +const uint32_t kX86TestEs = 0x02000000; +const uint32_t kX86TestFs = 0x03000000; +const uint32_t kX86TestGs = 0x04000000; +const uint32_t kX86TestEax = 0x00010101; +const uint32_t kX86TestEbx = 0x00020202; +const uint32_t kX86TestEcx = 0x00030303; +const uint32_t kX86TestEdx = 0x00040404; +const uint32_t kX86TestEsi = 0x00050505; +const uint32_t kX86TestEdi = 0x00060606; +const uint32_t kX86TestEsp = 0x00070707; +const uint32_t kX86TestEbp = 0x00080808; +const uint32_t kX86TestEip = 0x23230000; + +const uint64_t kAMD64TestRax = 0x0000010101010101ul; +const uint64_t kAMD64TestRbx = 0x0000020202020202ul; +const uint64_t kAMD64TestRcx = 0x0000030303030303ul; +const uint64_t kAMD64TestRdx = 0x0000040404040404ul; +const uint64_t kAMD64TestRsi = 0x0000050505050505ul; +const uint64_t kAMD64TestRdi = 0x0000060606060606ul; +const uint64_t kAMD64TestRsp = 0x0000070707070707ul; +const uint64_t kAMD64TestRbp = 0x0000080808080808ul; +const uint64_t kAMD64TestR8 = 0x0000090909090909ul; +const uint64_t kAMD64TestR9 = 0x00000a0a0a0a0a0aul; +const uint64_t kAMD64TestR10 = 0x00000b0b0b0b0b0bul; +const uint64_t kAMD64TestR11 = 0x00000c0c0c0c0c0cul; +const uint64_t kAMD64TestR12 = 0x00000d0d0d0d0d0dul; +const uint64_t kAMD64TestR13 = 0x00000e0e0e0e0e0eul; +const uint64_t kAMD64TestR14 = 0x00000f0f0f0f0f0ful; +const uint64_t kAMD64TestR15 = 0x0000001010101010ul; +const uint64_t kAMD64TestRip = 0x0000000023230000ul; + +class TestDumpContext : public DumpContext { + public: + TestDumpContext(bool x86_64 = false); + ~TestDumpContext() override; +}; + +TestDumpContext::TestDumpContext(bool x86_64) { + if (!x86_64) { + MDRawContextX86* raw_context = new MDRawContextX86(); + memset(raw_context, 0, sizeof(*raw_context)); + + raw_context->context_flags = MD_CONTEXT_X86_FULL; + + raw_context->ds = kX86TestDs; + raw_context->es = kX86TestEs; + raw_context->fs = kX86TestFs; + raw_context->gs = kX86TestGs; + raw_context->eax = kX86TestEax; + raw_context->ebx = kX86TestEbx; + raw_context->ecx = kX86TestEcx; + raw_context->edx = kX86TestEdx; + raw_context->esi = kX86TestEsi; + raw_context->edi = kX86TestEdi; + raw_context->esp = kX86TestEsp; + raw_context->ebp = kX86TestEbp; + raw_context->eip = kX86TestEip; + + SetContextFlags(raw_context->context_flags); + SetContextX86(raw_context); + this->valid_ = true; + } else { + MDRawContextAMD64* raw_context = new MDRawContextAMD64(); + memset(raw_context, 0, sizeof(*raw_context)); + + raw_context->context_flags = MD_CONTEXT_AMD64_FULL; + + raw_context->rax = kAMD64TestRax; + raw_context->rbx = kAMD64TestRbx; + raw_context->rcx = kAMD64TestRcx; + raw_context->rdx = kAMD64TestRdx; + raw_context->rsi = kAMD64TestRsi; + raw_context->rdi = kAMD64TestRdi; + raw_context->rsp = kAMD64TestRsp; + raw_context->rbp = kAMD64TestRbp; + raw_context->r8 = kAMD64TestR8; + raw_context->r9 = kAMD64TestR9; + raw_context->r10 = kAMD64TestR10; + raw_context->r11 = kAMD64TestR11; + raw_context->r12 = kAMD64TestR12; + raw_context->r13 = kAMD64TestR13; + raw_context->r14 = kAMD64TestR14; + raw_context->r15 = kAMD64TestR15; + raw_context->rip = kAMD64TestRip; + + SetContextFlags(raw_context->context_flags); + SetContextAMD64(raw_context); + this->valid_ = true; + } +} + +TestDumpContext::~TestDumpContext() { + FreeContext(); +} + +TEST(DisassemblerObjdumpTest, DisassembleInstructionX86) { + string instruction; + ASSERT_FALSE(DisassemblerObjdumpForTest::DisassembleInstruction( + MD_CONTEXT_X86, nullptr, 0, instruction)); + std::vector<uint8_t> pop_eax = {0x58}; + ASSERT_TRUE(DisassemblerObjdumpForTest::DisassembleInstruction( + MD_CONTEXT_X86, pop_eax.data(), pop_eax.size(), instruction)); + ASSERT_EQ(instruction, "pop eax"); +} + +TEST(DisassemblerObjdumpTest, DisassembleInstructionAMD64) { + string instruction; + ASSERT_FALSE(DisassemblerObjdumpForTest::DisassembleInstruction( + MD_CONTEXT_AMD64, nullptr, 0, instruction)); + std::vector<uint8_t> pop_rax = {0x58}; + ASSERT_TRUE(DisassemblerObjdumpForTest::DisassembleInstruction( + MD_CONTEXT_AMD64, pop_rax.data(), pop_rax.size(), instruction)); + ASSERT_EQ(instruction, "pop rax"); +} + +TEST(DisassemblerObjdumpTest, TokenizeInstruction) { + string operation, dest, src; + ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction( + "pop eax", operation, dest, src)); + ASSERT_EQ(operation, "pop"); + ASSERT_EQ(dest, "eax"); + + ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction( + "mov eax, ebx", operation, dest, src)); + ASSERT_EQ(operation, "mov"); + ASSERT_EQ(dest, "eax"); + ASSERT_EQ(src, "ebx"); + + ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction( + "pop rax", operation, dest, src)); + ASSERT_EQ(operation, "pop"); + ASSERT_EQ(dest, "rax"); + + ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction( + "mov rax, rbx", operation, dest, src)); + ASSERT_EQ(operation, "mov"); + ASSERT_EQ(dest, "rax"); + ASSERT_EQ(src, "rbx"); + + // Test the three parsing failure paths + ASSERT_FALSE(DisassemblerObjdumpForTest::TokenizeInstruction( + "mov rax,", operation, dest, src)); + ASSERT_FALSE(DisassemblerObjdumpForTest::TokenizeInstruction( + "mov rax rbx", operation, dest, src)); + ASSERT_FALSE(DisassemblerObjdumpForTest::TokenizeInstruction( + "mov rax, rbx, rcx", operation, dest, src)); + + // This is of course a nonsense instruction, but test that we do remove + // multiple instruction prefixes and can handle multiple memory operands. + ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction( + "rep lock mov DWORD PTR rax, QWORD PTR rbx", operation, dest, src)); + ASSERT_EQ(operation, "mov"); + ASSERT_EQ(dest, "rax"); + ASSERT_EQ(src, "rbx"); + + // Test that we ignore junk following a valid instruction + ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction( + "mov rax, rbx ; junk here", operation, dest, src)); + ASSERT_EQ(operation, "mov"); + ASSERT_EQ(dest, "rax"); + ASSERT_EQ(src, "rbx"); +} + +namespace x86 { +const TestMemoryRegion load_reg(kX86TestEip, {0x8b, 0x06}); // mov eax, [esi]; + +const TestMemoryRegion load_reg_index(kX86TestEip, + {0x8b, 0x04, + 0xbe}); // mov eax, [esi+edi*4]; + +const TestMemoryRegion load_reg_offset(kX86TestEip, + {0x8b, 0x46, + 0x10}); // mov eax, [esi+0x10]; + +const TestMemoryRegion load_reg_index_offset( + kX86TestEip, + {0x8b, 0x44, 0xbe, 0xf0}); // mov eax, [esi+edi*4-0x10]; + +const TestMemoryRegion rep_stosb(kX86TestEip, {0xf3, 0xaa}); // rep stosb; + +const TestMemoryRegion lock_cmpxchg(kX86TestEip, + {0xf0, 0x0f, 0xb1, 0x46, + 0x10}); // lock cmpxchg [esi + 0x10], eax; + +const TestMemoryRegion call_reg_offset(kX86TestEip, + {0xff, 0x96, 0x99, 0x99, 0x99, + 0x09}); // call [esi+0x9999999]; +} // namespace x86 + +TEST(DisassemblerObjdumpTest, X86LoadReg) { + TestDumpContext context; + DisassemblerObjdump dis(context.GetContextCPU(), &x86::load_reg, kX86TestEip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(src_address, kX86TestEsi); +} + +TEST(DisassemblerObjdumpTest, X86LoadRegIndex) { + TestDumpContext context; + DisassemblerObjdump dis(context.GetContextCPU(), &x86::load_reg_index, + kX86TestEip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(src_address, kX86TestEsi + (kX86TestEdi * 4)); +} + +TEST(DisassemblerObjdumpTest, X86LoadRegOffset) { + TestDumpContext context; + DisassemblerObjdump dis(context.GetContextCPU(), &x86::load_reg_offset, + kX86TestEip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(src_address, kX86TestEsi + 0x10); +} + +TEST(DisassemblerObjdumpTest, X86LoadRegIndexOffset) { + TestDumpContext context; + DisassemblerObjdump dis(context.GetContextCPU(), &x86::load_reg_index_offset, + kX86TestEip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(src_address, kX86TestEsi + (kX86TestEdi * 4) - 0x10); +} + +TEST(DisassemblerObjdumpTest, X86RepStosb) { + TestDumpContext context; + DisassemblerObjdump dis(context.GetContextCPU(), &x86::rep_stosb, + kX86TestEip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(dest_address, kX86TestEs + kX86TestEdi); +} + +TEST(DisassemblerObjdumpTest, X86LockCmpxchg) { + TestDumpContext context; + DisassemblerObjdump dis(context.GetContextCPU(), &x86::lock_cmpxchg, + kX86TestEip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(dest_address, kX86TestEsi + 0x10); +} + +TEST(DisassemblerObjdumpTest, X86CallRegOffset) { + TestDumpContext context; + DisassemblerObjdump dis(context.GetContextCPU(), &x86::call_reg_offset, + kX86TestEip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(dest_address, kX86TestEsi + 0x9999999); +} + +namespace amd64 { +const TestMemoryRegion load_reg(kAMD64TestRip, + {0x48, 0x8b, 0x06}); // mov rax, [rsi]; + +const TestMemoryRegion load_reg_index(kAMD64TestRip, + {0x48, 0x8b, 0x04, + 0xbe}); // mov rax, [rsi+rdi*4]; + +const TestMemoryRegion load_rip_relative(kAMD64TestRip, + {0x48, 0x8b, 0x05, 0x10, 0x00, 0x00, + 0x00}); // mov rax, [rip+0x10]; + +const TestMemoryRegion load_reg_index_offset( + kAMD64TestRip, + {0x48, 0x8b, 0x44, 0xbe, 0xf0}); // mov rax, [rsi+rdi*4-0x10]; + +const TestMemoryRegion rep_stosb(kAMD64TestRip, {0xf3, 0xaa}); // rep stosb; + +const TestMemoryRegion lock_cmpxchg(kAMD64TestRip, + {0xf0, 0x48, 0x0f, 0xb1, 0x46, + 0x10}); // lock cmpxchg [rsi + 0x10], rax; + +const TestMemoryRegion call_reg_offset(kAMD64TestRip, + {0xff, 0x96, 0x99, 0x99, 0x99, + 0x09}); // call [rsi+0x9999999]; +} // namespace amd64 + +TEST(DisassemblerObjdumpTest, AMD64LoadReg) { + TestDumpContext context(true); + DisassemblerObjdump dis(context.GetContextCPU(), &amd64::load_reg, + kAMD64TestRip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(src_address, kAMD64TestRsi); +} + +TEST(DisassemblerObjdumpTest, AMD64LoadRegIndex) { + TestDumpContext context(true); + DisassemblerObjdump dis(context.GetContextCPU(), &amd64::load_reg_index, + kAMD64TestRip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(src_address, kAMD64TestRsi + (kAMD64TestRdi * 4)); +} + +TEST(DisassemblerObjdumpTest, AMD64LoadRipRelative) { + TestDumpContext context(true); + DisassemblerObjdump dis(context.GetContextCPU(), &amd64::load_rip_relative, + kAMD64TestRip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(src_address, kAMD64TestRip + 0x10); +} + +TEST(DisassemblerObjdumpTest, AMD64LoadRegIndexOffset) { + TestDumpContext context(true); + DisassemblerObjdump dis(context.GetContextCPU(), + &amd64::load_reg_index_offset, kAMD64TestRip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(src_address, kAMD64TestRsi + (kAMD64TestRdi * 4) - 0x10); +} + +TEST(DisassemblerObjdumpTest, AMD64RepStosb) { + TestDumpContext context(true); + DisassemblerObjdump dis(context.GetContextCPU(), &amd64::rep_stosb, + kAMD64TestRip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(dest_address, kAMD64TestRdi); +} + +TEST(DisassemblerObjdumpTest, AMD64LockCmpxchg) { + TestDumpContext context(true); + DisassemblerObjdump dis(context.GetContextCPU(), &amd64::lock_cmpxchg, + kAMD64TestRip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(dest_address, kAMD64TestRsi + 0x10); +} + +TEST(DisassemblerObjdumpTest, AMD64CallRegOffset) { + TestDumpContext context(true); + DisassemblerObjdump dis(context.GetContextCPU(), &amd64::call_reg_offset, + kAMD64TestRip); + uint64_t src_address = 0, dest_address = 0; + ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address)); + ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address)); + ASSERT_EQ(dest_address, kAMD64TestRsi + 0x9999999); +} +} // namespace google_breakpad diff --git a/src/processor/disassembler_x86.cc b/src/processor/disassembler_x86.cc index 55902240..dffb996d 100644 --- a/src/processor/disassembler_x86.cc +++ b/src/processor/disassembler_x86.cc @@ -1,7 +1,16 @@ +// Copyright 2010 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -30,7 +39,7 @@ namespace google_breakpad { -DisassemblerX86::DisassemblerX86(const uint8_t *bytecode, +DisassemblerX86::DisassemblerX86(const uint8_t* bytecode, uint32_t size, uint32_t virtual_address) : bytecode_(bytecode), @@ -62,7 +71,7 @@ uint32_t DisassemblerX86::NextInstruction() { return 0; } uint32_t instr_size = 0; - instr_size = libdis::x86_disasm((unsigned char *)bytecode_, size_, + instr_size = libdis::x86_disasm((unsigned char*)bytecode_, size_, virtual_address_, current_byte_offset_, ¤t_instr_); if (instr_size == 0) { @@ -78,8 +87,8 @@ uint32_t DisassemblerX86::NextInstruction() { if (current_instr_.type == libdis::insn_return) end_of_block_ = true; - libdis::x86_op_t *src = libdis::x86_get_src_operand(¤t_instr_); - libdis::x86_op_t *dest = libdis::x86_get_dest_operand(¤t_instr_); + libdis::x86_op_t* src = libdis::x86_get_src_operand(¤t_instr_); + libdis::x86_op_t* dest = libdis::x86_get_dest_operand(¤t_instr_); if (register_valid_) { switch (current_instr_.group) { @@ -213,7 +222,7 @@ bool DisassemblerX86::setBadRead() { if (!instr_valid_) return false; - libdis::x86_op_t *operand = libdis::x86_get_src_operand(¤t_instr_); + libdis::x86_op_t* operand = libdis::x86_get_src_operand(¤t_instr_); if (!operand || operand->type != libdis::op_expression) return false; @@ -227,7 +236,7 @@ bool DisassemblerX86::setBadWrite() { if (!instr_valid_) return false; - libdis::x86_op_t *operand = libdis::x86_get_dest_operand(¤t_instr_); + libdis::x86_op_t* operand = libdis::x86_get_dest_operand(¤t_instr_); if (!operand || operand->type != libdis::op_expression) return false; diff --git a/src/processor/disassembler_x86.h b/src/processor/disassembler_x86.h index 71069410..493f7f2e 100644 --- a/src/processor/disassembler_x86.h +++ b/src/processor/disassembler_x86.h @@ -1,4 +1,4 @@ -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -63,7 +63,7 @@ class DisassemblerX86 { // TODO(cdn): Modify this class to take a MemoryRegion instead of just // a raw buffer. This will make it easier to use this on arbitrary // minidumps without first copying out the code segment. - DisassemblerX86(const uint8_t *bytecode, uint32_t, uint32_t); + DisassemblerX86(const uint8_t* bytecode, uint32_t, uint32_t); ~DisassemblerX86(); // This walks to the next instruction in the memory region and @@ -102,7 +102,7 @@ class DisassemblerX86 { bool setBadWrite(); protected: - const uint8_t *bytecode_; + const uint8_t* bytecode_; uint32_t size_; uint32_t virtual_address_; uint32_t current_byte_offset_; diff --git a/src/processor/disassembler_x86_unittest.cc b/src/processor/disassembler_x86_unittest.cc index 352905f2..117b3bf8 100644 --- a/src/processor/disassembler_x86_unittest.cc +++ b/src/processor/disassembler_x86_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -25,7 +24,7 @@ // 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 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <unistd.h> diff --git a/src/processor/dump_context.cc b/src/processor/dump_context.cc index da531b74..a8ab0084 100644 --- a/src/processor/dump_context.cc +++ b/src/processor/dump_context.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -140,6 +139,24 @@ const MDRawContextMIPS* DumpContext::GetContextMIPS() const { return context_.ctx_mips; } +const MDRawContextRISCV* DumpContext::GetContextRISCV() const { + if (GetContextCPU() != MD_CONTEXT_RISCV) { + BPLOG(ERROR) << "DumpContext cannot get RISCV context"; + return NULL; + } + + return context_.riscv; +} + +const MDRawContextRISCV64* DumpContext::GetContextRISCV64() const { + if (GetContextCPU() != MD_CONTEXT_RISCV64) { + BPLOG(ERROR) << "DumpContext cannot get RISCV64 context"; + return NULL; + } + + return context_.riscv64; +} + bool DumpContext::GetInstructionPointer(uint64_t* ip) const { BPLOG_IF(ERROR, !ip) << "DumpContext::GetInstructionPointer requires |ip|"; assert(ip); @@ -176,6 +193,12 @@ bool DumpContext::GetInstructionPointer(uint64_t* ip) const { case MD_CONTEXT_MIPS64: *ip = GetContextMIPS()->epc; break; + case MD_CONTEXT_RISCV: + *ip = GetContextRISCV()->pc; + break; + case MD_CONTEXT_RISCV64: + *ip = GetContextRISCV64()->pc; + break; default: // This should never happen. BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer"; @@ -220,6 +243,12 @@ bool DumpContext::GetStackPointer(uint64_t* sp) const { case MD_CONTEXT_MIPS64: *sp = GetContextMIPS()->iregs[MD_CONTEXT_MIPS_REG_SP]; break; + case MD_CONTEXT_RISCV: + *sp = GetContextRISCV()->sp; + break; + case MD_CONTEXT_RISCV64: + *sp = GetContextRISCV64()->sp; + break; default: // This should never happen. BPLOG(ERROR) << "Unknown CPU architecture in GetStackPointer"; @@ -264,6 +293,14 @@ void DumpContext::SetContextMIPS(MDRawContextMIPS* ctx_mips) { context_.ctx_mips = ctx_mips; } +void DumpContext::SetContextRISCV(MDRawContextRISCV* riscv) { + context_.riscv = riscv; +} + +void DumpContext::SetContextRISCV64(MDRawContextRISCV64* riscv64) { + context_.riscv64 = riscv64; +} + void DumpContext::FreeContext() { switch (GetContextCPU()) { case MD_CONTEXT_X86: @@ -299,6 +336,14 @@ void DumpContext::FreeContext() { delete context_.ctx_mips; break; + case MD_CONTEXT_RISCV: + delete context_.riscv; + break; + + case MD_CONTEXT_RISCV64: + delete context_.riscv64; + break; + default: // There is no context record (valid_ is false) or there's a // context record for an unknown CPU (shouldn't happen, only known @@ -655,6 +700,195 @@ void DumpContext::Print() { break; } + case MD_CONTEXT_RISCV: { + const MDRawContextRISCV* context_riscv = GetContextRISCV(); + printf("MDRawContextRISCV\n"); + printf(" context_flags = 0x%x\n", + context_riscv->context_flags); + + printf(" pc = 0x%" PRIx32 "\n", + context_riscv->pc); + printf(" ra = 0x%" PRIx32 "\n", + context_riscv->ra); + printf(" sp = 0x%" PRIx32 "\n", + context_riscv->sp); + printf(" gp = 0x%" PRIx32 "\n", + context_riscv->gp); + printf(" tp = 0x%" PRIx32 "\n", + context_riscv->tp); + printf(" t0 = 0x%" PRIx32 "\n", + context_riscv->t0); + printf(" t1 = 0x%" PRIx32 "\n", + context_riscv->t1); + printf(" t2 = 0x%" PRIx32 "\n", + context_riscv->t2); + printf(" s0 = 0x%" PRIx32 "\n", + context_riscv->s0); + printf(" s1 = 0x%" PRIx32 "\n", + context_riscv->s1); + printf(" a0 = 0x%" PRIx32 "\n", + context_riscv->a0); + printf(" a1 = 0x%" PRIx32 "\n", + context_riscv->a1); + printf(" a2 = 0x%" PRIx32 "\n", + context_riscv->a2); + printf(" a3 = 0x%" PRIx32 "\n", + context_riscv->a3); + printf(" a4 = 0x%" PRIx32 "\n", + context_riscv->a4); + printf(" a5 = 0x%" PRIx32 "\n", + context_riscv->a5); + printf(" a6 = 0x%" PRIx32 "\n", + context_riscv->a6); + printf(" a7 = 0x%" PRIx32 "\n", + context_riscv->a7); + printf(" s2 = 0x%" PRIx32 "\n", + context_riscv->s2); + printf(" s3 = 0x%" PRIx32 "\n", + context_riscv->s3); + printf(" s4 = 0x%" PRIx32 "\n", + context_riscv->s4); + printf(" s5 = 0x%" PRIx32 "\n", + context_riscv->s5); + printf(" s6 = 0x%" PRIx32 "\n", + context_riscv->s6); + printf(" s7 = 0x%" PRIx32 "\n", + context_riscv->s7); + printf(" s8 = 0x%" PRIx32 "\n", + context_riscv->s8); + printf(" s9 = 0x%" PRIx32 "\n", + context_riscv->s9); + printf(" s10 = 0x%" PRIx32 "\n", + context_riscv->s10); + printf(" s11 = 0x%" PRIx32 "\n", + context_riscv->s11); + printf(" t3 = 0x%" PRIx32 "\n", + context_riscv->t3); + printf(" t4 = 0x%" PRIx32 "\n", + context_riscv->t4); + printf(" t5 = 0x%" PRIx32 "\n", + context_riscv->t5); + printf(" t6 = 0x%" PRIx32 "\n", + context_riscv->t6); + +#if defined(__riscv) + for (unsigned int freg_index = 0; + freg_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++freg_index) { + riscv_fpr_size fp_value = context_riscv->float_save.regs[freg_index]; +# if __riscv_flen == 32 + printf(" float_save.regs[%2d] = 0x%" PRIx32 "\n", + freg_index, fp_value); +# elif __riscv_flen == 64 + printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", + freg_index, fp_value); +# elif __riscv_flen == 128 + printf(" float_save.regs[%2d] = 0x%" PRIx64 "%" PRIx64 "\n", + freg_index, fp_value.high, fp_value.low); +# else +# error "Unexpected __riscv_flen" +# endif + } + printf(" float_save.fpcsr = 0x%" PRIx32 "\n", + context_riscv->float_save.fpcsr); +#endif + break; + } + + case MD_CONTEXT_RISCV64: { + const MDRawContextRISCV64* context_riscv64 = GetContextRISCV64(); + printf("MDRawContextRISCV64\n"); + printf(" context_flags = 0x%x\n", + context_riscv64->context_flags); + + printf(" pc = 0x%" PRIx64 "\n", + context_riscv64->pc); + printf(" ra = 0x%" PRIx64 "\n", + context_riscv64->ra); + printf(" sp = 0x%" PRIx64 "\n", + context_riscv64->sp); + printf(" gp = 0x%" PRIx64 "\n", + context_riscv64->gp); + printf(" tp = 0x%" PRIx64 "\n", + context_riscv64->tp); + printf(" t0 = 0x%" PRIx64 "\n", + context_riscv64->t0); + printf(" t1 = 0x%" PRIx64 "\n", + context_riscv64->t1); + printf(" t2 = 0x%" PRIx64 "\n", + context_riscv64->t2); + printf(" s0 = 0x%" PRIx64 "\n", + context_riscv64->s0); + printf(" s1 = 0x%" PRIx64 "\n", + context_riscv64->s1); + printf(" a0 = 0x%" PRIx64 "\n", + context_riscv64->a0); + printf(" a1 = 0x%" PRIx64 "\n", + context_riscv64->a1); + printf(" a2 = 0x%" PRIx64 "\n", + context_riscv64->a2); + printf(" a3 = 0x%" PRIx64 "\n", + context_riscv64->a3); + printf(" a4 = 0x%" PRIx64 "\n", + context_riscv64->a4); + printf(" a5 = 0x%" PRIx64 "\n", + context_riscv64->a5); + printf(" a6 = 0x%" PRIx64 "\n", + context_riscv64->a6); + printf(" a7 = 0x%" PRIx64 "\n", + context_riscv64->a7); + printf(" s2 = 0x%" PRIx64 "\n", + context_riscv64->s2); + printf(" s3 = 0x%" PRIx64 "\n", + context_riscv64->s3); + printf(" s4 = 0x%" PRIx64 "\n", + context_riscv64->s4); + printf(" s5 = 0x%" PRIx64 "\n", + context_riscv64->s5); + printf(" s6 = 0x%" PRIx64 "\n", + context_riscv64->s6); + printf(" s7 = 0x%" PRIx64 "\n", + context_riscv64->s7); + printf(" s8 = 0x%" PRIx64 "\n", + context_riscv64->s8); + printf(" s9 = 0x%" PRIx64 "\n", + context_riscv64->s9); + printf(" s10 = 0x%" PRIx64 "\n", + context_riscv64->s10); + printf(" s11 = 0x%" PRIx64 "\n", + context_riscv64->s11); + printf(" t3 = 0x%" PRIx64 "\n", + context_riscv64->t3); + printf(" t4 = 0x%" PRIx64 "\n", + context_riscv64->t4); + printf(" t5 = 0x%" PRIx64 "\n", + context_riscv64->t5); + printf(" t6 = 0x%" PRIx64 "\n", + context_riscv64->t6); + +#if defined(__riscv) + for (unsigned int freg_index = 0; + freg_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++freg_index) { + riscv_fpr_size fp_value = context_riscv64->float_save.regs[freg_index]; +# if __riscv_flen == 32 + printf(" float_save.regs[%2d] = 0x%" PRIx32 "\n", + freg_index, fp_value); +# elif __riscv_flen == 64 + printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", + freg_index, fp_value); +# elif __riscv_flen == 128 + printf(" float_save.regs[%2d] = 0x%" + PRIx64 "%" PRIx64 "\n", + freg_index, fp_value.high, fp_value.low); +# else +# error "Unexpected __riscv_flen" +# endif + } + printf(" float_save.fpcsr = 0x%" PRIx32 "\n", + context_riscv64->float_save.fpcsr); +#endif + break; + } + default: { break; } diff --git a/src/processor/dump_object.cc b/src/processor/dump_object.cc index 2c82b200..6186c8fa 100644 --- a/src/processor/dump_object.cc +++ b/src/processor/dump_object.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/exploitability.cc b/src/processor/exploitability.cc index 5f05b510..7a4107bf 100644 --- a/src/processor/exploitability.cc +++ b/src/processor/exploitability.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/exploitability_linux.cc b/src/processor/exploitability_linux.cc index ccc9f145..63a12656 100644 --- a/src/processor/exploitability_linux.cc +++ b/src/processor/exploitability_linux.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -36,21 +35,13 @@ #include "processor/exploitability_linux.h" -#ifndef _WIN32 -#include <regex.h> -#include <stdio.h> -#include <stdlib.h> - -#include <sstream> -#include <iterator> -#endif // _WIN32 - #include <string.h> #include "google_breakpad/common/minidump_exception_linux.h" #include "google_breakpad/processor/call_stack.h" #include "google_breakpad/processor/process_state.h" #include "google_breakpad/processor/stack_frame.h" +#include "processor/disassembler_objdump.h" #include "processor/logging.h" namespace { @@ -68,22 +59,17 @@ constexpr char kStackCheckFailureFunction[] = "__stack_chk_fail"; // can determine that the call would overflow the target buffer. constexpr char kBoundsCheckFailureFunction[] = "__chk_fail"; -#ifndef _WIN32 -const unsigned int MAX_INSTRUCTION_LEN = 15; -const unsigned int MAX_OBJDUMP_BUFFER_LEN = 4096; -#endif // _WIN32 - } // namespace namespace google_breakpad { -ExploitabilityLinux::ExploitabilityLinux(Minidump *dump, - ProcessState *process_state) +ExploitabilityLinux::ExploitabilityLinux(Minidump* dump, + ProcessState* process_state) : Exploitability(dump, process_state), enable_objdump_(false) { } -ExploitabilityLinux::ExploitabilityLinux(Minidump *dump, - ProcessState *process_state, +ExploitabilityLinux::ExploitabilityLinux(Minidump* dump, + ProcessState* process_state, bool enable_objdump) : Exploitability(dump, process_state), enable_objdump_(enable_objdump) { } @@ -111,12 +97,12 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { } // Getting exception data. (It should exist for all minidumps.) - MinidumpException *exception = dump_->GetException(); + MinidumpException* exception = dump_->GetException(); if (exception == NULL) { BPLOG(INFO) << "No exception record."; return EXPLOITABILITY_ERR_PROCESSING; } - const MDRawExceptionStream *raw_exception_stream = exception->exception(); + const MDRawExceptionStream* raw_exception_stream = exception->exception(); if (raw_exception_stream == NULL) { BPLOG(INFO) << "No raw exception stream."; return EXPLOITABILITY_ERR_PROCESSING; @@ -132,7 +118,7 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { uint64_t instruction_ptr = 0; uint64_t stack_ptr = 0; - const MinidumpContext *context = exception->GetContext(); + const MinidumpContext* context = exception->GetContext(); if (context == NULL) { BPLOG(INFO) << "No exception context."; return EXPLOITABILITY_ERR_PROCESSING; @@ -172,10 +158,11 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) { #ifdef _WIN32 BPLOG(INFO) << "MinGW does not support fork and exec. Terminating method."; + return false; #else // Get memory region containing instruction pointer. - MinidumpMemoryList *memory_list = dump_->GetMemoryList(); - MinidumpMemoryRegion *memory_region = + MinidumpMemoryList* memory_list = dump_->GetMemoryList(); + MinidumpMemoryRegion* memory_region = memory_list ? memory_list->GetMemoryRegionForAddress(instruction_ptr) : NULL; if (!memory_region) { @@ -185,83 +172,44 @@ bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) { // Get exception data to find architecture. string architecture = ""; - MinidumpException *exception = dump_->GetException(); + MinidumpException* exception = dump_->GetException(); // This should never evaluate to true, since this should not be reachable // without checking for exception data earlier. if (!exception) { BPLOG(INFO) << "No exception data."; return false; } - const MDRawExceptionStream *raw_exception_stream = exception->exception(); - const MinidumpContext *context = exception->GetContext(); + const MDRawExceptionStream* raw_exception_stream = exception->exception(); + const MinidumpContext* context = exception->GetContext(); // This should not evaluate to true, for the same reason mentioned above. if (!raw_exception_stream || !context) { BPLOG(INFO) << "No exception or architecture data."; return false; } - // Check architecture and set architecture variable to corresponding flag - // in objdump. - switch (context->GetContextCPU()) { - case MD_CONTEXT_X86: - architecture = "i386"; - break; - case MD_CONTEXT_AMD64: - architecture = "i386:x86-64"; - break; - default: - // Unsupported architecture. Note that ARM architectures are not - // supported because objdump does not support ARM. - return false; - break; - } - // Get memory region around instruction pointer and the number of bytes - // before and after the instruction pointer in the memory region. - const uint8_t *raw_memory = memory_region->GetMemory(); - const uint64_t base = memory_region->GetBase(); - if (base > instruction_ptr) { - BPLOG(ERROR) << "Memory region base value exceeds instruction pointer."; - return false; - } - const uint64_t offset = instruction_ptr - base; - if (memory_region->GetSize() < MAX_INSTRUCTION_LEN + offset) { - BPLOG(INFO) << "Not enough bytes left to guarantee complete instruction."; - return false; - } - - // Convert bytes into objdump output. - char objdump_output_buffer[MAX_OBJDUMP_BUFFER_LEN] = {0}; - DisassembleBytes(architecture, - raw_memory + offset, - MAX_OBJDUMP_BUFFER_LEN, - objdump_output_buffer); - - string line; - if (!GetObjdumpInstructionLine(objdump_output_buffer, &line)) { + DisassemblerObjdump disassembler(context->GetContextCPU(), memory_region, + instruction_ptr); + if (!disassembler.IsValid()) { + BPLOG(INFO) << "Disassembling fault instruction failed."; return false; } - // Convert objdump instruction line into the operation and operands. - string instruction = ""; - string dest = ""; - string src = ""; - TokenizeObjdumpInstruction(line, &instruction, &dest, &src); - - // Check if the operation is a write to memory. First, the instruction - // must one that can write to memory. Second, the write destination - // must be a spot in memory rather than a register. Since there are no - // symbols from objdump, the destination will be enclosed by brackets. - if (dest.size() > 2 && dest.at(0) == '[' && dest.at(dest.size() - 1) == ']' && - (!instruction.compare("mov") || !instruction.compare("inc") || - !instruction.compare("dec") || !instruction.compare("and") || - !instruction.compare("or") || !instruction.compare("xor") || - !instruction.compare("not") || !instruction.compare("neg") || - !instruction.compare("add") || !instruction.compare("sub") || - !instruction.compare("shl") || !instruction.compare("shr"))) { - // Strip away enclosing brackets from the destination address. - dest = dest.substr(1, dest.size() - 2); + // Check if the operation is a write to memory. + // First, the instruction must one that can write to memory. + auto instruction = disassembler.operation(); + if (!instruction.compare("mov") || !instruction.compare("inc") || + !instruction.compare("dec") || !instruction.compare("and") || + !instruction.compare("or") || !instruction.compare("xor") || + !instruction.compare("not") || !instruction.compare("neg") || + !instruction.compare("add") || !instruction.compare("sub") || + !instruction.compare("shl") || !instruction.compare("shr")) { uint64_t write_address = 0; - CalculateAddress(dest, *context, &write_address); + + // Check that the destination is a memory address. CalculateDestAddress will + // return false if the destination is not a memory address. + if (!disassembler.CalculateDestAddress(*context, write_address)) { + return false; + } // If the program crashed as a result of a write, the destination of // the write must have been an address that did not permit writing. @@ -269,277 +217,19 @@ bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) { // the crash does not suggest exploitability for writes with such a // low target address. return write_address > 4096; - } -#endif // _WIN32 - return false; -} - -#ifndef _WIN32 -bool ExploitabilityLinux::CalculateAddress(const string &address_expression, - const DumpContext &context, - uint64_t *write_address) { - // The destination should be the format reg+a or reg-a, where reg - // is a register and a is a hexadecimal constant. Although more complex - // expressions can make valid instructions, objdump's disassembly outputs - // it in this simpler format. - // TODO(liuandrew): Handle more complex formats, should they arise. - - if (!write_address) { - BPLOG(ERROR) << "Null parameter."; + } else { return false; } - - // Clone parameter into a non-const string. - string expression = address_expression; - - // Parse out the constant that is added to the address (if it exists). - size_t delim = expression.find('+'); - bool positive_add_constant = true; - // Check if constant is subtracted instead of added. - if (delim == string::npos) { - positive_add_constant = false; - delim = expression.find('-'); - } - uint32_t add_constant = 0; - // Save constant and remove it from the expression. - if (delim != string::npos) { - if (!sscanf(expression.substr(delim + 1).c_str(), "%x", &add_constant)) { - BPLOG(ERROR) << "Failed to scan constant."; - return false; - } - expression = expression.substr(0, delim); - } - - // Set the the write address to the corresponding register. - // TODO(liuandrew): Add support for partial registers, such as - // the rax/eax/ax/ah/al chain. - switch (context.GetContextCPU()) { - case MD_CONTEXT_X86: - if (!expression.compare("eax")) { - *write_address = context.GetContextX86()->eax; - } else if (!expression.compare("ebx")) { - *write_address = context.GetContextX86()->ebx; - } else if (!expression.compare("ecx")) { - *write_address = context.GetContextX86()->ecx; - } else if (!expression.compare("edx")) { - *write_address = context.GetContextX86()->edx; - } else if (!expression.compare("edi")) { - *write_address = context.GetContextX86()->edi; - } else if (!expression.compare("esi")) { - *write_address = context.GetContextX86()->esi; - } else if (!expression.compare("ebp")) { - *write_address = context.GetContextX86()->ebp; - } else if (!expression.compare("esp")) { - *write_address = context.GetContextX86()->esp; - } else if (!expression.compare("eip")) { - *write_address = context.GetContextX86()->eip; - } else { - BPLOG(ERROR) << "Unsupported register"; - return false; - } - break; - case MD_CONTEXT_AMD64: - if (!expression.compare("rax")) { - *write_address = context.GetContextAMD64()->rax; - } else if (!expression.compare("rbx")) { - *write_address = context.GetContextAMD64()->rbx; - } else if (!expression.compare("rcx")) { - *write_address = context.GetContextAMD64()->rcx; - } else if (!expression.compare("rdx")) { - *write_address = context.GetContextAMD64()->rdx; - } else if (!expression.compare("rdi")) { - *write_address = context.GetContextAMD64()->rdi; - } else if (!expression.compare("rsi")) { - *write_address = context.GetContextAMD64()->rsi; - } else if (!expression.compare("rbp")) { - *write_address = context.GetContextAMD64()->rbp; - } else if (!expression.compare("rsp")) { - *write_address = context.GetContextAMD64()->rsp; - } else if (!expression.compare("rip")) { - *write_address = context.GetContextAMD64()->rip; - } else if (!expression.compare("r8")) { - *write_address = context.GetContextAMD64()->r8; - } else if (!expression.compare("r9")) { - *write_address = context.GetContextAMD64()->r9; - } else if (!expression.compare("r10")) { - *write_address = context.GetContextAMD64()->r10; - } else if (!expression.compare("r11")) { - *write_address = context.GetContextAMD64()->r11; - } else if (!expression.compare("r12")) { - *write_address = context.GetContextAMD64()->r12; - } else if (!expression.compare("r13")) { - *write_address = context.GetContextAMD64()->r13; - } else if (!expression.compare("r14")) { - *write_address = context.GetContextAMD64()->r14; - } else if (!expression.compare("r15")) { - *write_address = context.GetContextAMD64()->r15; - } else { - BPLOG(ERROR) << "Unsupported register"; - return false; - } - break; - default: - // This should not occur since the same switch condition - // should have terminated this method. - return false; - break; - } - - // Add or subtract constant from write address (if applicable). - *write_address = - positive_add_constant ? - *write_address + add_constant : *write_address - add_constant; - - return true; -} - -// static -bool ExploitabilityLinux::GetObjdumpInstructionLine( - const char *objdump_output_buffer, - string *instruction_line) { - // Put buffer data into stream to output line-by-line. - std::stringstream objdump_stream; - objdump_stream.str(string(objdump_output_buffer)); - - // Pipe each output line into the string until the string contains the first - // instruction from objdump. All lines before the "<.data>:" section are - // skipped. Loop until the line shows the first instruction or there are no - // lines left. - bool data_section_seen = false; - do { - if (!getline(objdump_stream, *instruction_line)) { - BPLOG(INFO) << "Objdump instructions not found"; - return false; - } - if (instruction_line->find("<.data>:") != string::npos) { - data_section_seen = true; - } - } while (!data_section_seen || instruction_line->find("0:") == string::npos); - // This first instruction contains the above substring. - - return true; -} - -bool ExploitabilityLinux::TokenizeObjdumpInstruction(const string &line, - string *operation, - string *dest, - string *src) { - if (!operation || !dest || !src) { - BPLOG(ERROR) << "Null parameters passed."; - return false; - } - - // Set all pointer values to empty strings. - *operation = ""; - *dest = ""; - *src = ""; - - // Tokenize the objdump line. - vector<string> tokens; - std::istringstream line_stream(line); - copy(std::istream_iterator<string>(line_stream), - std::istream_iterator<string>(), - std::back_inserter(tokens)); - - // Regex for the data in hex form. Each byte is two hex digits. - regex_t regex; - regcomp(®ex, "^[[:xdigit:]]{2}$", REG_EXTENDED | REG_NOSUB); - - // Find and set the location of the operator. The operator appears - // directly after the chain of bytes that define the instruction. The - // operands will be the last token, given that the instruction has operands. - // If not, the operator is the last token. The loop skips the first token - // because the first token is the instruction number (namely "0:"). - string operands = ""; - for (size_t i = 1; i < tokens.size(); i++) { - // Check if current token no longer is in byte format. - if (regexec(®ex, tokens[i].c_str(), 0, NULL, 0)) { - // instruction = tokens[i]; - *operation = tokens[i]; - // If the operator is the last token, there are no operands. - if (i != tokens.size() - 1) { - operands = tokens[tokens.size() - 1]; - } - break; - } - } - regfree(®ex); - - if (operation->empty()) { - BPLOG(ERROR) << "Failed to parse out operation from objdump instruction."; - return false; - } - - // Split operands into source and destination (if applicable). - if (!operands.empty()) { - size_t delim = operands.find(','); - if (delim == string::npos) { - *dest = operands; - } else { - *dest = operands.substr(0, delim); - *src = operands.substr(delim + 1); - } - } - return true; -} - -bool ExploitabilityLinux::DisassembleBytes(const string &architecture, - const uint8_t *raw_bytes, - const unsigned int buffer_len, - char *objdump_output_buffer) { - if (!raw_bytes || !objdump_output_buffer) { - BPLOG(ERROR) << "Bad input parameters."; - return false; - } - - // Write raw bytes around instruction pointer to a temporary file to - // pass as an argument to objdump. - char raw_bytes_tmpfile[] = "/tmp/breakpad_mem_region-raw_bytes-XXXXXX"; - int raw_bytes_fd = mkstemp(raw_bytes_tmpfile); - if (raw_bytes_fd < 0) { - BPLOG(ERROR) << "Failed to create tempfile."; - unlink(raw_bytes_tmpfile); - return false; - } - if (write(raw_bytes_fd, raw_bytes, MAX_INSTRUCTION_LEN) - != MAX_INSTRUCTION_LEN) { - BPLOG(ERROR) << "Writing of raw bytes failed."; - unlink(raw_bytes_tmpfile); - return false; - } - - char cmd[1024] = {0}; - snprintf(cmd, - 1024, - "objdump -D -b binary -M intel -m %s %s", - architecture.c_str(), - raw_bytes_tmpfile); - FILE *objdump_fp = popen(cmd, "r"); - if (!objdump_fp) { - fclose(objdump_fp); - unlink(raw_bytes_tmpfile); - BPLOG(ERROR) << "Failed to call objdump."; - return false; - } - if (fread(objdump_output_buffer, 1, buffer_len, objdump_fp) <= 0) { - fclose(objdump_fp); - unlink(raw_bytes_tmpfile); - BPLOG(ERROR) << "Failed to read objdump output."; - return false; - } - fclose(objdump_fp); - unlink(raw_bytes_tmpfile); - return true; -} #endif // _WIN32 +} bool ExploitabilityLinux::StackPointerOffStack(uint64_t stack_ptr) { - MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList(); + MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList(); // Inconclusive if there are no mappings available. if (!linux_maps_list) { return false; } - const MinidumpLinuxMaps *linux_maps = + const MinidumpLinuxMaps* linux_maps = linux_maps_list->GetLinuxMapsForAddress(stack_ptr); // Checks if the stack pointer maps to a valid mapping and if the mapping // is not the stack. If the mapping has no name, it is inconclusive whether @@ -550,10 +240,10 @@ bool ExploitabilityLinux::StackPointerOffStack(uint64_t stack_ptr) { } bool ExploitabilityLinux::ExecutableStackOrHeap() { - MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList(); + MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList(); if (linux_maps_list) { for (size_t i = 0; i < linux_maps_list->get_maps_count(); i++) { - const MinidumpLinuxMaps *linux_maps = + const MinidumpLinuxMaps* linux_maps = linux_maps_list->GetLinuxMapsAtIndex(i); // Check for executable stack or heap for each mapping. if (linux_maps && (!linux_maps->GetPathname().compare( @@ -574,15 +264,15 @@ bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) { // whether it is in a valid code region. If there is no mapping for the // instruction pointer, it is indicative that the instruction pointer is // not within a module, which implies that it is outside a valid area. - MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList(); - const MinidumpLinuxMaps *linux_maps = + MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList(); + const MinidumpLinuxMaps* linux_maps = linux_maps_list ? linux_maps_list->GetLinuxMapsForAddress(instruction_ptr) : NULL; return linux_maps ? linux_maps->IsExecutable() : false; } -bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream - *raw_exception_stream) { +bool ExploitabilityLinux::BenignCrashTrigger( + const MDRawExceptionStream* raw_exception_stream) { // Check the cause of crash. // If the exception of the crash is a benign exception, // it is probably not exploitable. @@ -616,10 +306,8 @@ bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream case MD_EXCEPTION_CODE_LIN_SIGSYS: case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: return true; - break; default: return false; - break; } } diff --git a/src/processor/exploitability_linux.h b/src/processor/exploitability_linux.h index e3ff13b6..7603e456 100644 --- a/src/processor/exploitability_linux.h +++ b/src/processor/exploitability_linux.h @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,8 +43,8 @@ namespace google_breakpad { class ExploitabilityLinux : public Exploitability { public: - ExploitabilityLinux(Minidump *dump, - ProcessState *process_state); + ExploitabilityLinux(Minidump* dump, + ProcessState* process_state); // Parameters are the minidump to analyze, the object representing process // state, and whether to enable objdump disassembly. @@ -53,8 +52,8 @@ class ExploitabilityLinux : public Exploitability { // objdump for diassembly. It is used to check the identity of the // instruction that caused the program to crash. If there are any // portability concerns, this should not be enabled. - ExploitabilityLinux(Minidump *dump, - ProcessState *process_state, + ExploitabilityLinux(Minidump* dump, + ProcessState* process_state, bool enable_objdump); virtual ExploitabilityRating CheckPlatformExploitability(); @@ -68,7 +67,7 @@ class ExploitabilityLinux : public Exploitability { // Checks the exception that triggered the creation of the // minidump and reports whether the exception suggests no exploitability. - bool BenignCrashTrigger(const MDRawExceptionStream *raw_exception_stream); + bool BenignCrashTrigger(const MDRawExceptionStream* raw_exception_stream); // This method checks if the crash occurred during a write to read-only or // invalid memory. It does so by checking if the instruction at the @@ -76,41 +75,6 @@ class ExploitabilityLinux : public Exploitability { // instruction is at a spot in memory that prohibits writes. bool EndedOnIllegalWrite(uint64_t instruction_ptr); -#ifndef _WIN32 - // Disassembles raw bytes via objdump and pipes the output into the provided - // buffer, given the desired architecture, the file from which objdump will - // read, and the buffer length. The method returns whether the disassembly - // was a success, and the caller owns all pointers. - static bool DisassembleBytes(const string &architecture, - const uint8_t *raw_bytes, - const unsigned int MAX_OBJDUMP_BUFFER_LEN, - char *objdump_output_buffer); - - // Parses the objdump output given in |objdump_output_buffer| and extracts - // the line of the first instruction into |instruction_line|. Returns true - // when the instruction line is successfully extracted. - static bool GetObjdumpInstructionLine( - const char *objdump_output_buffer, - string *instruction_line); - - // Tokenizes out the operation and operands from a line of instruction - // disassembled by objdump. This method modifies the pointers to match the - // tokens of the instruction, and returns if the tokenizing was a success. - // The caller owns all pointers. - static bool TokenizeObjdumpInstruction(const string &line, - string *operation, - string *dest, - string *src); - - // Calculates the effective address of an expression in the form reg+a or - // reg-a, where 'reg' is a register and 'a' is a constant, and writes the - // result in the pointer. The method returns whether the calculation was - // a success. The caller owns the pointer. - static bool CalculateAddress(const string &address_expression, - const DumpContext &context, - uint64_t *write_address); -#endif // _WIN32 - // Checks if the stack pointer points to a memory mapping that is not // labelled as the stack. bool StackPointerOffStack(uint64_t stack_ptr); diff --git a/src/processor/exploitability_unittest.cc b/src/processor/exploitability_unittest.cc index 528ee5f2..bc1823c6 100644 --- a/src/processor/exploitability_unittest.cc +++ b/src/processor/exploitability_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -25,11 +24,12 @@ // 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 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdlib.h> #include <unistd.h> +#include <type_traits> #include <string> #include "breakpad_googletest_includes.h" @@ -37,22 +37,13 @@ #include "google_breakpad/processor/basic_source_line_resolver.h" #include "google_breakpad/processor/minidump_processor.h" #include "google_breakpad/processor/process_state.h" -#ifndef _WIN32 +#ifdef __linux__ #include "processor/exploitability_linux.h" -#endif // _WIN32 +#endif // __linux__ #include "processor/simple_symbol_supplier.h" -#ifndef _WIN32 +#ifdef __linux__ namespace google_breakpad { - -class ExploitabilityLinuxTest : public ExploitabilityLinux { - public: - using ExploitabilityLinux::CalculateAddress; - using ExploitabilityLinux::DisassembleBytes; - using ExploitabilityLinux::GetObjdumpInstructionLine; - using ExploitabilityLinux::TokenizeObjdumpInstruction; -}; - class ExploitabilityLinuxTestMinidumpContext : public MinidumpContext { public: explicit ExploitabilityLinuxTestMinidumpContext( @@ -64,15 +55,14 @@ class ExploitabilityLinuxTestMinidumpContext : public MinidumpContext { }; } // namespace google_breakpad -#endif // _WIN32 +#endif // __linux__ namespace { using google_breakpad::BasicSourceLineResolver; -#ifndef _WIN32 -using google_breakpad::ExploitabilityLinuxTest; +#ifdef __linux__ using google_breakpad::ExploitabilityLinuxTestMinidumpContext; -#endif // _WIN32 +#endif // __linux__ using google_breakpad::MinidumpProcessor; using google_breakpad::ProcessState; using google_breakpad::SimpleSymbolSupplier; @@ -171,7 +161,7 @@ TEST(ExploitabilityTest, TestLinuxEngine) { ExploitabilityFor("linux_executable_heap.dmp")); ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, ExploitabilityFor("linux_jmp_to_module_not_exe_region.dmp")); -#ifndef _WIN32 +#ifdef __linux__ ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, ExploitabilityFor("linux_write_to_nonwritable_module.dmp")); ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, @@ -182,125 +172,7 @@ TEST(ExploitabilityTest, TestLinuxEngine) { ExploitabilityFor("linux_write_to_outside_module_via_math.dmp")); ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, ExploitabilityFor("linux_write_to_under_4k.dmp")); -#endif // _WIN32 -} - -#ifndef _WIN32 -TEST(ExploitabilityLinuxUtilsTest, DisassembleBytesTest) { - ASSERT_FALSE(ExploitabilityLinuxTest::DisassembleBytes("", NULL, 5, NULL)); - uint8_t bytes[6] = {0xc7, 0x0, 0x5, 0x0, 0x0, 0x0}; - char buffer[1024] = {0}; - ASSERT_TRUE(ExploitabilityLinuxTest::DisassembleBytes("i386:x86-64", - bytes, - 1024, - buffer)); - std::stringstream objdump_stream; - objdump_stream.str(string(buffer)); - string line = ""; - while (line.find("<.data>") == string::npos) - getline(objdump_stream, line); - getline(objdump_stream, line); - ASSERT_EQ(line, " 0:\tc7 00 05 00 00 00 \tmov DWORD PTR [rax],0x5"); -} - -TEST(ExploitabilityLinuxUtilsTest, GetObjdumpInstructionLine) { - string disassebly = - "\n" - "/tmp/breakpad_mem_region-raw_bytes-tMmMo0: file format binary\n" - "// Trying to confuse the parser 0:\n" - "\n" - "Disassembly of section .data:\n" - "\n" - "0000000000000000 <.data>:\n" - " 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1\n" - " 6:\t5d \tpop rbp\n" - " 7:\tc3 \tret \n" - " 8:\t55 \tpush rbp\n" - " 9:\t48 89 e5 \tmov rbp,rsp\n" - " c:\t53 \tpush rbx\n" - " d:\t48 \trex.W\n" - " e:\t81 \t.byte 0x81\n"; - string line; - EXPECT_TRUE(ExploitabilityLinuxTest::GetObjdumpInstructionLine( - disassebly.c_str(), &line)); - EXPECT_EQ(" 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1", line); - - // There is no "0:" after "<.data>:". Expected to return false. - disassebly = - "\n" - "/tmp/breakpad_mem_region-raw_bytes-tMmMo0: file format binary\n" - "// Trying to confuse the parser 0:\n" - "\n" - "Disassembly of section .data:\n" - "\n" - " 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1\n" - " 6:\t5d \tpop rbp\n" - " 7:\tc3 \tret \n" - " 8:\t55 \tpush rbp\n" - " 9:\t48 89 e5 \tmov rbp,rsp\n" - " d:\t48 \trex.W\n" - "0000000000000000 <.data>:\n" - " c:\t53 \tpush rbx\n"; - EXPECT_FALSE(ExploitabilityLinuxTest::GetObjdumpInstructionLine( - disassebly.c_str(), &line)); -} - -TEST(ExploitabilityLinuxUtilsTest, TokenizeObjdumpInstructionTest) { - ASSERT_FALSE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction("", - NULL, - NULL, - NULL)); - string line = "0: c7 00 05 00 00 00 mov DWORD PTR [rax],0x5"; - string operation = ""; - string dest = ""; - string src = ""; - ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line, - &operation, - &dest, - &src)); - ASSERT_EQ(operation, "mov"); - ASSERT_EQ(dest, "[rax]"); - ASSERT_EQ(src, "0x5"); - line = "0: c3 ret"; - ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line, - &operation, - &dest, - &src)); - ASSERT_EQ(operation, "ret"); - ASSERT_EQ(dest, ""); - ASSERT_EQ(src, ""); - line = "0: 5f pop rdi"; - ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line, - &operation, - &dest, - &src)); - ASSERT_EQ(operation, "pop"); - ASSERT_EQ(dest, "rdi"); - ASSERT_EQ(src, ""); -} - -TEST(ExploitabilityLinuxUtilsTest, CalculateAddressTest) { - MDRawContextAMD64 raw_context; - raw_context.rdx = 12345; - ExploitabilityLinuxTestMinidumpContext context(raw_context); - ASSERT_EQ(context.GetContextAMD64()->rdx, 12345U); - ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("", context, NULL)); - uint64_t write_address = 0; - ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx-0x4D2", - context, - &write_address)); - ASSERT_EQ(write_address, 11111U); - ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx+0x4D2", - context, - &write_address)); - ASSERT_EQ(write_address, 13579U); - ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("rdx+rax", - context, - &write_address)); - ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("0x3482+0x4D2", - context, - &write_address)); +#endif // __linux__ } -#endif // _WIN32 } // namespace diff --git a/src/processor/exploitability_win.cc b/src/processor/exploitability_win.cc index a1f8703a..accaadd3 100644 --- a/src/processor/exploitability_win.cc +++ b/src/processor/exploitability_win.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -69,30 +68,30 @@ static const size_t kHugeBump = 90; // The maximum number of bytes to disassemble past the program counter. static const size_t kDisassembleBytesBeyondPC = 2048; -ExploitabilityWin::ExploitabilityWin(Minidump *dump, - ProcessState *process_state) +ExploitabilityWin::ExploitabilityWin(Minidump* dump, + ProcessState* process_state) : Exploitability(dump, process_state) { } ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() { - MinidumpException *exception = dump_->GetException(); + MinidumpException* exception = dump_->GetException(); if (!exception) { BPLOG(INFO) << "Minidump does not have exception record."; return EXPLOITABILITY_ERR_PROCESSING; } - const MDRawExceptionStream *raw_exception = exception->exception(); + const MDRawExceptionStream* raw_exception = exception->exception(); if (!raw_exception) { BPLOG(INFO) << "Could not obtain raw exception info."; return EXPLOITABILITY_ERR_PROCESSING; } - const MinidumpContext *context = exception->GetContext(); + const MinidumpContext* context = exception->GetContext(); if (!context) { BPLOG(INFO) << "Could not obtain exception context."; return EXPLOITABILITY_ERR_PROCESSING; } - MinidumpMemoryList *memory_list = dump_->GetMemoryList(); + MinidumpMemoryList* memory_list = dump_->GetMemoryList(); bool memory_available = true; if (!memory_list) { BPLOG(INFO) << "Minidump memory segments not available."; @@ -193,9 +192,8 @@ ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() { default: BPLOG(INFO) << "Unrecognized access violation type."; return EXPLOITABILITY_ERR_PROCESSING; - break; } - MinidumpMemoryRegion *instruction_region = 0; + MinidumpMemoryRegion* instruction_region = 0; if (memory_available) { instruction_region = memory_list->GetMemoryRegionForAddress(instruction_ptr); @@ -211,7 +209,7 @@ ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() { available_memory = available_memory > kDisassembleBytesBeyondPC ? kDisassembleBytesBeyondPC : available_memory; if (available_memory) { - const uint8_t *raw_memory = + const uint8_t* raw_memory = instruction_region->GetMemory() + memory_offset; DisassemblerX86 disassembler(raw_memory, available_memory, diff --git a/src/processor/exploitability_win.h b/src/processor/exploitability_win.h index 4e08aef0..52cff8b7 100644 --- a/src/processor/exploitability_win.h +++ b/src/processor/exploitability_win.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/fast_source_line_resolver.cc b/src/processor/fast_source_line_resolver.cc index 4a3d0007..0d1ebc6b 100644 --- a/src/processor/fast_source_line_resolver.cc +++ b/src/processor/fast_source_line_resolver.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,17 +39,19 @@ #include "google_breakpad/processor/fast_source_line_resolver.h" #include "processor/fast_source_line_resolver_types.h" +#include <cassert> #include <map> #include <string> #include <utility> #include "common/scoped_ptr.h" #include "common/using_std_string.h" +#include "processor/logging.h" #include "processor/module_factory.h" #include "processor/simple_serializer-inl.h" -using std::map; -using std::make_pair; +using std::deque; +using std::unique_ptr; namespace google_breakpad { @@ -61,7 +62,9 @@ bool FastSourceLineResolver::ShouldDeleteMemoryBufferAfterLoadModule() { return false; } -void FastSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { +void FastSourceLineResolver::Module::LookupAddress( + StackFrame* frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const { MemAddr address = frame->instruction - frame->module->base_address(); // First, look for a FUNC record that covers address. Use @@ -81,15 +84,16 @@ void FastSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { if (functions_.RetrieveNearestRange(address, func_ptr, &function_base, &function_size) && address >= function_base && address - function_base < function_size) { - func.get()->CopyFrom(func_ptr); + func->CopyFrom(func_ptr); frame->function_name = func->name; frame->function_base = frame->module->base_address() + function_base; + frame->is_multiple = func->is_multiple; scoped_ptr<Line> line(new Line); const Line* line_ptr = 0; MemAddr line_base; if (func->lines.RetrieveRange(address, line_ptr, &line_base, NULL)) { - line.get()->CopyFrom(line_ptr); + line->CopyFrom(line_ptr); FileMap::iterator it = files_.find(line->source_file_id); if (it != files_.end()) { frame->source_file_name = @@ -98,18 +102,85 @@ void FastSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { frame->source_line = line->line; frame->source_line_base = frame->module->base_address() + line_base; } + // Check if this is inlined function call. + if (inlined_frames) { + ConstructInlineFrames(frame, address, func->inlines, inlined_frames); + } } else if (public_symbols_.Retrieve(address, public_symbol_ptr, &public_address) && (!func_ptr || public_address > function_base)) { - public_symbol.get()->CopyFrom(public_symbol_ptr); + public_symbol->CopyFrom(public_symbol_ptr); frame->function_name = public_symbol->name; frame->function_base = frame->module->base_address() + public_address; + frame->is_multiple = public_symbol->is_multiple; + } +} + +void FastSourceLineResolver::Module::ConstructInlineFrames( + StackFrame* frame, + MemAddr address, + const StaticContainedRangeMap<MemAddr, char>& inline_map, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const { + std::vector<const char*> inline_ptrs; + if (!inline_map.RetrieveRanges(address, inline_ptrs)) { + return; + } + + for (const char* inline_ptr : inline_ptrs) { + scoped_ptr<Inline> in(new Inline); + in->CopyFrom(inline_ptr); + unique_ptr<StackFrame> new_frame = + unique_ptr<StackFrame>(new StackFrame(*frame)); + auto origin_iter = inline_origins_.find(in->origin_id); + if (origin_iter != inline_origins_.end()) { + scoped_ptr<InlineOrigin> origin(new InlineOrigin); + origin->CopyFrom(origin_iter.GetValuePtr()); + new_frame->function_name = origin->name; + } else { + new_frame->function_name = "<name omitted>"; + } + + // Store call site file and line in current frame, which will be updated + // later. + new_frame->source_line = in->call_site_line; + if (in->has_call_site_file_id) { + auto file_iter = files_.find(in->call_site_file_id); + if (file_iter != files_.end()) { + new_frame->source_file_name = file_iter.GetValuePtr(); + } + } + + // Use the starting adress of the inlined range as inlined function base. + new_frame->function_base = new_frame->module->base_address(); + for (const auto& range : in->inline_ranges) { + if (address >= range.first && address < range.first + range.second) { + new_frame->function_base += range.first; + break; + } + } + new_frame->trust = StackFrame::FRAME_TRUST_INLINE; + + // The inlines vector has an order from innermost entry to outermost entry. + // By push_back, we will have inlined_frames with the same order. + inlined_frames->push_back(std::move(new_frame)); + } + + // Update the source file and source line for each inlined frame. + if (!inlined_frames->empty()) { + string parent_frame_source_file_name = frame->source_file_name; + int parent_frame_source_line = frame->source_line; + frame->source_file_name = inlined_frames->back()->source_file_name; + frame->source_line = inlined_frames->back()->source_line; + for (unique_ptr<StackFrame>& inlined_frame : *inlined_frames) { + std::swap(inlined_frame->source_file_name, parent_frame_source_file_name); + std::swap(inlined_frame->source_line, parent_frame_source_line); + } } } // WFI: WindowsFrameInfo. // Returns a WFI object reading from a raw memory chunk of data -WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) { +WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char* raw) { const WindowsFrameInfo::StackInfoTypes type = static_cast<const WindowsFrameInfo::StackInfoTypes>( *reinterpret_cast<const int32_t*>(raw)); @@ -117,7 +188,7 @@ WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) { // The first 8 bytes of int data are unused. // They correspond to "StackInfoTypes type_;" and "int valid;" // data member of WFI. - const uint32_t *para_uint32 = reinterpret_cast<const uint32_t*>( + const uint32_t* para_uint32 = reinterpret_cast<const uint32_t*>( raw + 2 * sizeof(int32_t)); uint32_t prolog_size = para_uint32[0];; @@ -126,7 +197,7 @@ WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) { uint32_t saved_register_size = para_uint32[3]; uint32_t local_size = para_uint32[4]; uint32_t max_stack_size = para_uint32[5]; - const char *boolean = reinterpret_cast<const char*>(para_uint32 + 6); + const char* boolean = reinterpret_cast<const char*>(para_uint32 + 6); bool allocates_base_pointer = (*boolean != 0); string program_string = boolean + 1; @@ -145,15 +216,15 @@ WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) { // Does NOT take ownership of mem_buffer. // In addition, treat mem_buffer as const char*. bool FastSourceLineResolver::Module::LoadMapFromMemory( - char *memory_buffer, + char* memory_buffer, size_t memory_buffer_size) { if (!memory_buffer) return false; // Read the "is_corrupt" flag. - const char *mem_buffer = memory_buffer; + const char* mem_buffer = memory_buffer; mem_buffer = SimpleSerializer<bool>::Read(mem_buffer, &is_corrupt_); - const uint32_t *map_sizes = reinterpret_cast<const uint32_t*>(mem_buffer); + const uint32_t* map_sizes = reinterpret_cast<const uint32_t*>(mem_buffer); unsigned int header_size = kNumberMaps_ * sizeof(unsigned int); @@ -166,6 +237,19 @@ bool FastSourceLineResolver::Module::LoadMapFromMemory( for (int i = 1; i < kNumberMaps_; ++i) { offsets[i] = offsets[i - 1] + map_sizes[i - 1]; } + unsigned int expected_size = sizeof(bool) + offsets[kNumberMaps_ - 1] + + map_sizes[kNumberMaps_ - 1] + 1; + if (expected_size != memory_buffer_size && + // Allow for having an extra null terminator. + expected_size != memory_buffer_size - 1) { + // This could either be a random corruption or the serialization format was + // changed without updating the version in kSerializedBreakpadFileExtension. + BPLOG(ERROR) << "Memory buffer is either corrupt or an unsupported version" + << ", expected size: " << expected_size + << ", actual size: " << memory_buffer_size; + return false; + } + BPLOG(INFO) << "Memory buffer size looks good, size: " << memory_buffer_size; // Use pointers to construct Static*Map data members in Module: int map_id = 0; @@ -174,19 +258,20 @@ bool FastSourceLineResolver::Module::LoadMapFromMemory( StaticRangeMap<MemAddr, Function>(mem_buffer + offsets[map_id++]); public_symbols_ = StaticAddressMap<MemAddr, PublicSymbol>(mem_buffer + offsets[map_id++]); - for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) + for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) { windows_frame_info_[i] = StaticContainedRangeMap<MemAddr, char>(mem_buffer + offsets[map_id++]); + } cfi_initial_rules_ = StaticRangeMap<MemAddr, char>(mem_buffer + offsets[map_id++]); cfi_delta_rules_ = StaticMap<MemAddr, char>(mem_buffer + offsets[map_id++]); - + inline_origins_ = StaticMap<int, char>(mem_buffer + offsets[map_id++]); return true; } -WindowsFrameInfo *FastSourceLineResolver::Module::FindWindowsFrameInfo( - const StackFrame *frame) const { +WindowsFrameInfo* FastSourceLineResolver::Module::FindWindowsFrameInfo( + const StackFrame* frame) const { MemAddr address = frame->instruction - frame->module->base_address(); scoped_ptr<WindowsFrameInfo> result(new WindowsFrameInfo()); @@ -218,7 +303,7 @@ WindowsFrameInfo *FastSourceLineResolver::Module::FindWindowsFrameInfo( if (functions_.RetrieveNearestRange(address, function_ptr, &function_base, &function_size) && address >= function_base && address - function_base < function_size) { - function.get()->CopyFrom(function_ptr); + function->CopyFrom(function_ptr); result->parameter_size = function->parameter_size; result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE; return result.release(); @@ -231,15 +316,15 @@ WindowsFrameInfo *FastSourceLineResolver::Module::FindWindowsFrameInfo( MemAddr public_address; if (public_symbols_.Retrieve(address, public_symbol_ptr, &public_address) && (!function_ptr || public_address > function_base)) { - public_symbol.get()->CopyFrom(public_symbol_ptr); + public_symbol->CopyFrom(public_symbol_ptr); result->parameter_size = public_symbol->parameter_size; } return NULL; } -CFIFrameInfo *FastSourceLineResolver::Module::FindCFIFrameInfo( - const StackFrame *frame) const { +CFIFrameInfo* FastSourceLineResolver::Module::FindCFIFrameInfo( + const StackFrame* frame) const { MemAddr address = frame->instruction - frame->module->base_address(); MemAddr initial_base, initial_size; const char* initial_rules = NULL; diff --git a/src/processor/fast_source_line_resolver_types.h b/src/processor/fast_source_line_resolver_types.h index 2c010470..75b9004f 100644 --- a/src/processor/fast_source_line_resolver_types.h +++ b/src/processor/fast_source_line_resolver_types.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,14 +36,16 @@ #ifndef PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__ #define PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__ -#include "google_breakpad/processor/fast_source_line_resolver.h" -#include "processor/source_line_resolver_base_types.h" - +#include <cstdint> #include <map> #include <string> +#include "google_breakpad/processor/fast_source_line_resolver.h" #include "google_breakpad/processor/stack_frame.h" #include "processor/cfi_frame_info.h" +#include "processor/contained_range_map.h" +#include "processor/simple_serializer-inl.h" +#include "processor/source_line_resolver_base_types.h" #include "processor/static_address_map-inl.h" #include "processor/static_contained_range_map-inl.h" #include "processor/static_map.h" @@ -53,74 +54,133 @@ namespace google_breakpad { +#define DESERIALIZE(raw_ptr, field) \ + field = *(reinterpret_cast<const decltype(field)*>(raw_ptr)); \ + raw_ptr += sizeof(field); + struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line { - void CopyFrom(const Line *line_ptr) { - const char *raw = reinterpret_cast<const char*>(line_ptr); + void CopyFrom(const Line* line_ptr) { + const char* raw = reinterpret_cast<const char*>(line_ptr); CopyFrom(raw); } // De-serialize the memory data of a Line. - void CopyFrom(const char *raw) { - address = *(reinterpret_cast<const MemAddr*>(raw)); - size = *(reinterpret_cast<const MemAddr*>(raw + sizeof(address))); - source_file_id = *(reinterpret_cast<const int32_t *>( - raw + 2 * sizeof(address))); - line = *(reinterpret_cast<const int32_t*>( - raw + 2 * sizeof(address) + sizeof(source_file_id))); + void CopyFrom(const char* raw) { + DESERIALIZE(raw, address); + DESERIALIZE(raw, size); + DESERIALIZE(raw, source_file_id); + DESERIALIZE(raw, line); } }; struct FastSourceLineResolver::Function : public SourceLineResolverBase::Function { - void CopyFrom(const Function *func_ptr) { - const char *raw = reinterpret_cast<const char*>(func_ptr); + void CopyFrom(const Function* func_ptr) { + const char* raw = reinterpret_cast<const char*>(func_ptr); CopyFrom(raw); } // De-serialize the memory data of a Function. - void CopyFrom(const char *raw) { + void CopyFrom(const char* raw) { size_t name_size = strlen(raw) + 1; name = raw; - address = *(reinterpret_cast<const MemAddr*>(raw + name_size)); - size = *(reinterpret_cast<const MemAddr*>( - raw + name_size + sizeof(MemAddr))); - parameter_size = *(reinterpret_cast<const int32_t*>( - raw + name_size + 2 * sizeof(MemAddr))); - lines = StaticRangeMap<MemAddr, Line>( - raw + name_size + 2 * sizeof(MemAddr) + sizeof(int32_t)); + raw += name_size; + DESERIALIZE(raw, address); + DESERIALIZE(raw, size); + DESERIALIZE(raw, parameter_size); + raw = SimpleSerializer<bool>::Read(raw, &is_multiple); + int32_t inline_size; + DESERIALIZE(raw, inline_size); + inlines = StaticContainedRangeMap<MemAddr, char>(raw); + lines = StaticRangeMap<MemAddr, Line>(raw + inline_size); } + StaticContainedRangeMap<MemAddr, char> inlines; StaticRangeMap<MemAddr, Line> lines; }; +struct FastSourceLineResolver::Inline : public SourceLineResolverBase::Inline { + void CopyFrom(const Inline* inline_ptr) { + const char* raw = reinterpret_cast<const char*>(inline_ptr); + CopyFrom(raw); + } + + // De-serialize the memory data of a Inline. + void CopyFrom(const char* raw) { + DESERIALIZE(raw, has_call_site_file_id); + DESERIALIZE(raw, inline_nest_level); + DESERIALIZE(raw, call_site_line); + DESERIALIZE(raw, call_site_file_id); + DESERIALIZE(raw, origin_id); + uint32_t inline_range_size; + DESERIALIZE(raw, inline_range_size); + for (size_t i = 0; i < inline_range_size; i += 2) { + std::pair<MemAddr, MemAddr> range; + DESERIALIZE(raw, range.first); + DESERIALIZE(raw, range.second); + inline_ranges.push_back(range); + } + } +}; + +struct FastSourceLineResolver::InlineOrigin + : public SourceLineResolverBase::InlineOrigin { + void CopyFrom(const InlineOrigin* origin_ptr) { + const char* raw = reinterpret_cast<const char*>(origin_ptr); + CopyFrom(raw); + } + + // De-serialize the memory data of a Line. + void CopyFrom(const char* raw) { + DESERIALIZE(raw, has_file_id); + DESERIALIZE(raw, source_file_id); + name = raw; + } +}; + struct FastSourceLineResolver::PublicSymbol : public SourceLineResolverBase::PublicSymbol { - void CopyFrom(const PublicSymbol *public_symbol_ptr) { - const char *raw = reinterpret_cast<const char*>(public_symbol_ptr); + void CopyFrom(const PublicSymbol* public_symbol_ptr) { + const char* raw = reinterpret_cast<const char*>(public_symbol_ptr); CopyFrom(raw); } // De-serialize the memory data of a PublicSymbol. - void CopyFrom(const char *raw) { + void CopyFrom(const char* raw) { size_t name_size = strlen(raw) + 1; name = raw; - address = *(reinterpret_cast<const MemAddr*>(raw + name_size)); - parameter_size = *(reinterpret_cast<const int32_t*>( - raw + name_size + sizeof(MemAddr))); + raw += name_size; + DESERIALIZE(raw, address); + DESERIALIZE(raw, parameter_size); + raw = SimpleSerializer<bool>::Read(raw, &is_multiple); } }; +#undef DESERIALIZE + class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { public: - explicit Module(const string &name) : name_(name), is_corrupt_(false) { } + explicit Module(const string& name) : name_(name), is_corrupt_(false) { } virtual ~Module() { } // Looks up the given relative address, and fills the StackFrame struct // with the result. - virtual void LookupAddress(StackFrame *frame) const; + virtual void LookupAddress( + StackFrame* frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const; + + // Construct inlined frames for |frame| and store them in |inline_frames|. + // |frame|'s source line and source file name may be updated if an inlined + // frame is found inside |frame|. As a result, the innermost inlined frame + // will be the first one in |inline_frames|. + virtual void ConstructInlineFrames( + StackFrame* frame, + MemAddr address, + const StaticContainedRangeMap<MemAddr, char>& inline_map, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const; // Loads a map from the given buffer in char* type. - virtual bool LoadMapFromMemory(char *memory_buffer, + virtual bool LoadMapFromMemory(char* memory_buffer, size_t memory_buffer_size); // Tells whether the loaded symbol data is corrupt. Return value is @@ -132,16 +192,16 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { // is not available, returns NULL. A NULL return value does not indicate // an error. The caller takes ownership of any returned WindowsFrameInfo // object. - virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) const; + virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame) const; // If CFI stack walking information is available covering ADDRESS, // return a CFIFrameInfo structure describing it. If the information // is not available, return NULL. The caller takes ownership of any // returned CFIFrameInfo object. - virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const; + virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const; // Number of serialized map components of Module. - static const int kNumberMaps_ = 5 + WindowsFrameInfo::STACK_INFO_LAST; + static const int kNumberMaps_ = 6 + WindowsFrameInfo::STACK_INFO_LAST; private: friend class FastSourceLineResolver; @@ -178,6 +238,10 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { // this map, or the end of the range as given by the cfi_initial_rules_ // entry (which FindCFIFrameInfo looks up first). StaticMap<MemAddr, char> cfi_delta_rules_; + + // INLINE_ORIGIN records: used as a function name string pool for INLINE + // records. + StaticMap<int, char> inline_origins_; }; } // namespace google_breakpad diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc index 87b13c52..1bb35019 100644 --- a/src/processor/fast_source_line_resolver_unittest.cc +++ b/src/processor/fast_source_line_resolver_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -64,7 +63,6 @@ using google_breakpad::CodeModule; using google_breakpad::MemoryRegion; using google_breakpad::StackFrame; using google_breakpad::WindowsFrameInfo; -using google_breakpad::linked_ptr; using google_breakpad::scoped_ptr; class TestCodeModule : public CodeModule { @@ -94,15 +92,15 @@ class TestCodeModule : public CodeModule { class MockMemoryRegion: public MemoryRegion { uint64_t GetBase() const { return 0x10000; } uint32_t GetSize() const { return 0x01000; } - bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { *value = address & 0xff; return true; } - bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { *value = address & 0xffff; return true; } - bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { switch (address) { case 0x10008: *value = 0x98ecadc3; break; // saved %ebx case 0x1000c: *value = 0x878f7524; break; // saved %esi @@ -113,7 +111,7 @@ class MockMemoryRegion: public MemoryRegion { } return true; } - bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { *value = address; return true; } @@ -127,9 +125,9 @@ class MockMemoryRegion: public MemoryRegion { // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and // ".cfa". static bool VerifyRegisters( - const char *file, int line, - const CFIFrameInfo::RegisterValueMap<uint32_t> &expected, - const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) { + const char* file, int line, + const CFIFrameInfo::RegisterValueMap<uint32_t>& expected, + const CFIFrameInfo::RegisterValueMap<uint32_t>& actual) { CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a; a = actual.find(".cfa"); if (a == actual.end()) @@ -158,7 +156,7 @@ static bool VerifyRegisters( return true; } -static bool VerifyEmpty(const StackFrame &frame) { +static bool VerifyEmpty(const StackFrame& frame) { if (frame.function_name.empty() && frame.source_file_name.empty() && frame.source_line == 0) @@ -166,7 +164,7 @@ static bool VerifyEmpty(const StackFrame &frame) { return false; } -static void ClearSourceLineInfo(StackFrame *frame) { +static void ClearSourceLineInfo(StackFrame* frame) { frame->function_name.clear(); frame->module = NULL; frame->source_file_name.clear(); @@ -217,16 +215,17 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { scoped_ptr<CFIFrameInfo> cfi_frame_info; frame.instruction = 0x1000; frame.module = NULL; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_FALSE(frame.module); ASSERT_TRUE(frame.function_name.empty()); ASSERT_EQ(frame.function_base, 0U); ASSERT_TRUE(frame.source_file_name.empty()); ASSERT_EQ(frame.source_line, 0); ASSERT_EQ(frame.source_line_base, 0U); + ASSERT_EQ(frame.is_multiple, false); frame.module = &module1; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Function1_1"); ASSERT_TRUE(frame.module); ASSERT_EQ(frame.module->code_file(), "module1"); @@ -234,6 +233,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { ASSERT_EQ(frame.source_file_name, "file1_1.cc"); ASSERT_EQ(frame.source_line, 44); ASSERT_EQ(frame.source_line_base, 0x1000U); + ASSERT_EQ(frame.is_multiple, true); windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); ASSERT_TRUE(windows_frame_info.get()); ASSERT_FALSE(windows_frame_info->allocates_base_pointer); @@ -243,13 +243,13 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { ClearSourceLineInfo(&frame); frame.instruction = 0x800; frame.module = &module1; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_TRUE(VerifyEmpty(frame)); windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); ASSERT_FALSE(windows_frame_info.get()); frame.instruction = 0x1280; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Function1_3"); ASSERT_TRUE(frame.source_file_name.empty()); ASSERT_EQ(frame.source_line, 0); @@ -260,7 +260,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { ASSERT_TRUE(windows_frame_info->program_string.empty()); frame.instruction = 0x1380; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Function1_4"); ASSERT_TRUE(frame.source_file_name.empty()); ASSERT_EQ(frame.source_line, 0); @@ -369,17 +369,18 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { frame.instruction = 0x2900; frame.module = &module1; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, string("PublicSymbol")); + EXPECT_EQ(frame.is_multiple, true); frame.instruction = 0x4000; frame.module = &module1; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, string("LargeFunction")); frame.instruction = 0x2181; frame.module = &module2; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Function2_2"); ASSERT_EQ(frame.function_base, 0x2170U); ASSERT_TRUE(frame.module); @@ -387,27 +388,133 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { ASSERT_EQ(frame.source_file_name, "file2_2.cc"); ASSERT_EQ(frame.source_line, 21); ASSERT_EQ(frame.source_line_base, 0x2180U); + ASSERT_EQ(frame.is_multiple, false); windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); ASSERT_TRUE(windows_frame_info.get()); ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA); ASSERT_EQ(windows_frame_info->prolog_size, 1U); frame.instruction = 0x216f; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Public2_1"); + EXPECT_EQ(frame.is_multiple, false); ClearSourceLineInfo(&frame); frame.instruction = 0x219f; frame.module = &module2; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_TRUE(frame.function_name.empty()); frame.instruction = 0x21a0; frame.module = &module2; - fast_resolver.FillSourceLineInfo(&frame); + fast_resolver.FillSourceLineInfo(&frame, nullptr); ASSERT_EQ(frame.function_name, "Public2_2"); } +// Test adapted from basic_source_line_resolver_unittest. +TEST_F(TestFastSourceLineResolver, TestLoadAndResolveOldInlines) { + TestCodeModule module("linux_inline"); + ASSERT_TRUE(basic_resolver.LoadModule( + &module, testdata_dir + + "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/" + "linux_inline.old.sym")); + ASSERT_TRUE(basic_resolver.HasModule(&module)); + // Convert module1 to fast_module: + ASSERT_TRUE(serializer.ConvertOneModule(module.code_file(), &basic_resolver, + &fast_resolver)); + ASSERT_TRUE(fast_resolver.HasModule(&module)); + + StackFrame frame; + std::deque<std::unique_ptr<StackFrame>> inlined_frames; + frame.instruction = 0x161b6; + frame.module = &module; + fast_resolver.FillSourceLineInfo(&frame, &inlined_frames); + + // main frame. + ASSERT_EQ(frame.function_name, "main"); + ASSERT_EQ(frame.function_base, 0x15b30U); + ASSERT_EQ(frame.source_file_name, "linux_inline.cpp"); + ASSERT_EQ(frame.source_line, 42); + ASSERT_EQ(frame.source_line_base, 0x161b6U); + ASSERT_EQ(frame.is_multiple, false); + + ASSERT_EQ(inlined_frames.size(), 3UL); + + // Inlined frames inside main frame. + ASSERT_EQ(inlined_frames[2]->function_name, "foo()"); + ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U); + ASSERT_EQ(inlined_frames[2]->source_file_name, "linux_inline.cpp"); + ASSERT_EQ(inlined_frames[2]->source_line, 39); + ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE); + + ASSERT_EQ(inlined_frames[1]->function_name, "bar()"); + ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U); + ASSERT_EQ(inlined_frames[1]->source_file_name, "linux_inline.cpp"); + ASSERT_EQ(inlined_frames[1]->source_line, 32); + ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE); + + ASSERT_EQ(inlined_frames[0]->function_name, "func()"); + ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U); + ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp"); + ASSERT_EQ(inlined_frames[0]->source_line, 27); + ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE); +} + +// Test adapted from basic_source_line_resolver_unittest. +TEST_F(TestFastSourceLineResolver, TestLoadAndResolveNewInlines) { + TestCodeModule module("linux_inline"); + ASSERT_TRUE(basic_resolver.LoadModule( + &module, testdata_dir + + "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/" + "linux_inline.new.sym")); + ASSERT_TRUE(basic_resolver.HasModule(&module)); + // Convert module1 to fast_module: + ASSERT_TRUE(serializer.ConvertOneModule(module.code_file(), &basic_resolver, + &fast_resolver)); + ASSERT_TRUE(fast_resolver.HasModule(&module)); + + StackFrame frame; + std::deque<std::unique_ptr<StackFrame>> inlined_frames; + frame.instruction = 0x161b6; + frame.module = &module; + fast_resolver.FillSourceLineInfo(&frame, &inlined_frames); + + // main frame. + ASSERT_EQ(frame.function_name, "main"); + ASSERT_EQ(frame.function_base, 0x15b30U); + ASSERT_EQ(frame.source_file_name, "a.cpp"); + ASSERT_EQ(frame.source_line, 42); + ASSERT_EQ(frame.source_line_base, 0x161b6U); + ASSERT_EQ(frame.is_multiple, false); + + ASSERT_EQ(inlined_frames.size(), 3UL); + + // Inlined frames inside main frame. + ASSERT_EQ(inlined_frames[2]->function_name, "foo()"); + ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U); + ASSERT_EQ(inlined_frames[2]->source_file_name, "b.cpp"); + ASSERT_EQ(inlined_frames[2]->source_line, 39); + ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE); + + ASSERT_EQ(inlined_frames[1]->function_name, "bar()"); + ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U); + ASSERT_EQ(inlined_frames[1]->source_file_name, "c.cpp"); + ASSERT_EQ(inlined_frames[1]->source_line, 32); + ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE); + + ASSERT_EQ(inlined_frames[0]->function_name, "func()"); + ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U); + ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp"); + ASSERT_EQ(inlined_frames[0]->source_line, 27); + ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U); + ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE); +} + TEST_F(TestFastSourceLineResolver, TestInvalidLoads) { TestCodeModule module3("module3"); ASSERT_TRUE(basic_resolver.LoadModule(&module3, @@ -467,7 +574,7 @@ TEST_F(TestFastSourceLineResolver, TestUnload) { } TEST_F(TestFastSourceLineResolver, CompareModule) { - char *symbol_data; + char* symbol_data; size_t symbol_data_size; string symbol_data_string; string filename; @@ -486,7 +593,7 @@ TEST_F(TestFastSourceLineResolver, CompareModule) { } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/src/processor/linked_ptr.h b/src/processor/linked_ptr.h index 72fbba84..5de49ee9 100644 --- a/src/processor/linked_ptr.h +++ b/src/processor/linked_ptr.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/logging.cc b/src/processor/logging.cc index d59175a7..136f4f8f 100644 --- a/src/processor/logging.cc +++ b/src/processor/logging.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,8 +46,8 @@ namespace google_breakpad { -LogStream::LogStream(std::ostream &stream, Severity severity, - const char *file, int line) +LogStream::LogStream(std::ostream& stream, Severity severity, + const char* file, int line) : stream_(stream) { time_t clock; time(&clock); @@ -61,7 +60,7 @@ LogStream::LogStream(std::ostream &stream, Severity severity, char time_string[20]; strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", &tm_struct); - const char *severity_string = "UNKNOWN_SEVERITY"; + const char* severity_string = "UNKNOWN_SEVERITY"; switch (severity) { case SEVERITY_INFO: severity_string = "INFO"; @@ -100,7 +99,7 @@ string HexString(int number) { return string(buffer); } -int ErrnoString(string *error_string) { +int ErrnoString(string* error_string) { assert(error_string); // strerror isn't necessarily thread-safe. strerror_r would be preferrable, diff --git a/src/processor/logging.h b/src/processor/logging.h index a9f30920..8c040837 100644 --- a/src/processor/logging.h +++ b/src/processor/logging.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -67,18 +66,6 @@ #include BP_LOGGING_INCLUDE #endif // BP_LOGGING_INCLUDE -#ifndef THIRD_PARTY_BREAKPAD_GOOGLE_GLUE_LOGGING_H_ -namespace base_logging { - -// The open-source copy of logging.h has diverged from Google's internal copy -// (temporarily, at least). To support the transition to structured logging -// a definition for base_logging::LogMessage is needed, which is a ostream- -// like object for streaming arguments to construct a log message. -typedef std::ostream LogMessage; - -} // namespace base_logging -#endif // THIRD_PARTY_BREAKPAD_GOOGLE_GLUE_LOGGING_H_ - namespace google_breakpad { // These are defined in Microsoft headers. @@ -101,22 +88,22 @@ class LogStream { // Begin logging a message to the stream identified by |stream|, at the // indicated severity. The file and line parameters should be set so as to // identify the line of source code that is producing a message. - LogStream(std::ostream &stream, Severity severity, - const char *file, int line); + LogStream(std::ostream& stream, Severity severity, + const char* file, int line); // Finish logging by printing a newline and flushing the output stream. ~LogStream(); - template<typename T> std::ostream& operator<<(const T &t) { + template<typename T> std::ostream& operator<<(const T& t) { return stream_ << t; } private: - std::ostream &stream_; + std::ostream& stream_; // Disallow copy constructor and assignment operator - explicit LogStream(const LogStream &that); - void operator=(const LogStream &that); + explicit LogStream(const LogStream& that); + void operator=(const LogStream& that); }; // This class is used to explicitly ignore values in the conditional logging @@ -128,7 +115,7 @@ class LogMessageVoidify { // This has to be an operator with a precedence lower than << but higher // than ?: - void operator&(base_logging::LogMessage &) {} + void operator&(std::ostream&) {} }; // Returns number formatted as a hexadecimal string, such as "0x7b". @@ -139,7 +126,7 @@ string HexString(int number); // Returns the error code as set in the global errno variable, and sets // error_string, a required argument, to a string describing that error // code. -int ErrnoString(string *error_string); +int ErrnoString(string* error_string); } // namespace google_breakpad diff --git a/src/processor/map_serializers-inl.h b/src/processor/map_serializers-inl.h index 61c7bbd7..577b95f7 100644 --- a/src/processor/map_serializers-inl.h +++ b/src/processor/map_serializers-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -53,7 +52,7 @@ namespace google_breakpad { template<typename Key, typename Value> size_t StdMapSerializer<Key, Value>::SizeOf( - const std::map<Key, Value> &m) const { + const std::map<Key, Value>& m) const { size_t size = 0; size_t header_size = (1 + m.size()) * sizeof(uint32_t); size += header_size; @@ -67,22 +66,22 @@ size_t StdMapSerializer<Key, Value>::SizeOf( } template<typename Key, typename Value> -char *StdMapSerializer<Key, Value>::Write(const std::map<Key, Value> &m, - char *dest) const { +char* StdMapSerializer<Key, Value>::Write(const std::map<Key, Value>& m, + char* dest) const { if (!dest) { BPLOG(ERROR) << "StdMapSerializer failed: write to NULL address."; return NULL; } - char *start_address = dest; + char* start_address = dest; // Write header: // Number of nodes. dest = SimpleSerializer<uint32_t>::Write(m.size(), dest); // Nodes offsets. - uint32_t *offsets = reinterpret_cast<uint32_t*>(dest); + uint32_t* offsets = reinterpret_cast<uint32_t*>(dest); dest += sizeof(uint32_t) * m.size(); - char *key_address = dest; + char* key_address = dest; dest += sizeof(Key) * m.size(); // Traverse map. @@ -97,12 +96,12 @@ char *StdMapSerializer<Key, Value>::Write(const std::map<Key, Value> &m, } template<typename Key, typename Value> -char *StdMapSerializer<Key, Value>::Serialize( - const std::map<Key, Value> &m, unsigned int *size) const { +char* StdMapSerializer<Key, Value>::Serialize( + const std::map<Key, Value>& m, unsigned int* size) const { // Compute size of memory to be allocated. unsigned int size_to_alloc = SizeOf(m); // Allocate memory. - char *serialized_data = new char[size_to_alloc]; + char* serialized_data = new char[size_to_alloc]; if (!serialized_data) { BPLOG(INFO) << "StdMapSerializer memory allocation failed."; if (size) *size = 0; @@ -117,7 +116,7 @@ char *StdMapSerializer<Key, Value>::Serialize( template<typename Address, typename Entry> size_t RangeMapSerializer<Address, Entry>::SizeOf( - const RangeMap<Address, Entry> &m) const { + const RangeMap<Address, Entry>& m) const { size_t size = 0; size_t header_size = (1 + m.map_.size()) * sizeof(uint32_t); size += header_size; @@ -135,22 +134,22 @@ size_t RangeMapSerializer<Address, Entry>::SizeOf( } template<typename Address, typename Entry> -char *RangeMapSerializer<Address, Entry>::Write( - const RangeMap<Address, Entry> &m, char *dest) const { +char* RangeMapSerializer<Address, Entry>::Write( + const RangeMap<Address, Entry>& m, char* dest) const { if (!dest) { BPLOG(ERROR) << "RangeMapSerializer failed: write to NULL address."; return NULL; } - char *start_address = dest; + char* start_address = dest; // Write header: // Number of nodes. dest = SimpleSerializer<uint32_t>::Write(m.map_.size(), dest); // Nodes offsets. - uint32_t *offsets = reinterpret_cast<uint32_t*>(dest); + uint32_t* offsets = reinterpret_cast<uint32_t*>(dest); dest += sizeof(uint32_t) * m.map_.size(); - char *key_address = dest; + char* key_address = dest; dest += sizeof(Address) * m.map_.size(); // Traverse map. @@ -166,12 +165,12 @@ char *RangeMapSerializer<Address, Entry>::Write( } template<typename Address, typename Entry> -char *RangeMapSerializer<Address, Entry>::Serialize( - const RangeMap<Address, Entry> &m, unsigned int *size) const { +char* RangeMapSerializer<Address, Entry>::Serialize( + const RangeMap<Address, Entry>& m, unsigned int* size) const { // Compute size of memory to be allocated. unsigned int size_to_alloc = SizeOf(m); // Allocate memory. - char *serialized_data = new char[size_to_alloc]; + char* serialized_data = new char[size_to_alloc]; if (!serialized_data) { BPLOG(INFO) << "RangeMapSerializer memory allocation failed."; if (size) *size = 0; @@ -188,7 +187,7 @@ char *RangeMapSerializer<Address, Entry>::Serialize( template<class AddrType, class EntryType> size_t ContainedRangeMapSerializer<AddrType, EntryType>::SizeOf( - const ContainedRangeMap<AddrType, EntryType> *m) const { + const ContainedRangeMap<AddrType, EntryType>* m) const { size_t size = 0; size_t header_size = addr_serializer_.SizeOf(m->base_) + entry_serializer_.SizeOf(m->entry_) @@ -209,8 +208,8 @@ size_t ContainedRangeMapSerializer<AddrType, EntryType>::SizeOf( } template<class AddrType, class EntryType> -char *ContainedRangeMapSerializer<AddrType, EntryType>::Write( - const ContainedRangeMap<AddrType, EntryType> *m, char *dest) const { +char* ContainedRangeMapSerializer<AddrType, EntryType>::Write( + const ContainedRangeMap<AddrType, EntryType>* m, char* dest) const { if (!dest) { BPLOG(ERROR) << "StdMapSerializer failed: write to NULL address."; return NULL; @@ -221,15 +220,15 @@ char *ContainedRangeMapSerializer<AddrType, EntryType>::Write( dest = entry_serializer_.Write(m->entry_, dest); // Write map<<AddrType, ContainedRangeMap*>: - char *map_address = dest; + char* map_address = dest; if (m->map_ == NULL) { dest = SimpleSerializer<uint32_t>::Write(0, dest); } else { dest = SimpleSerializer<uint32_t>::Write(m->map_->size(), dest); - uint32_t *offsets = reinterpret_cast<uint32_t*>(dest); + uint32_t* offsets = reinterpret_cast<uint32_t*>(dest); dest += sizeof(uint32_t) * m->map_->size(); - char *key_address = dest; + char* key_address = dest; dest += sizeof(AddrType) * m->map_->size(); // Traverse map. @@ -246,11 +245,11 @@ char *ContainedRangeMapSerializer<AddrType, EntryType>::Write( } template<class AddrType, class EntryType> -char *ContainedRangeMapSerializer<AddrType, EntryType>::Serialize( - const ContainedRangeMap<AddrType, EntryType> *m, unsigned int *size) const { +char* ContainedRangeMapSerializer<AddrType, EntryType>::Serialize( + const ContainedRangeMap<AddrType, EntryType>* m, unsigned int* size) const { unsigned int size_to_alloc = SizeOf(m); // Allocating memory. - char *serialized_data = new char[size_to_alloc]; + char* serialized_data = new char[size_to_alloc]; if (!serialized_data) { BPLOG(INFO) << "ContainedRangeMapSerializer memory allocation failed."; if (size) *size = 0; diff --git a/src/processor/map_serializers.h b/src/processor/map_serializers.h index a0b9d3fd..54153f8a 100644 --- a/src/processor/map_serializers.h +++ b/src/processor/map_serializers.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -53,20 +52,20 @@ template<typename Key, typename Value> class StdMapSerializer { public: // Calculate the memory size of serialized data. - size_t SizeOf(const std::map<Key, Value> &m) const; + size_t SizeOf(const std::map<Key, Value>& m) const; // Writes the serialized data to memory with start address = dest, // and returns the "end" of data, i.e., return the address follow the final // byte of data. // NOTE: caller has to allocate enough memory before invoke Write() method. - char* Write(const std::map<Key, Value> &m, char* dest) const; + char* Write(const std::map<Key, Value>& m, char* dest) const; // Serializes a std::map object into a chunk of memory data with format // described in "StaticMap.h" comment. // Returns a pointer to the serialized data. If size != NULL, *size is set // to the size of serialized data, i.e., SizeOf(m). // Caller has the ownership of memory allocated as "new char[]". - char* Serialize(const std::map<Key, Value> &m, unsigned int *size) const; + char* Serialize(const std::map<Key, Value>& m, unsigned int* size) const; private: SimpleSerializer<Key> key_serializer_; @@ -79,14 +78,14 @@ template<typename Addr, typename Entry> class AddressMapSerializer { public: // Calculate the memory size of serialized data. - size_t SizeOf(const AddressMap<Addr, Entry> &m) const { + size_t SizeOf(const AddressMap<Addr, Entry>& m) const { return std_map_serializer_.SizeOf(m.map_); } // Write the serialized data to specified memory location. Return the "end" // of data, i.e., return the address after the final byte of data. // NOTE: caller has to allocate enough memory before invoke Write() method. - char* Write(const AddressMap<Addr, Entry> &m, char *dest) const { + char* Write(const AddressMap<Addr, Entry>& m, char* dest) const { return std_map_serializer_.Write(m.map_, dest); } @@ -94,7 +93,7 @@ class AddressMapSerializer { // Returns a pointer to the serialized data. If size != NULL, *size is set // to the size of serialized data, i.e., SizeOf(m). // Caller has the ownership of memory allocated as "new char[]". - char* Serialize(const AddressMap<Addr, Entry> &m, unsigned int *size) const { + char* Serialize(const AddressMap<Addr, Entry>& m, unsigned int* size) const { return std_map_serializer_.Serialize(m.map_, size); } @@ -110,18 +109,18 @@ template<typename Address, typename Entry> class RangeMapSerializer { public: // Calculate the memory size of serialized data. - size_t SizeOf(const RangeMap<Address, Entry> &m) const; + size_t SizeOf(const RangeMap<Address, Entry>& m) const; // Write the serialized data to specified memory location. Return the "end" // of data, i.e., return the address after the final byte of data. // NOTE: caller has to allocate enough memory before invoke Write() method. - char* Write(const RangeMap<Address, Entry> &m, char* dest) const; + char* Write(const RangeMap<Address, Entry>& m, char* dest) const; // Serializes a RangeMap object into a chunk of memory data. // Returns a pointer to the serialized data. If size != NULL, *size is set // to the size of serialized data, i.e., SizeOf(m). // Caller has the ownership of memory allocated as "new char[]". - char* Serialize(const RangeMap<Address, Entry> &m, unsigned int *size) const; + char* Serialize(const RangeMap<Address, Entry>& m, unsigned int* size) const; private: // Convenient type name for Range. @@ -139,20 +138,20 @@ template<class AddrType, class EntryType> class ContainedRangeMapSerializer { public: // Calculate the memory size of serialized data. - size_t SizeOf(const ContainedRangeMap<AddrType, EntryType> *m) const; + size_t SizeOf(const ContainedRangeMap<AddrType, EntryType>* m) const; // Write the serialized data to specified memory location. Return the "end" // of data, i.e., return the address after the final byte of data. // NOTE: caller has to allocate enough memory before invoke Write() method. - char* Write(const ContainedRangeMap<AddrType, EntryType> *m, + char* Write(const ContainedRangeMap<AddrType, EntryType>* m, char* dest) const; // Serializes a ContainedRangeMap object into a chunk of memory data. // Returns a pointer to the serialized data. If size != NULL, *size is set // to the size of serialized data, i.e., SizeOf(m). // Caller has the ownership of memory allocated as "new char[]". - char* Serialize(const ContainedRangeMap<AddrType, EntryType> *m, - unsigned int *size) const; + char* Serialize(const ContainedRangeMap<AddrType, EntryType>* m, + unsigned int* size) const; private: // Convenient type name for the underlying map type. diff --git a/src/processor/map_serializers_unittest.cc b/src/processor/map_serializers_unittest.cc index 0d872ec2..74ebd5e5 100644 --- a/src/processor/map_serializers_unittest.cc +++ b/src/processor/map_serializers_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -63,7 +62,7 @@ class TestStdMapSerializer : public ::testing::Test { std::map<AddrType, EntryType> std_map_; google_breakpad::StdMapSerializer<AddrType, EntryType> serializer_; uint32_t serialized_size_; - char *serialized_data_; + char* serialized_data_; }; TEST_F(TestStdMapSerializer, EmptyMapTestCase) { @@ -135,7 +134,7 @@ class TestAddressMapSerializer : public ::testing::Test { google_breakpad::AddressMap<AddrType, EntryType> address_map_; google_breakpad::AddressMapSerializer<AddrType, EntryType> serializer_; uint32_t serialized_size_; - char *serialized_data_; + char* serialized_data_; }; TEST_F(TestAddressMapSerializer, EmptyMapTestCase) { @@ -210,7 +209,7 @@ class TestRangeMapSerializer : public ::testing::Test { google_breakpad::RangeMap<AddrType, EntryType> range_map_; google_breakpad::RangeMapSerializer<AddrType, EntryType> serializer_; uint32_t serialized_size_; - char *serialized_data_; + char* serialized_data_; }; TEST_F(TestRangeMapSerializer, EmptyMapTestCase) { @@ -283,7 +282,7 @@ class TestContainedRangeMapSerializer : public ::testing::Test { google_breakpad::ContainedRangeMap<AddrType, EntryType> crm_map_; google_breakpad::ContainedRangeMapSerializer<AddrType, EntryType> serializer_; uint32_t serialized_size_; - char *serialized_data_; + char* serialized_data_; }; TEST_F(TestContainedRangeMapSerializer, EmptyMapTestCase) { @@ -379,7 +378,7 @@ TEST_F(TestContainedRangeMapSerializer, MapWithTwoLevelsTestCase) { } -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/src/processor/microdump.cc b/src/processor/microdump.cc index d8141a2a..83fb098c 100644 --- a/src/processor/microdump.cc +++ b/src/processor/microdump.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014 Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/microdump_processor.cc b/src/processor/microdump_processor.cc index 2d3a9558..be6150cd 100644 --- a/src/processor/microdump_processor.cc +++ b/src/processor/microdump_processor.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/microdump_processor_unittest.cc b/src/processor/microdump_processor_unittest.cc index 83bdef95..3362431b 100644 --- a/src/processor/microdump_processor_unittest.cc +++ b/src/processor/microdump_processor_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014, Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/microdump_stackwalk.cc b/src/processor/microdump_stackwalk.cc index 220396ed..593b07d6 100644 --- a/src/processor/microdump_stackwalk.cc +++ b/src/processor/microdump_stackwalk.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2014 Google Inc. -// All rights reserved. +// Copyright 2014 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -110,7 +109,10 @@ int PrintMicrodumpProcess(const Options& options) { if (options.machine_readable) { PrintProcessStateMachineReadable(process_state); } else { - PrintProcessState(process_state, options.output_stack_contents, &resolver); + // Microdump has only one thread, |output_requesting_thread_only|'s value + // has no effect. + PrintProcessState(process_state, options.output_stack_contents, + /*output_requesting_thread_only=*/false, &resolver); } return 0; } @@ -140,7 +142,7 @@ static void SetupOptions(int argc, const char *argv[], Options* options) { options->machine_readable = false; options->output_stack_contents = false; - while ((ch = getopt(argc, (char * const *)argv, "hms")) != -1) { + while ((ch = getopt(argc, (char * const*)argv, "hms")) != -1) { switch (ch) { case 'h': Usage(argc, argv, false); diff --git a/src/processor/microdump_stackwalk_machine_readable_test b/src/processor/microdump_stackwalk_machine_readable_test index f5614e20..a0898466 100755 --- a/src/processor/microdump_stackwalk_machine_readable_test +++ b/src/processor/microdump_stackwalk_machine_readable_test @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2014, Google Inc. -# All rights reserved. +# Copyright 2014 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/processor/microdump_stackwalk_test b/src/processor/microdump_stackwalk_test index e1897656..cb895082 100755 --- a/src/processor/microdump_stackwalk_test +++ b/src/processor/microdump_stackwalk_test @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2014, Google Inc. -# All rights reserved. +# Copyright 2014 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 4c0b26ab..135770d5 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,6 +36,7 @@ #include <assert.h> #include <fcntl.h> +#include <inttypes.h> #include <stddef.h> #include <string.h> #include <time.h> @@ -96,6 +96,10 @@ bool IsContextSizeUnique(uint32_t context_size) { num_matching_contexts++; if (context_size == sizeof(MDRawContextMIPS)) num_matching_contexts++; + if (context_size == sizeof(MDRawContextRISCV)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextRISCV64)) + num_matching_contexts++; return num_matching_contexts == 1; } @@ -212,6 +216,12 @@ inline void Swap(MDRawSimpleStringDictionaryEntry* entry) { Swap(&entry->value); } +inline void Swap(MDRawCrashpadAnnotation* annotation) { + Swap(&annotation->name); + Swap(&annotation->type); + Swap(&annotation->value); +} + inline void Swap(uint16_t* data, size_t size_in_bytes) { size_t data_length = size_in_bytes / sizeof(data[0]); for (size_t i = 0; i < data_length; i++) { @@ -470,7 +480,16 @@ bool MinidumpContext::Read(uint32_t expected_size) { // First, figure out what type of CPU this context structure is for. // For some reason, the AMD64 Context doesn't have context_flags // at the beginning of the structure, so special case it here. - if (expected_size == sizeof(MDRawContextAMD64)) { + + uint32_t sysinfo_cpu_type = 0; + if (!minidump_->GetContextCPUFlagsFromSystemInfo(&sysinfo_cpu_type)) { + BPLOG(ERROR) << "Failed to preserve the current stream position"; + return false; + } + + if (expected_size == sizeof(MDRawContextAMD64) || + (sysinfo_cpu_type == MD_CONTEXT_AMD64 && + expected_size >= sizeof(MDRawContextAMD64))) { BPLOG(INFO) << "MinidumpContext: looks like AMD64 context"; scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64()); @@ -480,17 +499,24 @@ bool MinidumpContext::Read(uint32_t expected_size) { return false; } + // Context may include xsave registers and so be larger than + // sizeof(MDRawContextAMD64). For now we skip this extended data. + if (expected_size > sizeof(MDRawContextAMD64)) { + size_t bytes_left = expected_size - sizeof(MDRawContextAMD64); + std::vector<uint8_t> xstate(bytes_left); + if (!minidump_->ReadBytes(xstate.data(), + bytes_left)) { + BPLOG(ERROR) << "MinidumpContext could not skip amd64 xstate"; + return false; + } + } + if (minidump_->swap()) Swap(&context_amd64->context_flags); uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK; if (cpu_type == 0) { - if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { - context_amd64->context_flags |= cpu_type; - } else { - BPLOG(ERROR) << "Failed to preserve the current stream position"; - return false; - } + context_amd64->context_flags |= sysinfo_cpu_type; } if (cpu_type != MD_CONTEXT_AMD64) { @@ -765,13 +791,10 @@ bool MinidumpContext::Read(uint32_t expected_size) { } } + // Fixup if we were not provided a cpu type. if (cpu_type == 0) { - if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { - context_flags |= cpu_type; - } else { - BPLOG(ERROR) << "Failed to preserve the current stream position"; - return false; - } + cpu_type = sysinfo_cpu_type; + context_flags |= cpu_type; } // Allocate the context structure for the correct CPU and fill it. The @@ -1157,13 +1180,169 @@ bool MinidumpContext::Read(uint32_t expected_size) { break; } + case MD_CONTEXT_RISCV: { + if (expected_size != sizeof(MDRawContextRISCV)) { + BPLOG(ERROR) << "MinidumpContext RISCV size mismatch, " + << expected_size + << " != " + << sizeof(MDRawContextRISCV); + return false; + } + + scoped_ptr<MDRawContextRISCV> context_riscv(new MDRawContextRISCV()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_riscv->context_flags = context_flags; + + size_t flags_size = sizeof(context_riscv->context_flags); + uint8_t* context_after_flags = + reinterpret_cast<uint8_t*>(context_riscv.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextRISCV) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read RISCV context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext RISCV does not match system info"; + return false; + } + + if (minidump_->swap()) { + Swap(&context_riscv->pc); + Swap(&context_riscv->ra); + Swap(&context_riscv->sp); + Swap(&context_riscv->gp); + Swap(&context_riscv->tp); + Swap(&context_riscv->t0); + Swap(&context_riscv->t1); + Swap(&context_riscv->t2); + Swap(&context_riscv->s0); + Swap(&context_riscv->s1); + Swap(&context_riscv->a0); + Swap(&context_riscv->a1); + Swap(&context_riscv->a2); + Swap(&context_riscv->a3); + Swap(&context_riscv->a4); + Swap(&context_riscv->a5); + Swap(&context_riscv->a6); + Swap(&context_riscv->a7); + Swap(&context_riscv->s2); + Swap(&context_riscv->s3); + Swap(&context_riscv->s4); + Swap(&context_riscv->s5); + Swap(&context_riscv->s6); + Swap(&context_riscv->s7); + Swap(&context_riscv->s8); + Swap(&context_riscv->s9); + Swap(&context_riscv->s10); + Swap(&context_riscv->s11); + Swap(&context_riscv->t3); + Swap(&context_riscv->t4); + Swap(&context_riscv->t5); + Swap(&context_riscv->t6); + + for (int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; + ++fpr_index) { + Swap(&context_riscv->float_save.regs[fpr_index]); + } + Swap(&context_riscv->float_save.fpcsr); + } + SetContextRISCV(context_riscv.release()); + + break; + } + + case MD_CONTEXT_RISCV64: { + if (expected_size != sizeof(MDRawContextRISCV64)) { + BPLOG(ERROR) << "MinidumpContext RISCV64 size mismatch, " + << expected_size + << " != " + << sizeof(MDRawContextRISCV64); + return false; + } + + scoped_ptr<MDRawContextRISCV64> context_riscv64( + new MDRawContextRISCV64()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_riscv64->context_flags = context_flags; + + size_t flags_size = sizeof(context_riscv64->context_flags); + uint8_t* context_after_flags = + reinterpret_cast<uint8_t*>(context_riscv64.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextRISCV64) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read RISCV context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext RISCV does not match system info"; + return false; + } + + if (minidump_->swap()) { + Swap(&context_riscv64->pc); + Swap(&context_riscv64->ra); + Swap(&context_riscv64->sp); + Swap(&context_riscv64->gp); + Swap(&context_riscv64->tp); + Swap(&context_riscv64->t0); + Swap(&context_riscv64->t1); + Swap(&context_riscv64->t2); + Swap(&context_riscv64->s0); + Swap(&context_riscv64->s1); + Swap(&context_riscv64->a0); + Swap(&context_riscv64->a1); + Swap(&context_riscv64->a2); + Swap(&context_riscv64->a3); + Swap(&context_riscv64->a4); + Swap(&context_riscv64->a5); + Swap(&context_riscv64->a6); + Swap(&context_riscv64->a7); + Swap(&context_riscv64->s2); + Swap(&context_riscv64->s3); + Swap(&context_riscv64->s4); + Swap(&context_riscv64->s5); + Swap(&context_riscv64->s6); + Swap(&context_riscv64->s7); + Swap(&context_riscv64->s8); + Swap(&context_riscv64->s9); + Swap(&context_riscv64->s10); + Swap(&context_riscv64->s11); + Swap(&context_riscv64->t3); + Swap(&context_riscv64->t4); + Swap(&context_riscv64->t5); + Swap(&context_riscv64->t6); + + for (int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; + ++fpr_index) { + Swap(&context_riscv64->float_save.regs[fpr_index]); + } + Swap(&context_riscv64->float_save.fpcsr); + } + SetContextRISCV64(context_riscv64.release()); + + break; + } + default: { // Unknown context type - Don't log as an error yet. Let the // caller work that out. BPLOG(INFO) << "MinidumpContext unknown context type " << HexString(cpu_type); return false; - break; } } SetContextFlags(context_flags); @@ -1250,6 +1429,16 @@ bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) { if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS64) return_value = true; break; + + case MD_CONTEXT_RISCV: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_RISCV) + return_value = true; + break; + + case MD_CONTEXT_RISCV64: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_RISCV64) + return_value = true; + break; } BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " << @@ -1611,7 +1800,7 @@ MinidumpContext* MinidumpThread::GetContext() { } -bool MinidumpThread::GetThreadID(uint32_t *thread_id) const { +bool MinidumpThread::GetThreadID(uint32_t* thread_id) const { BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires " "|thread_id|"; assert(thread_id); @@ -1831,6 +2020,229 @@ void MinidumpThreadList::Print() { } } +// +// MinidumpThreadName +// + +MinidumpThreadName::MinidumpThreadName(Minidump* minidump) + : MinidumpObject(minidump), + thread_name_valid_(false), + thread_name_(), + name_(NULL) {} + +MinidumpThreadName::~MinidumpThreadName() { + delete name_; +} + +bool MinidumpThreadName::Read() { + // Invalidate cached data. + delete name_; + name_ = NULL; + + valid_ = false; + + if (!minidump_->ReadBytes(&thread_name_, sizeof(thread_name_))) { + BPLOG(ERROR) << "MinidumpThreadName cannot read thread name"; + return false; + } + + if (minidump_->swap()) { + Swap(&thread_name_.thread_id); + Swap(&thread_name_.thread_name_rva); + } + + thread_name_valid_ = true; + return true; +} + +bool MinidumpThreadName::ReadAuxiliaryData() { + if (!thread_name_valid_) { + BPLOG(ERROR) << "Invalid MinidumpThreadName for ReadAuxiliaryData"; + return false; + } + + // On 32-bit systems, check that the RVA64 is within range (off_t is 32 bits). + if (thread_name_.thread_name_rva > numeric_limits<off_t>::max()) { + BPLOG(ERROR) << "MinidumpThreadName RVA64 out of range"; + return false; + } + + // Read the thread name. + const off_t thread_name_rva_offset = + static_cast<off_t>(thread_name_.thread_name_rva); + name_ = minidump_->ReadString(thread_name_rva_offset); + if (!name_) { + BPLOG(ERROR) << "MinidumpThreadName could not read name"; + return false; + } + + // At this point, we have enough info for the thread name to be valid. + valid_ = true; + return true; +} + +bool MinidumpThreadName::GetThreadID(uint32_t* thread_id) const { + BPLOG_IF(ERROR, !thread_id) << "MinidumpThreadName::GetThreadID requires " + "|thread_id|"; + assert(thread_id); + *thread_id = 0; + + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThreadName for GetThreadID"; + return false; + } + + *thread_id = thread_name_.thread_id; + return true; +} + +string MinidumpThreadName::GetThreadName() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThreadName for GetThreadName"; + return ""; + } + + return *name_; +} + +void MinidumpThreadName::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpThreadName cannot print invalid data"; + return; + } + + printf("MDRawThreadName\n"); + printf(" thread_id = 0x%x\n", thread_name_.thread_id); + printf(" thread_name_rva = 0x%" PRIx64 "\n", + thread_name_.thread_name_rva); + printf(" thread_name = \"%s\"\n", GetThreadName().c_str()); + printf("\n"); +} + +// +// MinidumpThreadNameList +// + +MinidumpThreadNameList::MinidumpThreadNameList(Minidump* minidump) + : MinidumpStream(minidump), thread_names_(NULL), thread_name_count_(0) {} + +MinidumpThreadNameList::~MinidumpThreadNameList() { + delete thread_names_; +} + +bool MinidumpThreadNameList::Read(uint32_t expected_size) { + // Invalidate cached data. + delete thread_names_; + thread_names_ = NULL; + thread_name_count_ = 0; + + valid_ = false; + + uint32_t thread_name_count; + if (expected_size < sizeof(thread_name_count)) { + BPLOG(ERROR) << "MinidumpThreadNameList count size mismatch, " + << expected_size << " < " << sizeof(thread_name_count); + return false; + } + if (!minidump_->ReadBytes(&thread_name_count, sizeof(thread_name_count))) { + BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name count"; + return false; + } + + if (minidump_->swap()) + Swap(&thread_name_count); + + if (thread_name_count > + numeric_limits<uint32_t>::max() / sizeof(MDRawThreadName)) { + BPLOG(ERROR) << "MinidumpThreadNameList thread name count " + << thread_name_count << " would cause multiplication overflow"; + return false; + } + + if (expected_size != + sizeof(thread_name_count) + thread_name_count * sizeof(MDRawThreadName)) { + BPLOG(ERROR) << "MinidumpThreadNameList size mismatch, " << expected_size + << " != " + << sizeof(thread_name_count) + + thread_name_count * sizeof(MDRawThreadName); + return false; + } + + if (thread_name_count > MinidumpThreadList::max_threads()) { + BPLOG(ERROR) << "MinidumpThreadNameList count " << thread_name_count + << " exceeds maximum " << MinidumpThreadList::max_threads(); + return false; + } + + if (thread_name_count != 0) { + scoped_ptr<MinidumpThreadNames> thread_names(new MinidumpThreadNames( + thread_name_count, MinidumpThreadName(minidump_))); + + for (unsigned int thread_name_index = 0; + thread_name_index < thread_name_count; ++thread_name_index) { + MinidumpThreadName* thread_name = &(*thread_names)[thread_name_index]; + + // Assume that the file offset is correct after the last read. + if (!thread_name->Read()) { + BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name " + << thread_name_index << "/" << thread_name_count; + return false; + } + } + + for (unsigned int thread_name_index = 0; + thread_name_index < thread_name_count; ++thread_name_index) { + MinidumpThreadName* thread_name = &(*thread_names)[thread_name_index]; + + if (!thread_name->ReadAuxiliaryData() && !thread_name->valid()) { + BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name " + << thread_name_index << "/" << thread_name_count; + return false; + } + } + + thread_names_ = thread_names.release(); + } + + thread_name_count_ = thread_name_count; + + valid_ = true; + return true; +} + +MinidumpThreadName* MinidumpThreadNameList::GetThreadNameAtIndex( + unsigned int index) const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThreadNameList for GetThreadNameAtIndex"; + return NULL; + } + + if (index >= thread_name_count_) { + BPLOG(ERROR) << "MinidumpThreadNameList index out of range: " << index + << "/" << thread_name_count_; + return NULL; + } + + return &(*thread_names_)[index]; +} + +void MinidumpThreadNameList::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpThreadNameList cannot print invalid data"; + return; + } + + printf("MinidumpThreadNameList\n"); + printf(" thread_name_count = %d\n", thread_name_count_); + printf("\n"); + + for (unsigned int thread_name_index = 0; + thread_name_index < thread_name_count_; ++thread_name_index) { + printf("thread_name[%d]\n", thread_name_index); + + (*thread_names_)[thread_name_index].Print(); + } +} // // MinidumpModule @@ -1973,14 +2385,14 @@ string MinidumpModule::code_identifier() const { if (!has_debug_info_) return ""; - MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo(); + MinidumpSystemInfo* minidump_system_info = minidump_->GetSystemInfo(); if (!minidump_system_info) { BPLOG(ERROR) << "MinidumpModule code_identifier requires " "MinidumpSystemInfo"; return ""; } - const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info(); + const MDRawSystemInfo* raw_system_info = minidump_system_info->system_info(); if (!raw_system_info) { BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo"; return ""; @@ -2093,7 +2505,7 @@ string MinidumpModule::debug_file() const { // No usable CodeView record. Try the miscellaneous debug record. if (misc_record_) { const MDImageDebugMisc* misc_record = - reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]); + reinterpret_cast<const MDImageDebugMisc*>(&(*misc_record_)[0]); if (!misc_record->unicode) { // If it's not Unicode, just stuff it into the string. It's unclear // if misc_record->data is 0-terminated, so use an explicit size. @@ -2202,7 +2614,7 @@ string MinidumpModule::debug_identifier() const { // with age = 0. Historically Breakpad would do this during dump // writing to fit the build id data into a MDCVInfoPDB70 struct. // The full build id is available by calling code_identifier. - MDGUID guid = {}; + MDGUID guid = {0}; memcpy(&guid, &cv_record_elf->build_id, std::min(cv_record_->size() - MDCVInfoELF_minsize, sizeof(MDGUID))); @@ -2549,7 +2961,7 @@ void MinidumpModule::Print() { code_identifier().c_str()); uint32_t cv_record_size; - const uint8_t *cv_record = GetCVRecord(&cv_record_size); + const uint8_t* cv_record = GetCVRecord(&cv_record_size); if (cv_record) { if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { const MDCVInfoPDB70* cv_record_70 = @@ -3215,7 +3627,7 @@ bool MinidumpException::Read(uint32_t expected_size) { } -bool MinidumpException::GetThreadID(uint32_t *thread_id) const { +bool MinidumpException::GetThreadID(uint32_t* thread_id) const { BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires " "|thread_id|"; assert(thread_id); @@ -3538,6 +3950,14 @@ string MinidumpSystemInfo::GetCPU() { cpu = "arm64"; break; + case MD_CPU_ARCHITECTURE_RISCV: + cpu = "riscv"; + break; + + case MD_CPU_ARCHITECTURE_RISCV64: + cpu = "riscv64"; + break; + default: BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " << HexString(system_info_.processor_architecture); @@ -3603,8 +4023,8 @@ void MinidumpSystemInfo::Print() { } printf("MDRawSystemInfo\n"); - printf(" processor_architecture = 0x%x\n", - system_info_.processor_architecture); + printf(" processor_architecture = 0x%x (%s)\n", + system_info_.processor_architecture, GetCPU().c_str()); printf(" processor_level = %d\n", system_info_.processor_level); printf(" processor_revision = 0x%x\n", @@ -3619,8 +4039,8 @@ void MinidumpSystemInfo::Print() { system_info_.minor_version); printf(" build_number = %d\n", system_info_.build_number); - printf(" platform_id = 0x%x\n", - system_info_.platform_id); + printf(" platform_id = 0x%x (%s)\n", + system_info_.platform_id, GetOS().c_str()); printf(" csd_version_rva = 0x%x\n", system_info_.csd_version_rva); printf(" suite_mask = 0x%x\n", @@ -3699,14 +4119,14 @@ string MinidumpUnloadedModule::code_identifier() const { return ""; } - MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo(); + MinidumpSystemInfo* minidump_system_info = minidump_->GetSystemInfo(); if (!minidump_system_info) { BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires " "MinidumpSystemInfo"; return ""; } - const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info(); + const MDRawSystemInfo* raw_system_info = minidump_system_info->system_info(); if (!raw_system_info) { BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires " << "MDRawSystemInfo"; @@ -4356,7 +4776,7 @@ bool MinidumpBreakpadInfo::Read(uint32_t expected_size) { } -bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const { +bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t* thread_id) const { BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID " "requires |thread_id|"; assert(thread_id); @@ -4377,7 +4797,7 @@ bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const { } -bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t *thread_id) +bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t* thread_id) const { BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID " "requires |thread_id|"; @@ -4695,7 +5115,7 @@ void MinidumpMemoryInfoList::Print() { // MinidumpLinuxMaps // -MinidumpLinuxMaps::MinidumpLinuxMaps(Minidump *minidump) +MinidumpLinuxMaps::MinidumpLinuxMaps(Minidump* minidump) : MinidumpObject(minidump) { } @@ -4711,7 +5131,7 @@ void MinidumpLinuxMaps::Print() const { // MinidumpLinuxMapsList // -MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump *minidump) +MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump* minidump) : MinidumpStream(minidump), maps_(NULL), maps_count_(0) { @@ -4726,7 +5146,7 @@ MinidumpLinuxMapsList::~MinidumpLinuxMapsList() { } } -const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsForAddress( +const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsForAddress( uint64_t address) const { if (!valid_ || (maps_ == NULL)) { BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsForAddress"; @@ -4748,7 +5168,7 @@ const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsForAddress( return NULL; } -const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsAtIndex( +const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsAtIndex( unsigned int index) const { if (!valid_ || (maps_ == NULL)) { BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsAtIndex"; @@ -4847,6 +5267,7 @@ MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump) module_crashpad_info_(), module_crashpad_info_list_annotations_(), module_crashpad_info_simple_annotations_(), + module_crashpad_info_annotation_objects_(), simple_annotations_() { } @@ -4854,16 +5275,52 @@ MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump) bool MinidumpCrashpadInfo::Read(uint32_t expected_size) { valid_ = false; - if (expected_size != sizeof(crashpad_info_)) { - BPLOG(ERROR) << "MinidumpCrashpadInfo size mismatch, " << expected_size << - " != " << sizeof(crashpad_info_); + // Support old minidumps that do not implement newer crashpad_info_ + // fields, currently limited to the address mask. + static_assert(sizeof(crashpad_info_) == 64, + "Updated ::Read for new crashpad_info field."); + + constexpr size_t crashpad_info_min_size = + offsetof(decltype(crashpad_info_), reserved); + if (expected_size < crashpad_info_min_size) { + BPLOG(ERROR) << "MinidumpCrashpadInfo size mismatch, " << expected_size + << " < " << crashpad_info_min_size; return false; } - if (!minidump_->ReadBytes(&crashpad_info_, sizeof(crashpad_info_))) { + if (!minidump_->ReadBytes(&crashpad_info_, crashpad_info_min_size)) { BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad info"; return false; } + expected_size -= crashpad_info_min_size; + + // Read `reserved` if available. + size_t crashpad_reserved_size = sizeof(crashpad_info_.reserved); + if (expected_size >= crashpad_reserved_size) { + if (!minidump_->ReadBytes( + &crashpad_info_.reserved, + crashpad_reserved_size)) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read reserved"; + return false; + } + expected_size -= crashpad_reserved_size; + } else { + crashpad_info_.reserved = 0; + } + + // Read `address_mask` if available. + size_t crashpad_address_mask_size = sizeof(crashpad_info_.address_mask); + if (expected_size >= crashpad_address_mask_size) { + if (!minidump_->ReadBytes( + &crashpad_info_.address_mask, + crashpad_address_mask_size)) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read address mask"; + return false; + } + expected_size -= crashpad_address_mask_size; + } else { + crashpad_info_.address_mask = 0; + } if (minidump_->swap()) { Swap(&crashpad_info_.version); @@ -4871,6 +5328,8 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) { Swap(&crashpad_info_.client_id); Swap(&crashpad_info_.simple_annotations); Swap(&crashpad_info_.module_list); + Swap(&crashpad_info_.reserved); + Swap(&crashpad_info_.address_mask); } if (crashpad_info_.simple_annotations.data_size) { @@ -4934,6 +5393,7 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) { Swap(&module_crashpad_info.version); Swap(&module_crashpad_info.list_annotations); Swap(&module_crashpad_info.simple_annotations); + Swap(&module_crashpad_info.annotation_objects); } std::vector<std::string> list_annotations; @@ -4958,11 +5418,23 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) { } } + std::vector<MinidumpCrashpadInfo::AnnotationObject> annotation_objects; + if (module_crashpad_info.annotation_objects.data_size) { + if (!minidump_->ReadCrashpadAnnotationsList( + module_crashpad_info.annotation_objects.rva, + &annotation_objects)) { + BPLOG(ERROR) + << "MinidumpCrashpadInfo cannot read Crashpad annotations list"; + return false; + } + } + module_crashpad_info_links_.push_back( module_crashpad_info_links[index].minidump_module_list_index); module_crashpad_info_.push_back(module_crashpad_info); module_crashpad_info_list_annotations_.push_back(list_annotations); module_crashpad_info_simple_annotations_.push_back(simple_annotations); + module_crashpad_info_annotation_objects_.push_back(annotation_objects); } } @@ -4983,12 +5455,9 @@ void MinidumpCrashpadInfo::Print() { MDGUIDToString(crashpad_info_.report_id).c_str()); printf(" client_id = %s\n", MDGUIDToString(crashpad_info_.client_id).c_str()); - for (std::map<std::string, std::string>::const_iterator iterator = - simple_annotations_.begin(); - iterator != simple_annotations_.end(); - ++iterator) { - printf(" simple_annotations[\"%s\"] = %s\n", - iterator->first.c_str(), iterator->second.c_str()); + for (const auto& annot : simple_annotations_) { + printf(" simple_annotations[\"%s\"] = %s\n", annot.first.c_str(), + annot.second.c_str()); } for (uint32_t module_index = 0; module_index < module_crashpad_info_links_.size(); @@ -4997,24 +5466,20 @@ void MinidumpCrashpadInfo::Print() { module_index, module_crashpad_info_links_[module_index]); printf(" module_list[%d].version = %d\n", module_index, module_crashpad_info_[module_index].version); - for (uint32_t annotation_index = 0; - annotation_index < - module_crashpad_info_list_annotations_[module_index].size(); + const auto& list_annots = + module_crashpad_info_list_annotations_[module_index]; + for (uint32_t annotation_index = 0; annotation_index < list_annots.size(); ++annotation_index) { - printf(" module_list[%d].list_annotations[%d] = %s\n", - module_index, - annotation_index, - module_crashpad_info_list_annotations_ - [module_index][annotation_index].c_str()); + printf(" module_list[%d].list_annotations[%d] = %s\n", module_index, + annotation_index, list_annots[annotation_index].c_str()); } - for (std::map<std::string, std::string>::const_iterator iterator = - module_crashpad_info_simple_annotations_[module_index].begin(); - iterator != - module_crashpad_info_simple_annotations_[module_index].end(); - ++iterator) { + const auto& simple_annots = + module_crashpad_info_simple_annotations_[module_index]; + for (const auto& annot : simple_annots) { printf(" module_list[%d].simple_annotations[\"%s\"] = %s\n", - module_index, iterator->first.c_str(), iterator->second.c_str()); + module_index, annot.first.c_str(), annot.second.c_str()); } + printf(" address_mask = %" PRIu64 "\n", crashpad_info_.address_mask); } printf("\n"); @@ -5090,7 +5555,7 @@ bool Minidump::Open() { return true; } -bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) { +bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags) { // Initialize output parameters *context_cpu_flags = 0; @@ -5155,6 +5620,12 @@ bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) { case MD_CPU_ARCHITECTURE_SPARC: *context_cpu_flags = MD_CONTEXT_SPARC; break; + case MD_CPU_ARCHITECTURE_RISCV: + *context_cpu_flags = MD_CONTEXT_RISCV; + break; + case MD_CPU_ARCHITECTURE_RISCV64: + *context_cpu_flags = MD_CONTEXT_RISCV64; + break; case MD_CPU_ARCHITECTURE_UNKNOWN: *context_cpu_flags = 0; break; @@ -5276,6 +5747,7 @@ bool Minidump::Read() { unsigned int stream_type = directory_entry->stream_type; switch (stream_type) { case MD_THREAD_LIST_STREAM: + case MD_THREAD_NAME_LIST_STREAM: case MD_MODULE_LIST_STREAM: case MD_MEMORY_LIST_STREAM: case MD_EXCEPTION_STREAM: @@ -5314,6 +5786,10 @@ MinidumpThreadList* Minidump::GetThreadList() { return GetStream(&thread_list); } +MinidumpThreadNameList* Minidump::GetThreadNameList() { + MinidumpThreadNameList* thread_name_list; + return GetStream(&thread_name_list); +} MinidumpModuleList* Minidump::GetModuleList() { MinidumpModuleList* module_list; @@ -5366,8 +5842,8 @@ MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() { return GetStream(&memory_info_list); } -MinidumpLinuxMapsList *Minidump::GetLinuxMapsList() { - MinidumpLinuxMapsList *linux_maps_list; +MinidumpLinuxMapsList* Minidump::GetLinuxMapsList() { + MinidumpLinuxMapsList* linux_maps_list; return GetStream(&linux_maps_list); } @@ -5413,6 +5889,8 @@ static const char* get_stream_name(uint32_t stream_type) { return "MD_RESERVED_STREAM_1"; case MD_THREAD_LIST_STREAM: return "MD_THREAD_LIST_STREAM"; + case MD_THREAD_NAME_LIST_STREAM: + return "MD_THREAD_NAME_LIST_STREAM"; case MD_MODULE_LIST_STREAM: return "MD_MODULE_LIST_STREAM"; case MD_MEMORY_LIST_STREAM: @@ -5807,6 +6285,73 @@ bool Minidump::ReadSimpleStringDictionary( return true; } +bool Minidump::ReadCrashpadAnnotationsList( + off_t offset, + std::vector<MinidumpCrashpadInfo::AnnotationObject>* annotations_list) { + annotations_list->clear(); + + if (!SeekSet(offset)) { + BPLOG(ERROR) << "Minidump cannot seek to annotations_list"; + return false; + } + + uint32_t count; + if (!ReadBytes(&count, sizeof(count))) { + BPLOG(ERROR) << "Minidump cannot read annotations_list count"; + return false; + } + + if (swap_) { + Swap(&count); + } + + scoped_array<MDRawCrashpadAnnotation> objects( + new MDRawCrashpadAnnotation[count]); + + // Read the entire array in one fell swoop, instead of reading one entry + // at a time in the loop. + if (!ReadBytes(&objects[0], sizeof(MDRawCrashpadAnnotation) * count)) { + BPLOG(ERROR) << "Minidump could not read annotations_list"; + return false; + } + + for (uint32_t index = 0; index < count; ++index) { + MDRawCrashpadAnnotation annotation = objects[index]; + + if (swap_) { + Swap(&annotation); + } + + string name; + if (!ReadUTF8String(annotation.name, &name)) { + BPLOG(ERROR) << "Minidump could not read annotation name"; + return false; + } + + if (!SeekSet(annotation.value)) { + BPLOG(ERROR) << "Minidump cannot seek to annotations value"; + return false; + } + + uint32_t value_length; + if (!ReadBytes(&value_length, sizeof(value_length))) { + BPLOG(ERROR) << "Minidump could not read annotation value length"; + return false; + } + + std::vector<uint8_t> value_data(value_length); + if (!ReadBytes(value_data.data(), value_length)) { + BPLOG(ERROR) << "Minidump could not read annotation value"; + return false; + } + + MinidumpCrashpadInfo::AnnotationObject object = {annotation.type, name, + value_data}; + annotations_list->push_back(object); + } + + return true; +} bool Minidump::SeekToStreamType(uint32_t stream_type, uint32_t* stream_length) { diff --git a/src/processor/minidump_dump.cc b/src/processor/minidump_dump.cc index 4716aa08..83afd1da 100644 --- a/src/processor/minidump_dump.cc +++ b/src/processor/minidump_dump.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -36,6 +35,7 @@ #include <string.h> #include <unistd.h> +#include "common/path_helper.h" #include "common/scoped_ptr.h" #include "google_breakpad/processor/minidump.h" #include "processor/logging.h" @@ -44,6 +44,7 @@ namespace { using google_breakpad::Minidump; using google_breakpad::MinidumpThreadList; +using google_breakpad::MinidumpThreadNameList; using google_breakpad::MinidumpModuleList; using google_breakpad::MinidumpMemoryInfoList; using google_breakpad::MinidumpMemoryList; @@ -91,7 +92,7 @@ static void DumpRawStream(Minidump *minidump, // in compatibility warnings. uint32_t int_remaining = remaining; printf("%.*s", int_remaining, &contents[current_offset]); - char *next_null = reinterpret_cast<char *>( + char *next_null = reinterpret_cast<char*>( memchr(&contents[current_offset], 0, remaining)); if (next_null == NULL) break; @@ -121,6 +122,11 @@ static bool PrintMinidumpDump(const Options& options) { thread_list->Print(); } + MinidumpThreadNameList *thread_name_list = minidump.GetThreadNameList(); + if (thread_name_list) { + thread_name_list->Print(); + } + // It's useful to be able to see the full list of modules here even if it // would cause minidump_stackwalk to fail. MinidumpModuleList::set_max_modules(UINT32_MAX); @@ -233,7 +239,7 @@ Usage(int argc, char *argv[], bool error) { " <minidump> should be a minidump.\n" " -x:\t Display memory in a hexdump like format\n" " -h:\t Usage\n", - argv[0]); + google_breakpad::BaseName(argv[0]).c_str()); } //============================================================================= @@ -241,7 +247,7 @@ static void SetupOptions(int argc, char *argv[], Options *options) { int ch; - while ((ch = getopt(argc, (char * const *)argv, "xh")) != -1) { + while ((ch = getopt(argc, (char * const*)argv, "xh")) != -1) { switch (ch) { case 'x': options->hexdump = true; diff --git a/src/processor/minidump_dump_test b/src/processor/minidump_dump_test index fb62ace7..32ae38c5 100755 --- a/src/processor/minidump_dump_test +++ b/src/processor/minidump_dump_test @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2006, Google Inc. -# All rights reserved. +# Copyright 2006 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index 4ea4cb70..fb330e26 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -31,7 +30,11 @@ #include <assert.h> +#include <algorithm> +#include <limits> +#include <map> #include <string> +#include <utility> #include "common/scoped_ptr.h" #include "common/stdio_wrapper.h" @@ -41,22 +44,23 @@ #include "google_breakpad/processor/process_state.h" #include "google_breakpad/processor/exploitability.h" #include "google_breakpad/processor/stack_frame_symbolizer.h" +#include "processor/disassembler_objdump.h" #include "processor/logging.h" #include "processor/stackwalker_x86.h" #include "processor/symbolic_constants_win.h" namespace google_breakpad { -MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, - SourceLineResolverInterface *resolver) +MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, + SourceLineResolverInterface* resolver) : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), own_frame_symbolizer_(true), enable_exploitability_(false), enable_objdump_(false) { } -MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, - SourceLineResolverInterface *resolver, +MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, + SourceLineResolverInterface* resolver, bool enable_exploitability) : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), own_frame_symbolizer_(true), @@ -64,7 +68,7 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, enable_objdump_(false) { } -MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer *frame_symbolizer, +MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer, bool enable_exploitability) : frame_symbolizer_(frame_symbolizer), own_frame_symbolizer_(false), @@ -78,13 +82,13 @@ MinidumpProcessor::~MinidumpProcessor() { } ProcessResult MinidumpProcessor::Process( - Minidump *dump, ProcessState *process_state) { + Minidump* dump, ProcessState* process_state) { assert(dump); assert(process_state); process_state->Clear(); - const MDRawHeader *header = dump->header(); + const MDRawHeader* header = dump->header(); if (!header) { BPLOG(ERROR) << "Minidump " << dump->path() << " has no header"; return PROCESS_ERROR_NO_MINIDUMP_HEADER; @@ -102,20 +106,20 @@ ProcessResult MinidumpProcessor::Process( uint32_t requesting_thread_id = 0; bool has_requesting_thread = false; - MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo(); + MinidumpBreakpadInfo* breakpad_info = dump->GetBreakpadInfo(); if (breakpad_info) { has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id); has_requesting_thread = breakpad_info->GetRequestingThreadID(&requesting_thread_id); } - MinidumpException *exception = dump->GetException(); + MinidumpException* exception = dump->GetException(); if (exception) { process_state->crashed_ = true; has_requesting_thread = exception->GetThreadID(&requesting_thread_id); process_state->crash_reason_ = GetCrashReason( - dump, &process_state->crash_address_); + dump, &process_state->crash_address_, enable_objdump_); process_state->exception_record_.set_code( exception->exception()->exception_record.exception_code, @@ -128,8 +132,10 @@ ProcessResult MinidumpProcessor::Process( process_state->exception_record_.set_nested_exception_record_address( exception->exception()->exception_record.exception_record); process_state->exception_record_.set_address(process_state->crash_address_); - for (uint32_t i = 0; - i < exception->exception()->exception_record.number_parameters; i++) { + const uint32_t num_parameters = + std::min(exception->exception()->exception_record.number_parameters, + MD_EXCEPTION_MAXIMUM_PARAMETERS); + for (uint32_t i = 0; i < num_parameters; ++i) { process_state->exception_record_.add_parameter( exception->exception()->exception_record.exception_information[i], // TODO(ivanpe): Populate description. @@ -140,7 +146,7 @@ ProcessResult MinidumpProcessor::Process( // This will just return an empty string if it doesn't exist. process_state->assertion_ = GetAssertion(dump); - MinidumpModuleList *module_list = dump->GetModuleList(); + MinidumpModuleList* module_list = dump->GetModuleList(); // Put a copy of the module list into ProcessState object. This is not // necessarily a MinidumpModuleList, but it adheres to the CodeModules @@ -160,19 +166,19 @@ ProcessResult MinidumpProcessor::Process( } } - MinidumpUnloadedModuleList *unloaded_module_list = + MinidumpUnloadedModuleList* unloaded_module_list = dump->GetUnloadedModuleList(); if (unloaded_module_list) { process_state->unloaded_modules_ = unloaded_module_list->Copy(); } - MinidumpMemoryList *memory_list = dump->GetMemoryList(); + MinidumpMemoryList* memory_list = dump->GetMemoryList(); if (memory_list) { BPLOG(INFO) << "Found " << memory_list->region_count() << " memory regions."; } - MinidumpThreadList *threads = dump->GetThreadList(); + MinidumpThreadList* threads = dump->GetThreadList(); if (!threads) { BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list"; return PROCESS_ERROR_NO_THREAD_LIST; @@ -196,6 +202,28 @@ ProcessResult MinidumpProcessor::Process( // Reset frame_symbolizer_ at the beginning of stackwalk for each minidump. frame_symbolizer_->Reset(); + + MinidumpThreadNameList* thread_names = dump->GetThreadNameList(); + std::map<uint32_t, string> thread_id_to_name; + if (thread_names) { + const unsigned int thread_name_count = thread_names->thread_name_count(); + for (unsigned int thread_name_index = 0; + thread_name_index < thread_name_count; + ++thread_name_index) { + MinidumpThreadName* thread_name = thread_names->GetThreadNameAtIndex(thread_name_index); + if (!thread_name) { + BPLOG(ERROR) << "Could not get thread name for thread at index " << thread_name_index; + return PROCESS_ERROR_GETTING_THREAD_NAME; + } + uint32_t thread_id; + if (!thread_name->GetThreadID(&thread_id)) { + BPLOG(ERROR) << "Could not get thread ID for thread at index " << thread_name_index; + return PROCESS_ERROR_GETTING_THREAD_NAME; + } + thread_id_to_name.insert(std::make_pair(thread_id, thread_name->GetThreadName())); + } + } + for (unsigned int thread_index = 0; thread_index < thread_count; ++thread_index) { @@ -204,7 +232,7 @@ ProcessResult MinidumpProcessor::Process( thread_index, thread_count); string thread_string = dump->path() + ":" + thread_string_buffer; - MinidumpThread *thread = threads->GetThreadAtIndex(thread_index); + MinidumpThread* thread = threads->GetThreadAtIndex(thread_index); if (!thread) { BPLOG(ERROR) << "Could not get thread for " << thread_string; return PROCESS_ERROR_GETTING_THREAD; @@ -217,6 +245,14 @@ ProcessResult MinidumpProcessor::Process( } thread_string += " id " + HexString(thread_id); + auto thread_name_iter = thread_id_to_name.find(thread_id); + string thread_name; + if (thread_name_iter != thread_id_to_name.end()) { + thread_name = thread_name_iter->second; + } + if (!thread_name.empty()) { + thread_string += " name [" + thread_name + "]"; + } BPLOG(INFO) << "Looking at thread " << thread_string; // If this thread is the thread that produced the minidump, don't process @@ -227,7 +263,7 @@ ProcessResult MinidumpProcessor::Process( continue; } - MinidumpContext *context = thread->GetContext(); + MinidumpContext* context = thread->GetContext(); if (has_requesting_thread && thread_id == requesting_thread_id) { if (found_requesting_thread) { @@ -254,7 +290,7 @@ ProcessResult MinidumpProcessor::Process( // would not result in the expected stack trace from the time of the // crash. If the exception context is invalid, however, we fall back // on the thread context. - MinidumpContext *ctx = exception->GetContext(); + MinidumpContext* ctx = exception->GetContext(); context = ctx ? ctx : thread->GetContext(); } } @@ -262,7 +298,7 @@ ProcessResult MinidumpProcessor::Process( // If the memory region for the stack cannot be read using the RVA stored // in the memory descriptor inside MINIDUMP_THREAD, try to locate and use // a memory region (containing the stack) from the minidump memory list. - MinidumpMemoryRegion *thread_memory = thread->GetMemory(); + MinidumpMemoryRegion* thread_memory = thread->GetMemory(); if (!thread_memory && memory_list) { uint64_t start_stack_memory_range = thread->GetStartOfStackMemoryRange(); if (start_stack_memory_range) { @@ -308,6 +344,7 @@ ProcessResult MinidumpProcessor::Process( stack->set_tid(thread_id); process_state->threads_.push_back(stack.release()); process_state->thread_memory_regions_.push_back(thread_memory); + process_state->thread_names_.push_back(thread_name); } if (interrupted) { @@ -347,7 +384,7 @@ ProcessResult MinidumpProcessor::Process( } ProcessResult MinidumpProcessor::Process( - const string &minidump_file, ProcessState *process_state) { + const string& minidump_file, ProcessState* process_state) { BPLOG(INFO) << "Processing minidump in file " << minidump_file; Minidump dump(minidump_file); @@ -362,9 +399,9 @@ ProcessResult MinidumpProcessor::Process( // Returns the MDRawSystemInfo from a minidump, or NULL if system info is // not available from the minidump. If system_info is non-NULL, it is used // to pass back the MinidumpSystemInfo object. -static const MDRawSystemInfo* GetSystemInfo(Minidump *dump, - MinidumpSystemInfo **system_info) { - MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo(); +static const MDRawSystemInfo* GetSystemInfo(Minidump* dump, + MinidumpSystemInfo** system_info) { + MinidumpSystemInfo* minidump_system_info = dump->GetSystemInfo(); if (!minidump_system_info) return NULL; @@ -517,15 +554,15 @@ static void GetARMCpuInfo(const MDRawSystemInfo* raw_info, } // static -bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { +bool MinidumpProcessor::GetCPUInfo(Minidump* dump, SystemInfo* info) { assert(dump); assert(info); info->cpu.clear(); info->cpu_info.clear(); - MinidumpSystemInfo *system_info; - const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info); + MinidumpSystemInfo* system_info; + const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, &system_info); if (!raw_system_info) return false; @@ -538,7 +575,7 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { else info->cpu = "amd64"; - const string *cpu_vendor = system_info->GetCPUVendor(); + const string* cpu_vendor = system_info->GetCPUVendor(); if (cpu_vendor) { info->cpu_info = *cpu_vendor; info->cpu_info.append(" "); @@ -605,7 +642,7 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { } // static -bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) { +bool MinidumpProcessor::GetOSInfo(Minidump* dump, SystemInfo* info) { assert(dump); assert(info); @@ -613,8 +650,8 @@ bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) { info->os_short.clear(); info->os_version.clear(); - MinidumpSystemInfo *system_info; - const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info); + MinidumpSystemInfo* system_info; + const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, &system_info); if (!raw_system_info) return false; @@ -688,7 +725,7 @@ bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) { raw_system_info->build_number); info->os_version = os_version_string; - const string *csd_version = system_info->GetCSDVersion(); + const string* csd_version = system_info->GetCSDVersion(); if (csd_version) { info->os_version.append(" "); info->os_version.append(*csd_version); @@ -723,13 +760,87 @@ bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump, return true; } +static bool IsCanonicalAddress(uint64_t address) { + uint64_t sign_bit = (address >> 63) & 1; + for (int shift = 48; shift < 63; ++shift) { + if (sign_bit != ((address >> shift) & 1)) { + return false; + } + } + return true; +} + +static void CalculateFaultAddressFromInstruction(Minidump* dump, + uint64_t* address) { + MinidumpException* exception = dump->GetException(); + if (exception == NULL) { + BPLOG(INFO) << "Failed to get exception."; + return; + } + + MinidumpContext* context = exception->GetContext(); + if (context == NULL) { + BPLOG(INFO) << "Failed to get exception context."; + return; + } + + uint64_t instruction_ptr = 0; + if (!context->GetInstructionPointer(&instruction_ptr)) { + BPLOG(INFO) << "Failed to get instruction pointer."; + return; + } + + // Get memory region containing instruction pointer. + MinidumpMemoryList* memory_list = dump->GetMemoryList(); + MinidumpMemoryRegion* memory_region = + memory_list ? + memory_list->GetMemoryRegionForAddress(instruction_ptr) : NULL; + if (!memory_region) { + BPLOG(INFO) << "No memory region around instruction pointer."; + return; + } + + DisassemblerObjdump disassembler(context->GetContextCPU(), memory_region, + instruction_ptr); + fprintf(stderr, "%s %s %s\n", disassembler.operation().c_str(), + disassembler.src().c_str(), disassembler.dest().c_str()); + if (!disassembler.IsValid()) { + BPLOG(INFO) << "Disassembling fault instruction failed."; + return; + } + + // It's possible that we reach here when the faulting address is already + // correct, so we only update it if we find that at least one of the src/dest + // addresses is non-canonical. If both are non-canonical, we arbitrarily set + // it to the larger of the two, as this is more likely to be a known poison + // value. + + bool valid_read, valid_write; + uint64_t read_address, write_address; + + valid_read = disassembler.CalculateSrcAddress(*context, read_address); + valid_read &= !IsCanonicalAddress(read_address); + + valid_write = disassembler.CalculateDestAddress(*context, write_address); + valid_write &= !IsCanonicalAddress(write_address); + + if (valid_read && valid_write) { + *address = read_address > write_address ? read_address : write_address; + } else if (valid_read) { + *address = read_address; + } else if (valid_write) { + *address = write_address; + } +} + // static -string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { - MinidumpException *exception = dump->GetException(); +string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address, + bool enable_objdump) { + MinidumpException* exception = dump->GetException(); if (!exception) return ""; - const MDRawExceptionStream *raw_exception = exception->exception(); + const MDRawExceptionStream* raw_exception = exception->exception(); if (!raw_exception) return ""; @@ -749,7 +860,7 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { flags_string); string reason = reason_string; - const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, NULL); + const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, NULL); if (!raw_system_info) return reason; @@ -1132,9 +1243,20 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { reason = "EXC_RPC_ALERT / "; reason.append(flags_string); break; + case MD_EXCEPTION_MAC_RESOURCE: + reason = "EXC_RESOURCE / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_MAC_GUARD: + reason = "EXC_GUARD / "; + reason.append(flags_string); + break; case MD_EXCEPTION_MAC_SIMULATED: reason = "Simulated Exception"; break; + case MD_NS_EXCEPTION_SIMULATED: + reason = "Uncaught NSException"; + break; } break; } @@ -1291,7 +1413,220 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { reason = "EXCEPTION_POSSIBLE_DEADLOCK"; break; case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN: - reason = "EXCEPTION_STACK_BUFFER_OVERRUN"; + if (raw_exception->exception_record.number_parameters >= 1) { + MDFastFailSubcodeTypeWin subcode = + static_cast<MDFastFailSubcodeTypeWin>( + raw_exception->exception_record.exception_information[0]); + switch (subcode) { + // Note - we skip the '0'/GS case as it exists for legacy reasons. + case MD_FAST_FAIL_VTGUARD_CHECK_FAILURE: + reason = "FAST_FAIL_VTGUARD_CHECK_FAILURE"; + break; + case MD_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE: + reason = "FAST_FAIL_STACK_COOKIE_CHECK_FAILURE"; + break; + case MD_FAST_FAIL_CORRUPT_LIST_ENTRY: + reason = "FAST_FAIL_CORRUPT_LIST_ENTRY"; + break; + case MD_FAST_FAIL_INCORRECT_STACK: + reason = "FAST_FAIL_INCORRECT_STACK"; + break; + case MD_FAST_FAIL_INVALID_ARG: + reason = "FAST_FAIL_INVALID_ARG"; + break; + case MD_FAST_FAIL_GS_COOKIE_INIT: + reason = "FAST_FAIL_GS_COOKIE_INIT"; + break; + case MD_FAST_FAIL_FATAL_APP_EXIT: + reason = "FAST_FAIL_FATAL_APP_EXIT"; + break; + case MD_FAST_FAIL_RANGE_CHECK_FAILURE: + reason = "FAST_FAIL_RANGE_CHECK_FAILURE"; + break; + case MD_FAST_FAIL_UNSAFE_REGISTRY_ACCESS: + reason = "FAST_FAIL_UNSAFE_REGISTRY_ACCESS"; + break; + case MD_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE: + reason = "FAST_FAIL_GUARD_ICALL_CHECK_FAILURE"; + break; + case MD_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE: + reason = "FAST_FAIL_GUARD_WRITE_CHECK_FAILURE"; + break; + case MD_FAST_FAIL_INVALID_FIBER_SWITCH: + reason = "FAST_FAIL_INVALID_FIBER_SWITCH"; + break; + case MD_FAST_FAIL_INVALID_SET_OF_CONTEXT: + reason = "FAST_FAIL_INVALID_SET_OF_CONTEXT"; + break; + case MD_FAST_FAIL_INVALID_REFERENCE_COUNT: + reason = "FAST_FAIL_INVALID_REFERENCE_COUNT"; + break; + case MD_FAST_FAIL_INVALID_JUMP_BUFFER: + reason = "FAST_FAIL_INVALID_JUMP_BUFFER"; + break; + case MD_FAST_FAIL_MRDATA_MODIFIED: + reason = "FAST_FAIL_MRDATA_MODIFIED"; + break; + case MD_FAST_FAIL_CERTIFICATION_FAILURE: + reason = "FAST_FAIL_CERTIFICATION_FAILURE"; + break; + case MD_FAST_FAIL_INVALID_EXCEPTION_CHAIN: + reason = "FAST_FAIL_INVALID_EXCEPTION_CHAIN"; + break; + case MD_FAST_FAIL_CRYPTO_LIBRARY: + reason = "FAST_FAIL_CRYPTO_LIBRARY"; + break; + case MD_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT: + reason = "FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT"; + break; + case MD_FAST_FAIL_INVALID_IMAGE_BASE: + reason = "FAST_FAIL_INVALID_IMAGE_BASE"; + break; + case MD_FAST_FAIL_DLOAD_PROTECTION_FAILURE: + reason = "FAST_FAIL_DLOAD_PROTECTION_FAILURE"; + break; + case MD_FAST_FAIL_UNSAFE_EXTENSION_CALL: + reason = "FAST_FAIL_UNSAFE_EXTENSION_CALL"; + break; + case MD_FAST_FAIL_DEPRECATED_SERVICE_INVOKED: + reason = "FAST_FAIL_DEPRECATED_SERVICE_INVOKED"; + break; + case MD_FAST_FAIL_INVALID_BUFFER_ACCESS: + reason = "FAST_FAIL_INVALID_BUFFER_ACCESS"; + break; + case MD_FAST_FAIL_INVALID_BALANCED_TREE: + reason = "FAST_FAIL_INVALID_BALANCED_TREE"; + break; + case MD_FAST_FAIL_INVALID_NEXT_THREAD: + reason = "FAST_FAIL_INVALID_NEXT_THREAD"; + break; + case MD_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED: + reason = "FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED"; + break; + case MD_FAST_FAIL_APCS_DISABLED: + reason = "FAST_FAIL_APCS_DISABLED"; + break; + case MD_FAST_FAIL_INVALID_IDLE_STATE: + reason = "FAST_FAIL_INVALID_IDLE_STATE"; + break; + case MD_FAST_FAIL_MRDATA_PROTECTION_FAILURE: + reason = "FAST_FAIL_MRDATA_PROTECTION_FAILURE"; + break; + case MD_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION: + reason = "FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION"; + break; + case MD_FAST_FAIL_INVALID_LOCK_STATE: + reason = "FAST_FAIL_INVALID_LOCK_STATE"; + break; + case MD_FAST_FAIL_GUARD_JUMPTABLE: + reason = "FAST_FAIL_GUARD_JUMPTABLE"; + break; + case MD_FAST_FAIL_INVALID_LONGJUMP_TARGET: + reason = "FAST_FAIL_INVALID_LONGJUMP_TARGET"; + break; + case MD_FAST_FAIL_INVALID_DISPATCH_CONTEXT: + reason = "FAST_FAIL_INVALID_DISPATCH_CONTEXT"; + break; + case MD_FAST_FAIL_INVALID_THREAD: + reason = "FAST_FAIL_INVALID_THREAD"; + break; + case MD_FAST_FAIL_INVALID_SYSCALL_NUMBER: + reason = "FAST_FAIL_INVALID_SYSCALL_NUMBER"; + break; + case MD_FAST_FAIL_INVALID_FILE_OPERATION: + reason = "FAST_FAIL_INVALID_FILE_OPERATION"; + break; + case MD_FAST_FAIL_LPAC_ACCESS_DENIED: + reason = "FAST_FAIL_LPAC_ACCESS_DENIED"; + break; + case MD_FAST_FAIL_GUARD_SS_FAILURE: + reason = "FAST_FAIL_GUARD_SS_FAILURE"; + break; + case MD_FAST_FAIL_LOADER_CONTINUITY_FAILURE: + reason = "FAST_FAIL_LOADER_CONTINUITY_FAILURE"; + break; + case MD_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE: + reason = "FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE"; + break; + case MD_FAST_FAIL_INVALID_CONTROL_STACK: + reason = "FAST_FAIL_INVALID_CONTROL_STACK"; + break; + case MD_FAST_FAIL_SET_CONTEXT_DENIED: + reason = "FAST_FAIL_SET_CONTEXT_DENIED"; + break; + case MD_FAST_FAIL_INVALID_IAT: + reason = "FAST_FAIL_INVALID_IAT"; + break; + case MD_FAST_FAIL_HEAP_METADATA_CORRUPTION: + reason = "FAST_FAIL_HEAP_METADATA_CORRUPTION"; + break; + case MD_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION: + reason = "FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION"; + break; + case MD_FAST_FAIL_LOW_LABEL_ACCESS_DENIED: + reason = "FAST_FAIL_LOW_LABEL_ACCESS_DENIED"; + break; + case MD_FAST_FAIL_ENCLAVE_CALL_FAILURE: + reason = "FAST_FAIL_ENCLAVE_CALL_FAILURE"; + break; + case MD_FAST_FAIL_UNHANDLED_LSS_EXCEPTON: + reason = "FAST_FAIL_UNHANDLED_LSS_EXCEPTON"; + break; + case MD_FAST_FAIL_ADMINLESS_ACCESS_DENIED: + reason = "FAST_FAIL_ADMINLESS_ACCESS_DENIED"; + break; + case MD_FAST_FAIL_UNEXPECTED_CALL: + reason = "FAST_FAIL_UNEXPECTED_CALL"; + break; + case MD_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS: + reason = "FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS"; + break; + case MD_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR: + reason = "FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR"; + break; + case MD_FAST_FAIL_FLAGS_CORRUPTION: + reason = "FAST_FAIL_FLAGS_CORRUPTION"; + break; + case MD_FAST_FAIL_VEH_CORRUPTION: + reason = "FAST_FAIL_VEH_CORRUPTION"; + break; + case MD_FAST_FAIL_ETW_CORRUPTION: + reason = "FAST_FAIL_ETW_CORRUPTION"; + break; + case MD_FAST_FAIL_RIO_ABORT: + reason = "FAST_FAIL_RIO_ABORT"; + break; + case MD_FAST_FAIL_INVALID_PFN: + reason = "FAST_FAIL_INVALID_PFN"; + break; + case MD_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG: + reason = "FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG"; + break; + case MD_FAST_FAIL_CAST_GUARD: + reason = "FAST_FAIL_CAST_GUARD"; + break; + case MD_FAST_FAIL_HOST_VISIBILITY_CHANGE: + reason = "FAST_FAIL_HOST_VISIBILITY_CHANGE"; + break; + case MD_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST: + reason = "FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST"; + break; + case MD_FAST_FAIL_PATCH_CALLBACK_FAILED: + reason = "FAST_FAIL_PATCH_CALLBACK_FAILED"; + break; + case MD_FAST_FAIL_NTDLL_PATCH_FAILED: + reason = "FAST_FAIL_NTDLL_PATCH_FAILED"; + break; + case MD_FAST_FAIL_INVALID_FLS_DATA: + reason = "FAST_FAIL_INVALID_FLS_DATA"; + break; + default: + reason = "EXCEPTION_STACK_BUFFER_OVERRUN"; + break; + } + } else { + reason = "EXCEPTION_STACK_BUFFER_OVERRUN"; + } break; case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION: reason = "EXCEPTION_HEAP_CORRUPTION"; @@ -1734,18 +2069,27 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { *address = GetAddressForArchitecture( static_cast<MDCPUArchitecture>(raw_system_info->processor_architecture), *address); + + // For invalid accesses to non-canonical addresses, amd64 cpus don't provide + // the fault address, so recover it from the disassembly and register state + // if possible. + if (enable_objdump + && raw_system_info->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 + && std::numeric_limits<uint64_t>::max() == *address) { + CalculateFaultAddressFromInstruction(dump, address); + } } return reason; } // static -string MinidumpProcessor::GetAssertion(Minidump *dump) { - MinidumpAssertion *assertion = dump->GetAssertion(); +string MinidumpProcessor::GetAssertion(Minidump* dump) { + MinidumpAssertion* assertion = dump->GetAssertion(); if (!assertion) return ""; - const MDRawAssertionInfo *raw_assertion = assertion->assertion(); + const MDRawAssertionInfo* raw_assertion = assertion->assertion(); if (!raw_assertion) return ""; diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc index a4ac3685..1ca8c9fb 100644 --- a/src/processor/minidump_processor_unittest.cc +++ b/src/processor/minidump_processor_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -127,16 +126,16 @@ class MockMinidumpMemoryRegion : public MinidumpMemoryRegion { uint64_t GetBase() const { return region_.GetBase(); } uint32_t GetSize() const { return region_.GetSize(); } - bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { return region_.GetMemoryAtAddress(address, value); } - bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { return region_.GetMemoryAtAddress(address, value); } - bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { return region_.GetMemoryAtAddress(address, value); } - bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { return region_.GetMemoryAtAddress(address, value); } @@ -188,11 +187,11 @@ using ::testing::Property; using ::testing::Return; using ::testing::SetArgumentPointee; -static const char *kSystemInfoOS = "Windows NT"; -static const char *kSystemInfoOSShort = "windows"; -static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2"; -static const char *kSystemInfoCPU = "x86"; -static const char *kSystemInfoCPUInfo = +static const char* kSystemInfoOS = "Windows NT"; +static const char* kSystemInfoOSShort = "windows"; +static const char* kSystemInfoOSVersion = "5.1.2600 Service Pack 2"; +static const char* kSystemInfoCPU = "x86"; +static const char* kSystemInfoCPUInfo = "GenuineIntel family 6 model 13 stepping 8"; #define ASSERT_TRUE_ABORT(cond) \ @@ -204,7 +203,7 @@ static const char *kSystemInfoCPUInfo = #define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2)) static string GetTestDataPath() { - char *srcdir = getenv("srcdir"); + char* srcdir = getenv("srcdir"); return string(srcdir ? srcdir : ".") + "/src/processor/testdata/"; } @@ -213,35 +212,35 @@ class TestSymbolSupplier : public SymbolSupplier { public: TestSymbolSupplier() : interrupt_(false) {} - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file); + virtual SymbolResult GetSymbolFile(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file); - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data); + virtual SymbolResult GetSymbolFile(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + string* symbol_data); - virtual SymbolResult GetCStringSymbolData(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size); + virtual SymbolResult GetCStringSymbolData(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + char** symbol_data, + size_t* symbol_data_size); - virtual void FreeSymbolData(const CodeModule *module); + virtual void FreeSymbolData(const CodeModule* module); // When set to true, causes the SymbolSupplier to return INTERRUPT void set_interrupt(bool interrupt) { interrupt_ = interrupt; } private: bool interrupt_; - map<string, char *> memory_buffers_; + map<string, char*> memory_buffers_; }; SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( - const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file) { + const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file) { ASSERT_TRUE_ABORT(module); ASSERT_TRUE_ABORT(system_info); ASSERT_EQ_ABORT(system_info->cpu, kSystemInfoCPU); @@ -264,10 +263,10 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( } SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( - const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data) { + const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + string* symbol_data) { SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info, symbol_file); if (s == FOUND) { @@ -281,11 +280,11 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( } SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData( - const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size) { + const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + char** symbol_data, + size_t* symbol_data_size) { string symbol_data_string; SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info, @@ -307,8 +306,8 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData( return s; } -void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) { - map<string, char *>::iterator it = memory_buffers_.find(module->code_file()); +void TestSymbolSupplier::FreeSymbolData(const CodeModule* module) { + map<string, char*>::iterator it = memory_buffers_.find(module->code_file()); if (it != memory_buffers_.end()) { delete [] it->second; memory_buffers_.erase(it); @@ -523,7 +522,7 @@ TEST_F(MinidumpProcessorTest, TestBasicProcessing) { EXPECT_EQ(1171480435U, state.time_date_stamp()); EXPECT_EQ(1171480435U, state.process_create_time()); - CallStack *stack = state.threads()->at(0); + CallStack* stack = state.threads()->at(0); ASSERT_TRUE(stack); ASSERT_EQ(stack->frames()->size(), 4U); @@ -761,9 +760,67 @@ TEST_F(MinidumpProcessorTest, Test32BitCrashingAddress) { ASSERT_EQ(state.crash_address(), 0x45U); } +TEST_F(MinidumpProcessorTest, TestXStateAmd64ContextMinidump) { + // This tests if we can passively process a minidump with cet registers in its + // context. Dump is captured from a toy executable and is readable by windbg. + MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/); + + string minidump_file = GetTestDataPath() + + "tiny-exe-with-cet-xsave.dmp"; + + ProcessState state; + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_OK); + ASSERT_EQ(state.system_info()->os, "Windows NT"); + ASSERT_EQ(state.system_info()->os_version, "10.0.22000 282"); + ASSERT_EQ(state.system_info()->cpu, "amd64"); + ASSERT_EQ(state.system_info()->cpu_info, + "family 6 model 140 stepping 1"); + ASSERT_FALSE(state.crashed()); + ASSERT_EQ(state.threads()->size(), size_t(1)); + + // TODO: verify cetumsr and cetussp once these are supported by + // breakpad. +} + +TEST_F(MinidumpProcessorTest, TestFastFailException) { + // This tests if we can understand fastfail exception subcodes. + // Dump is captured from a toy executable and is readable by windbg. + MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/); + + string minidump_file = GetTestDataPath() + + "tiny-exe-fastfail.dmp"; + + ProcessState state; + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_OK); + ASSERT_TRUE(state.crashed()); + ASSERT_EQ(state.threads()->size(), size_t(4)); + ASSERT_EQ(state.crash_reason(), "FAST_FAIL_FATAL_APP_EXIT"); +} + +#ifdef __linux__ +TEST_F(MinidumpProcessorTest, TestNonCanonicalAddress) { + // This tests if we can correctly fixup non-canonical address GPF fault + // addresses. + // Dump is captured from a toy executable and is readable by windbg. + MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/); + processor.set_enable_objdump(true); + + string minidump_file = GetTestDataPath() + + "write_av_non_canonical.dmp"; + + ProcessState state; + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_OK); + ASSERT_TRUE(state.crashed()); + ASSERT_EQ(state.crash_address(), 0xfefefefefefefefeU); +} +#endif // __linux__ + } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc index acf80972..cee9a734 100644 --- a/src/processor/minidump_stackwalk.cc +++ b/src/processor/minidump_stackwalk.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -57,6 +56,7 @@ namespace { struct Options { bool machine_readable; bool output_stack_contents; + bool output_requesting_thread_only; string minidump_file; std::vector<string> symbol_paths; @@ -111,7 +111,8 @@ bool PrintMinidumpProcess(const Options& options) { if (options.machine_readable) { PrintProcessStateMachineReadable(process_state); } else { - PrintProcessState(process_state, options.output_stack_contents, &resolver); + PrintProcessState(process_state, options.output_stack_contents, + options.output_requesting_thread_only, &resolver); } return true; @@ -128,7 +129,8 @@ static void Usage(int argc, const char *argv[], bool error) { "Options:\n" "\n" " -m Output in machine-readable format\n" - " -s Output stack contents\n", + " -s Output stack contents\n" + " -c Output thread that causes crash or dump only\n", google_breakpad::BaseName(argv[0]).c_str()); } @@ -137,14 +139,18 @@ static void SetupOptions(int argc, const char *argv[], Options* options) { options->machine_readable = false; options->output_stack_contents = false; + options->output_requesting_thread_only = false; - while ((ch = getopt(argc, (char * const *)argv, "hms")) != -1) { + while ((ch = getopt(argc, (char * const*)argv, "chms")) != -1) { switch (ch) { case 'h': Usage(argc, argv, false); exit(0); break; + case 'c': + options->output_requesting_thread_only = true; + break; case 'm': options->machine_readable = true; break; diff --git a/src/processor/minidump_stackwalk_machine_readable_test b/src/processor/minidump_stackwalk_machine_readable_test index 2aadb241..84672183 100755 --- a/src/processor/minidump_stackwalk_machine_readable_test +++ b/src/processor/minidump_stackwalk_machine_readable_test @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2007, Google Inc. -# All rights reserved. +# Copyright 2007 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/processor/minidump_stackwalk_test b/src/processor/minidump_stackwalk_test index f9790279..c7da9c4a 100755 --- a/src/processor/minidump_stackwalk_test +++ b/src/processor/minidump_stackwalk_test @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2006, Google Inc. -# All rights reserved. +# Copyright 2006 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/processor/minidump_unittest.cc b/src/processor/minidump_unittest.cc index 036d03f1..53d44ae1 100644 --- a/src/processor/minidump_unittest.cc +++ b/src/processor/minidump_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -48,6 +47,7 @@ namespace { using google_breakpad::Minidump; using google_breakpad::MinidumpContext; +using google_breakpad::MinidumpCrashpadInfo; using google_breakpad::MinidumpException; using google_breakpad::MinidumpMemoryInfo; using google_breakpad::MinidumpMemoryInfoList; @@ -95,9 +95,9 @@ TEST_F(MinidumpTest, TestMinidumpFromFile) { ASSERT_NE(header, (MDRawHeader*)NULL); ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); - MinidumpModuleList *md_module_list = minidump.GetModuleList(); + MinidumpModuleList* md_module_list = minidump.GetModuleList(); ASSERT_TRUE(md_module_list != NULL); - const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); ASSERT_TRUE(md_module != NULL); ASSERT_EQ("c:\\test_app.exe", md_module->code_file()); ASSERT_EQ("c:\\test_app.pdb", md_module->debug_file()); @@ -131,6 +131,42 @@ TEST_F(MinidumpTest, TestMinidumpFromStream) { //TODO: add more checks here } +TEST_F(MinidumpTest, TestMinidumpWithCrashpadAnnotations) { + string crashpad_minidump_file = + string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata/minidump_crashpad_annotation.dmp"; + + Minidump minidump(crashpad_minidump_file); + ASSERT_EQ(minidump.path(), crashpad_minidump_file); + ASSERT_TRUE(minidump.Read()); + + MinidumpCrashpadInfo* crashpad_info = minidump.GetCrashpadInfo(); + ASSERT_TRUE(crashpad_info != NULL); + + const std::vector<std::vector<MinidumpCrashpadInfo::AnnotationObject>>* + annotation_objects_list = + crashpad_info->GetModuleCrashpadInfoAnnotationObjects(); + ASSERT_EQ(2U, annotation_objects_list->size()); + + std::vector<MinidumpCrashpadInfo::AnnotationObject> annotation_objects = + annotation_objects_list->at(0); + ASSERT_EQ(5U, annotation_objects.size()); + + std::vector<std::string> annotation_names; + for (size_t i = 0; i < annotation_objects.size(); i++) { + MinidumpCrashpadInfo::AnnotationObject annotation_object = + annotation_objects.at(i); + annotation_names.push_back(annotation_object.name); + ASSERT_TRUE(annotation_object.type > 0); + ASSERT_TRUE(annotation_object.value.size() > 0); + } + + std::vector<std::string> expected_strings{ + "exceptionReason", "exceptionName", "firstexception_bt", "firstexception", + "CounterAnnotation"}; + ASSERT_EQ(annotation_names, expected_strings); +} + TEST(Dump, ReadBackEmpty) { Dump dump(0); dump.Finish(); @@ -167,7 +203,7 @@ TEST(Dump, OneStream) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); + const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); ASSERT_TRUE(dir != NULL); EXPECT_EQ(0xfbb7fa2bU, dir->stream_type); @@ -203,18 +239,18 @@ TEST(Dump, OneMemory) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); + const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); ASSERT_TRUE(dir != NULL); EXPECT_EQ((uint32_t) MD_MEMORY_LIST_STREAM, dir->stream_type); - MinidumpMemoryList *memory_list = minidump.GetMemoryList(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); ASSERT_TRUE(memory_list != NULL); ASSERT_EQ(1U, memory_list->region_count()); - MinidumpMemoryRegion *region1 = memory_list->GetMemoryRegionAtIndex(0); + MinidumpMemoryRegion* region1 = memory_list->GetMemoryRegionAtIndex(0); ASSERT_EQ(0x309d68010bd21b2cULL, region1->GetBase()); ASSERT_EQ(15U, region1->GetSize()); - const uint8_t *region1_bytes = region1->GetMemory(); + const uint8_t* region1_bytes = region1->GetMemory(); ASSERT_TRUE(memcmp("memory contents", region1_bytes, 15) == 0); } @@ -257,33 +293,33 @@ TEST(Dump, OneThread) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); - MinidumpMemoryList *md_memory_list = minidump.GetMemoryList(); + MinidumpMemoryList* md_memory_list = minidump.GetMemoryList(); ASSERT_TRUE(md_memory_list != NULL); ASSERT_EQ(1U, md_memory_list->region_count()); - MinidumpMemoryRegion *md_region = md_memory_list->GetMemoryRegionAtIndex(0); + MinidumpMemoryRegion* md_region = md_memory_list->GetMemoryRegionAtIndex(0); ASSERT_EQ(0x2326a0faU, md_region->GetBase()); ASSERT_EQ(16U, md_region->GetSize()); - const uint8_t *region_bytes = md_region->GetMemory(); + const uint8_t* region_bytes = md_region->GetMemory(); ASSERT_TRUE(memcmp("stack for thread", region_bytes, 16) == 0); - MinidumpThreadList *thread_list = minidump.GetThreadList(); + MinidumpThreadList* thread_list = minidump.GetThreadList(); ASSERT_TRUE(thread_list != NULL); ASSERT_EQ(1U, thread_list->thread_count()); - MinidumpThread *md_thread = thread_list->GetThreadAtIndex(0); + MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); ASSERT_TRUE(md_thread != NULL); uint32_t thread_id; ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); ASSERT_EQ(0xa898f11bU, thread_id); - MinidumpMemoryRegion *md_stack = md_thread->GetMemory(); + MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); ASSERT_TRUE(md_stack != NULL); ASSERT_EQ(0x2326a0faU, md_stack->GetBase()); ASSERT_EQ(16U, md_stack->GetSize()); - const uint8_t *md_stack_bytes = md_stack->GetMemory(); + const uint8_t* md_stack_bytes = md_stack->GetMemory(); ASSERT_TRUE(memcmp("stack for thread", md_stack_bytes, 16) == 0); - MinidumpContext *md_context = md_thread->GetContext(); + MinidumpContext* md_context = md_thread->GetContext(); ASSERT_TRUE(md_context != NULL); ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); @@ -291,7 +327,7 @@ TEST(Dump, OneThread) { ASSERT_TRUE(md_context->GetInstructionPointer(&eip)); EXPECT_EQ(kExpectedEIP, eip); - const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); + const MDRawContextX86* md_raw_context = md_context->GetContextX86(); ASSERT_TRUE(md_raw_context != NULL); ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), (md_raw_context->context_flags @@ -425,16 +461,16 @@ TEST(Dump, OneUnloadedModule) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); - const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(1); + const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(1); ASSERT_TRUE(dir != NULL); EXPECT_EQ((uint32_t) MD_UNLOADED_MODULE_LIST_STREAM, dir->stream_type); - MinidumpUnloadedModuleList *md_unloaded_module_list = + MinidumpUnloadedModuleList* md_unloaded_module_list = minidump.GetUnloadedModuleList(); ASSERT_TRUE(md_unloaded_module_list != NULL); ASSERT_EQ(1U, md_unloaded_module_list->module_count()); - const MinidumpUnloadedModule *md_unloaded_module = + const MinidumpUnloadedModule* md_unloaded_module = md_unloaded_module_list->GetModuleAtIndex(0); ASSERT_TRUE(md_unloaded_module != NULL); ASSERT_EQ(0xa90206ca83eb2852ULL, md_unloaded_module->base_address()); @@ -445,7 +481,7 @@ TEST(Dump, OneUnloadedModule) { ASSERT_EQ("B1054D2Aada542bd", md_unloaded_module->code_identifier()); ASSERT_EQ("", md_unloaded_module->debug_identifier()); - const MDRawUnloadedModule *md_raw_unloaded_module = + const MDRawUnloadedModule* md_raw_unloaded_module = md_unloaded_module->module(); ASSERT_TRUE(md_raw_unloaded_module != NULL); ASSERT_EQ(0xb1054d2aU, md_raw_unloaded_module->time_date_stamp); @@ -506,15 +542,15 @@ TEST(Dump, OneModule) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); - const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(1); + const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(1); ASSERT_TRUE(dir != NULL); EXPECT_EQ((uint32_t) MD_MODULE_LIST_STREAM, dir->stream_type); - MinidumpModuleList *md_module_list = minidump.GetModuleList(); + MinidumpModuleList* md_module_list = minidump.GetModuleList(); ASSERT_TRUE(md_module_list != NULL); ASSERT_EQ(1U, md_module_list->module_count()); - const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); ASSERT_TRUE(md_module != NULL); ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); ASSERT_EQ(0xada542bd, md_module->size()); @@ -524,7 +560,7 @@ TEST(Dump, OneModule) { ASSERT_EQ("B1054D2Aada542bd", md_module->code_identifier()); ASSERT_EQ("ABCD1234F00DBEEF01020304050607081", md_module->debug_identifier()); - const MDRawModule *md_raw_module = md_module->module(); + const MDRawModule* md_raw_module = md_module->module(); ASSERT_TRUE(md_raw_module != NULL); ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); ASSERT_EQ(0x34571371U, md_raw_module->checksum); @@ -588,11 +624,11 @@ TEST(Dump, OneModuleCVELF) { Minidump minidump(minidump_stream); ASSERT_TRUE(minidump.Read()); - MinidumpModuleList *md_module_list = minidump.GetModuleList(); + MinidumpModuleList* md_module_list = minidump.GetModuleList(); ASSERT_TRUE(md_module_list != NULL); ASSERT_EQ(1U, md_module_list->module_count()); - const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); ASSERT_TRUE(md_module != NULL); ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); ASSERT_EQ(0xada542bd, md_module->size()); @@ -606,7 +642,7 @@ TEST(Dump, OneModuleCVELF) { // age appended ASSERT_EQ("B4CDA95F53101BDF86FAB733B4DF37380", md_module->debug_identifier()); - const MDRawModule *md_raw_module = md_module->module(); + const MDRawModule* md_raw_module = md_module->module(); ASSERT_TRUE(md_raw_module != NULL); ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); ASSERT_EQ(0x34571371U, md_raw_module->checksum); @@ -670,11 +706,11 @@ TEST(Dump, CVELFShort) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); - MinidumpModuleList *md_module_list = minidump.GetModuleList(); + MinidumpModuleList* md_module_list = minidump.GetModuleList(); ASSERT_TRUE(md_module_list != NULL); ASSERT_EQ(1U, md_module_list->module_count()); - const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); ASSERT_TRUE(md_module != NULL); // just the build_id, directly ASSERT_EQ("5fa9cdb4", md_module->code_identifier()); @@ -742,11 +778,11 @@ TEST(Dump, CVELFLong) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); - MinidumpModuleList *md_module_list = minidump.GetModuleList(); + MinidumpModuleList* md_module_list = minidump.GetModuleList(); ASSERT_TRUE(md_module_list != NULL); ASSERT_EQ(1U, md_module_list->module_count()); - const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0); ASSERT_TRUE(md_module != NULL); // just the build_id, directly ASSERT_EQ( @@ -773,11 +809,11 @@ TEST(Dump, OneSystemInfo) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); + const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); ASSERT_TRUE(dir != NULL); EXPECT_EQ((uint32_t) MD_SYSTEM_INFO_STREAM, dir->stream_type); - MinidumpSystemInfo *md_system_info = minidump.GetSystemInfo(); + MinidumpSystemInfo* md_system_info = minidump.GetSystemInfo(); ASSERT_TRUE(md_system_info != NULL); ASSERT_EQ("windows", md_system_info->GetOS()); ASSERT_EQ("x86", md_system_info->GetCPU()); @@ -912,7 +948,7 @@ TEST(Dump, BigDump) { ASSERT_EQ(5U, minidump.GetDirectoryEntryCount()); // Check the threads. - MinidumpThreadList *thread_list = minidump.GetThreadList(); + MinidumpThreadList* thread_list = minidump.GetThreadList(); ASSERT_TRUE(thread_list != NULL); ASSERT_EQ(5U, thread_list->thread_count()); uint32_t thread_id; @@ -957,7 +993,7 @@ TEST(Dump, BigDump) { ->eip); // Check the modules. - MinidumpModuleList *md_module_list = minidump.GetModuleList(); + MinidumpModuleList* md_module_list = minidump.GetModuleList(); ASSERT_TRUE(md_module_list != NULL); ASSERT_EQ(3U, md_module_list->module_count()); EXPECT_EQ(0xeb77da57b5d4cbdaULL, @@ -968,7 +1004,7 @@ TEST(Dump, BigDump) { md_module_list->GetModuleAtIndex(2)->base_address()); // Check unloaded modules - MinidumpUnloadedModuleList *md_unloaded_module_list = + MinidumpUnloadedModuleList* md_unloaded_module_list = minidump.GetUnloadedModuleList(); ASSERT_TRUE(md_unloaded_module_list != NULL); ASSERT_EQ(3U, md_unloaded_module_list->module_count()); @@ -979,7 +1015,7 @@ TEST(Dump, BigDump) { EXPECT_EQ(umodule3_base, md_unloaded_module_list->GetModuleAtIndex(2)->base_address()); - const MinidumpUnloadedModule *umodule = + const MinidumpUnloadedModule* umodule = md_unloaded_module_list->GetModuleForAddress( umodule1_base + umodule1_size / 2); EXPECT_EQ(umodule1_base, umodule->base_address()); @@ -1025,22 +1061,22 @@ TEST(Dump, OneMemoryInfo) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); + const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0); ASSERT_TRUE(dir != NULL); EXPECT_EQ((uint32_t) MD_MEMORY_INFO_LIST_STREAM, dir->stream_type); - MinidumpMemoryInfoList *info_list = minidump.GetMemoryInfoList(); + MinidumpMemoryInfoList* info_list = minidump.GetMemoryInfoList(); ASSERT_TRUE(info_list != NULL); ASSERT_EQ(1U, info_list->info_count()); - const MinidumpMemoryInfo *info1 = info_list->GetMemoryInfoAtIndex(0); + const MinidumpMemoryInfo* info1 = info_list->GetMemoryInfoAtIndex(0); ASSERT_EQ(kBaseAddress, info1->GetBase()); ASSERT_EQ(kRegionSize, info1->GetSize()); ASSERT_TRUE(info1->IsExecutable()); ASSERT_TRUE(info1->IsWritable()); // Should get back the same memory region here. - const MinidumpMemoryInfo *info2 = + const MinidumpMemoryInfo* info2 = info_list->GetMemoryInfoForAddress(kBaseAddress + kRegionSize / 2); ASSERT_EQ(kBaseAddress, info2->GetBase()); ASSERT_EQ(kRegionSize, info2->GetSize()); @@ -1083,7 +1119,7 @@ TEST(Dump, OneExceptionX86) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - MinidumpException *md_exception = minidump.GetException(); + MinidumpException* md_exception = minidump.GetException(); ASSERT_TRUE(md_exception != NULL); uint32_t thread_id; @@ -1097,10 +1133,10 @@ TEST(Dump, OneExceptionX86) { EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); - MinidumpContext *md_context = md_exception->GetContext(); + MinidumpContext* md_context = md_exception->GetContext(); ASSERT_TRUE(md_context != NULL); ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); - const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); + const MDRawContextX86* md_raw_context = md_context->GetContextX86(); ASSERT_TRUE(md_raw_context != NULL); ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), (md_raw_context->context_flags @@ -1157,7 +1193,7 @@ TEST(Dump, OneExceptionX86XState) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - MinidumpException *md_exception = minidump.GetException(); + MinidumpException* md_exception = minidump.GetException(); ASSERT_TRUE(md_exception != NULL); uint32_t thread_id; @@ -1171,10 +1207,10 @@ TEST(Dump, OneExceptionX86XState) { EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); - MinidumpContext *md_context = md_exception->GetContext(); + MinidumpContext* md_context = md_exception->GetContext(); ASSERT_TRUE(md_context != NULL); ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); - const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); + const MDRawContextX86* md_raw_context = md_context->GetContextX86(); ASSERT_TRUE(md_raw_context != NULL); ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), (md_raw_context->context_flags @@ -1242,7 +1278,7 @@ TEST(Dump, OneExceptionX86NoCPUFlags) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); - MinidumpException *md_exception = minidump.GetException(); + MinidumpException* md_exception = minidump.GetException(); ASSERT_TRUE(md_exception != NULL); uint32_t thread_id; @@ -1256,11 +1292,11 @@ TEST(Dump, OneExceptionX86NoCPUFlags) { EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); - MinidumpContext *md_context = md_exception->GetContext(); + MinidumpContext* md_context = md_exception->GetContext(); ASSERT_TRUE(md_context != NULL); ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); - const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); + const MDRawContextX86* md_raw_context = md_context->GetContextX86(); ASSERT_TRUE(md_raw_context != NULL); // Even though the CPU flags were missing from the context_flags, the @@ -1324,7 +1360,7 @@ TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - MinidumpException *md_exception = minidump.GetException(); + MinidumpException* md_exception = minidump.GetException(); ASSERT_TRUE(md_exception != NULL); uint32_t thread_id; @@ -1341,7 +1377,7 @@ TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) { // The context record of the exception is unusable because the context_flags // don't have CPU type information and at the same time the minidump lacks // system info stream so it is impossible to deduce the CPU type. - MinidumpContext *md_context = md_exception->GetContext(); + MinidumpContext* md_context = md_exception->GetContext(); ASSERT_EQ(NULL, md_context); } @@ -1387,7 +1423,7 @@ TEST(Dump, OneExceptionARM) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - MinidumpException *md_exception = minidump.GetException(); + MinidumpException* md_exception = minidump.GetException(); ASSERT_TRUE(md_exception != NULL); uint32_t thread_id; @@ -1401,10 +1437,10 @@ TEST(Dump, OneExceptionARM) { EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); - MinidumpContext *md_context = md_exception->GetContext(); + MinidumpContext* md_context = md_exception->GetContext(); ASSERT_TRUE(md_context != NULL); ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); - const MDRawContextARM *md_raw_context = md_context->GetContextARM(); + const MDRawContextARM* md_raw_context = md_context->GetContextARM(); ASSERT_TRUE(md_raw_context != NULL); ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, (md_raw_context->context_flags @@ -1471,7 +1507,7 @@ TEST(Dump, OneExceptionARMOldFlags) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - MinidumpException *md_exception = minidump.GetException(); + MinidumpException* md_exception = minidump.GetException(); ASSERT_TRUE(md_exception != NULL); uint32_t thread_id; @@ -1485,10 +1521,10 @@ TEST(Dump, OneExceptionARMOldFlags) { EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, raw_exception->exception_record.exception_address); - MinidumpContext *md_context = md_exception->GetContext(); + MinidumpContext* md_context = md_exception->GetContext(); ASSERT_TRUE(md_context != NULL); ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); - const MDRawContextARM *md_raw_context = md_context->GetContextARM(); + const MDRawContextARM* md_raw_context = md_context->GetContextARM(); ASSERT_TRUE(md_raw_context != NULL); ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, (md_raw_context->context_flags @@ -1570,7 +1606,7 @@ TEST(Dump, OneExceptionMIPS) { ASSERT_TRUE(minidump.Read()); ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); - MinidumpException *md_exception = minidump.GetException(); + MinidumpException* md_exception = minidump.GetException(); ASSERT_TRUE(md_exception != NULL); uint32_t thread_id; diff --git a/src/processor/module_comparer.cc b/src/processor/module_comparer.cc index 025ab883..389712c5 100644 --- a/src/processor/module_comparer.cc +++ b/src/processor/module_comparer.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,7 +51,7 @@ namespace google_breakpad { -bool ModuleComparer::Compare(const string &symbol_data) { +bool ModuleComparer::Compare(const string& symbol_data) { scoped_ptr<BasicModule> basic_module(new BasicModule("test_module")); scoped_ptr<FastModule> fast_module(new FastModule("test_module")); @@ -284,7 +283,7 @@ bool ModuleComparer::CompareCRM( while (iter1 != basic_crm->map_->end() && iter2 != fast_crm->map_.end()) { ASSERT_TRUE(iter1->first == iter2.GetKey()); - StaticContainedRangeMap<MemAddr, char> *child = + StaticContainedRangeMap<MemAddr, char>* child = new StaticContainedRangeMap<MemAddr, char>( reinterpret_cast<const char*>(iter2.GetValuePtr())); ASSERT_TRUE(CompareCRM(iter1->second, child)); diff --git a/src/processor/module_comparer.h b/src/processor/module_comparer.h index fcbd5177..6bd3e7b8 100644 --- a/src/processor/module_comparer.h +++ b/src/processor/module_comparer.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -64,7 +63,7 @@ class ModuleComparer { // FastSourceLineResolver loads its module using the serialized memory chunk, // Then, traverse both modules together and compare underlying data // return true if both modules contain exactly same data. - bool Compare(const string &symbol_data); + bool Compare(const string& symbol_data); private: typedef BasicSourceLineResolver::Module BasicModule; diff --git a/src/processor/module_factory.h b/src/processor/module_factory.h index 7aa7caa5..3df85a60 100644 --- a/src/processor/module_factory.h +++ b/src/processor/module_factory.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -46,14 +45,14 @@ class ModuleFactory { public: virtual ~ModuleFactory() { }; virtual SourceLineResolverBase::Module* CreateModule( - const string &name) const = 0; + const string& name) const = 0; }; class BasicModuleFactory : public ModuleFactory { public: virtual ~BasicModuleFactory() { } virtual BasicSourceLineResolver::Module* CreateModule( - const string &name) const { + const string& name) const { return new BasicSourceLineResolver::Module(name); } }; @@ -62,7 +61,7 @@ class FastModuleFactory : public ModuleFactory { public: virtual ~FastModuleFactory() { } virtual FastSourceLineResolver::Module* CreateModule( - const string &name) const { + const string& name) const { return new FastSourceLineResolver::Module(name); } }; diff --git a/src/processor/module_serializer.cc b/src/processor/module_serializer.cc index 6ac60c1f..d0445094 100644 --- a/src/processor/module_serializer.cc +++ b/src/processor/module_serializer.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -43,12 +42,17 @@ namespace google_breakpad { -// Definition of static member variable in SimplerSerializer<Funcion>, which -// is declared in file "simple_serializer-inl.h" -RangeMapSerializer< MemAddr, linked_ptr<BasicSourceLineResolver::Line> > -SimpleSerializer<BasicSourceLineResolver::Function>::range_map_serializer_; - -size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) { +// Definition of static member variables in SimplerSerializer<Funcion> and +// SimplerSerializer<Inline>, which are declared in file +// "simple_serializer-inl.h" +RangeMapSerializer<MemAddr, linked_ptr<BasicSourceLineResolver::Line>> + SimpleSerializer<BasicSourceLineResolver::Function>::range_map_serializer_; +ContainedRangeMapSerializer<MemAddr, + linked_ptr<BasicSourceLineResolver::Inline>> + SimpleSerializer< + BasicSourceLineResolver::Function>::inline_range_map_serializer_; + +size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module& module) { size_t total_size_alloc_ = 0; // Size of the "is_corrupt" flag. @@ -66,6 +70,8 @@ size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) { module.cfi_initial_rules_); map_sizes_[map_index++] = cfi_delta_rules_serializer_.SizeOf( module.cfi_delta_rules_); + map_sizes_[map_index++] = + inline_origin_serializer_.SizeOf(module.inline_origins_); // Header size. total_size_alloc_ += kNumberMaps_ * sizeof(uint32_t); @@ -80,8 +86,8 @@ size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) { return total_size_alloc_; } -char *ModuleSerializer::Write(const BasicSourceLineResolver::Module &module, - char *dest) { +char* ModuleSerializer::Write(const BasicSourceLineResolver::Module& module, + char* dest) { // Write the is_corrupt flag. dest = SimpleSerializer<bool>::Write(module.is_corrupt_, dest); // Write header. @@ -95,18 +101,19 @@ char *ModuleSerializer::Write(const BasicSourceLineResolver::Module &module, dest = wfi_serializer_.Write(&(module.windows_frame_info_[i]), dest); dest = cfi_init_rules_serializer_.Write(module.cfi_initial_rules_, dest); dest = cfi_delta_rules_serializer_.Write(module.cfi_delta_rules_, dest); + dest = inline_origin_serializer_.Write(module.inline_origins_, dest); // Write a null terminator. dest = SimpleSerializer<char>::Write(0, dest); return dest; } char* ModuleSerializer::Serialize( - const BasicSourceLineResolver::Module &module, unsigned int *size) { + const BasicSourceLineResolver::Module& module, unsigned int* size) { // Compute size of memory to allocate. unsigned int size_to_alloc = SizeOf(module); // Allocate memory for serialized data. - char *serialized_data = new char[size_to_alloc]; + char* serialized_data = new char[size_to_alloc]; if (!serialized_data) { BPLOG(ERROR) << "ModuleSerializer: memory allocation failed, " << "size to alloc: " << size_to_alloc; @@ -115,7 +122,7 @@ char* ModuleSerializer::Serialize( } // Write serialized data to allocated memory chunk. - char *end_address = Write(module, serialized_data); + char* end_address = Write(module, serialized_data); // Verify the allocated memory size is equal to the size of data been written. unsigned int size_written = static_cast<unsigned int>(end_address - serialized_data); @@ -131,8 +138,8 @@ char* ModuleSerializer::Serialize( } bool ModuleSerializer::SerializeModuleAndLoadIntoFastResolver( - const BasicSourceLineResolver::ModuleMap::const_iterator &iter, - FastSourceLineResolver *fast_resolver) { + const BasicSourceLineResolver::ModuleMap::const_iterator& iter, + FastSourceLineResolver* fast_resolver) { BPLOG(INFO) << "Converting symbol " << iter->first.c_str(); // Cast SourceLineResolverBase::Module* to BasicSourceLineResolver::Module*. @@ -161,8 +168,8 @@ bool ModuleSerializer::SerializeModuleAndLoadIntoFastResolver( } void ModuleSerializer::ConvertAllModules( - const BasicSourceLineResolver *basic_resolver, - FastSourceLineResolver *fast_resolver) { + const BasicSourceLineResolver* basic_resolver, + FastSourceLineResolver* fast_resolver) { // Check for NULL pointer. if (!basic_resolver || !fast_resolver) return; @@ -175,9 +182,9 @@ void ModuleSerializer::ConvertAllModules( } bool ModuleSerializer::ConvertOneModule( - const string &moduleid, - const BasicSourceLineResolver *basic_resolver, - FastSourceLineResolver *fast_resolver) { + const string& moduleid, + const BasicSourceLineResolver* basic_resolver, + FastSourceLineResolver* fast_resolver) { // Check for NULL pointer. if (!basic_resolver || !fast_resolver) return false; @@ -191,7 +198,7 @@ bool ModuleSerializer::ConvertOneModule( } char* ModuleSerializer::SerializeSymbolFileData( - const string &symbol_data, unsigned int *size) { + const string& symbol_data, unsigned int* size) { scoped_ptr<BasicSourceLineResolver::Module> module( new BasicSourceLineResolver::Module("no name")); scoped_array<char> buffer(new char[symbol_data.size() + 1]); diff --git a/src/processor/module_serializer.h b/src/processor/module_serializer.h index effb0091..4e365a41 100644 --- a/src/processor/module_serializer.h +++ b/src/processor/module_serializer.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -61,49 +60,50 @@ class ModuleSerializer { public: // Compute the size of memory required to serialize a module. Return the // total size needed for serialization. - size_t SizeOf(const BasicSourceLineResolver::Module &module); + size_t SizeOf(const BasicSourceLineResolver::Module& module); // Write a module into an allocated memory chunk with required size. // Return the "end" of data, i.e., the address after the final byte of data. - char* Write(const BasicSourceLineResolver::Module &module, char *dest); + char* Write(const BasicSourceLineResolver::Module& module, char* dest); // Serializes a loaded Module object into a chunk of memory data and returns // the address of memory chunk. If size != NULL, *size is set to the memory // size allocated for the serialized data. // Caller takes the ownership of the memory chunk (allocated on heap), and // owner should call delete [] to free the memory after use. - char* Serialize(const BasicSourceLineResolver::Module &module, - unsigned int *size = NULL); + char* Serialize(const BasicSourceLineResolver::Module& module, + unsigned int* size = NULL); // Given the string format symbol_data, produces a chunk of serialized data. // Caller takes ownership of the serialized data (on heap), and owner should // call delete [] to free the memory after use. - char* SerializeSymbolFileData(const string &symbol_data, - unsigned int *size = NULL); + char* SerializeSymbolFileData(const string& symbol_data, + unsigned int* size = NULL); // Serializes one loaded module with given moduleid in the basic source line // resolver, and loads the serialized data into the fast source line resolver. // Return false if the basic source line doesn't have a module with the given // moduleid. - bool ConvertOneModule(const string &moduleid, - const BasicSourceLineResolver *basic_resolver, - FastSourceLineResolver *fast_resolver); + bool ConvertOneModule(const string& moduleid, + const BasicSourceLineResolver* basic_resolver, + FastSourceLineResolver* fast_resolver); // Serializes all the loaded modules in a basic source line resolver, and // loads the serialized data into a fast source line resolver. - void ConvertAllModules(const BasicSourceLineResolver *basic_resolver, - FastSourceLineResolver *fast_resolver); + void ConvertAllModules(const BasicSourceLineResolver* basic_resolver, + FastSourceLineResolver* fast_resolver); private: // Convenient type names. typedef BasicSourceLineResolver::Line Line; typedef BasicSourceLineResolver::Function Function; typedef BasicSourceLineResolver::PublicSymbol PublicSymbol; + typedef BasicSourceLineResolver::InlineOrigin InlineOrigin; // Internal implementation for ConvertOneModule and ConvertAllModules methods. bool SerializeModuleAndLoadIntoFastResolver( - const BasicSourceLineResolver::ModuleMap::const_iterator &iter, - FastSourceLineResolver *fast_resolver); + const BasicSourceLineResolver::ModuleMap::const_iterator& iter, + FastSourceLineResolver* fast_resolver); // Number of Maps that Module class contains. static const int32_t kNumberMaps_ = @@ -120,6 +120,7 @@ class ModuleSerializer { linked_ptr<WindowsFrameInfo> > wfi_serializer_; RangeMapSerializer<MemAddr, string> cfi_init_rules_serializer_; StdMapSerializer<MemAddr, string> cfi_delta_rules_serializer_; + StdMapSerializer<int, linked_ptr<InlineOrigin>> inline_origin_serializer_; }; } // namespace google_breakpad diff --git a/src/processor/pathname_stripper.cc b/src/processor/pathname_stripper.cc index 839287bd..f34b53f7 100644 --- a/src/processor/pathname_stripper.cc +++ b/src/processor/pathname_stripper.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,7 +37,7 @@ namespace google_breakpad { // static -string PathnameStripper::File(const string &path) { +string PathnameStripper::File(const string& path) { string::size_type slash = path.rfind('/'); string::size_type backslash = path.rfind('\\'); diff --git a/src/processor/pathname_stripper.h b/src/processor/pathname_stripper.h index 423ca0d0..62c9bddd 100644 --- a/src/processor/pathname_stripper.h +++ b/src/processor/pathname_stripper.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -45,7 +44,7 @@ class PathnameStripper { // Given path, a pathname with components separated by slashes (/) or // backslashes (\), returns the trailing component, without any separator. // If path ends in a separator character, returns an empty string. - static string File(const string &path); + static string File(const string& path); }; } // namespace google_breakpad diff --git a/src/processor/pathname_stripper_unittest.cc b/src/processor/pathname_stripper_unittest.cc index 1bff4cb0..ff474a7b 100644 --- a/src/processor/pathname_stripper_unittest.cc +++ b/src/processor/pathname_stripper_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -80,7 +79,7 @@ static bool RunTests() { } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { BPLOG_INIT(&argc, &argv); return RunTests() ? 0 : 1; diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h index d7dbeac2..abdf259e 100644 --- a/src/processor/postfix_evaluator-inl.h +++ b/src/processor/postfix_evaluator-inl.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -58,19 +57,19 @@ using std::ostringstream; // before returning failure. class AutoStackClearer { public: - explicit AutoStackClearer(vector<string> *stack) : stack_(stack) {} + explicit AutoStackClearer(vector<string>* stack) : stack_(stack) {} ~AutoStackClearer() { stack_->clear(); } private: - vector<string> *stack_; + vector<string>* stack_; }; template<typename ValueType> bool PostfixEvaluator<ValueType>::EvaluateToken( - const string &token, - const string &expression, - DictionaryValidityType *assigned) { + const string& token, + const string& expression, + DictionaryValidityType* assigned) { // There are enough binary operations that do exactly the same thing // (other than the specific operation, of course) that it makes sense // to share as much code as possible. @@ -203,8 +202,8 @@ bool PostfixEvaluator<ValueType>::EvaluateToken( template<typename ValueType> bool PostfixEvaluator<ValueType>::EvaluateInternal( - const string &expression, - DictionaryValidityType *assigned) { + const string& expression, + DictionaryValidityType* assigned) { // Tokenize, splitting on whitespace. istringstream stream(expression); string token; @@ -231,8 +230,8 @@ bool PostfixEvaluator<ValueType>::EvaluateInternal( } template<typename ValueType> -bool PostfixEvaluator<ValueType>::Evaluate(const string &expression, - DictionaryValidityType *assigned) { +bool PostfixEvaluator<ValueType>::Evaluate(const string& expression, + DictionaryValidityType* assigned) { // Ensure that the stack is cleared before returning. AutoStackClearer clearer(&stack_); @@ -250,8 +249,8 @@ bool PostfixEvaluator<ValueType>::Evaluate(const string &expression, } template<typename ValueType> -bool PostfixEvaluator<ValueType>::EvaluateForValue(const string &expression, - ValueType *result) { +bool PostfixEvaluator<ValueType>::EvaluateForValue(const string& expression, + ValueType* result) { // Ensure that the stack is cleared before returning. AutoStackClearer clearer(&stack_); @@ -271,7 +270,7 @@ bool PostfixEvaluator<ValueType>::EvaluateForValue(const string &expression, template<typename ValueType> typename PostfixEvaluator<ValueType>::PopResult PostfixEvaluator<ValueType>::PopValueOrIdentifier( - ValueType *value, string *identifier) { + ValueType* value, string* identifier) { // There needs to be at least one element on the stack to pop. if (!stack_.size()) return POP_RESULT_FAIL; @@ -314,7 +313,7 @@ PostfixEvaluator<ValueType>::PopValueOrIdentifier( template<typename ValueType> -bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) { +bool PostfixEvaluator<ValueType>::PopValue(ValueType* value) { ValueType literal = ValueType(); string token; PopResult result; @@ -343,14 +342,14 @@ bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) { template<typename ValueType> -bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1, - ValueType *value2) { +bool PostfixEvaluator<ValueType>::PopValues(ValueType* value1, + ValueType* value2) { return PopValue(value2) && PopValue(value1); } template<typename ValueType> -void PostfixEvaluator<ValueType>::PushValue(const ValueType &value) { +void PostfixEvaluator<ValueType>::PushValue(const ValueType& value) { ostringstream token_stream; token_stream << value; stack_.push_back(token_stream.str()); diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h index 94b66190..b6f718ab 100644 --- a/src/processor/postfix_evaluator.h +++ b/src/processor/postfix_evaluator.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -95,7 +94,7 @@ class PostfixEvaluator { // (^) will not be supported. |dictionary| may be NULL, but evaluation // will fail in that case unless set_dictionary is used before calling // Evaluate. - PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory) + PostfixEvaluator(DictionaryType* dictionary, const MemoryRegion* memory) : dictionary_(dictionary), memory_(memory), stack_() {} // Evaluate the expression, starting with an empty stack. The results of @@ -105,18 +104,18 @@ class PostfixEvaluator { // non-NULL, any keys set in the dictionary as a result of evaluation // will also be set to true in assigned, providing a way to determine if // an expression modifies any of its input variables. - bool Evaluate(const string &expression, DictionaryValidityType *assigned); + bool Evaluate(const string& expression, DictionaryValidityType* assigned); // Like Evaluate, but provides the value left on the stack to the // caller. If evaluation succeeds and leaves exactly one value on // the stack, pop that value, store it in *result, and return true. // Otherwise, return false. - bool EvaluateForValue(const string &expression, ValueType *result); + bool EvaluateForValue(const string& expression, ValueType* result); DictionaryType* dictionary() const { return dictionary_; } // Reset the dictionary. PostfixEvaluator does not take ownership. - void set_dictionary(DictionaryType *dictionary) {dictionary_ = dictionary; } + void set_dictionary(DictionaryType* dictionary) {dictionary_ = dictionary; } private: // Return values for PopValueOrIdentifier @@ -132,40 +131,40 @@ class PostfixEvaluator { // if the topmost entry is a constant or variable identifier, and sets // |identifier| accordingly. Returns POP_RESULT_FAIL on failure, such // as when the stack is empty. - PopResult PopValueOrIdentifier(ValueType *value, string *identifier); + PopResult PopValueOrIdentifier(ValueType* value, string* identifier); // Retrieves the topmost value on the stack. If the topmost entry is // an identifier, the dictionary is queried for the identifier's value. // Returns false on failure, such as when the stack is empty or when // a nonexistent identifier is named. - bool PopValue(ValueType *value); + bool PopValue(ValueType* value); // Retrieves the top two values on the stack, in the style of PopValue. // value2 is popped before value1, so that value1 corresponds to the // entry that was pushed prior to value2. Returns false on failure. - bool PopValues(ValueType *value1, ValueType *value2); + bool PopValues(ValueType* value1, ValueType* value2); // Pushes a new value onto the stack. - void PushValue(const ValueType &value); + void PushValue(const ValueType& value); // Evaluate expression, updating *assigned if it is non-zero. Return // true if evaluation completes successfully. Do not clear the stack // upon successful evaluation. - bool EvaluateInternal(const string &expression, - DictionaryValidityType *assigned); + bool EvaluateInternal(const string& expression, + DictionaryValidityType* assigned); - bool EvaluateToken(const string &token, - const string &expression, - DictionaryValidityType *assigned); + bool EvaluateToken(const string& token, + const string& expression, + DictionaryValidityType* assigned); // The dictionary mapping constant and variable identifiers (strings) to // values. Keys beginning with '$' are treated as variable names, and // PostfixEvaluator is free to create and modify these keys. Weak pointer. - DictionaryType *dictionary_; + DictionaryType* dictionary_; // If non-NULL, the MemoryRegion used for dereference (^) operations. // If NULL, dereferencing is unsupported and will fail. Weak pointer. - const MemoryRegion *memory_; + const MemoryRegion* memory_; // The stack contains state information as execution progresses. Values // are pushed on to it as the expression string is read and as operations diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc index f1189828..76d85751 100644 --- a/src/processor/postfix_evaluator_unittest.cc +++ b/src/processor/postfix_evaluator_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -60,19 +59,19 @@ class FakeMemoryRegion : public MemoryRegion { public: virtual uint64_t GetBase() const { return 0; } virtual uint32_t GetSize() const { return 0; } - virtual bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + virtual bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { *value = address + 1; return true; } - virtual bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { *value = address + 1; return true; } - virtual bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { *value = address + 1; return true; } - virtual bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { *value = address + 1; return true; } @@ -94,17 +93,17 @@ struct EvaluateTest { struct EvaluateTestSet { // The dictionary used for all tests in the set. - PostfixEvaluator<unsigned int>::DictionaryType *dictionary; + PostfixEvaluator<unsigned int>::DictionaryType* dictionary; // The list of tests. - const EvaluateTest *evaluate_tests; + const EvaluateTest* evaluate_tests; // The number of tests. unsigned int evaluate_test_count; // Identifiers and their expected values upon completion of the Evaluate // tests in the set. - map<string, unsigned int> *validate_data; + map<string, unsigned int>* validate_data; }; @@ -227,9 +226,9 @@ static bool RunTests() { for (unsigned int evaluate_test_set_index = 0; evaluate_test_set_index < evaluate_test_set_count; ++evaluate_test_set_index) { - EvaluateTestSet *evaluate_test_set = + EvaluateTestSet* evaluate_test_set = &evaluate_test_sets[evaluate_test_set_index]; - const EvaluateTest *evaluate_tests = evaluate_test_set->evaluate_tests; + const EvaluateTest* evaluate_tests = evaluate_test_set->evaluate_tests; unsigned int evaluate_test_count = evaluate_test_set->evaluate_test_count; // The same dictionary will be used for each test in the set. Earlier @@ -242,7 +241,7 @@ static bool RunTests() { for (unsigned int evaluate_test_index = 0; evaluate_test_index < evaluate_test_count; ++evaluate_test_index) { - const EvaluateTest *evaluate_test = &evaluate_tests[evaluate_test_index]; + const EvaluateTest* evaluate_test = &evaluate_tests[evaluate_test_index]; // Do the test. bool result = postfix_evaluator.Evaluate(evaluate_test->expression, @@ -344,7 +343,7 @@ static bool RunTests() { postfix_evaluator.set_dictionary(&dictionary_2); for (int i = 0; i < evaluate_for_value_tests_2_size; i++) { - const EvaluateForValueTest *test = &evaluate_for_value_tests_2[i]; + const EvaluateForValueTest* test = &evaluate_for_value_tests_2[i]; unsigned int result; if (postfix_evaluator.EvaluateForValue(test->expression, &result) != test->evaluable) { @@ -396,7 +395,7 @@ static bool RunTests() { } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { BPLOG_INIT(&argc, &argv); return RunTests() ? 0 : 1; diff --git a/src/processor/proc_maps_linux.cc b/src/processor/proc_maps_linux.cc index 3c0dea25..05c1145a 100644 --- a/src/processor/proc_maps_linux.cc +++ b/src/processor/proc_maps_linux.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 2013 Google LLC // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/src/processor/proc_maps_linux_unittest.cc b/src/processor/proc_maps_linux_unittest.cc index 466f2345..dc51babb 100644 --- a/src/processor/proc_maps_linux_unittest.cc +++ b/src/processor/proc_maps_linux_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 2013 Google LLC // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/src/processor/process_state.cc b/src/processor/process_state.cc index 43c4a4b8..95bbd48d 100644 --- a/src/processor/process_state.cc +++ b/src/processor/process_state.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -51,13 +50,14 @@ void ProcessState::Clear() { crash_address_ = 0; assertion_.clear(); requesting_thread_ = -1; - for (vector<CallStack *>::const_iterator iterator = threads_.begin(); + for (vector<CallStack*>::const_iterator iterator = threads_.begin(); iterator != threads_.end(); ++iterator) { delete *iterator; } threads_.clear(); system_info_.Clear(); + thread_names_.clear(); // modules_without_symbols_ and modules_with_corrupt_symbols_ DO NOT own // the underlying CodeModule pointers. Just clear the vectors. modules_without_symbols_.clear(); diff --git a/src/processor/processor.gyp b/src/processor/processor.gyp deleted file mode 100644 index 93896c0e..00000000 --- a/src/processor/processor.gyp +++ /dev/null @@ -1,187 +0,0 @@ -# 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': [ - '../build/common.gypi', - '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', - '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', - 'convert_old_arm64_context.cc', - 'convert_old_arm64_context.h', - 'disassembler_x86.cc', - 'disassembler_x86.h', - 'dump_context.cc', - 'dump_object.cc', - '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', - 'microdump_processor.cc', - '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', - 'proc_maps_linux.cc', - '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', - 'stackwalk_common.cc', - 'stackwalk_common.h', - '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', - 'symbolic_constants_win.cc', - 'symbolic_constants_win.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', - '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', - 'microdump_processor_unittest.cc', - 'minidump_processor_unittest.cc', - 'minidump_unittest.cc', - 'pathname_stripper_unittest.cc', - 'postfix_evaluator_unittest.cc', - 'range_map_truncate_lower_unittest.cc', - 'range_map_truncate_upper_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_mips64_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.gyp:gmock', - '../build/testing.gyp:gtest', - ], - }, - ], -} diff --git a/src/processor/processor_tools.gypi b/src/processor/processor_tools.gypi deleted file mode 100644 index ecb450d6..00000000 --- a/src/processor/processor_tools.gypi +++ /dev/null @@ -1,57 +0,0 @@ -# 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', - ], - }, - ], -} diff --git a/src/processor/proto/process_state.proto b/src/processor/proto/process_state.proto index d3e02dc3..f6b5fb4f 100644 --- a/src/processor/proto/process_state.proto +++ b/src/processor/proto/process_state.proto @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/range_map-inl.h b/src/processor/range_map-inl.h index 4d3b0eb9..860314f5 100644 --- a/src/processor/range_map-inl.h +++ b/src/processor/range_map-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -39,6 +38,7 @@ #include <assert.h> +#include "common/safe_math.h" #include "processor/range_map.h" #include "processor/linked_ptr.h" #include "processor/logging.h" @@ -47,20 +47,25 @@ namespace google_breakpad { template<typename AddressType, typename EntryType> -bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType &base, - const AddressType &size, - const EntryType &entry) { +bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType& base, + const AddressType& size, + const EntryType& entry) { return StoreRangeInternal(base, 0 /* delta */, size, entry); } template<typename AddressType, typename EntryType> bool RangeMap<AddressType, EntryType>::StoreRangeInternal( - const AddressType &base, const AddressType &delta, - const AddressType &size, const EntryType &entry) { - AddressType high = base + (size - 1); - + const AddressType& base, const AddressType& delta, + const AddressType& size, const EntryType& entry) { + AddressType high; + bool high_ok = false; + if (size > 0) { + std::pair<AddressType, bool> result = AddWithOverflowCheck(base, size - 1); + high = result.first; + high_ok = !result.second; + } // Check for undersize or overflow. - if (size <= 0 || high < base) { + if (!high_ok) { // The processor will hit this case too frequently with common symbol // files in the size == 0 case, which is more suited to a DEBUG channel. // Filter those out since there's no DEBUG channel at the moment. @@ -181,8 +186,8 @@ bool RangeMap<AddressType, EntryType>::StoreRangeInternal( template<typename AddressType, typename EntryType> bool RangeMap<AddressType, EntryType>::RetrieveRange( - const AddressType &address, EntryType *entry, AddressType *entry_base, - AddressType *entry_delta, AddressType *entry_size) const { + const AddressType& address, EntryType* entry, AddressType* entry_base, + AddressType* entry_delta, AddressType* entry_size) const { BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRange requires |entry|"; assert(entry); @@ -212,8 +217,8 @@ bool RangeMap<AddressType, EntryType>::RetrieveRange( template<typename AddressType, typename EntryType> bool RangeMap<AddressType, EntryType>::RetrieveNearestRange( - const AddressType &address, EntryType *entry, AddressType *entry_base, - AddressType *entry_delta, AddressType *entry_size) const { + const AddressType& address, EntryType* entry, AddressType* entry_base, + AddressType* entry_delta, AddressType* entry_size) const { BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveNearestRange requires |entry|"; assert(entry); @@ -245,8 +250,8 @@ bool RangeMap<AddressType, EntryType>::RetrieveNearestRange( template<typename AddressType, typename EntryType> bool RangeMap<AddressType, EntryType>::RetrieveRangeAtIndex( - int index, EntryType *entry, AddressType *entry_base, - AddressType *entry_delta, AddressType *entry_size) const { + int index, EntryType* entry, AddressType* entry_base, + AddressType* entry_delta, AddressType* entry_size) const { BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRangeAtIndex requires |entry|"; assert(entry); diff --git a/src/processor/range_map.h b/src/processor/range_map.h index 33f32973..578bd144 100644 --- a/src/processor/range_map.h +++ b/src/processor/range_map.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -78,17 +77,17 @@ class RangeMap { // stored in the map. If enable_shrink_down is true and there is an overlap // between the current range and some other range (already in the map), // shrink down the range which ends at a higher address. - bool StoreRange(const AddressType &base, const AddressType &size, - const EntryType &entry); + bool StoreRange(const AddressType& base, const AddressType& size, + const EntryType& entry); // Locates the range encompassing the supplied address. If there is no such // range, returns false. entry_base, entry_delta, and entry_size, if // non-NULL, are set to the base, delta, and size of the entry's range. // A positive entry delta (> 0) indicates that there was an overlap and the // entry was shrunk down (original start address was increased by delta). - bool RetrieveRange(const AddressType &address, EntryType *entry, - AddressType *entry_base, AddressType *entry_delta, - AddressType *entry_size) const; + bool RetrieveRange(const AddressType& address, EntryType* entry, + AddressType* entry_base, AddressType* entry_delta, + AddressType* entry_size) const; // Locates the range encompassing the supplied address, if one exists. // If no range encompasses the supplied address, locates the nearest range @@ -97,9 +96,9 @@ class RangeMap { // if non-NULL, are set to the base, delta, and size of the entry's range. // A positive entry delta (> 0) indicates that there was an overlap and the // entry was shrunk down (original start address was increased by delta). - bool RetrieveNearestRange(const AddressType &address, EntryType *entry, - AddressType *entry_base, AddressType *entry_delta, - AddressType *entry_size) const; + bool RetrieveNearestRange(const AddressType& address, EntryType* entry, + AddressType* entry_base, AddressType* entry_delta, + AddressType* entry_size) const; // Treating all ranges as a list ordered by the address spaces that they // occupy, locates the range at the index specified by index. Returns @@ -110,9 +109,9 @@ class RangeMap { // entry was shrunk down (original start address was increased by delta). // // RetrieveRangeAtIndex is not optimized for speedy operation. - bool RetrieveRangeAtIndex(int index, EntryType *entry, - AddressType *entry_base, AddressType *entry_delta, - AddressType *entry_size) const; + bool RetrieveRangeAtIndex(int index, EntryType* entry, + AddressType* entry_base, AddressType* entry_delta, + AddressType* entry_size) const; // Returns the number of ranges stored in the RangeMap. int GetCount() const; @@ -128,13 +127,13 @@ class RangeMap { // Same a StoreRange() with the only exception that the |delta| can be // passed in. - bool StoreRangeInternal(const AddressType &base, const AddressType &delta, - const AddressType &size, const EntryType &entry); + bool StoreRangeInternal(const AddressType& base, const AddressType& delta, + const AddressType& size, const EntryType& entry); class Range { public: - Range(const AddressType &base, const AddressType &delta, - const EntryType &entry) + Range(const AddressType& base, const AddressType& delta, + const EntryType& entry) : base_(base), delta_(delta), entry_(entry) {} AddressType base() const { return base_; } diff --git a/src/processor/range_map_truncate_lower_unittest.cc b/src/processor/range_map_truncate_lower_unittest.cc index a933c956..12dad873 100644 --- a/src/processor/range_map_truncate_lower_unittest.cc +++ b/src/processor/range_map_truncate_lower_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2019, Google Inc. -// All rights reserved. +// Copyright 2019 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -25,7 +24,7 @@ // 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 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <limits.h> #include <stdio.h> diff --git a/src/processor/range_map_truncate_upper_unittest.cc b/src/processor/range_map_truncate_upper_unittest.cc index 7e3034f2..57046e19 100644 --- a/src/processor/range_map_truncate_upper_unittest.cc +++ b/src/processor/range_map_truncate_upper_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2016, Google Inc. -// All rights reserved. +// Copyright 2016 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -25,7 +24,7 @@ // 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 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // range_map_shrink_down_unittest.cc: Unit tests for RangeMap that specifically // test shrink down when ranges overlap. diff --git a/src/processor/range_map_unittest.cc b/src/processor/range_map_unittest.cc index 31b89e5d..2745e809 100644 --- a/src/processor/range_map_unittest.cc +++ b/src/processor/range_map_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -43,11 +42,10 @@ namespace { - +using google_breakpad::AddIgnoringOverflow; using google_breakpad::linked_ptr; -using google_breakpad::scoped_ptr; using google_breakpad::RangeMap; - +using google_breakpad::scoped_ptr; // A CountedObject holds an int. A global (not thread safe!) count of // allocated CountedObjects is maintained to help test memory management. @@ -92,7 +90,7 @@ struct RangeTest { // sequence on the same RangeMap. struct RangeTestSet { // An array of RangeTests - const RangeTest *range_tests; + const RangeTest* range_tests; // The number of tests in the set unsigned int range_test_count; @@ -102,7 +100,7 @@ struct RangeTestSet { // StoreTest uses the data in a RangeTest and calls StoreRange on the // test RangeMap. It returns true if the expected result occurred, and // false if something else happened. -static bool StoreTest(TestMap *range_map, const RangeTest *range_test) { +static bool StoreTest(TestMap* range_map, const RangeTest* range_test) { linked_ptr<CountedObject> object(new CountedObject(range_test->id)); bool stored = range_map->StoreRange(range_test->address, range_test->size, @@ -126,7 +124,7 @@ static bool StoreTest(TestMap *range_map, const RangeTest *range_test) { // map entry at the specified range,) it returns true, otherwise, it returns // false. RetrieveTest will check the values around the base address and // the high address of a range to guard against off-by-one errors. -static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) { +static bool RetrieveTest(TestMap* range_map, const RangeTest* range_test) { for (unsigned int side = 0; side <= 1; ++side) { // When side == 0, check the low side (base address) of each range. // When side == 1, check the high side (base + size) of each range. @@ -148,10 +146,10 @@ static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) { } for (AddressType offset = low_offset; offset <= high_offset; ++offset) { - AddressType address = - offset + - (!side ? range_test->address : - range_test->address + range_test->size - 1); + AddressType address = AddIgnoringOverflow( + offset, (!side ? range_test->address + : AddIgnoringOverflow(range_test->address, + range_test->size - 1))); bool expected_result = false; // This is correct for tests not stored. if (range_test->expect_storable) { @@ -270,9 +268,9 @@ static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) { // and verifying that each call returns a different object than the previous // call, and that ranges are returned with increasing base addresses. Returns // false if the test fails. -static bool RetrieveIndexTest(TestMap *range_map, int set) { +static bool RetrieveIndexTest(TestMap* range_map, int set) { linked_ptr<CountedObject> object; - CountedObject *last_object = NULL; + CountedObject* last_object = NULL; AddressType last_base = 0; int object_count = range_map->GetCount(); @@ -469,7 +467,7 @@ static bool RunTests() { for (unsigned int range_test_set_index = 0; range_test_set_index < range_test_set_count; ++range_test_set_index) { - const RangeTest *range_tests = + const RangeTest* range_tests = range_test_sets[range_test_set_index].range_tests; unsigned int range_test_count = range_test_sets[range_test_set_index].range_test_count; @@ -480,7 +478,7 @@ static bool RunTests() { for (unsigned int range_test_index = 0; range_test_index < range_test_count; ++range_test_index) { - const RangeTest *range_test = &range_tests[range_test_index]; + const RangeTest* range_test = &range_tests[range_test_index]; if (!StoreTest(range_map.get(), range_test)) return false; @@ -512,7 +510,7 @@ static bool RunTests() { for (unsigned int range_test_index = 0; range_test_index < range_test_count; ++range_test_index) { - const RangeTest *range_test = &range_tests[range_test_index]; + const RangeTest* range_test = &range_tests[range_test_index]; if (!RetrieveTest(range_map.get(), range_test)) return false; } @@ -552,7 +550,7 @@ static bool RunTests() { } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { BPLOG_INIT(&argc, &argv); return RunTests() ? 0 : 1; diff --git a/src/processor/simple_serializer-inl.h b/src/processor/simple_serializer-inl.h index 606bb3ce..bc2c8def 100644 --- a/src/processor/simple_serializer-inl.h +++ b/src/processor/simple_serializer-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,14 +37,15 @@ #ifndef PROCESSOR_SIMPLE_SERIALIZER_INL_H__ #define PROCESSOR_SIMPLE_SERIALIZER_INL_H__ -#include <string> - #include "processor/simple_serializer.h" -#include "map_serializers-inl.h" + +#include <cstdint> +#include <string> #include "google_breakpad/processor/basic_source_line_resolver.h" #include "processor/basic_source_line_resolver_types.h" #include "processor/linked_ptr.h" +#include "processor/map_serializers-inl.h" #include "processor/windows_frame_info.h" namespace google_breakpad { @@ -56,12 +56,12 @@ class SimpleSerializer<bool> { public: static size_t SizeOf(bool boolean) { return 1; } - static char *Write(bool boolean, char *dest) { + static char* Write(bool boolean, char* dest) { *dest = static_cast<char>(boolean? 255 : 0); return ++dest; } - static const char *Read(const char *source, bool *value) { + static const char* Read(const char* source, bool* value) { *value = ((*source) == 0 ? false : true); return ++source; } @@ -71,9 +71,9 @@ class SimpleSerializer<bool> { template<> class SimpleSerializer<string> { public: - static size_t SizeOf(const string &str) { return str.size() + 1; } + static size_t SizeOf(const string& str) { return str.size() + 1; } - static char *Write(const string &str, char *dest) { + static char* Write(const string& str, char* dest) { strcpy(dest, str.c_str()); return dest + SizeOf(str); } @@ -83,11 +83,11 @@ class SimpleSerializer<string> { template<> class SimpleSerializer<const char*> { public: - static size_t SizeOf(const char *cstring) { + static size_t SizeOf(const char* cstring) { return strlen(cstring) + 1; } - static char *Write(const char *cstring, char *dest) { + static char* Write(const char* cstring, char* dest) { strcpy(dest, cstring); return dest + SizeOf(cstring); } @@ -98,13 +98,13 @@ template<> class SimpleSerializer<BasicSourceLineResolver::Line> { typedef BasicSourceLineResolver::Line Line; public: - static size_t SizeOf(const Line &line) { + static size_t SizeOf(const Line& line) { return SimpleSerializer<MemAddr>::SizeOf(line.address) + SimpleSerializer<MemAddr>::SizeOf(line.size) + SimpleSerializer<int32_t>::SizeOf(line.source_file_id) + SimpleSerializer<int32_t>::SizeOf(line.line); } - static char *Write(const Line &line, char *dest) { + static char* Write(const Line& line, char* dest) { dest = SimpleSerializer<MemAddr>::Write(line.address, dest); dest = SimpleSerializer<MemAddr>::Write(line.size, dest); dest = SimpleSerializer<int32_t>::Write(line.source_file_id, dest); @@ -113,20 +113,41 @@ class SimpleSerializer<BasicSourceLineResolver::Line> { } }; +// Specializations of SimpleSerializer: InlineOrigin +template <> +class SimpleSerializer<BasicSourceLineResolver::InlineOrigin> { + typedef BasicSourceLineResolver::InlineOrigin InlineOrigin; + + public: + static size_t SizeOf(const InlineOrigin& origin) { + return SimpleSerializer<bool>::SizeOf(origin.has_file_id) + + SimpleSerializer<int32_t>::SizeOf(origin.source_file_id) + + SimpleSerializer<string>::SizeOf(origin.name); + } + static char* Write(const InlineOrigin& origin, char* dest) { + dest = SimpleSerializer<bool>::Write(origin.has_file_id, dest); + dest = SimpleSerializer<int32_t>::Write(origin.source_file_id, dest); + dest = SimpleSerializer<string>::Write(origin.name, dest); + return dest; + } +}; + // Specializations of SimpleSerializer: PublicSymbol template<> class SimpleSerializer<BasicSourceLineResolver::PublicSymbol> { typedef BasicSourceLineResolver::PublicSymbol PublicSymbol; public: - static size_t SizeOf(const PublicSymbol &pubsymbol) { + static size_t SizeOf(const PublicSymbol& pubsymbol) { return SimpleSerializer<string>::SizeOf(pubsymbol.name) + SimpleSerializer<MemAddr>::SizeOf(pubsymbol.address) - + SimpleSerializer<int32_t>::SizeOf(pubsymbol.parameter_size); + + SimpleSerializer<int32_t>::SizeOf(pubsymbol.parameter_size) + + SimpleSerializer<bool>::SizeOf(pubsymbol.is_multiple); } - static char *Write(const PublicSymbol &pubsymbol, char *dest) { + static char* Write(const PublicSymbol& pubsymbol, char* dest) { dest = SimpleSerializer<string>::Write(pubsymbol.name, dest); dest = SimpleSerializer<MemAddr>::Write(pubsymbol.address, dest); dest = SimpleSerializer<int32_t>::Write(pubsymbol.parameter_size, dest); + dest = SimpleSerializer<bool>::Write(pubsymbol.is_multiple, dest); return dest; } }; @@ -135,7 +156,7 @@ class SimpleSerializer<BasicSourceLineResolver::PublicSymbol> { template<> class SimpleSerializer<WindowsFrameInfo> { public: - static size_t SizeOf(const WindowsFrameInfo &wfi) { + static size_t SizeOf(const WindowsFrameInfo& wfi) { unsigned int size = 0; size += sizeof(int32_t); // wfi.type_ size += SimpleSerializer<int32_t>::SizeOf(wfi.valid); @@ -149,7 +170,7 @@ class SimpleSerializer<WindowsFrameInfo> { size += SimpleSerializer<string>::SizeOf(wfi.program_string); return size; } - static char *Write(const WindowsFrameInfo &wfi, char *dest) { + static char* Write(const WindowsFrameInfo& wfi, char* dest) { dest = SimpleSerializer<int32_t>::Write( static_cast<const int32_t>(wfi.type_), dest); dest = SimpleSerializer<int32_t>::Write(wfi.valid, dest); @@ -165,61 +186,151 @@ class SimpleSerializer<WindowsFrameInfo> { }; // Specializations of SimpleSerializer: Linked_ptr version of -// Line, Function, PublicSymbol, WindowsFrameInfo. +// Line, InlineOrigin, Inline, Function, PublicSymbol, WindowsFrameInfo. template<> class SimpleSerializer< linked_ptr<BasicSourceLineResolver::Line> > { typedef BasicSourceLineResolver::Line Line; public: - static size_t SizeOf(const linked_ptr<Line> &lineptr) { + static size_t SizeOf(const linked_ptr<Line>& lineptr) { if (lineptr.get() == NULL) return 0; return SimpleSerializer<Line>::SizeOf(*(lineptr.get())); } - static char *Write(const linked_ptr<Line> &lineptr, char *dest) { + static char* Write(const linked_ptr<Line>& lineptr, char* dest) { if (lineptr.get()) dest = SimpleSerializer<Line>::Write(*(lineptr.get()), dest); return dest; } }; +template <> +class SimpleSerializer<linked_ptr<BasicSourceLineResolver::InlineOrigin>> { + typedef BasicSourceLineResolver::InlineOrigin InlineOrigin; + + public: + static size_t SizeOf(const linked_ptr<InlineOrigin>& origin_ptr) { + if (origin_ptr.get() == NULL) + return 0; + return SimpleSerializer<InlineOrigin>::SizeOf(*(origin_ptr.get())); + } + static char* Write(const linked_ptr<InlineOrigin>& origin_ptr, char* dest) { + if (origin_ptr.get()) + dest = SimpleSerializer<InlineOrigin>::Write(*(origin_ptr.get()), dest); + return dest; + } +}; + +// Specializations of SimpleSerializer: Inline +template <> +class SimpleSerializer<linked_ptr<BasicSourceLineResolver::Inline>>; +template <> +class SimpleSerializer<BasicSourceLineResolver::Inline> { + typedef BasicSourceLineResolver::Inline Inline; + + public: + inline static size_t SizeOf(const Inline& in); + inline static char* Write(const Inline& in, char* dest); +}; + +template <> +class SimpleSerializer<linked_ptr<BasicSourceLineResolver::Inline>> { + typedef BasicSourceLineResolver::Inline Inline; + + public: + static size_t SizeOf(const linked_ptr<Inline>& inline_ptr) { + if (inline_ptr.get() == NULL) + return 0; + return SimpleSerializer<Inline>::SizeOf(*(inline_ptr.get())); + } + static char* Write(const linked_ptr<Inline>& inline_ptr, char* dest) { + if (inline_ptr.get()) + dest = SimpleSerializer<Inline>::Write(*(inline_ptr.get()), dest); + return dest; + } +}; + +size_t SimpleSerializer<BasicSourceLineResolver::Inline>::SizeOf( + const Inline& in) { + return SimpleSerializer<bool>::SizeOf(in.has_call_site_file_id) + + SimpleSerializer<int32_t>::SizeOf(in.inline_nest_level) + + SimpleSerializer<int32_t>::SizeOf(in.call_site_line) + + SimpleSerializer<int32_t>::SizeOf(in.call_site_file_id) + + SimpleSerializer<int32_t>::SizeOf(in.origin_id) + + sizeof(uint32_t) + // This is to store the size of inline_ranges. + (in.inline_ranges.size() * sizeof(MemAddr) * 2); +} + +char* SimpleSerializer<BasicSourceLineResolver::Inline>::Write(const Inline& in, + char* dest) { + dest = SimpleSerializer<bool>::Write(in.has_call_site_file_id, dest); + dest = SimpleSerializer<int32_t>::Write(in.inline_nest_level, dest); + dest = SimpleSerializer<int32_t>::Write(in.call_site_line, dest); + dest = SimpleSerializer<int32_t>::Write(in.call_site_file_id, dest); + dest = SimpleSerializer<int32_t>::Write(in.origin_id, dest); + // Write the size of inline_ranges. + dest = SimpleSerializer<int32_t>::Write(in.inline_ranges.size(), dest); + for (const std::pair<MemAddr, MemAddr>& range : in.inline_ranges) { + dest = SimpleSerializer<MemAddr>::Write(range.first, dest); + dest = SimpleSerializer<MemAddr>::Write(range.second, dest); + } + return dest; +} + template<> class SimpleSerializer<BasicSourceLineResolver::Function> { // Convenient type names. typedef BasicSourceLineResolver::Function Function; typedef BasicSourceLineResolver::Line Line; + typedef BasicSourceLineResolver::Inline Inline; + public: - static size_t SizeOf(const Function &func) { + static size_t SizeOf(const Function& func) { unsigned int size = 0; size += SimpleSerializer<string>::SizeOf(func.name); size += SimpleSerializer<MemAddr>::SizeOf(func.address); size += SimpleSerializer<MemAddr>::SizeOf(func.size); size += SimpleSerializer<int32_t>::SizeOf(func.parameter_size); + size += SimpleSerializer<bool>::SizeOf(func.is_multiple); + // This extra size is used to store the size of serialized func.inlines, so + // we know where to start de-serialize func.lines. + size += sizeof(int32_t); + size += inline_range_map_serializer_.SizeOf(&func.inlines); size += range_map_serializer_.SizeOf(func.lines); return size; } - static char *Write(const Function &func, char *dest) { + static char* Write(const Function& func, char* dest) { dest = SimpleSerializer<string>::Write(func.name, dest); dest = SimpleSerializer<MemAddr>::Write(func.address, dest); dest = SimpleSerializer<MemAddr>::Write(func.size, dest); dest = SimpleSerializer<int32_t>::Write(func.parameter_size, dest); + dest = SimpleSerializer<bool>::Write(func.is_multiple, dest); + char* old_dest = dest; + dest += sizeof(int32_t); + dest = inline_range_map_serializer_.Write(&func.inlines, dest); + // Write the size of serialized func.inlines. The size doesn't include size + // field itself. + SimpleSerializer<MemAddr>::Write(dest - old_dest - sizeof(int32_t), + old_dest); dest = range_map_serializer_.Write(func.lines, dest); return dest; } private: // This static member is defined in module_serializer.cc. - static RangeMapSerializer< MemAddr, linked_ptr<Line> > range_map_serializer_; + static RangeMapSerializer<MemAddr, linked_ptr<Line>> range_map_serializer_; + static ContainedRangeMapSerializer<MemAddr, linked_ptr<Inline>> + inline_range_map_serializer_; }; template<> class SimpleSerializer< linked_ptr<BasicSourceLineResolver::Function> > { typedef BasicSourceLineResolver::Function Function; public: - static size_t SizeOf(const linked_ptr<Function> &func) { + static size_t SizeOf(const linked_ptr<Function>& func) { if (!func.get()) return 0; return SimpleSerializer<Function>::SizeOf(*(func.get())); } - static char *Write(const linked_ptr<Function> &func, char *dest) { + static char* Write(const linked_ptr<Function>& func, char* dest) { if (func.get()) dest = SimpleSerializer<Function>::Write(*(func.get()), dest); return dest; @@ -230,11 +341,11 @@ template<> class SimpleSerializer< linked_ptr<BasicSourceLineResolver::PublicSymbol> > { typedef BasicSourceLineResolver::PublicSymbol PublicSymbol; public: - static size_t SizeOf(const linked_ptr<PublicSymbol> &pubsymbol) { + static size_t SizeOf(const linked_ptr<PublicSymbol>& pubsymbol) { if (pubsymbol.get() == NULL) return 0; return SimpleSerializer<PublicSymbol>::SizeOf(*(pubsymbol.get())); } - static char *Write(const linked_ptr<PublicSymbol> &pubsymbol, char *dest) { + static char* Write(const linked_ptr<PublicSymbol>& pubsymbol, char* dest) { if (pubsymbol.get()) dest = SimpleSerializer<PublicSymbol>::Write(*(pubsymbol.get()), dest); return dest; @@ -244,11 +355,11 @@ class SimpleSerializer< linked_ptr<BasicSourceLineResolver::PublicSymbol> > { template<> class SimpleSerializer< linked_ptr<WindowsFrameInfo> > { public: - static size_t SizeOf(const linked_ptr<WindowsFrameInfo> &wfi) { + static size_t SizeOf(const linked_ptr<WindowsFrameInfo>& wfi) { if (wfi.get() == NULL) return 0; return SimpleSerializer<WindowsFrameInfo>::SizeOf(*(wfi.get())); } - static char *Write(const linked_ptr<WindowsFrameInfo> &wfi, char *dest) { + static char* Write(const linked_ptr<WindowsFrameInfo>& wfi, char* dest) { if (wfi.get()) dest = SimpleSerializer<WindowsFrameInfo>::Write(*(wfi.get()), dest); return dest; diff --git a/src/processor/simple_serializer.h b/src/processor/simple_serializer.h index 275f51ce..bd6cc84c 100644 --- a/src/processor/simple_serializer.h +++ b/src/processor/simple_serializer.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,6 +37,8 @@ #ifndef PROCESSOR_SIMPLE_SERIALIZER_H__ #define PROCESSOR_SIMPLE_SERIALIZER_H__ +#include <stddef.h> + #include "google_breakpad/common/breakpad_types.h" namespace google_breakpad { @@ -49,10 +50,10 @@ typedef uint64_t MemAddr; template<class Type> class SimpleSerializer { public: // Calculate and return the size of the 'item'. - static size_t SizeOf(const Type &item) { return sizeof(item); } + static size_t SizeOf(const Type& item) { return sizeof(item); } // Write 'item' to memory location 'dest', and return to the "end" address of // data written, i.e., the address after the final byte written. - static char *Write(const Type &item, char *dest) { + static char* Write(const Type& item, char* dest) { new (dest) Type(item); return dest + SizeOf(item); } diff --git a/src/processor/simple_symbol_supplier.cc b/src/processor/simple_symbol_supplier.cc index bc5ebb68..5b3f6819 100644 --- a/src/processor/simple_symbol_supplier.cc +++ b/src/processor/simple_symbol_supplier.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,14 +51,14 @@ namespace google_breakpad { -static bool file_exists(const string &file_name) { +static bool file_exists(const string& file_name) { struct stat sb; return stat(file_name.c_str(), &sb) == 0; } SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile( - const CodeModule *module, const SystemInfo *system_info, - string *symbol_file) { + const CodeModule* module, const SystemInfo* system_info, + string* symbol_file) { BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFile " "requires |symbol_file|"; assert(symbol_file); @@ -77,10 +76,10 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile( } SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile( - const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data) { + const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + string* symbol_data) { assert(symbol_data); symbol_data->clear(); @@ -96,11 +95,11 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile( } SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData( - const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size) { + const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + char** symbol_data, + size_t* symbol_data_size) { assert(symbol_data); assert(symbol_data_size); @@ -123,13 +122,13 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData( return s; } -void SimpleSymbolSupplier::FreeSymbolData(const CodeModule *module) { +void SimpleSymbolSupplier::FreeSymbolData(const CodeModule* module) { if (!module) { BPLOG(INFO) << "Cannot free symbol data buffer for NULL module"; return; } - map<string, char *>::iterator it = memory_buffers_.find(module->code_file()); + map<string, char*>::iterator it = memory_buffers_.find(module->code_file()); if (it == memory_buffers_.end()) { BPLOG(INFO) << "Cannot find symbol data buffer for module " << module->code_file(); @@ -140,8 +139,8 @@ void SimpleSymbolSupplier::FreeSymbolData(const CodeModule *module) { } SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPathFromRoot( - const CodeModule *module, const SystemInfo *system_info, - const string &root_path, string *symbol_file) { + const CodeModule* module, const SystemInfo* system_info, + const string& root_path, string* symbol_file) { BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFileAtPath " "requires |symbol_file|"; assert(symbol_file); diff --git a/src/processor/simple_symbol_supplier.h b/src/processor/simple_symbol_supplier.h index 0cde85cd..3302bab6 100644 --- a/src/processor/simple_symbol_supplier.h +++ b/src/processor/simple_symbol_supplier.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -94,44 +93,44 @@ class SimpleSymbolSupplier : public SymbolSupplier { public: // Creates a new SimpleSymbolSupplier, using path as the root path where // symbols are stored. - explicit SimpleSymbolSupplier(const string &path) : paths_(1, path) {} + explicit SimpleSymbolSupplier(const string& path) : paths_(1, path) {} // Creates a new SimpleSymbolSupplier, using paths as a list of root // paths where symbols may be stored. - explicit SimpleSymbolSupplier(const vector<string> &paths) : paths_(paths) {} + explicit SimpleSymbolSupplier(const vector<string>& paths) : paths_(paths) {} virtual ~SimpleSymbolSupplier() {} // Returns the path to the symbol file for the given module. See the // description above. - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file); + virtual SymbolResult GetSymbolFile(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file); - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data); + virtual SymbolResult GetSymbolFile(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + string* symbol_data); // Allocates data buffer on heap and writes symbol data into buffer. // Symbol supplier ALWAYS takes ownership of the data buffer. - virtual SymbolResult GetCStringSymbolData(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size); + virtual SymbolResult GetCStringSymbolData(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + char** symbol_data, + size_t* symbol_data_size); // Free the data buffer allocated in the above GetCStringSymbolData(); - virtual void FreeSymbolData(const CodeModule *module); + virtual void FreeSymbolData(const CodeModule* module); protected: - SymbolResult GetSymbolFileAtPathFromRoot(const CodeModule *module, - const SystemInfo *system_info, - const string &root_path, - string *symbol_file); + SymbolResult GetSymbolFileAtPathFromRoot(const CodeModule* module, + const SystemInfo* system_info, + const string& root_path, + string* symbol_file); private: - map<string, char *> memory_buffers_; + map<string, char*> memory_buffers_; vector<string> paths_; }; diff --git a/src/processor/source_line_resolver_base.cc b/src/processor/source_line_resolver_base.cc index 6eff1f99..5c0b6cd7 100644 --- a/src/processor/source_line_resolver_base.cc +++ b/src/processor/source_line_resolver_base.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,16 +41,16 @@ #include <utility> #include "google_breakpad/processor/source_line_resolver_base.h" -#include "processor/source_line_resolver_base_types.h" +#include "processor/logging.h" #include "processor/module_factory.h" +#include "processor/source_line_resolver_base_types.h" -using std::map; using std::make_pair; namespace google_breakpad { SourceLineResolverBase::SourceLineResolverBase( - ModuleFactory *module_factory) + ModuleFactory* module_factory) : modules_(new ModuleMap), corrupt_modules_(new ModuleSet), memory_buffers_(new MemoryMap), @@ -85,9 +84,9 @@ SourceLineResolverBase::~SourceLineResolverBase() { module_factory_ = NULL; } -bool SourceLineResolverBase::ReadSymbolFile(const string &map_file, - char **symbol_data, - size_t *symbol_data_size) { +bool SourceLineResolverBase::ReadSymbolFile(const string& map_file, + char** symbol_data, + size_t* symbol_data_size) { if (symbol_data == NULL || symbol_data_size == NULL) { BPLOG(ERROR) << "Could not Read file into Null memory pointer"; return false; @@ -117,7 +116,7 @@ bool SourceLineResolverBase::ReadSymbolFile(const string &map_file, BPLOG(INFO) << "Opening " << map_file; - FILE *f = fopen(map_file.c_str(), "rt"); + FILE* f = fopen(map_file.c_str(), "rt"); if (!f) { string error_string; error_code = ErrnoString(&error_string); @@ -148,8 +147,8 @@ bool SourceLineResolverBase::ReadSymbolFile(const string &map_file, return true; } -bool SourceLineResolverBase::LoadModule(const CodeModule *module, - const string &map_file) { +bool SourceLineResolverBase::LoadModule(const CodeModule* module, + const string& map_file) { if (module == NULL) return false; @@ -163,12 +162,14 @@ bool SourceLineResolverBase::LoadModule(const CodeModule *module, BPLOG(INFO) << "Loading symbols for module " << module->code_file() << " from " << map_file; - char *memory_buffer; + char* memory_buffer; size_t memory_buffer_size; if (!ReadSymbolFile(map_file, &memory_buffer, &memory_buffer_size)) return false; - BPLOG(INFO) << "Read symbol file " << map_file << " succeeded"; + BPLOG(INFO) << "Read symbol file " << map_file << " succeeded. " + << "module = " << module->code_file() + << ", memory_buffer_size = " << memory_buffer_size; bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer, memory_buffer_size); @@ -184,7 +185,10 @@ bool SourceLineResolverBase::LoadModule(const CodeModule *module, } bool SourceLineResolverBase::LoadModuleUsingMapBuffer( - const CodeModule *module, const string &map_buffer) { + const CodeModule* module, const string& map_buffer) { + BPLOG(INFO) << "SourceLineResolverBase::LoadModuleUsingMapBuffer(module = " + << module->code_file() + << ", map_buffer.size() = " << map_buffer.size() << ")"; if (module == NULL) return false; @@ -196,7 +200,7 @@ bool SourceLineResolverBase::LoadModuleUsingMapBuffer( } size_t memory_buffer_size = map_buffer.size() + 1; - char *memory_buffer = new char[memory_buffer_size]; + char* memory_buffer = new char[memory_buffer_size]; if (memory_buffer == NULL) { BPLOG(ERROR) << "Could not allocate memory for " << module->code_file(); return false; @@ -220,8 +224,8 @@ bool SourceLineResolverBase::LoadModuleUsingMapBuffer( } bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer( - const CodeModule *module, - char *memory_buffer, + const CodeModule* module, + char* memory_buffer, size_t memory_buffer_size) { if (!module) return false; @@ -234,9 +238,9 @@ bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer( } BPLOG(INFO) << "Loading symbols for module " << module->code_file() - << " from memory buffer"; + << " from memory buffer, size: " << memory_buffer_size; - Module *basic_module = module_factory_->CreateModule(module->code_file()); + Module* basic_module = module_factory_->CreateModule(module->code_file()); // Ownership of memory is NOT transfered to Module::LoadMapFromMemory(). if (!basic_module->LoadMapFromMemory(memory_buffer, memory_buffer_size)) { @@ -259,13 +263,13 @@ bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() { return true; } -void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) { +void SourceLineResolverBase::UnloadModule(const CodeModule* code_module) { if (!code_module) return; ModuleMap::iterator mod_iter = modules_->find(code_module->code_file()); if (mod_iter != modules_->end()) { - Module *symbol_module = mod_iter->second; + Module* symbol_module = mod_iter->second; delete symbol_module; corrupt_modules_->erase(mod_iter->first); modules_->erase(mod_iter); @@ -283,29 +287,31 @@ void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) { } } -bool SourceLineResolverBase::HasModule(const CodeModule *module) { +bool SourceLineResolverBase::HasModule(const CodeModule* module) { if (!module) return false; return modules_->find(module->code_file()) != modules_->end(); } -bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule *module) { +bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule* module) { if (!module) return false; return corrupt_modules_->find(module->code_file()) != corrupt_modules_->end(); } -void SourceLineResolverBase::FillSourceLineInfo(StackFrame *frame) { +void SourceLineResolverBase::FillSourceLineInfo( + StackFrame* frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames) { if (frame->module) { ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); if (it != modules_->end()) { - it->second->LookupAddress(frame); + it->second->LookupAddress(frame, inlined_frames); } } } -WindowsFrameInfo *SourceLineResolverBase::FindWindowsFrameInfo( - const StackFrame *frame) { +WindowsFrameInfo* SourceLineResolverBase::FindWindowsFrameInfo( + const StackFrame* frame) { if (frame->module) { ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); if (it != modules_->end()) { @@ -315,8 +321,8 @@ WindowsFrameInfo *SourceLineResolverBase::FindWindowsFrameInfo( return NULL; } -CFIFrameInfo *SourceLineResolverBase::FindCFIFrameInfo( - const StackFrame *frame) { +CFIFrameInfo* SourceLineResolverBase::FindCFIFrameInfo( + const StackFrame* frame) { if (frame->module) { ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); if (it != modules_->end()) { @@ -327,12 +333,12 @@ CFIFrameInfo *SourceLineResolverBase::FindCFIFrameInfo( } bool SourceLineResolverBase::CompareString::operator()( - const string &s1, const string &s2) const { + const string& s1, const string& s2) const { return strcmp(s1.c_str(), s2.c_str()) < 0; } bool SourceLineResolverBase::Module::ParseCFIRuleSet( - const string &rule_set, CFIFrameInfo *frame_info) const { + const string& rule_set, CFIFrameInfo* frame_info) const { CFIFrameInfoParseHandler handler(frame_info); CFIRuleParser parser(&handler); return parser.Parse(rule_set); diff --git a/src/processor/source_line_resolver_base_types.h b/src/processor/source_line_resolver_base_types.h index ca744e00..4b3b366c 100644 --- a/src/processor/source_line_resolver_base_types.h +++ b/src/processor/source_line_resolver_base_types.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -40,13 +39,17 @@ #include <stdio.h> +#include <deque> #include <map> +#include <memory> #include <string> #include "google_breakpad/common/breakpad_types.h" #include "google_breakpad/processor/source_line_resolver_base.h" #include "google_breakpad/processor/stack_frame.h" #include "processor/cfi_frame_info.h" +#include "processor/linked_ptr.h" +#include "processor/range_map.h" #include "processor/windows_frame_info.h" #ifndef PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__ @@ -56,14 +59,51 @@ namespace google_breakpad { class SourceLineResolverBase::AutoFileCloser { public: - explicit AutoFileCloser(FILE *file) : file_(file) {} + explicit AutoFileCloser(FILE* file) : file_(file) {} ~AutoFileCloser() { if (file_) fclose(file_); } private: - FILE *file_; + FILE* file_; +}; + +struct SourceLineResolverBase::InlineOrigin { + InlineOrigin() {} + InlineOrigin(bool has_file_id, int32_t source_file_id, const string& name) + : has_file_id(has_file_id), + source_file_id(source_file_id), + name(name) {} + // If it's old format, source file id is set, otherwise not useful. + bool has_file_id; + int32_t source_file_id; + string name; +}; + +struct SourceLineResolverBase::Inline { + // A vector of (address, size) pair for a INLINE record. + using InlineRanges = std::vector<std::pair<MemAddr, MemAddr>>; + Inline() {} + Inline(bool has_call_site_file_id, + int32_t inline_nest_level, + int32_t call_site_line, + int32_t call_site_file_id, + int32_t origin_id, + InlineRanges inline_ranges) + : has_call_site_file_id(has_call_site_file_id), + inline_nest_level(inline_nest_level), + call_site_line(call_site_line), + call_site_file_id(call_site_file_id), + origin_id(origin_id), + inline_ranges(inline_ranges) {} + // If it's new format, call site file id is set, otherwise not useful. + bool has_call_site_file_id; + int32_t inline_nest_level; + int32_t call_site_line; + int32_t call_site_file_id; + int32_t origin_id; + InlineRanges inline_ranges; }; struct SourceLineResolverBase::Line { @@ -82,7 +122,7 @@ struct SourceLineResolverBase::Line { struct SourceLineResolverBase::Function { Function() { } - Function(const string &function_name, + Function(const string& function_name, MemAddr function_address, MemAddr code_size, int set_parameter_size, @@ -133,7 +173,7 @@ class SourceLineResolverBase::Module { // The passed in |memory buffer| is of size |memory_buffer_size|. If it is // not null terminated, LoadMapFromMemory will null terminate it by modifying // the passed in buffer. - virtual bool LoadMapFromMemory(char *memory_buffer, + virtual bool LoadMapFromMemory(char* memory_buffer, size_t memory_buffer_size) = 0; // Tells whether the loaded symbol data is corrupt. Return value is @@ -142,24 +182,26 @@ class SourceLineResolverBase::Module { // Looks up the given relative address, and fills the StackFrame struct // with the result. - virtual void LookupAddress(StackFrame *frame) const = 0; + virtual void LookupAddress( + StackFrame* frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const = 0; // If Windows stack walking information is available covering ADDRESS, // return a WindowsFrameInfo structure describing it. If the information // is not available, returns NULL. A NULL return value does not indicate // an error. The caller takes ownership of any returned WindowsFrameInfo // object. - virtual WindowsFrameInfo * - FindWindowsFrameInfo(const StackFrame *frame) const = 0; + virtual WindowsFrameInfo* + FindWindowsFrameInfo(const StackFrame* frame) const = 0; // If CFI stack walking information is available covering ADDRESS, // return a CFIFrameInfo structure describing it. If the information // is not available, return NULL. The caller takes ownership of any // returned CFIFrameInfo object. - virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const = 0; + virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const = 0; protected: - virtual bool ParseCFIRuleSet(const string &rule_set, - CFIFrameInfo *frame_info) const; + virtual bool ParseCFIRuleSet(const string& rule_set, + CFIFrameInfo* frame_info) const; }; } // namespace google_breakpad diff --git a/src/processor/stack_frame_cpu.cc b/src/processor/stack_frame_cpu.cc index 6175dc7f..e31a3198 100644 --- a/src/processor/stack_frame_cpu.cc +++ b/src/processor/stack_frame_cpu.cc @@ -1,5 +1,4 @@ -// Copyright 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/stack_frame_symbolizer.cc b/src/processor/stack_frame_symbolizer.cc index 7a44f243..0d124a02 100644 --- a/src/processor/stack_frame_symbolizer.cc +++ b/src/processor/stack_frame_symbolizer.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012 Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -57,7 +56,8 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo( const CodeModules* modules, const CodeModules* unloaded_modules, const SystemInfo* system_info, - StackFrame* frame) { + StackFrame* frame, + std::deque<std::unique_ptr<StackFrame>>* inlined_frames) { assert(frame); const CodeModule* module = NULL; @@ -80,7 +80,7 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo( // If module is already loaded, go ahead to fill source line info and return. if (resolver_->HasModule(frame->module)) { - resolver_->FillSourceLineInfo(frame); + resolver_->FillSourceLineInfo(frame, inlined_frames); return resolver_->IsModuleCorrupt(frame->module) ? kWarningCorruptSymbols : kNoError; } @@ -108,7 +108,7 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo( } if (load_success) { - resolver_->FillSourceLineInfo(frame); + resolver_->FillSourceLineInfo(frame, inlined_frames); return resolver_->IsModuleCorrupt(frame->module) ? kWarningCorruptSymbols : kNoError; } else { diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc index 704039f3..a1b6364d 100644 --- a/src/processor/stackwalk_common.cc +++ b/src/processor/stackwalk_common.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -57,6 +56,7 @@ namespace google_breakpad { namespace { using std::vector; +using std::unique_ptr; // Separator character for machine readable output. static const char kOutputSeparator = '|'; @@ -69,7 +69,7 @@ static const char kOutputSeparator = '|'; // of registers is completely printed, regardless of the number of calls // to PrintRegister. static const int kMaxWidth = 80; // optimize for an 80-column terminal -static int PrintRegister(const char *name, uint32_t value, int start_col) { +static int PrintRegister(const char* name, uint32_t value, int start_col) { char buffer[64]; snprintf(buffer, sizeof(buffer), " %5s = 0x%08x", name, value); @@ -83,7 +83,7 @@ static int PrintRegister(const char *name, uint32_t value, int start_col) { } // PrintRegister64 does the same thing, but for 64-bit registers. -static int PrintRegister64(const char *name, uint64_t value, int start_col) { +static int PrintRegister64(const char* name, uint64_t value, int start_col) { char buffer[64]; snprintf(buffer, sizeof(buffer), " %5s = 0x%016" PRIx64 , name, value); @@ -98,7 +98,7 @@ static int PrintRegister64(const char *name, uint64_t value, int start_col) { // StripSeparator takes a string |original| and returns a copy // of the string with all occurences of |kOutputSeparator| removed. -static string StripSeparator(const string &original) { +static string StripSeparator(const string& original) { string result = original; string::size_type position = 0; while ((position = result.find(kOutputSeparator, position)) != string::npos) { @@ -112,20 +112,20 @@ static string StripSeparator(const string &original) { } // PrintStackContents prints the stack contents of the current frame to stdout. -static void PrintStackContents(const string &indent, - const StackFrame *frame, - const StackFrame *prev_frame, - const string &cpu, - const MemoryRegion *memory, +static void PrintStackContents(const string& indent, + const StackFrame* frame, + const StackFrame* prev_frame, + const string& cpu, + const MemoryRegion* memory, const CodeModules* modules, - SourceLineResolverInterface *resolver) { + SourceLineResolverInterface* resolver) { // Find stack range. int word_length = 0; uint64_t stack_begin = 0, stack_end = 0; if (cpu == "x86") { word_length = 4; - const StackFrameX86 *frame_x86 = static_cast<const StackFrameX86*>(frame); - const StackFrameX86 *prev_frame_x86 = + const StackFrameX86* frame_x86 = static_cast<const StackFrameX86*>(frame); + const StackFrameX86* prev_frame_x86 = static_cast<const StackFrameX86*>(prev_frame); if ((frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) && (prev_frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)) { @@ -134,9 +134,9 @@ static void PrintStackContents(const string &indent, } } else if (cpu == "amd64") { word_length = 8; - const StackFrameAMD64 *frame_amd64 = + const StackFrameAMD64* frame_amd64 = static_cast<const StackFrameAMD64*>(frame); - const StackFrameAMD64 *prev_frame_amd64 = + const StackFrameAMD64* prev_frame_amd64 = static_cast<const StackFrameAMD64*>(prev_frame); if ((frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) && (prev_frame_amd64->context_validity & @@ -146,26 +146,54 @@ static void PrintStackContents(const string &indent, } } else if (cpu == "arm") { word_length = 4; - const StackFrameARM *frame_arm = static_cast<const StackFrameARM*>(frame); - const StackFrameARM *prev_frame_arm = + const StackFrameARM* frame_arm = static_cast<const StackFrameARM*>(frame); + const StackFrameARM* prev_frame_arm = static_cast<const StackFrameARM*>(prev_frame); - if ((frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) && + if ((frame_arm->context_validity & + StackFrameARM::CONTEXT_VALID_SP) && (prev_frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { stack_begin = frame_arm->context.iregs[13]; stack_end = prev_frame_arm->context.iregs[13]; } } else if (cpu == "arm64") { word_length = 8; - const StackFrameARM64 *frame_arm64 = + const StackFrameARM64* frame_arm64 = static_cast<const StackFrameARM64*>(frame); - const StackFrameARM64 *prev_frame_arm64 = + const StackFrameARM64* prev_frame_arm64 = static_cast<const StackFrameARM64*>(prev_frame); - if ((frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) && + if ((frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_SP) && (prev_frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP)) { stack_begin = frame_arm64->context.iregs[31]; stack_end = prev_frame_arm64->context.iregs[31]; } + } else if (cpu == "riscv") { + word_length = 4; + const StackFrameRISCV* frame_riscv = + static_cast<const StackFrameRISCV*>(frame); + const StackFrameRISCV* prev_frame_riscv = + static_cast<const StackFrameRISCV*>(prev_frame); + if ((frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_SP) && + (prev_frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_SP)) { + stack_begin = frame_riscv->context.sp; + stack_end = prev_frame_riscv->context.sp; + } + } else if (cpu == "riscv64") { + word_length = 8; + const StackFrameRISCV64* frame_riscv64 = + static_cast<const StackFrameRISCV64*>(frame); + const StackFrameRISCV64* prev_frame_riscv64 = + static_cast<const StackFrameRISCV64*>(prev_frame); + if ((frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_SP) && + (prev_frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_SP)) { + stack_begin = frame_riscv64->context.sp; + stack_end = prev_frame_riscv64->context.sp; + } } if (!word_length || !stack_begin || !stack_end) return; @@ -217,25 +245,30 @@ static void PrintStackContents(const string &indent, modules->GetModuleForAddress(pointee_frame.instruction); // Try to look up the function name. + std::deque<unique_ptr<StackFrame>> inlined_frames; if (pointee_frame.module) - resolver->FillSourceLineInfo(&pointee_frame); + resolver->FillSourceLineInfo(&pointee_frame, &inlined_frames); // Print function name. - if (!pointee_frame.function_name.empty()) { - if (word_length == 4) { - printf("%s *(0x%08x) = 0x%08x", indent.c_str(), - static_cast<uint32_t>(address), - static_cast<uint32_t>(pointee_frame.instruction)); - } else { - printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64, - indent.c_str(), address, pointee_frame.instruction); + auto print_function_name = [&](StackFrame* frame) { + if (!frame->function_name.empty()) { + if (word_length == 4) { + printf("%s *(0x%08x) = 0x%08x", indent.c_str(), + static_cast<uint32_t>(address), + static_cast<uint32_t>(frame->instruction)); + } else { + printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64, indent.c_str(), + address, frame->instruction); + } + printf( + " <%s> [%s : %d + 0x%" PRIx64 "]\n", frame->function_name.c_str(), + PathnameStripper::File(frame->source_file_name).c_str(), + frame->source_line, frame->instruction - frame->source_line_base); } - printf(" <%s> [%s : %d + 0x%" PRIx64 "]\n", - pointee_frame.function_name.c_str(), - PathnameStripper::File(pointee_frame.source_file_name).c_str(), - pointee_frame.source_line, - pointee_frame.instruction - pointee_frame.source_line_base); - } + }; + print_function_name(&pointee_frame); + for (unique_ptr<StackFrame> &frame : inlined_frames) + print_function_name(frame.get()); } printf("\n"); } @@ -249,8 +282,8 @@ static void PrintStackContents(const string &indent, // // If |cpu| is a recognized CPU name, relevant register state for each stack // frame printed is also output, if available. -static void PrintStack(const CallStack *stack, - const string &cpu, +static void PrintStack(const CallStack* stack, + const string& cpu, bool output_stack_contents, const MemoryRegion* memory, const CodeModules* modules, @@ -260,7 +293,7 @@ static void PrintStack(const CallStack *stack, printf(" <no frames>\n"); } for (int frame_index = 0; frame_index < frame_count; ++frame_index) { - const StackFrame *frame = stack->frames()->at(frame_index); + const StackFrame* frame = stack->frames()->at(frame_index); printf("%2d ", frame_index); uint64_t instruction_address = frame->ReturnAddress(); @@ -287,321 +320,615 @@ static void PrintStack(const CallStack *stack, } printf("\n "); - int sequence = 0; - if (cpu == "x86") { - const StackFrameX86 *frame_x86 = - reinterpret_cast<const StackFrameX86*>(frame); - - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP) - sequence = PrintRegister("eip", frame_x86->context.eip, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) - sequence = PrintRegister("esp", frame_x86->context.esp, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP) - sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX) - sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI) - sequence = PrintRegister("esi", frame_x86->context.esi, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI) - sequence = PrintRegister("edi", frame_x86->context.edi, sequence); - if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) { - sequence = PrintRegister("eax", frame_x86->context.eax, sequence); - sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence); - sequence = PrintRegister("edx", frame_x86->context.edx, sequence); - sequence = PrintRegister("efl", frame_x86->context.eflags, sequence); - } - } else if (cpu == "ppc") { - const StackFramePPC *frame_ppc = - reinterpret_cast<const StackFramePPC*>(frame); - - if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0) - sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); - if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1) - sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence); - } else if (cpu == "amd64") { - const StackFrameAMD64 *frame_amd64 = - reinterpret_cast<const StackFrameAMD64*>(frame); - - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RAX) - sequence = PrintRegister64("rax", frame_amd64->context.rax, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDX) - sequence = PrintRegister64("rdx", frame_amd64->context.rdx, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RCX) - sequence = PrintRegister64("rcx", frame_amd64->context.rcx, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBX) - sequence = PrintRegister64("rbx", frame_amd64->context.rbx, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSI) - sequence = PrintRegister64("rsi", frame_amd64->context.rsi, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDI) - sequence = PrintRegister64("rdi", frame_amd64->context.rdi, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP) - sequence = PrintRegister64("rbp", frame_amd64->context.rbp, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) - sequence = PrintRegister64("rsp", frame_amd64->context.rsp, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R8) - sequence = PrintRegister64("r8", frame_amd64->context.r8, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R9) - sequence = PrintRegister64("r9", frame_amd64->context.r9, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R10) - sequence = PrintRegister64("r10", frame_amd64->context.r10, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R11) - sequence = PrintRegister64("r11", frame_amd64->context.r11, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R12) - sequence = PrintRegister64("r12", frame_amd64->context.r12, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R13) - sequence = PrintRegister64("r13", frame_amd64->context.r13, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R14) - sequence = PrintRegister64("r14", frame_amd64->context.r14, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R15) - sequence = PrintRegister64("r15", frame_amd64->context.r15, sequence); - if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP) - sequence = PrintRegister64("rip", frame_amd64->context.rip, sequence); - } else if (cpu == "sparc") { - const StackFrameSPARC *frame_sparc = - reinterpret_cast<const StackFrameSPARC*>(frame); - - if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP) - sequence = PrintRegister("sp", frame_sparc->context.g_r[14], sequence); - if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP) - sequence = PrintRegister("fp", frame_sparc->context.g_r[30], sequence); - if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC) - sequence = PrintRegister("pc", frame_sparc->context.pc, sequence); - } else if (cpu == "arm") { - const StackFrameARM *frame_arm = - reinterpret_cast<const StackFrameARM*>(frame); - - // Argument registers (caller-saves), which will likely only be valid - // for the youngest frame. - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0) - sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1) - sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2) - sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3) - sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence); - - // General-purpose callee-saves registers. - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4) - sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R5) - sequence = PrintRegister("r5", frame_arm->context.iregs[5], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R6) - sequence = PrintRegister("r6", frame_arm->context.iregs[6], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R7) - sequence = PrintRegister("r7", frame_arm->context.iregs[7], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R8) - sequence = PrintRegister("r8", frame_arm->context.iregs[8], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R9) - sequence = PrintRegister("r9", frame_arm->context.iregs[9], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R10) - sequence = PrintRegister("r10", frame_arm->context.iregs[10], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R12) - sequence = PrintRegister("r12", frame_arm->context.iregs[12], sequence); - - // Registers with a dedicated or conventional purpose. - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_FP) - sequence = PrintRegister("fp", frame_arm->context.iregs[11], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) - sequence = PrintRegister("sp", frame_arm->context.iregs[13], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_LR) - sequence = PrintRegister("lr", frame_arm->context.iregs[14], sequence); - if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_PC) - sequence = PrintRegister("pc", frame_arm->context.iregs[15], sequence); - } else if (cpu == "arm64") { - const StackFrameARM64 *frame_arm64 = - reinterpret_cast<const StackFrameARM64*>(frame); - - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X0) { - sequence = - PrintRegister64("x0", frame_arm64->context.iregs[0], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X1) { - sequence = - PrintRegister64("x1", frame_arm64->context.iregs[1], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X2) { - sequence = - PrintRegister64("x2", frame_arm64->context.iregs[2], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X3) { - sequence = - PrintRegister64("x3", frame_arm64->context.iregs[3], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X4) { - sequence = - PrintRegister64("x4", frame_arm64->context.iregs[4], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X5) { - sequence = - PrintRegister64("x5", frame_arm64->context.iregs[5], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X6) { - sequence = - PrintRegister64("x6", frame_arm64->context.iregs[6], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X7) { - sequence = - PrintRegister64("x7", frame_arm64->context.iregs[7], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X8) { - sequence = - PrintRegister64("x8", frame_arm64->context.iregs[8], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X9) { - sequence = - PrintRegister64("x9", frame_arm64->context.iregs[9], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X10) { - sequence = - PrintRegister64("x10", frame_arm64->context.iregs[10], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X11) { - sequence = - PrintRegister64("x11", frame_arm64->context.iregs[11], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X12) { - sequence = - PrintRegister64("x12", frame_arm64->context.iregs[12], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X13) { - sequence = - PrintRegister64("x13", frame_arm64->context.iregs[13], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X14) { - sequence = - PrintRegister64("x14", frame_arm64->context.iregs[14], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X15) { - sequence = - PrintRegister64("x15", frame_arm64->context.iregs[15], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X16) { - sequence = - PrintRegister64("x16", frame_arm64->context.iregs[16], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X17) { - sequence = - PrintRegister64("x17", frame_arm64->context.iregs[17], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X18) { - sequence = - PrintRegister64("x18", frame_arm64->context.iregs[18], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X19) { - sequence = - PrintRegister64("x19", frame_arm64->context.iregs[19], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X20) { - sequence = - PrintRegister64("x20", frame_arm64->context.iregs[20], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X21) { - sequence = - PrintRegister64("x21", frame_arm64->context.iregs[21], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X22) { - sequence = - PrintRegister64("x22", frame_arm64->context.iregs[22], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X23) { - sequence = - PrintRegister64("x23", frame_arm64->context.iregs[23], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X24) { - sequence = - PrintRegister64("x24", frame_arm64->context.iregs[24], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X25) { - sequence = - PrintRegister64("x25", frame_arm64->context.iregs[25], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X26) { - sequence = - PrintRegister64("x26", frame_arm64->context.iregs[26], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X27) { - sequence = - PrintRegister64("x27", frame_arm64->context.iregs[27], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X28) { - sequence = - PrintRegister64("x28", frame_arm64->context.iregs[28], sequence); - } + // Inlined frames don't have registers info. + if (frame->trust != StackFrameAMD64::FRAME_TRUST_INLINE) { + int sequence = 0; + if (cpu == "x86") { + const StackFrameX86* frame_x86 = + reinterpret_cast<const StackFrameX86*>(frame); + + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP) + sequence = PrintRegister("eip", frame_x86->context.eip, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) + sequence = PrintRegister("esp", frame_x86->context.esp, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP) + sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX) + sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI) + sequence = PrintRegister("esi", frame_x86->context.esi, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI) + sequence = PrintRegister("edi", frame_x86->context.edi, sequence); + if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) { + sequence = PrintRegister("eax", frame_x86->context.eax, sequence); + sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence); + sequence = PrintRegister("edx", frame_x86->context.edx, sequence); + sequence = PrintRegister("efl", frame_x86->context.eflags, sequence); + } + } else if (cpu == "ppc") { + const StackFramePPC* frame_ppc = + reinterpret_cast<const StackFramePPC*>(frame); + + if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0) + sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); + if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1) + sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence); + } else if (cpu == "amd64") { + const StackFrameAMD64* frame_amd64 = + reinterpret_cast<const StackFrameAMD64*>(frame); + + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RAX) + sequence = PrintRegister64("rax", frame_amd64->context.rax, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDX) + sequence = PrintRegister64("rdx", frame_amd64->context.rdx, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RCX) + sequence = PrintRegister64("rcx", frame_amd64->context.rcx, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBX) + sequence = PrintRegister64("rbx", frame_amd64->context.rbx, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSI) + sequence = PrintRegister64("rsi", frame_amd64->context.rsi, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDI) + sequence = PrintRegister64("rdi", frame_amd64->context.rdi, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP) + sequence = PrintRegister64("rbp", frame_amd64->context.rbp, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) + sequence = PrintRegister64("rsp", frame_amd64->context.rsp, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R8) + sequence = PrintRegister64("r8", frame_amd64->context.r8, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R9) + sequence = PrintRegister64("r9", frame_amd64->context.r9, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R10) + sequence = PrintRegister64("r10", frame_amd64->context.r10, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R11) + sequence = PrintRegister64("r11", frame_amd64->context.r11, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R12) + sequence = PrintRegister64("r12", frame_amd64->context.r12, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R13) + sequence = PrintRegister64("r13", frame_amd64->context.r13, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R14) + sequence = PrintRegister64("r14", frame_amd64->context.r14, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R15) + sequence = PrintRegister64("r15", frame_amd64->context.r15, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP) + sequence = PrintRegister64("rip", frame_amd64->context.rip, sequence); + } else if (cpu == "sparc") { + const StackFrameSPARC* frame_sparc = + reinterpret_cast<const StackFrameSPARC*>(frame); + + if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP) + sequence = + PrintRegister("sp", frame_sparc->context.g_r[14], sequence); + if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP) + sequence = + PrintRegister("fp", frame_sparc->context.g_r[30], sequence); + if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC) + sequence = PrintRegister("pc", frame_sparc->context.pc, sequence); + } else if (cpu == "arm") { + const StackFrameARM* frame_arm = + reinterpret_cast<const StackFrameARM*>(frame); + + // Argument registers (caller-saves), which will likely only be valid + // for the youngest frame. + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0) + sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1) + sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2) + sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3) + sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence); + + // General-purpose callee-saves registers. + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4) + sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R5) + sequence = PrintRegister("r5", frame_arm->context.iregs[5], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R6) + sequence = PrintRegister("r6", frame_arm->context.iregs[6], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R7) + sequence = PrintRegister("r7", frame_arm->context.iregs[7], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R8) + sequence = PrintRegister("r8", frame_arm->context.iregs[8], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R9) + sequence = PrintRegister("r9", frame_arm->context.iregs[9], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R10) + sequence = + PrintRegister("r10", frame_arm->context.iregs[10], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R12) + sequence = + PrintRegister("r12", frame_arm->context.iregs[12], sequence); + + // Registers with a dedicated or conventional purpose. + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_FP) + sequence = + PrintRegister("fp", frame_arm->context.iregs[11], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) + sequence = + PrintRegister("sp", frame_arm->context.iregs[13], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_LR) + sequence = + PrintRegister("lr", frame_arm->context.iregs[14], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_PC) + sequence = + PrintRegister("pc", frame_arm->context.iregs[15], sequence); + } else if (cpu == "arm64") { + const StackFrameARM64* frame_arm64 = + reinterpret_cast<const StackFrameARM64*>(frame); + + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X0) { + sequence = + PrintRegister64("x0", frame_arm64->context.iregs[0], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X1) { + sequence = + PrintRegister64("x1", frame_arm64->context.iregs[1], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X2) { + sequence = + PrintRegister64("x2", frame_arm64->context.iregs[2], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X3) { + sequence = + PrintRegister64("x3", frame_arm64->context.iregs[3], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X4) { + sequence = + PrintRegister64("x4", frame_arm64->context.iregs[4], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X5) { + sequence = + PrintRegister64("x5", frame_arm64->context.iregs[5], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X6) { + sequence = + PrintRegister64("x6", frame_arm64->context.iregs[6], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X7) { + sequence = + PrintRegister64("x7", frame_arm64->context.iregs[7], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X8) { + sequence = + PrintRegister64("x8", frame_arm64->context.iregs[8], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X9) { + sequence = + PrintRegister64("x9", frame_arm64->context.iregs[9], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X10) { + sequence = + PrintRegister64("x10", frame_arm64->context.iregs[10], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X11) { + sequence = + PrintRegister64("x11", frame_arm64->context.iregs[11], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X12) { + sequence = + PrintRegister64("x12", frame_arm64->context.iregs[12], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X13) { + sequence = + PrintRegister64("x13", frame_arm64->context.iregs[13], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X14) { + sequence = + PrintRegister64("x14", frame_arm64->context.iregs[14], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X15) { + sequence = + PrintRegister64("x15", frame_arm64->context.iregs[15], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X16) { + sequence = + PrintRegister64("x16", frame_arm64->context.iregs[16], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X17) { + sequence = + PrintRegister64("x17", frame_arm64->context.iregs[17], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X18) { + sequence = + PrintRegister64("x18", frame_arm64->context.iregs[18], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X19) { + sequence = + PrintRegister64("x19", frame_arm64->context.iregs[19], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X20) { + sequence = + PrintRegister64("x20", frame_arm64->context.iregs[20], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X21) { + sequence = + PrintRegister64("x21", frame_arm64->context.iregs[21], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X22) { + sequence = + PrintRegister64("x22", frame_arm64->context.iregs[22], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X23) { + sequence = + PrintRegister64("x23", frame_arm64->context.iregs[23], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X24) { + sequence = + PrintRegister64("x24", frame_arm64->context.iregs[24], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X25) { + sequence = + PrintRegister64("x25", frame_arm64->context.iregs[25], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X26) { + sequence = + PrintRegister64("x26", frame_arm64->context.iregs[26], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X27) { + sequence = + PrintRegister64("x27", frame_arm64->context.iregs[27], sequence); + } + if (frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_X28) { + sequence = + PrintRegister64("x28", frame_arm64->context.iregs[28], sequence); + } - // Registers with a dedicated or conventional purpose. - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_FP) { - sequence = - PrintRegister64("fp", frame_arm64->context.iregs[29], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_LR) { - sequence = - PrintRegister64("lr", frame_arm64->context.iregs[30], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) { - sequence = - PrintRegister64("sp", frame_arm64->context.iregs[31], sequence); - } - if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_PC) { - sequence = - PrintRegister64("pc", frame_arm64->context.iregs[32], sequence); + // Registers with a dedicated or conventional purpose. + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_FP) { + sequence = + PrintRegister64("fp", frame_arm64->context.iregs[29], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_LR) { + sequence = + PrintRegister64("lr", frame_arm64->context.iregs[30], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) { + sequence = + PrintRegister64("sp", frame_arm64->context.iregs[31], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_PC) { + sequence = + PrintRegister64("pc", frame_arm64->context.iregs[32], sequence); + } + } else if ((cpu == "mips") || (cpu == "mips64")) { + const StackFrameMIPS* frame_mips = + reinterpret_cast<const StackFrameMIPS*>(frame); + + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_GP) + sequence = PrintRegister64( + "gp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_GP], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_SP) + sequence = PrintRegister64( + "sp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_SP], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_FP) + sequence = PrintRegister64( + "fp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_FP], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_RA) + sequence = PrintRegister64( + "ra", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_RA], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_PC) + sequence = PrintRegister64("pc", frame_mips->context.epc, sequence); + + // Save registers s0-s7 + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S0) + sequence = PrintRegister64( + "s0", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S0], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S1) + sequence = PrintRegister64( + "s1", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S1], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S2) + sequence = PrintRegister64( + "s2", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S2], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S3) + sequence = PrintRegister64( + "s3", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S3], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S4) + sequence = PrintRegister64( + "s4", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S4], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S5) + sequence = PrintRegister64( + "s5", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S5], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6) + sequence = PrintRegister64( + "s6", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7) + sequence = PrintRegister64( + "s7", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7], + sequence); + } else if (cpu == "riscv") { + const StackFrameRISCV* frame_riscv = + reinterpret_cast<const StackFrameRISCV*>(frame); + + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_PC) + sequence = PrintRegister( + "pc", frame_riscv->context.pc, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_RA) + sequence = PrintRegister( + "ra", frame_riscv->context.ra, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_SP) + sequence = PrintRegister( + "sp", frame_riscv->context.sp, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_GP) + sequence = PrintRegister( + "gp", frame_riscv->context.gp, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_TP) + sequence = PrintRegister( + "tp", frame_riscv->context.tp, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_T0) + sequence = PrintRegister( + "t0", frame_riscv->context.t0, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_T1) + sequence = PrintRegister( + "t1", frame_riscv->context.t1, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_T2) + sequence = PrintRegister( + "t2", frame_riscv->context.t2, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S0) + sequence = PrintRegister( + "s0", frame_riscv->context.s0, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S1) + sequence = PrintRegister( + "s1", frame_riscv->context.s1, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_A0) + sequence = PrintRegister( + "a0", frame_riscv->context.a0, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_A1) + sequence = PrintRegister( + "a1", frame_riscv->context.a1, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_A2) + sequence = PrintRegister( + "a2", frame_riscv->context.a2, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_A3) + sequence = PrintRegister( + "a3", frame_riscv->context.a3, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_A4) + sequence = PrintRegister( + "a4", frame_riscv->context.a4, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_A5) + sequence = PrintRegister( + "a5", frame_riscv->context.a5, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_A6) + sequence = PrintRegister( + "a6", frame_riscv->context.a6, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_A7) + sequence = PrintRegister( + "a7", frame_riscv->context.a7, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S2) + sequence = PrintRegister( + "s2", frame_riscv->context.s2, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S3) + sequence = PrintRegister( + "s3", frame_riscv->context.s3, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S4) + sequence = PrintRegister( + "s4", frame_riscv->context.s4, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S5) + sequence = PrintRegister( + "s5", frame_riscv->context.s5, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S6) + sequence = PrintRegister( + "s6", frame_riscv->context.s6, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S7) + sequence = PrintRegister( + "s7", frame_riscv->context.s7, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S8) + sequence = PrintRegister( + "s8", frame_riscv->context.s8, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S9) + sequence = PrintRegister( + "s9", frame_riscv->context.s9, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S10) + sequence = PrintRegister( + "s10", frame_riscv->context.s10, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_S11) + sequence = PrintRegister( + "s11", frame_riscv->context.s11, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_T3) + sequence = PrintRegister( + "t3", frame_riscv->context.t3, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_T4) + sequence = PrintRegister( + "t4", frame_riscv->context.t4, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_T5) + sequence = PrintRegister( + "t5", frame_riscv->context.t5, sequence); + if (frame_riscv->context_validity & + StackFrameRISCV::CONTEXT_VALID_T6) + sequence = PrintRegister( + "t6", frame_riscv->context.t6, sequence); + } else if (cpu == "riscv64") { + const StackFrameRISCV64* frame_riscv64 = + reinterpret_cast<const StackFrameRISCV64*>(frame); + + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_PC) + sequence = PrintRegister64( + "pc", frame_riscv64->context.pc, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_RA) + sequence = PrintRegister64( + "ra", frame_riscv64->context.ra, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_SP) + sequence = PrintRegister64( + "sp", frame_riscv64->context.sp, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_GP) + sequence = PrintRegister64( + "gp", frame_riscv64->context.gp, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_TP) + sequence = PrintRegister64( + "tp", frame_riscv64->context.tp, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_T0) + sequence = PrintRegister64( + "t0", frame_riscv64->context.t0, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_T1) + sequence = PrintRegister64( + "t1", frame_riscv64->context.t1, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_T2) + sequence = PrintRegister64( + "t2", frame_riscv64->context.t2, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S0) + sequence = PrintRegister64( + "s0", frame_riscv64->context.s0, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S1) + sequence = PrintRegister64( + "s1", frame_riscv64->context.s1, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_A0) + sequence = PrintRegister64( + "a0", frame_riscv64->context.a0, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_A1) + sequence = PrintRegister64( + "a1", frame_riscv64->context.a1, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_A2) + sequence = PrintRegister64( + "a2", frame_riscv64->context.a2, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_A3) + sequence = PrintRegister64( + "a3", frame_riscv64->context.a3, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_A4) + sequence = PrintRegister64( + "a4", frame_riscv64->context.a4, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_A5) + sequence = PrintRegister64( + "a5", frame_riscv64->context.a5, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_A6) + sequence = PrintRegister64( + "a6", frame_riscv64->context.a6, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_A7) + sequence = PrintRegister64( + "a7", frame_riscv64->context.a7, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S2) + sequence = PrintRegister64( + "s2", frame_riscv64->context.s2, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S3) + sequence = PrintRegister64( + "s3", frame_riscv64->context.s3, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S4) + sequence = PrintRegister64( + "s4", frame_riscv64->context.s4, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S5) + sequence = PrintRegister64( + "s5", frame_riscv64->context.s5, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S6) + sequence = PrintRegister64( + "s6", frame_riscv64->context.s6, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S7) + sequence = PrintRegister64( + "s7", frame_riscv64->context.s7, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S8) + sequence = PrintRegister64( + "s8", frame_riscv64->context.s8, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S9) + sequence = PrintRegister64( + "s9", frame_riscv64->context.s9, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S10) + sequence = PrintRegister64( + "s10", frame_riscv64->context.s10, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S11) + sequence = PrintRegister64( + "s11", frame_riscv64->context.s11, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_T3) + sequence = PrintRegister64( + "t3", frame_riscv64->context.t3, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_T4) + sequence = PrintRegister64( + "t4", frame_riscv64->context.t4, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_T5) + sequence = PrintRegister64( + "t5", frame_riscv64->context.t5, sequence); + if (frame_riscv64->context_validity & + StackFrameRISCV64::CONTEXT_VALID_T6) + sequence = PrintRegister64( + "t6", frame_riscv64->context.t6, sequence); } - } else if ((cpu == "mips") || (cpu == "mips64")) { - const StackFrameMIPS* frame_mips = - reinterpret_cast<const StackFrameMIPS*>(frame); - - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_GP) - sequence = PrintRegister64("gp", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_GP], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_SP) - sequence = PrintRegister64("sp", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_SP], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_FP) - sequence = PrintRegister64("fp", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_FP], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_RA) - sequence = PrintRegister64("ra", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_RA], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_PC) - sequence = PrintRegister64("pc", frame_mips->context.epc, sequence); - - // Save registers s0-s7 - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S0) - sequence = PrintRegister64("s0", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S0], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S1) - sequence = PrintRegister64("s1", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S1], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S2) - sequence = PrintRegister64("s2", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S2], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S3) - sequence = PrintRegister64("s3", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S3], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S4) - sequence = PrintRegister64("s4", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S4], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S5) - sequence = PrintRegister64("s5", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S5], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6) - sequence = PrintRegister64("s6", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6], - sequence); - if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7) - sequence = PrintRegister64("s7", - frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7], - sequence); } printf("\n Found by: %s\n", frame->trust_description().c_str()); @@ -621,10 +948,10 @@ static void PrintStack(const CallStack *stack, // Module, function, source file, and source line may all be empty // depending on availability. The code offset follows the same rules as // PrintStack above. -static void PrintStackMachineReadable(int thread_num, const CallStack *stack) { +static void PrintStackMachineReadable(int thread_num, const CallStack* stack) { int frame_count = stack->frames()->size(); for (int frame_index = 0; frame_index < frame_count; ++frame_index) { - const StackFrame *frame = stack->frames()->at(frame_index); + const StackFrame* frame = stack->frames()->at(frame_index); printf("%d%c%d%c", thread_num, kOutputSeparator, frame_index, kOutputSeparator); @@ -676,8 +1003,8 @@ static void PrintStackMachineReadable(int thread_num, const CallStack *stack) { // ContainsModule checks whether a given |module| is in the vector // |modules_without_symbols|. static bool ContainsModule( - const vector<const CodeModule*> *modules, - const CodeModule *module) { + const vector<const CodeModule*>* modules, + const CodeModule* module) { assert(modules); assert(module); vector<const CodeModule*>::const_iterator iter; @@ -694,9 +1021,9 @@ static bool ContainsModule( // |modules_without_symbols| should contain the list of modules that were // confirmed to be missing their symbols during the stack walk. static void PrintModule( - const CodeModule *module, - const vector<const CodeModule*> *modules_without_symbols, - const vector<const CodeModule*> *modules_with_corrupt_symbols, + const CodeModule* module, + const vector<const CodeModule*>* modules_without_symbols, + const vector<const CodeModule*>* modules_with_corrupt_symbols, uint64_t main_address) { string symbol_issues; if (ContainsModule(modules_without_symbols, module)) { @@ -721,9 +1048,9 @@ static void PrintModule( // |modules_without_symbols| should contain the list of modules that were // confirmed to be missing their symbols during the stack walk. static void PrintModules( - const CodeModules *modules, - const vector<const CodeModule*> *modules_without_symbols, - const vector<const CodeModule*> *modules_with_corrupt_symbols) { + const CodeModules* modules, + const vector<const CodeModule*>* modules_without_symbols, + const vector<const CodeModule*>* modules_with_corrupt_symbols) { if (!modules) return; @@ -731,7 +1058,7 @@ static void PrintModules( printf("Loaded modules:\n"); uint64_t main_address = 0; - const CodeModule *main_module = modules->GetMainModule(); + const CodeModule* main_module = modules->GetMainModule(); if (main_module) { main_address = main_module->base_address(); } @@ -740,7 +1067,7 @@ static void PrintModules( for (unsigned int module_sequence = 0; module_sequence < module_count; ++module_sequence) { - const CodeModule *module = modules->GetModuleAtSequence(module_sequence); + const CodeModule* module = modules->GetModuleAtSequence(module_sequence); PrintModule(module, modules_without_symbols, modules_with_corrupt_symbols, main_address); } @@ -751,12 +1078,12 @@ static void PrintModules( // text format: // Module|{Module Filename}|{Version}|{Debug Filename}|{Debug Identifier}| // {Base Address}|{Max Address}|{Main} -static void PrintModulesMachineReadable(const CodeModules *modules) { +static void PrintModulesMachineReadable(const CodeModules* modules) { if (!modules) return; uint64_t main_address = 0; - const CodeModule *main_module = modules->GetMainModule(); + const CodeModule* main_module = modules->GetMainModule(); if (main_module) { main_address = main_module->base_address(); } @@ -765,7 +1092,7 @@ static void PrintModulesMachineReadable(const CodeModules *modules) { for (unsigned int module_sequence = 0; module_sequence < module_count; ++module_sequence) { - const CodeModule *module = modules->GetModuleAtSequence(module_sequence); + const CodeModule* module = modules->GetModuleAtSequence(module_sequence); uint64_t base_address = module->base_address(); printf("Module%c%s%c%s%c%s%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n", kOutputSeparator, @@ -786,6 +1113,7 @@ static void PrintModulesMachineReadable(const CodeModules *modules) { void PrintProcessState(const ProcessState& process_state, bool output_stack_contents, + bool output_requesting_thread_only, SourceLineResolverInterface* resolver) { // Print OS and CPU information. string cpu = process_state.system_info()->cpu; @@ -856,17 +1184,19 @@ void PrintProcessState(const ProcessState& process_state, process_state.modules(), resolver); } - // Print all of the threads in the dump. - int thread_count = process_state.threads()->size(); - for (int thread_index = 0; thread_index < thread_count; ++thread_index) { - if (thread_index != requesting_thread) { - // Don't print the crash thread again, it was already printed. - printf("\n"); - printf("Thread %d\n", thread_index); - PrintStack(process_state.threads()->at(thread_index), cpu, - output_stack_contents, - process_state.thread_memory_regions()->at(thread_index), - process_state.modules(), resolver); + if (!output_requesting_thread_only) { + // Print all of the threads in the dump. + int thread_count = process_state.threads()->size(); + for (int thread_index = 0; thread_index < thread_count; ++thread_index) { + if (thread_index != requesting_thread) { + // Don't print the crash thread again, it was already printed. + printf("\n"); + printf("Thread %d\n", thread_index); + PrintStack(process_state.threads()->at(thread_index), cpu, + output_stack_contents, + process_state.thread_memory_regions()->at(thread_index), + process_state.modules(), resolver); + } } } diff --git a/src/processor/stackwalk_common.h b/src/processor/stackwalk_common.h index a74f7b6d..bb12b98f 100644 --- a/src/processor/stackwalk_common.h +++ b/src/processor/stackwalk_common.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,6 +41,7 @@ class SourceLineResolverInterface; void PrintProcessStateMachineReadable(const ProcessState& process_state); void PrintProcessState(const ProcessState& process_state, bool output_stack_contents, + bool output_requesting_thread_only, SourceLineResolverInterface* resolver); } // namespace google_breakpad diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index 4988ef1e..e607b721 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -55,6 +54,8 @@ #include "processor/stackwalker_arm.h" #include "processor/stackwalker_arm64.h" #include "processor/stackwalker_mips.h" +#include "processor/stackwalker_riscv.h" +#include "processor/stackwalker_riscv64.h" namespace google_breakpad { @@ -138,11 +139,12 @@ bool Stackwalker::Walk( // frame_pointer fields. The frame structure comes from either the // context frame (above) or a caller frame (below). + std::deque<std::unique_ptr<StackFrame>> inlined_frames; // Resolve the module information, if a module map was provided. StackFrameSymbolizer::SymbolizerResult symbolizer_result = frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_, system_info_, - frame.get()); + frame.get(), &inlined_frames); switch (symbolizer_result) { case StackFrameSymbolizer::kInterrupt: BPLOG(INFO) << "Stack walk is interrupted."; @@ -173,7 +175,12 @@ bool Stackwalker::Walk( default: break; } - + // Add all nested inlined frames belonging to this frame from the innermost + // frame to the outermost frame. + while (!inlined_frames.empty()) { + stack->frames_.push_back(inlined_frames.front().release()); + inlined_frames.pop_front(); + } // Add the frame to the call stack. Relinquish the ownership claim // over the frame, because the stack now owns it. stack->frames_.push_back(frame.release()); @@ -265,6 +272,20 @@ Stackwalker* Stackwalker::StackwalkerForCPU( memory, modules, frame_symbolizer); break; + + case MD_CONTEXT_RISCV: + cpu_stackwalker = new StackwalkerRISCV(system_info, + context->GetContextRISCV(), + memory, modules, + frame_symbolizer); + break; + + case MD_CONTEXT_RISCV64: + cpu_stackwalker = new StackwalkerRISCV64(system_info, + context->GetContextRISCV64(), + memory, modules, + frame_symbolizer); + break; } BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) << @@ -307,7 +328,7 @@ bool Stackwalker::InstructionAddressSeemsValid(uint64_t address) const { frame.instruction = address; StackFrameSymbolizer::SymbolizerResult symbolizer_result = frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_, - system_info_, &frame); + system_info_, &frame, nullptr); if (!frame.module) { // not inside any loaded module diff --git a/src/processor/stackwalker_address_list.cc b/src/processor/stackwalker_address_list.cc index e81fec28..b393d475 100644 --- a/src/processor/stackwalker_address_list.cc +++ b/src/processor/stackwalker_address_list.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/stackwalker_address_list.h b/src/processor/stackwalker_address_list.h index 0f8c989e..28d377c3 100644 --- a/src/processor/stackwalker_address_list.h +++ b/src/processor/stackwalker_address_list.h @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/stackwalker_address_list_unittest.cc b/src/processor/stackwalker_address_list_unittest.cc index ab4e9c08..feda6268 100644 --- a/src/processor/stackwalker_address_list_unittest.cc +++ b/src/processor/stackwalker_address_list_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -56,6 +55,7 @@ using google_breakpad::StackwalkerAddressList; using std::vector; using testing::_; using testing::AnyNumber; +using testing::DoAll; using testing::Return; using testing::SetArgumentPointee; @@ -94,9 +94,9 @@ class StackwalkerAddressListTest : public testing::Test { // Set the Breakpad symbol information that supplier should return for // MODULE to INFO. - void SetModuleSymbols(MockCodeModule *module, const string &info) { + void SetModuleSymbols(MockCodeModule* module, const string& info) { size_t buffer_size; - char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + char* buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); EXPECT_CALL(supplier, GetCStringSymbolData(module, NULL, _, _, _)) .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), SetArgumentPointee<4>(buffer_size), diff --git a/src/processor/stackwalker_amd64.cc b/src/processor/stackwalker_amd64.cc index d5ac6c65..6a539709 100644 --- a/src/processor/stackwalker_amd64.cc +++ b/src/processor/stackwalker_amd64.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -126,7 +125,7 @@ StackFrame* StackwalkerAMD64::GetContextFrame() { } StackFrameAMD64* StackwalkerAMD64::GetCallerByCFIFrameInfo( - const vector<StackFrame*> &frames, + const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info) { StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back()); @@ -143,6 +142,11 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByCFIFrameInfo( if ((frame->context_validity & essentials) != essentials) return NULL; + if (!frame->context.rip || !frame->context.rsp) { + BPLOG(ERROR) << "invalid rip/rsp"; + return NULL; + } + frame->trust = StackFrame::FRAME_TRUST_CFI; return frame.release(); } @@ -216,14 +220,44 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery( return NULL; } +StackFrameAMD64* StackwalkerAMD64::GetCallerBySimulatingReturn( + const vector<StackFrame*>& frames) { + assert(frames.back()->trust == StackFrame::FRAME_TRUST_CONTEXT); + StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back()); + uint64_t last_rsp = last_frame->context.rsp; + uint64_t caller_rip_address, caller_rip; + int searchwords = 1; + if (!ScanForReturnAddress(last_rsp, &caller_rip_address, &caller_rip, + searchwords)) { + // No plausible return address at the top of the stack. Unable to simulate + // a return. + return NULL; + } + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameAMD64* frame = new StackFrameAMD64(); + + frame->trust = StackFrame::FRAME_TRUST_LEAF; + frame->context = last_frame->context; + frame->context.rip = caller_rip; + // The caller's %rsp is directly underneath the return address pushed by + // the call. + frame->context.rsp = caller_rip_address + 8; + frame->context_validity = last_frame->context_validity; + + return frame; +} + StackFrameAMD64* StackwalkerAMD64::GetCallerByStackScan( - const vector<StackFrame*> &frames) { + const vector<StackFrame*>& frames) { StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back()); uint64_t last_rsp = last_frame->context.rsp; uint64_t caller_rip_address, caller_rip; if (!ScanForReturnAddress(last_rsp, &caller_rip_address, &caller_rip, - frames.size() == 1 /* is_context_frame */)) { + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { // No plausible return address was found. return NULL; } @@ -273,18 +307,32 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack, return NULL; } - const vector<StackFrame*> &frames = *stack->frames(); + const vector<StackFrame*>& frames = *stack->frames(); StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back()); scoped_ptr<StackFrameAMD64> new_frame; - // If we have DWARF CFI information, use it. + // If we have CFI information, use it. scoped_ptr<CFIFrameInfo> cfi_frame_info( frame_symbolizer_->FindCFIFrameInfo(last_frame)); if (cfi_frame_info.get()) new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); + // If CFI was not available and this is a Windows x64 stack, check whether + // this is a leaf function which doesn't touch any callee-saved registers. + // According to https://reviews.llvm.org/D24748, LLVM doesn't generate unwind + // info for such functions. According to MSDN, leaf functions can be unwound + // simply by simulating a return. + if (!new_frame.get() && + last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT && + system_info_->os_short == "windows") { + new_frame.reset(GetCallerBySimulatingReturn(frames)); + } + // If CFI was not available or failed, try using frame pointer recovery. - if (!new_frame.get()) { + // Never try to use frame pointer unwinding on Windows x64 stack. MSVC never + // generates code that works with frame pointer chasing, and LLVM does the + // same. Stack scanning would be better. + if (!new_frame.get() && system_info_->os_short != "windows") { new_frame.reset(GetCallerByFramePointerRecovery(frames)); } @@ -309,7 +357,9 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack, // Should we terminate the stack walk? (end-of-stack or broken invariant) if (TerminateWalk(new_frame->context.rip, new_frame->context.rsp, - last_frame->context.rsp, frames.size() == 1)) { + last_frame->context.rsp, + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { return NULL; } diff --git a/src/processor/stackwalker_amd64.h b/src/processor/stackwalker_amd64.h index 8f3dbd52..307f2444 100644 --- a/src/processor/stackwalker_amd64.h +++ b/src/processor/stackwalker_amd64.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -75,7 +74,7 @@ class StackwalkerAMD64 : public Stackwalker { // Use cfi_frame_info (derived from STACK CFI records) to construct // the frame that called frames.back(). The caller takes ownership // of the returned frame. Return NULL on failure. - StackFrameAMD64* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames, + StackFrameAMD64* GetCallerByCFIFrameInfo(const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info); // Assumes a traditional frame layout where the frame pointer has not been @@ -88,7 +87,12 @@ class StackwalkerAMD64 : public Stackwalker { // 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); + StackFrameAMD64* GetCallerByStackScan(const vector<StackFrame*>& frames); + + // Trying to simulate a return. The caller takes ownership of the returned + // frame. Return NULL on failure. + StackFrameAMD64* GetCallerBySimulatingReturn( + const vector<StackFrame*>& frames); // Stores the CPU context corresponding to the innermost stack frame to // be returned by GetContextFrame. diff --git a/src/processor/stackwalker_amd64_unittest.cc b/src/processor/stackwalker_amd64_unittest.cc index efcd812a..a7e513e9 100644 --- a/src/processor/stackwalker_amd64_unittest.cc +++ b/src/processor/stackwalker_amd64_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -104,7 +103,7 @@ class StackwalkerAMD64Fixture { // Set the Breakpad symbol information that supplier should return for // MODULE to INFO. - void SetModuleSymbols(MockCodeModule *module, const string &info) { + void SetModuleSymbols(MockCodeModule* module, const string& info) { size_t buffer_size; char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) @@ -125,7 +124,7 @@ class StackwalkerAMD64Fixture { void BrandContext(MDRawContextAMD64 *raw_context) { uint8_t x = 173; for (size_t i = 0; i < sizeof(*raw_context); i++) - reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17); + reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17); } SystemInfo system_info; @@ -138,7 +137,7 @@ class StackwalkerAMD64Fixture { MockSymbolSupplier supplier; BasicSourceLineResolver resolver; CallStack call_stack; - const vector<StackFrame *> *frames; + const vector<StackFrame*>* frames; }; class GetContextFrame: public StackwalkerAMD64Fixture, public Test { }; @@ -166,7 +165,7 @@ TEST_F(SanityCheck, NoResolver) { ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); ASSERT_GE(1U, frames->size()); - StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -192,7 +191,7 @@ TEST_F(GetContextFrame, Simple) { ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); ASSERT_GE(1U, frames->size()); - StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -216,7 +215,7 @@ TEST_F(GetContextFrame, NoStackMemory) { ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); ASSERT_GE(1U, frames->size()); - StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -279,12 +278,12 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) { frames = call_stack.frames(); ASSERT_EQ(3U, frames->size()); - StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP | @@ -294,7 +293,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) { EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp); - StackFrameAMD64 *frame2 = static_cast<StackFrameAMD64 *>(frames->at(2)); + StackFrameAMD64 *frame2 = static_cast<StackFrameAMD64*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP), @@ -352,13 +351,13 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ("platypus", frame0->function_name); EXPECT_EQ(0x00007400c0000100ULL, frame0->function_base); - StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP | @@ -464,7 +463,7 @@ TEST_F(GetCallerFrame, GetCallerByFramePointerRecovery) { ASSERT_EQ(3U, frames->size()); { // To avoid reusing locals by mistake - StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame->trust); ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame->context_validity); EXPECT_EQ("", frame->function_name); @@ -475,7 +474,7 @@ TEST_F(GetCallerFrame, GetCallerByFramePointerRecovery) { } { // To avoid reusing locals by mistake - StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(1)); + StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP | @@ -489,7 +488,7 @@ TEST_F(GetCallerFrame, GetCallerByFramePointerRecovery) { } { // To avoid reusing locals by mistake - StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(2)); + StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP | @@ -540,12 +539,12 @@ TEST_F(GetCallerFrame, FramePointerNotAligned) { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP), @@ -590,12 +589,12 @@ TEST_F(GetCallerFrame, NonCanonicalInstructionPointerFromFramePointer) { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP), @@ -660,7 +659,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) { frames = call_stack.frames(); ASSERT_EQ(1U, frames->size()); - StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); @@ -718,14 +717,14 @@ TEST_F(GetCallerFrame, CallerPushedRBP) { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(frame0_rbp.Value(), frame0->context.rbp); EXPECT_EQ("sasquatch", frame0->function_name); EXPECT_EQ(0x00007400c0000100ULL, frame0->function_base); - StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP | @@ -799,13 +798,13 @@ struct CFIFixture: public StackwalkerAMD64Fixture { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0)); + StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ("enchiridion", frame0->function_name); EXPECT_EQ(0x00007400c0004000ULL, frame0->function_base); - StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1)); + StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | StackFrameAMD64::CONTEXT_VALID_RSP | diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc index 1313416f..7df2eb6d 100644 --- a/src/processor/stackwalker_arm.cc +++ b/src/processor/stackwalker_arm.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -78,7 +77,7 @@ StackFrame* StackwalkerARM::GetContextFrame() { } StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( - const vector<StackFrame*> &frames, + const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info) { StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); @@ -162,13 +161,14 @@ StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( } StackFrameARM* StackwalkerARM::GetCallerByStackScan( - const vector<StackFrame*> &frames) { + const vector<StackFrame*>& frames) { StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; uint32_t caller_sp, caller_pc; if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, - frames.size() == 1 /* is_context_frame */)) { + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { // No plausible return address was found. return NULL; } @@ -193,7 +193,7 @@ StackFrameARM* StackwalkerARM::GetCallerByStackScan( } StackFrameARM* StackwalkerARM::GetCallerByFramePointer( - const vector<StackFrame*> &frames) { + const vector<StackFrame*>& frames) { StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); if (!(last_frame->context_validity & @@ -245,7 +245,7 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack, return NULL; } - const vector<StackFrame*> &frames = *stack->frames(); + const vector<StackFrame*>& frames = *stack->frames(); StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); scoped_ptr<StackFrameARM> frame; @@ -276,7 +276,8 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack, if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM_REG_PC], frame->context.iregs[MD_CONTEXT_ARM_REG_SP], last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP], - frames.size() == 1)) { + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { return NULL; } diff --git a/src/processor/stackwalker_arm.h b/src/processor/stackwalker_arm.h index 9081a40c..d95b4e32 100644 --- a/src/processor/stackwalker_arm.h +++ b/src/processor/stackwalker_arm.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -75,16 +74,16 @@ class StackwalkerARM : public Stackwalker { // Use cfi_frame_info (derived from STACK CFI records) to construct // the frame that called frames.back(). The caller takes ownership // of the returned frame. Return NULL on failure. - StackFrameARM* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames, + StackFrameARM* GetCallerByCFIFrameInfo(const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info); // Use the frame pointer. The caller takes ownership of the returned frame. // Return NULL on failure. - StackFrameARM* GetCallerByFramePointer(const vector<StackFrame*> &frames); + StackFrameARM* GetCallerByFramePointer(const vector<StackFrame*>& frames); // Scan the stack for plausible return addresses. The caller takes ownership // of the returned frame. Return NULL on failure. - StackFrameARM* GetCallerByStackScan(const vector<StackFrame*> &frames); + StackFrameARM* GetCallerByStackScan(const vector<StackFrame*>& frames); // Stores the CPU context corresponding to the youngest stack frame, to // be returned by GetContextFrame. diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc index 5bfd2636..ae3a0595 100644 --- a/src/processor/stackwalker_arm64.cc +++ b/src/processor/stackwalker_arm64.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -99,7 +98,7 @@ StackFrame* StackwalkerARM64::GetContextFrame() { } StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo( - const vector<StackFrame*> &frames, + const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info) { StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back()); @@ -170,18 +169,21 @@ StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo( if ((frame->context_validity & essentials) != essentials) return NULL; + frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = + PtrauthStrip(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC]); frame->trust = StackFrame::FRAME_TRUST_CFI; return frame.release(); } StackFrameARM64* StackwalkerARM64::GetCallerByStackScan( - const vector<StackFrame*> &frames) { + const vector<StackFrame*>& frames) { StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back()); uint64_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]; uint64_t caller_sp, caller_pc; if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, - frames.size() == 1 /* is_context_frame */)) { + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { // No plausible return address was found. return NULL; } @@ -206,7 +208,7 @@ StackFrameARM64* StackwalkerARM64::GetCallerByStackScan( } StackFrameARM64* StackwalkerARM64::GetCallerByFramePointer( - const vector<StackFrame*> &frames) { + const vector<StackFrame*>& frames) { StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back()); if (!(last_frame->context_validity & StackFrameARM64::CONTEXT_VALID_LR)) { CorrectRegLRByFramePointer(frames, last_frame); @@ -294,7 +296,7 @@ StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack, return NULL; } - const vector<StackFrame*> &frames = *stack->frames(); + const vector<StackFrame*>& frames = *stack->frames(); StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back()); scoped_ptr<StackFrameARM64> frame; @@ -320,7 +322,8 @@ StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack, if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC], frame->context.iregs[MD_CONTEXT_ARM64_REG_SP], last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP], - frames.size() == 1)) { + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { return NULL; } diff --git a/src/processor/stackwalker_arm64.h b/src/processor/stackwalker_arm64.h index 39735c67..193ab302 100644 --- a/src/processor/stackwalker_arm64.h +++ b/src/processor/stackwalker_arm64.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -79,16 +78,16 @@ class StackwalkerARM64 : public Stackwalker { // Use cfi_frame_info (derived from STACK CFI records) to construct // the frame that called frames.back(). The caller takes ownership // of the returned frame. Return NULL on failure. - StackFrameARM64* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames, + StackFrameARM64* GetCallerByCFIFrameInfo(const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info); // Use the frame pointer. The caller takes ownership of the returned frame. // Return NULL on failure. - StackFrameARM64* GetCallerByFramePointer(const vector<StackFrame*> &frames); + StackFrameARM64* GetCallerByFramePointer(const vector<StackFrame*>& frames); // Scan the stack for plausible return addresses. The caller takes ownership // of the returned frame. Return NULL on failure. - StackFrameARM64* GetCallerByStackScan(const vector<StackFrame*> &frames); + StackFrameARM64* GetCallerByStackScan(const vector<StackFrame*>& frames); // GetCallerByFramePointer() depends on the previous frame having recovered // x30($LR) which may not have been done when using CFI. diff --git a/src/processor/stackwalker_arm64_unittest.cc b/src/processor/stackwalker_arm64_unittest.cc index d86fa127..37475058 100644 --- a/src/processor/stackwalker_arm64_unittest.cc +++ b/src/processor/stackwalker_arm64_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -105,7 +104,7 @@ class StackwalkerARM64Fixture { // Set the Breakpad symbol information that supplier should return for // MODULE to INFO. - void SetModuleSymbols(MockCodeModule *module, const string &info) { + void SetModuleSymbols(MockCodeModule* module, const string& info) { size_t buffer_size; char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) @@ -126,7 +125,7 @@ class StackwalkerARM64Fixture { void BrandContext(MDRawContextARM64 *raw_context) { uint8_t x = 173; for (size_t i = 0; i < sizeof(*raw_context); i++) - reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17); + reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17); } SystemInfo system_info; @@ -139,7 +138,7 @@ class StackwalkerARM64Fixture { MockSymbolSupplier supplier; BasicSourceLineResolver resolver; CallStack call_stack; - const vector<StackFrame *> *frames; + const vector<StackFrame*>* frames; }; class SanityCheck: public StackwalkerARM64Fixture, public Test { }; @@ -159,7 +158,7 @@ TEST_F(SanityCheck, NoResolver) { ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); ASSERT_EQ(1U, frames->size()); - StackFrameARM64 *frame = static_cast<StackFrameARM64 *>(frames->at(0)); + StackFrameARM64 *frame = static_cast<StackFrameARM64*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -181,7 +180,7 @@ TEST_F(GetContextFrame, NoStackMemory) { ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); ASSERT_EQ(1U, frames->size()); - StackFrameARM64 *frame = static_cast<StackFrameARM64 *>(frames->at(0)); + StackFrameARM64 *frame = static_cast<StackFrameARM64*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -237,13 +236,13 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) { frames = call_stack.frames(); ASSERT_EQ(3U, frames->size()); - StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0)); + StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1)); + StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | StackFrameARM64::CONTEXT_VALID_SP), @@ -251,7 +250,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) { EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM64_REG_PC]); EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM64_REG_SP]); - StackFrameARM64 *frame2 = static_cast<StackFrameARM64 *>(frames->at(2)); + StackFrameARM64 *frame2 = static_cast<StackFrameARM64*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | StackFrameARM64::CONTEXT_VALID_SP), @@ -307,7 +306,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0)); + StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, frame0->context_validity); @@ -315,7 +314,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { EXPECT_EQ("monotreme", frame0->function_name); EXPECT_EQ(0x40000100ULL, frame0->function_base); - StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1)); + StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | StackFrameARM64::CONTEXT_VALID_SP), @@ -376,13 +375,13 @@ TEST_F(GetCallerFrame, ScanFirstFrame) { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0)); + StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1)); + StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | StackFrameARM64::CONTEXT_VALID_SP), @@ -440,7 +439,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) { frames = call_stack.frames(); ASSERT_EQ(1U, frames->size()); - StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0)); + StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, frame0->context_validity); @@ -503,13 +502,13 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) { frames = call_stack.frames(); ASSERT_EQ(3U, frames->size()); - StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0)); + StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1)); + StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | StackFrameARM64::CONTEXT_VALID_LR | @@ -522,7 +521,7 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) { EXPECT_EQ(frame2_fp.Value(), frame1->context.iregs[MD_CONTEXT_ARM64_REG_FP]); - StackFrameARM64 *frame2 = static_cast<StackFrameARM64 *>(frames->at(2)); + StackFrameARM64 *frame2 = static_cast<StackFrameARM64*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust); ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | StackFrameARM64::CONTEXT_VALID_LR | @@ -642,13 +641,13 @@ struct CFIFixture: public StackwalkerARM64Fixture { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0)); + StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(context_frame_validity, frame0->context_validity); EXPECT_EQ("enchiridion", frame0->function_name); EXPECT_EQ(0x0000000040004000UL, frame0->function_base); - StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1)); + StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ(expected_validity, frame1->context_validity); if (expected_validity & StackFrameARM64::CONTEXT_VALID_X1) diff --git a/src/processor/stackwalker_arm_unittest.cc b/src/processor/stackwalker_arm_unittest.cc index 256f7648..20c810a7 100644 --- a/src/processor/stackwalker_arm_unittest.cc +++ b/src/processor/stackwalker_arm_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -106,7 +105,7 @@ class StackwalkerARMFixture { // Set the Breakpad symbol information that supplier should return for // MODULE to INFO. - void SetModuleSymbols(MockCodeModule *module, const string &info) { + void SetModuleSymbols(MockCodeModule* module, const string& info) { size_t buffer_size; char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) @@ -127,7 +126,7 @@ class StackwalkerARMFixture { void BrandContext(MDRawContextARM *raw_context) { uint8_t x = 173; for (size_t i = 0; i < sizeof(*raw_context); i++) - reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17); + reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17); } SystemInfo system_info; @@ -140,7 +139,7 @@ class StackwalkerARMFixture { MockSymbolSupplier supplier; BasicSourceLineResolver resolver; CallStack call_stack; - const vector<StackFrame *> *frames; + const vector<StackFrame*>* frames; }; class SanityCheck: public StackwalkerARMFixture, public Test { }; @@ -161,7 +160,7 @@ TEST_F(SanityCheck, NoResolver) { ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); ASSERT_EQ(1U, frames->size()); - StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame = static_cast<StackFrameARM*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -184,7 +183,7 @@ TEST_F(GetContextFrame, Simple) { ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); ASSERT_EQ(1U, frames->size()); - StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame = static_cast<StackFrameARM*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -204,7 +203,7 @@ TEST_F(GetContextFrame, NoStackMemory) { ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); ASSERT_EQ(1U, frames->size()); - StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame = static_cast<StackFrameARM*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -260,12 +259,12 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) { frames = call_stack.frames(); ASSERT_EQ(3U, frames->size()); - StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1)); + StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_SP), @@ -273,7 +272,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) { EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]); EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]); - StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2)); + StackFrameARM *frame2 = static_cast<StackFrameARM*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_SP), @@ -329,14 +328,14 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); EXPECT_EQ("monotreme", frame0->function_name); EXPECT_EQ(0x40000100U, frame0->function_base); - StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1)); + StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_SP), @@ -397,12 +396,12 @@ TEST_F(GetCallerFrame, ScanFirstFrame) { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1)); + StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_SP), @@ -460,7 +459,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) { frames = call_stack.frames(); ASSERT_EQ(1U, frames->size()); - StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); @@ -565,13 +564,13 @@ struct CFIFixture: public StackwalkerARMFixture { frames = call_stack.frames(); ASSERT_EQ(2U, frames->size()); - StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(context_frame_validity, frame0->context_validity); EXPECT_EQ("enchiridion", frame0->function_name); EXPECT_EQ(0x40004000U, frame0->function_base); - StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1)); + StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ(expected_validity, frame1->context_validity); if (expected_validity & StackFrameARM::CONTEXT_VALID_R1) @@ -848,12 +847,12 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) { frames = call_stack.frames(); ASSERT_EQ(3U, frames->size()); - StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1)); + StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_LR | @@ -866,7 +865,7 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) { EXPECT_EQ(frame2_fp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]); - StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2)); + StackFrameARM *frame2 = static_cast<StackFrameARM*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust); ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_LR | @@ -944,12 +943,12 @@ TEST_F(GetFramesByFramePointer, FramePointerAndCFI) { frames = call_stack.frames(); ASSERT_EQ(3U, frames->size()); - StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0)); + StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); - StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1)); + StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_LR | @@ -965,7 +964,7 @@ TEST_F(GetFramesByFramePointer, FramePointerAndCFI) { EXPECT_EQ(0x40004000U, frame1->function_base); - StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2)); + StackFrameARM *frame2 = static_cast<StackFrameARM*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_LR | diff --git a/src/processor/stackwalker_mips.cc b/src/processor/stackwalker_mips.cc index c33ecdbe..11b08fae 100644 --- a/src/processor/stackwalker_mips.cc +++ b/src/processor/stackwalker_mips.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -276,7 +275,8 @@ StackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack, if (TerminateWalk(new_frame->context.epc, new_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP], last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP], - frames.size() == 1)) { + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { return NULL; } diff --git a/src/processor/stackwalker_mips.h b/src/processor/stackwalker_mips.h index 5f97791f..e9776074 100644 --- a/src/processor/stackwalker_mips.h +++ b/src/processor/stackwalker_mips.h @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/stackwalker_mips64_unittest.cc b/src/processor/stackwalker_mips64_unittest.cc index 2a9784bf..aefcf8ee 100644 --- a/src/processor/stackwalker_mips64_unittest.cc +++ b/src/processor/stackwalker_mips64_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -65,6 +64,7 @@ using google_breakpad::test_assembler::Section; using std::vector; using testing::_; using testing::AnyNumber; +using testing::DoAll; using testing::Return; using testing::SetArgumentPointee; using testing::Test; @@ -644,8 +644,10 @@ struct CFIFixture: public StackwalkerMIPSFixture { EXPECT_EQ(0x00405000U, frame1->function_base); } - // The values we expect to find for the caller's registers. - MDRawContextMIPS expected; + // The values we expect to find for the caller's registers. Forcibly + // default-init it, since it's POD and not all bits are always overwritten by + // the constructor. + MDRawContextMIPS expected{}; // The validity mask for expected. int expected_validity; diff --git a/src/processor/stackwalker_mips_unittest.cc b/src/processor/stackwalker_mips_unittest.cc index a172f17b..ac7324c4 100644 --- a/src/processor/stackwalker_mips_unittest.cc +++ b/src/processor/stackwalker_mips_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013, Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -64,6 +63,7 @@ using google_breakpad::test_assembler::Section; using std::vector; using testing::_; using testing::AnyNumber; +using testing::DoAll; using testing::Return; using testing::SetArgumentPointee; using testing::Test; diff --git a/src/processor/stackwalker_ppc.cc b/src/processor/stackwalker_ppc.cc index 1e34c383..e71d9138 100644 --- a/src/processor/stackwalker_ppc.cc +++ b/src/processor/stackwalker_ppc.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -132,10 +131,9 @@ StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack* stack, frame->trust = StackFrame::FRAME_TRUST_FP; // Should we terminate the stack walk? (end-of-stack or broken invariant) - if (TerminateWalk(instruction, - stack_pointer, - last_frame->context.gpr[1], - stack->frames()->size() == 1)) { + if (TerminateWalk(instruction, stack_pointer, last_frame->context.gpr[1], + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { return NULL; } diff --git a/src/processor/stackwalker_ppc.h b/src/processor/stackwalker_ppc.h index 012e5c32..182e46d4 100644 --- a/src/processor/stackwalker_ppc.h +++ b/src/processor/stackwalker_ppc.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/stackwalker_ppc64.cc b/src/processor/stackwalker_ppc64.cc index fb2bac3c..9ac8e45b 100644 --- a/src/processor/stackwalker_ppc64.cc +++ b/src/processor/stackwalker_ppc64.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -123,10 +122,9 @@ StackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack, frame->trust = StackFrame::FRAME_TRUST_FP; // Should we terminate the stack walk? (end-of-stack or broken invariant) - if (TerminateWalk(instruction, - stack_pointer, - last_frame->context.gpr[1], - stack->frames()->size() == 1)) { + if (TerminateWalk(instruction, stack_pointer, last_frame->context.gpr[1], + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { return NULL; } diff --git a/src/processor/stackwalker_ppc64.h b/src/processor/stackwalker_ppc64.h index a406343a..ede0b51c 100644 --- a/src/processor/stackwalker_ppc64.h +++ b/src/processor/stackwalker_ppc64.h @@ -1,5 +1,4 @@ -// Copyright (c) 2013 Google Inc. -// All rights reserved. +// Copyright 2013 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/stackwalker_riscv.cc b/src/processor/stackwalker_riscv.cc new file mode 100644 index 00000000..3d8a64f4 --- /dev/null +++ b/src/processor/stackwalker_riscv.cc @@ -0,0 +1,535 @@ +// Copyright 2013 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* stackwalker_riscv.cc: riscv-specific stackwalker. + * + * See stackwalker_riscv.h for documentation. + * + * Author: Iacopo Colonnelli + */ + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/cfi_frame_info.h" +#include "processor/logging.h" +#include "processor/stackwalker_riscv.h" + +namespace google_breakpad { + +StackwalkerRISCV::StackwalkerRISCV(const SystemInfo* system_info, + const MDRawContextRISCV* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context), + context_frame_validity_(StackFrameRISCV::CONTEXT_VALID_ALL) { +} + + +StackFrame* StackwalkerRISCV::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFrameRISCV* frame = new StackFrameRISCV(); + + frame->context = *context_; + frame->context_validity = context_frame_validity_; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.pc; + + return frame; +} + +StackFrameRISCV* StackwalkerRISCV::GetCallerByCFIFrameInfo( + const vector<StackFrame*>& frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameRISCV* last_frame = + static_cast<StackFrameRISCV*>(frames.back()); + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_PC) + callee_registers["pc"] = last_frame->context.pc; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_RA) + callee_registers["ra"] = last_frame->context.ra; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_SP) + callee_registers["sp"] = last_frame->context.sp; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_GP) + callee_registers["gp"] = last_frame->context.gp; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_TP) + callee_registers["tp"] = last_frame->context.tp; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T0) + callee_registers["t0"] = last_frame->context.t0; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T1) + callee_registers["t1"] = last_frame->context.t1; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T2) + callee_registers["t2"] = last_frame->context.t2; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S0) + callee_registers["s0"] = last_frame->context.s0; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S1) + callee_registers["s1"] = last_frame->context.s1; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A0) + callee_registers["a0"] = last_frame->context.a0; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A1) + callee_registers["a1"] = last_frame->context.a1; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A2) + callee_registers["a2"] = last_frame->context.a2; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A3) + callee_registers["a3"] = last_frame->context.a3; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A4) + callee_registers["a4"] = last_frame->context.a4; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A5) + callee_registers["a5"] = last_frame->context.a5; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A6) + callee_registers["a6"] = last_frame->context.a6; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A7) + callee_registers["a7"] = last_frame->context.a7; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S2) + callee_registers["s2"] = last_frame->context.s2; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S3) + callee_registers["s3"] = last_frame->context.s3; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S4) + callee_registers["s4"] = last_frame->context.s4; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S5) + callee_registers["s5"] = last_frame->context.s5; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S6) + callee_registers["s6"] = last_frame->context.s6; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S7) + callee_registers["s7"] = last_frame->context.s7; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S8) + callee_registers["s8"] = last_frame->context.s8; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S9) + callee_registers["s9"] = last_frame->context.s9; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S10) + callee_registers["s10"] = last_frame->context.s10; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S11) + callee_registers["s11"] = last_frame->context.s11; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T3) + callee_registers["t3"] = last_frame->context.t3; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T4) + callee_registers["t4"] = last_frame->context.t4; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T5) + callee_registers["t5"] = last_frame->context.t5; + if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T6) + callee_registers["t6"] = last_frame->context.t6; + + // Use the STACK CFI data to recover the caller's register values. + CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) { + return NULL; + } + + // Construct a new stack frame given the values the CFI recovered. + CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry; + scoped_ptr<StackFrameRISCV> frame(new StackFrameRISCV()); + entry = caller_registers.find("pc"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_PC; + frame->context.pc = entry->second; + } else{ + // If the CFI doesn't recover the PC explicitly, then use .ra. + entry = caller_registers.find(".ra"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_PC; + frame->context.pc = entry->second; + } + } + entry = caller_registers.find("ra"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_RA; + frame->context.ra = entry->second; + } + entry = caller_registers.find("sp"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_SP; + frame->context.sp = entry->second; + } else { + // If the CFI doesn't recover the SP explicitly, then use .cfa. + entry = caller_registers.find(".cfa"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_SP; + frame->context.sp = entry->second; + } + } + entry = caller_registers.find("gp"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_GP; + frame->context.gp = entry->second; + } + entry = caller_registers.find("tp"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_TP; + frame->context.tp = entry->second; + } + entry = caller_registers.find("t0"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T0; + frame->context.t0 = entry->second; + } + entry = caller_registers.find("t1"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T1; + frame->context.t1 = entry->second; + } + entry = caller_registers.find("t2"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T2; + frame->context.t2 = entry->second; + } + entry = caller_registers.find("s0"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S0; + frame->context.s0 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S0) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S0; + frame->context.s0 = last_frame->context.s0; + } + entry = caller_registers.find("s1"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S1; + frame->context.s1 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S1) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S1; + frame->context.s1 = last_frame->context.s1; + } + entry = caller_registers.find("a0"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A0; + frame->context.a0 = entry->second; + } + entry = caller_registers.find("a1"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A1; + frame->context.a1 = entry->second; + } + entry = caller_registers.find("a2"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A2; + frame->context.a2 = entry->second; + } + entry = caller_registers.find("a3"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A3; + frame->context.a3 = entry->second; + } + entry = caller_registers.find("a4"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A4; + frame->context.a4 = entry->second; + } + entry = caller_registers.find("a5"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A5; + frame->context.a5 = entry->second; + } + entry = caller_registers.find("a6"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A6; + frame->context.a6 = entry->second; + } + entry = caller_registers.find("a7"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A7; + frame->context.a7 = entry->second; + } + entry = caller_registers.find("s2"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S2; + frame->context.s2 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S2) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S2; + frame->context.s2 = last_frame->context.s2; + } + entry = caller_registers.find("s3"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S3; + frame->context.s3 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S3) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S3; + frame->context.s3 = last_frame->context.s3; + } + entry = caller_registers.find("s4"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S4; + frame->context.s4 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S4) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S4; + frame->context.s4 = last_frame->context.s4; + } + entry = caller_registers.find("s5"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S5; + frame->context.s5 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S5) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S5; + frame->context.s5 = last_frame->context.s5; + } + entry = caller_registers.find("s6"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S6; + frame->context.s6 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S6) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S6; + frame->context.s6 = last_frame->context.s6; + } + entry = caller_registers.find("s7"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S7; + frame->context.s7 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S7) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S7; + frame->context.s7 = last_frame->context.s7; + } + entry = caller_registers.find("s8"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S8; + frame->context.s8 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S8) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S8; + frame->context.s8 = last_frame->context.s8; + } + entry = caller_registers.find("s9"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S9; + frame->context.s9 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S9) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S9; + frame->context.s9 = last_frame->context.s9; + } + entry = caller_registers.find("s10"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S10; + frame->context.s10 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S10) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S10; + frame->context.s10 = last_frame->context.s10; + } + entry = caller_registers.find("s11"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S11; + frame->context.s11 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV::CONTEXT_VALID_S11) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S11; + frame->context.s11 = last_frame->context.s11; + } + entry = caller_registers.find("t3"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T3; + frame->context.t3 = entry->second; + } + entry = caller_registers.find("t4"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T4; + frame->context.t4 = entry->second; + } + entry = caller_registers.find("t5"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T5; + frame->context.t5 = entry->second; + } + entry = caller_registers.find("t6"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T6; + frame->context.t6 = entry->second; + } + + // If we didn't recover the PC and the SP, then the frame isn't very useful. + static const uint64_t essentials = (StackFrameRISCV::CONTEXT_VALID_SP + | StackFrameRISCV::CONTEXT_VALID_PC); + if ((frame->context_validity & essentials) != essentials) + return NULL; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + return frame.release(); +} + +StackFrameRISCV* StackwalkerRISCV::GetCallerByStackScan( + const vector<StackFrame*>& frames) { + StackFrameRISCV* last_frame = + static_cast<StackFrameRISCV*>(frames.back()); + uint32_t last_sp = last_frame->context.sp; + uint32_t caller_sp, caller_pc; + + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, + last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT)) { + // No plausible return address was found. + return NULL; + } + + // ScanForReturnAddress found a reasonable return address. Advance + // sp to the location above the one where the return address was + // found. + caller_sp += 4; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameRISCV* frame = new StackFrameRISCV(); + + frame->trust = StackFrame::FRAME_TRUST_SCAN; + frame->context = last_frame->context; + frame->context.pc = caller_pc; + frame->context.sp = caller_sp; + frame->context_validity = StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_SP; + + return frame; +} + + StackFrameRISCV* StackwalkerRISCV::GetCallerByFramePointer( + const vector<StackFrame*>& frames) { + StackFrameRISCV* last_frame = + static_cast<StackFrameRISCV*>(frames.back()); + + uint32_t last_fp = last_frame->context.s0; + + uint32_t caller_fp = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { + BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" + << std::hex << last_fp; + return NULL; + } + + uint32_t caller_ra = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 4, &caller_ra)) { + BPLOG(ERROR) << "Unable to read caller_ra from last_fp + 4: 0x" + << std::hex << (last_fp + 4); + return NULL; + } + + uint32_t caller_sp = last_fp ? last_fp + 8 : last_frame->context.s0; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameRISCV* frame = new StackFrameRISCV(); + + frame->trust = StackFrame::FRAME_TRUST_FP; + frame->context = last_frame->context; + frame->context.s0 = caller_fp; + frame->context.sp = caller_sp; + frame->context.pc = last_frame->context.ra; + frame->context.ra = caller_ra; + frame->context_validity = StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_RA | + StackFrameRISCV::CONTEXT_VALID_S0 | + StackFrameRISCV::CONTEXT_VALID_SP; + return frame; +} + +StackFrame* StackwalkerRISCV::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + const vector<StackFrame*>& frames = *stack->frames(); + StackFrameRISCV* last_frame = + static_cast<StackFrameRISCV*>(frames.back()); + scoped_ptr<StackFrameRISCV> frame; + + // Try to recover caller information from CFI. + scoped_ptr<CFIFrameInfo> cfi_frame_info( + frame_symbolizer_->FindCFIFrameInfo(last_frame)); + if (cfi_frame_info.get()) + frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); + + // If CFI failed, or there wasn't CFI available, fall back to frame pointer. + if (!frame.get()) + frame.reset(GetCallerByFramePointer(frames)); + + // If everything failed, fall back to stack scanning. + if (stack_scan_allowed && !frame.get()) + frame.reset(GetCallerByStackScan(frames)); + + // If nothing worked, tell the caller. + if (!frame.get()) + return NULL; + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(frame->context.pc, frame->context.sp, + last_frame->context.sp, + last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT)) { + return NULL; + } + + // The new frame's context's PC is the return address, which is one + // instruction past the instruction that caused us to arrive at the callee. + // RISCV instructions have a uniform 4-byte encoding, so subtracting 4 off + // the return address gets back to the beginning of the call instruction. + // Callers that require the exact return address value may access + // frame->context.pc. + frame->instruction = frame->context.pc - 4; + + return frame.release(); +} + +} // namespace google_breakpad diff --git a/src/processor/stackwalker_riscv.h b/src/processor/stackwalker_riscv.h new file mode 100644 index 00000000..863914d8 --- /dev/null +++ b/src/processor/stackwalker_riscv.h @@ -0,0 +1,100 @@ +// Copyright 2013 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* stackwalker_riscv.h: riscv-specific stackwalker. + * + * Provides stack frames given riscv register context and a memory region + * corresponding to a riscv stack. + * + * Author: Iacopo Colonnelli + */ + +#ifndef PROCESSOR_STACKWALKER_RISCV_H__ +#define PROCESSOR_STACKWALKER_RISCV_H__ + +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/stackwalker.h" + +namespace google_breakpad { + +class CodeModules; + +class StackwalkerRISCV : public Stackwalker { +public: + // Context is a riscv context object that gives access to riscv-specific + // register state corresponding to the innermost called frame to be + // included in the stack. The other arguments are passed directly + // through to the base Stackwalker constructor. + StackwalkerRISCV(const SystemInfo* system_info, + const MDRawContextRISCV* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + // Change the context validity mask of the frame returned by + // GetContextFrame to VALID. This is only for use by unit tests; the + // default behavior is correct for all application code. + void SetContextFrameValidity(int valid) { + context_frame_validity_ = valid; + } + +private: + // Implementation of Stackwalker, using riscv context and stack conventions. + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame( + const CallStack* stack, bool stack_scan_allowed); + + // Use cfi_frame_info (derived from STACK CFI records) to construct + // the frame that called frames.back(). The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameRISCV* GetCallerByCFIFrameInfo( + const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info); + + // Use the frame pointer. The caller takes ownership of the returned frame. + // Return NULL on failure. + StackFrameRISCV* GetCallerByFramePointer( + const vector<StackFrame*>& frames); + + // Scan the stack for plausible return addresses. The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameRISCV* GetCallerByStackScan( + const vector<StackFrame*>& frames); + + // Stores the CPU context corresponding to the innermost stack frame to + // be returned by GetContextFrame. + const MDRawContextRISCV* context_; + + // Validity mask for youngest stack frame. This is always + // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of + // unit tests. + int context_frame_validity_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_STACKWALKER_RISCV_H__ diff --git a/src/processor/stackwalker_riscv64.cc b/src/processor/stackwalker_riscv64.cc new file mode 100644 index 00000000..d97bad63 --- /dev/null +++ b/src/processor/stackwalker_riscv64.cc @@ -0,0 +1,535 @@ +// Copyright 2013 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* stackwalker_riscv64.cc: riscv64-specific stackwalker. + * + * See stackwalker_riscv64.h for documentation. + * + * Author: Iacopo Colonnelli + */ + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/cfi_frame_info.h" +#include "processor/logging.h" +#include "processor/stackwalker_riscv64.h" + +namespace google_breakpad { + +StackwalkerRISCV64::StackwalkerRISCV64(const SystemInfo* system_info, + const MDRawContextRISCV64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context), + context_frame_validity_(StackFrameRISCV::CONTEXT_VALID_ALL) { +} + + +StackFrame* StackwalkerRISCV64::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFrameRISCV64* frame = new StackFrameRISCV64(); + + frame->context = *context_; + frame->context_validity = context_frame_validity_; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.pc; + + return frame; +} + +StackFrameRISCV64* StackwalkerRISCV64::GetCallerByCFIFrameInfo( + const vector<StackFrame*>& frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameRISCV64* last_frame = + static_cast<StackFrameRISCV64*>(frames.back()); + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap<uint64_t> callee_registers; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_PC) + callee_registers["pc"] = last_frame->context.pc; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_RA) + callee_registers["ra"] = last_frame->context.ra; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_SP) + callee_registers["sp"] = last_frame->context.sp; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_GP) + callee_registers["gp"] = last_frame->context.gp; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_TP) + callee_registers["tp"] = last_frame->context.tp; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T0) + callee_registers["t0"] = last_frame->context.t0; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T1) + callee_registers["t1"] = last_frame->context.t1; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T2) + callee_registers["t2"] = last_frame->context.t2; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S0) + callee_registers["s0"] = last_frame->context.s0; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S1) + callee_registers["s1"] = last_frame->context.s1; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A0) + callee_registers["a0"] = last_frame->context.a0; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A1) + callee_registers["a1"] = last_frame->context.a1; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A2) + callee_registers["a2"] = last_frame->context.a2; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A3) + callee_registers["a3"] = last_frame->context.a3; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A4) + callee_registers["a4"] = last_frame->context.a4; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A5) + callee_registers["a5"] = last_frame->context.a5; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A6) + callee_registers["a6"] = last_frame->context.a6; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A7) + callee_registers["a7"] = last_frame->context.a7; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S2) + callee_registers["s2"] = last_frame->context.s2; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S3) + callee_registers["s3"] = last_frame->context.s3; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S4) + callee_registers["s4"] = last_frame->context.s4; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S5) + callee_registers["s5"] = last_frame->context.s5; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S6) + callee_registers["s6"] = last_frame->context.s6; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S7) + callee_registers["s7"] = last_frame->context.s7; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S8) + callee_registers["s8"] = last_frame->context.s8; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S9) + callee_registers["s9"] = last_frame->context.s9; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S10) + callee_registers["s10"] = last_frame->context.s10; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S11) + callee_registers["s11"] = last_frame->context.s11; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T3) + callee_registers["t3"] = last_frame->context.t3; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T4) + callee_registers["t4"] = last_frame->context.t4; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T5) + callee_registers["t5"] = last_frame->context.t5; + if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T6) + callee_registers["t6"] = last_frame->context.t6; + + // Use the STACK CFI data to recover the caller's register values. + CFIFrameInfo::RegisterValueMap<uint64_t> caller_registers; + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) { + return NULL; + } + + // Construct a new stack frame given the values the CFI recovered. + CFIFrameInfo::RegisterValueMap<uint64_t>::iterator entry; + scoped_ptr<StackFrameRISCV64> frame(new StackFrameRISCV64()); + entry = caller_registers.find("pc"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_PC; + frame->context.pc = entry->second; + } else{ + // If the CFI doesn't recover the PC explicitly, then use .ra. + entry = caller_registers.find(".ra"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_PC; + frame->context.pc = entry->second; + } + } + entry = caller_registers.find("ra"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_RA; + frame->context.ra = entry->second; + } + entry = caller_registers.find("sp"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_SP; + frame->context.sp = entry->second; + } else { + // If the CFI doesn't recover the SP explicitly, then use .cfa. + entry = caller_registers.find(".cfa"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_SP; + frame->context.sp = entry->second; + } + } + entry = caller_registers.find("gp"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_GP; + frame->context.gp = entry->second; + } + entry = caller_registers.find("tp"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_TP; + frame->context.tp = entry->second; + } + entry = caller_registers.find("t0"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T0; + frame->context.t0 = entry->second; + } + entry = caller_registers.find("t1"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T1; + frame->context.t1 = entry->second; + } + entry = caller_registers.find("t2"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T2; + frame->context.t2 = entry->second; + } + entry = caller_registers.find("s0"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S0; + frame->context.s0 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S0) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S0; + frame->context.s0 = last_frame->context.s0; + } + entry = caller_registers.find("s1"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S1; + frame->context.s1 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S1) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S1; + frame->context.s1 = last_frame->context.s1; + } + entry = caller_registers.find("a0"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A0; + frame->context.a0 = entry->second; + } + entry = caller_registers.find("a1"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A1; + frame->context.a1 = entry->second; + } + entry = caller_registers.find("a2"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A2; + frame->context.a2 = entry->second; + } + entry = caller_registers.find("a3"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A3; + frame->context.a3 = entry->second; + } + entry = caller_registers.find("a4"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A4; + frame->context.a4 = entry->second; + } + entry = caller_registers.find("a5"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A5; + frame->context.a5 = entry->second; + } + entry = caller_registers.find("a6"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A6; + frame->context.a6 = entry->second; + } + entry = caller_registers.find("a7"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A7; + frame->context.a7 = entry->second; + } + entry = caller_registers.find("s2"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S2; + frame->context.s2 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S2) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S2; + frame->context.s2 = last_frame->context.s2; + } + entry = caller_registers.find("s3"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S3; + frame->context.s3 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S3) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S3; + frame->context.s3 = last_frame->context.s3; + } + entry = caller_registers.find("s4"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S4; + frame->context.s4 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S4) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S4; + frame->context.s4 = last_frame->context.s4; + } + entry = caller_registers.find("s5"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S5; + frame->context.s5 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S5) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S5; + frame->context.s5 = last_frame->context.s5; + } + entry = caller_registers.find("s6"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S6; + frame->context.s6 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S6) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S6; + frame->context.s6 = last_frame->context.s6; + } + entry = caller_registers.find("s7"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S7; + frame->context.s7 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S7) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S7; + frame->context.s7 = last_frame->context.s7; + } + entry = caller_registers.find("s8"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S8; + frame->context.s8 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S8) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S8; + frame->context.s8 = last_frame->context.s8; + } + entry = caller_registers.find("s9"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S9; + frame->context.s9 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S9) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S9; + frame->context.s9 = last_frame->context.s9; + } + entry = caller_registers.find("s10"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S10; + frame->context.s10 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S10) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S10; + frame->context.s10 = last_frame->context.s10; + } + entry = caller_registers.find("s11"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S11; + frame->context.s11 = entry->second; + } else if (last_frame->context_validity & + StackFrameRISCV64::CONTEXT_VALID_S11) { + // Since the register is callee-saves, assume the callee + // has not yet changed it. + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S11; + frame->context.s11 = last_frame->context.s11; + } + entry = caller_registers.find("t3"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T3; + frame->context.t3 = entry->second; + } + entry = caller_registers.find("t4"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T4; + frame->context.t4 = entry->second; + } + entry = caller_registers.find("t5"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T5; + frame->context.t5 = entry->second; + } + entry = caller_registers.find("t6"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T6; + frame->context.t6 = entry->second; + } + + // If we didn't recover the PC and the SP, then the frame isn't very useful. + static const uint64_t essentials = (StackFrameRISCV64::CONTEXT_VALID_SP + | StackFrameRISCV64::CONTEXT_VALID_PC); + if ((frame->context_validity & essentials) != essentials) + return NULL; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + return frame.release(); +} + +StackFrameRISCV64* StackwalkerRISCV64::GetCallerByStackScan( + const vector<StackFrame*>& frames) { + StackFrameRISCV64* last_frame = + static_cast<StackFrameRISCV64*>(frames.back()); + uint64_t last_sp = last_frame->context.sp; + uint64_t caller_sp, caller_pc; + + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, + last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT)) { + // No plausible return address was found. + return NULL; + } + + // ScanForReturnAddress found a reasonable return address. Advance + // sp to the location above the one where the return address was + // found. + caller_sp += 8; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameRISCV64* frame = new StackFrameRISCV64(); + + frame->trust = StackFrame::FRAME_TRUST_SCAN; + frame->context = last_frame->context; + frame->context.pc = caller_pc; + frame->context.sp = caller_sp; + frame->context_validity = StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_SP; + + return frame; +} + +StackFrameRISCV64* StackwalkerRISCV64::GetCallerByFramePointer( + const vector<StackFrame*>& frames) { + StackFrameRISCV64* last_frame = + static_cast<StackFrameRISCV64*>(frames.back()); + + uint64_t last_fp = last_frame->context.s0; + + uint64_t caller_fp = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { + BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" + << std::hex << last_fp; + return NULL; + } + + uint64_t caller_ra = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 8, &caller_ra)) { + BPLOG(ERROR) << "Unable to read caller_ra from last_fp + 8: 0x" + << std::hex << (last_fp + 8); + return NULL; + } + + uint64_t caller_sp = last_fp ? last_fp + 16 : last_frame->context.s0; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameRISCV64* frame = new StackFrameRISCV64(); + + frame->trust = StackFrame::FRAME_TRUST_FP; + frame->context = last_frame->context; + frame->context.s0 = caller_fp; + frame->context.sp = caller_sp; + frame->context.pc = last_frame->context.ra; + frame->context.ra = caller_ra; + frame->context_validity = StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_RA | + StackFrameRISCV64::CONTEXT_VALID_S0 | + StackFrameRISCV64::CONTEXT_VALID_SP; + return frame; +} + +StackFrame* StackwalkerRISCV64::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + const vector<StackFrame*>& frames = *stack->frames(); + StackFrameRISCV64* last_frame = + static_cast<StackFrameRISCV64*>(frames.back()); + scoped_ptr<StackFrameRISCV64> frame; + + // Try to recover caller information from CFI. + scoped_ptr<CFIFrameInfo> cfi_frame_info( + frame_symbolizer_->FindCFIFrameInfo(last_frame)); + if (cfi_frame_info.get()) + frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); + + // If CFI failed, or there wasn't CFI available, fall back to frame pointer. + if (!frame.get()) + frame.reset(GetCallerByFramePointer(frames)); + + // If everything failed, fall back to stack scanning. + if (stack_scan_allowed && !frame.get()) + frame.reset(GetCallerByStackScan(frames)); + + // If nothing worked, tell the caller. + if (!frame.get()) + return NULL; + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(frame->context.pc, frame->context.sp, + last_frame->context.sp, + last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT)) { + return NULL; + } + + // The new frame's context's PC is the return address, which is one + // instruction past the instruction that caused us to arrive at the callee. + // RISCV instructions have a uniform 4-byte encoding, so subtracting 4 off + // the return address gets back to the beginning of the call instruction. + // Callers that require the exact return address value may access + // frame->context.pc. + frame->instruction = frame->context.pc - 4; + + return frame.release(); +} + +} // namespace google_breakpad diff --git a/src/processor/stackwalker_riscv64.h b/src/processor/stackwalker_riscv64.h new file mode 100644 index 00000000..89ab12ff --- /dev/null +++ b/src/processor/stackwalker_riscv64.h @@ -0,0 +1,100 @@ +// Copyright 2013 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* stackwalker_riscv64.h: riscv64-specific stackwalker. + * + * Provides stack frames given riscv64 register context and a memory region + * corresponding to a riscv64 stack. + * + * Author: Iacopo Colonnelli + */ + +#ifndef PROCESSOR_STACKWALKER_RISCV64_H__ +#define PROCESSOR_STACKWALKER_RISCV64_H__ + +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/stackwalker.h" + +namespace google_breakpad { + +class CodeModules; + +class StackwalkerRISCV64 : public Stackwalker { +public: + // Context is a riscv context object that gives access to riscv-specific + // register state corresponding to the innermost called frame to be + // included in the stack. The other arguments are passed directly + // through to the base Stackwalker constructor. + StackwalkerRISCV64(const SystemInfo* system_info, + const MDRawContextRISCV64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + // Change the context validity mask of the frame returned by + // GetContextFrame to VALID. This is only for use by unit tests; the + // default behavior is correct for all application code. + void SetContextFrameValidity(int valid) { + context_frame_validity_ = valid; + } + +private: + // Implementation of Stackwalker, using riscv context and stack conventions. + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame( + const CallStack* stack, bool stack_scan_allowed); + + // Use cfi_frame_info (derived from STACK CFI records) to construct + // the frame that called frames.back(). The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameRISCV64* GetCallerByCFIFrameInfo( + const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info); + + // Use the frame pointer. The caller takes ownership of the returned frame. + // Return NULL on failure. + StackFrameRISCV64* GetCallerByFramePointer( + const vector<StackFrame*>& frames); + + // Scan the stack for plausible return addresses. The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameRISCV64* GetCallerByStackScan( + const vector<StackFrame*>& frames); + + // Stores the CPU context corresponding to the innermost stack frame to + // be returned by GetContextFrame. + const MDRawContextRISCV64* context_; + + // Validity mask for youngest stack frame. This is always + // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of + // unit tests. + int context_frame_validity_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_STACKWALKER_RISCV64_H__ diff --git a/src/processor/stackwalker_riscv64_unittest.cc b/src/processor/stackwalker_riscv64_unittest.cc new file mode 100644 index 00000000..73c06264 --- /dev/null +++ b/src/processor/stackwalker_riscv64_unittest.cc @@ -0,0 +1,883 @@ +// Copyright 2013 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* stackwalker_riscv64_unittest.cc: Unit tests for StackwalkerRISCV64 class. + * + * Author: Iacopo Colonnelli + */ + +#include <string.h> +#include <string> +#include <vector> + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_riscv64.h" +#include "processor/windows_frame_info.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameRISCV64; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerRISCV64; +using google_breakpad::SystemInfo; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::DoAll; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class StackwalkerRISCV64Fixture { +public: + StackwalkerRISCV64Fixture() + : stack_section(kLittleEndian), + // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(0x40000000, 0x10000, "module1", "version1"), + module2(0x50000000, 0x10000, "module2", "version2") { + // Identify the system as an iOS system. + system_info.os = "iOS"; + system_info.os_short = "ios"; + system_info.cpu = "riscv64"; + system_info.cpu_info = ""; + + // Put distinctive values in the raw CPU context. + BrandContext(&raw_context); + + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + + // Reset max_frames_scanned since it's static. + Stackwalker::set_max_frames_scanned(1024); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule* module, const string& info) { + size_t buffer_size; + char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + // Populate stack_region with the contents of stack_section. Use + // stack_section.start() as the region's starting address. + void RegionFromSection() { + string contents; + ASSERT_TRUE(stack_section.GetContents(&contents)); + stack_region.Init(stack_section.start().Value(), contents); + } + + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. + void BrandContext(MDRawContextRISCV64 *raw_context) { + uint8_t x = 173; + for (size_t i = 0; i < sizeof(*raw_context); i++) + reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17); + } + + SystemInfo system_info; + MDRawContextRISCV64 raw_context; + Section stack_section; + MockMemoryRegion stack_region; + MockCodeModule module1; + MockCodeModule module2; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + CallStack call_stack; + const vector<StackFrame*>* frames; +}; + +class SanityCheck: public StackwalkerRISCV64Fixture, public Test { }; + +TEST_F(SanityCheck, NoResolver) { + // Since the context's frame pointer is garbage, the stack walk will end after + // the first frame. + StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + // This should succeed even without a resolver or supplier. + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameRISCV64 *frame = static_cast<StackFrameRISCV64*>(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetContextFrame: public StackwalkerRISCV64Fixture, public Test { }; + +// The stackwalker should be able to produce the context frame even +// without stack memory present. +TEST_F(GetContextFrame, NoStackMemory) { + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, NULL, &modules, + &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameRISCV64 *frame = static_cast<StackFrameRISCV64*>(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetCallerFrame: public StackwalkerRISCV64Fixture, public Test { }; + +TEST_F(GetCallerFrame, ScanWithoutSymbols) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + // Force scanning through three frames to ensure that the + // stack pointer is set properly in scan-recovered frames. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x40090000) // junk that's not + .D64(0x60000000) // a return address + + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D64(0xF0000000) // more junk + .D64(0x0000000D) + + .D64(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.pc = 0x40005510; + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.pc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.sp); + + StackFrameRISCV64 *frame2 = static_cast<StackFrameRISCV64*>(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); + ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.pc); + EXPECT_EQ(frame2_sp.Value(), frame2->context.sp); +} + +TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { + // During stack scanning, if a potential return address + // is located within a loaded module that has symbols, + // it is only considered a valid return address if it + // lies within a function's bounds. + stack_section.start() = 0x80000000; + uint64_t return_address = 0x50000200; + Label frame1_sp; + + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x40090000) // junk that's not + .D64(0x60000000) // a return address + + .D64(0x40001000) // a couple of plausible addresses + .D64(0x5000F000) // that are not within functions + + .D64(return_address) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.pc = 0x40000200; + raw_context.sp = stack_section.start().Value(); + + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 100 400 10 monotreme\n"); + SetModuleSymbols(&module2, + // The calling frame's function. + "FUNC 100 400 10 marsupial\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + EXPECT_EQ("monotreme", frame0->function_name); + EXPECT_EQ(0x40000100ULL, frame0->function_base); + + StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address, frame1->context.pc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.sp); + EXPECT_EQ("marsupial", frame1->function_name); + EXPECT_EQ(0x50000100ULL, frame1->function_base); +} + +TEST_F(GetCallerFrame, ScanFirstFrame) { + // If the stackwalker resorts to stack scanning, it will scan much + // farther to find the caller of the context frame. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(32, 0) // space + + .D64(0x40090000) // junk that's not + .D64(0x60000000) // a return address + + .Append(96, 0) // more space + + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0) // space + + .D64(0xF0000000) // more junk + .D64(0x0000000D) + + .Append(336, 0) // more space + + .D64(return_address2) // actual return address + // (won't be found) + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.pc = 0x40005510; + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.pc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.sp); +} + +// Test that set_max_frames_scanned prevents using stack scanning +// to find caller frames. +TEST_F(GetCallerFrame, ScanningNotAllowed) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x40090000) // junk that's not + .D64(0x60000000) // a return address + + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D64(0xF0000000) // more junk + .D64(0x0000000D) + + .D64(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.pc = 0x40005510; + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + Stackwalker::set_max_frames_scanned(0); + + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + + StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); +} + +class GetFramesByFramePointer: + public StackwalkerRISCV64Fixture, + public Test { }; + +TEST_F(GetFramesByFramePointer, OnlyFramePointer) { + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + Label frame1_fp, frame2_fp; + stack_section + // frame 0 + .Append(64, 0) // Whatever values on the stack. + .D64(0x0000000D) // junk that's not + .D64(0xF0000000) // a return address. + + .Mark(&frame1_fp) // Next fp will point to the next value. + .D64(frame2_fp) // Save current frame pointer. + .D64(return_address2) // Save current link register. + .Mark(&frame1_sp) + + // frame 1 + .Append(64, 0) // Whatever values on the stack. + .D64(0x0000000D) // junk that's not + .D64(0xF0000000) // a return address. + + .Mark(&frame2_fp) + .D64(0) + .D64(0) + .Mark(&frame2_sp) + + // frame 2 + .Append(64, 0) // Whatever values on the stack. + .D64(0x0000000D) // junk that's not + .D64(0xF0000000); // a return address. + RegionFromSection(); + + + raw_context.pc = 0x40005510; + raw_context.ra = return_address1; + raw_context.s0 = frame1_fp.Value(); + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, + &stack_region, &modules, &frame_symbolizer); + + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); + ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_RA | + StackFrameRISCV64::CONTEXT_VALID_S0 | + StackFrameRISCV64::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.pc); + EXPECT_EQ(return_address2, frame1->context.ra); + EXPECT_EQ(frame1_sp.Value(), frame1->context.sp); + EXPECT_EQ(frame2_fp.Value(), frame1->context.s0); + + StackFrameRISCV64 *frame2 = static_cast<StackFrameRISCV64*>(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust); + ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_RA | + StackFrameRISCV64::CONTEXT_VALID_S0 | + StackFrameRISCV64::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.pc); + EXPECT_EQ(0U, frame2->context.ra); + EXPECT_EQ(frame2_sp.Value(), frame2->context.sp); + EXPECT_EQ(0U, frame2->context.s0); +} + +struct CFIFixture: public StackwalkerRISCV64Fixture { + CFIFixture() { + // Provide a bunch of STACK CFI records; we'll walk to the caller + // from every point in this series, expecting to find the same set + // of register values. + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 4000 1000 10 enchiridion\n" + // Initially, nothing has been pushed on the stack, + // and the return address is still in the return + // address register (ra). + "STACK CFI INIT 4000 100 .cfa: sp 0 + .ra: ra\n" + // Push s1, s2, the frame pointer (s0) and the + // return address register. + "STACK CFI 4001 .cfa: sp 32 + .ra: .cfa -8 + ^" + " s1: .cfa -32 + ^ s2: .cfa -24 + ^ " + " s0: .cfa -16 + ^\n" + // Save s1..s4 in a1..a4: verify that we populate + // the youngest frame with all the values we have. + "STACK CFI 4002 s1: a1 s2: a2 s3: a3 s4: a4\n" + // Restore s1..s4. Save the non-callee-saves register a2. + "STACK CFI 4003 .cfa: sp 40 + a2: .cfa 40 - ^" + " s1: s1 s2: s2 s3: s3 s4: s4\n" + // Move the .cfa back eight bytes, to point at the return + // address, and restore the sp explicitly. + "STACK CFI 4005 .cfa: sp 32 + a2: .cfa 32 - ^" + " s0: .cfa 8 - ^ .ra: .cfa ^ sp: .cfa 8 +\n" + // Recover the PC explicitly from a new stack slot; + // provide garbage for the .ra. + "STACK CFI 4006 .cfa: sp 40 + pc: .cfa 40 - ^\n" + + // The calling function. + "FUNC 5000 1000 10 epictetus\n" + // Mark it as end of stack. + "STACK CFI INIT 5000 1000 .cfa: 0 .ra: 0\n" + + // A function whose CFI makes the stack pointer + // go backwards. + "FUNC 6000 1000 20 palinal\n" + "STACK CFI INIT 6000 1000 .cfa: sp 8 - .ra: ra\n" + + // A function with CFI expressions that can't be + // evaluated. + "FUNC 7000 1000 20 rhetorical\n" + "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n"); + + // Provide some distinctive values for the caller's registers. + expected.pc = 0x0000000040005510L; + expected.sp = 0x0000000080000000L; + expected.s1 = 0x5e68b5d5b5d55e68L; + expected.s2 = 0x34f3ebd1ebd134f3L; + expected.s3 = 0x74bca31ea31e74bcL; + expected.s4 = 0x16b32dcb2dcb16b3L; + expected.s5 = 0x21372ada2ada2137L; + expected.s6 = 0x557dbbbbbbbb557dL; + expected.s7 = 0x8ca748bf48bf8ca7L; + expected.s8 = 0x21f0ab46ab4621f0L; + expected.s9 = 0x146732b732b71467L; + expected.s10 = 0xa673645fa673645fL; + expected.s11 = 0xa673645fa673645fL; + expected.s0 = 0xe11081128112e110L; + + // Expect CFI to recover all callee-saves registers. Since CFI is the + // only stack frame construction technique we have, aside from the + // context frame itself, there's no way for us to have a set of valid + // registers smaller than this. + expected_validity = (StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_SP | + StackFrameRISCV64::CONTEXT_VALID_S1 | + StackFrameRISCV64::CONTEXT_VALID_S2 | + StackFrameRISCV64::CONTEXT_VALID_S3 | + StackFrameRISCV64::CONTEXT_VALID_S4 | + StackFrameRISCV64::CONTEXT_VALID_S5 | + StackFrameRISCV64::CONTEXT_VALID_S6 | + StackFrameRISCV64::CONTEXT_VALID_S7 | + StackFrameRISCV64::CONTEXT_VALID_S8 | + StackFrameRISCV64::CONTEXT_VALID_S9 | + StackFrameRISCV64::CONTEXT_VALID_S10 | + StackFrameRISCV64::CONTEXT_VALID_S11 | + StackFrameRISCV64::CONTEXT_VALID_S0); + + // By default, context frames provide all registers, as normal. + context_frame_validity = StackFrameRISCV64::CONTEXT_VALID_ALL; + + // By default, registers are unchanged. + raw_context = expected; + } + + // Walk the stack, using stack_section as the contents of the stack + // and raw_context as the current register values. (Set the stack + // pointer to the stack's starting address.) Expect two stack + // frames; in the older frame, expect the callee-saves registers to + // have values matching those in 'expected'. + void CheckWalk() { + RegionFromSection(); + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + walker.SetContextFrameValidity(context_frame_validity); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(context_frame_validity, frame0->context_validity); + EXPECT_EQ("enchiridion", frame0->function_name); + EXPECT_EQ(0x0000000040004000UL, frame0->function_base); + + StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ(expected_validity, frame1->context_validity); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_A2) + EXPECT_EQ(expected.a2, frame1->context.a2); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S1) + EXPECT_EQ(expected.s1, frame1->context.s1); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S2) + EXPECT_EQ(expected.s2, frame1->context.s2); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S3) + EXPECT_EQ(expected.s3, frame1->context.s3); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S4) + EXPECT_EQ(expected.s4, frame1->context.s4); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S5) + EXPECT_EQ(expected.s5, frame1->context.s5); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S6) + EXPECT_EQ(expected.s6, frame1->context.s6); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S7) + EXPECT_EQ(expected.s7, frame1->context.s7); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S8) + EXPECT_EQ(expected.s8, frame1->context.s8); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S9) + EXPECT_EQ(expected.s9, frame1->context.s9); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S10) + EXPECT_EQ(expected.s10, frame1->context.s10); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S11) + EXPECT_EQ(expected.s11, frame1->context.s11); + if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S0) + EXPECT_EQ(expected.s0, frame1->context.s0); + + // We would never have gotten a frame in the first place if the SP + // and PC weren't valid or ->instruction weren't set. + EXPECT_EQ(expected.sp, frame1->context.sp); + EXPECT_EQ(expected.pc, frame1->context.pc); + EXPECT_EQ(expected.pc, frame1->instruction + 4); + EXPECT_EQ("epictetus", frame1->function_name); + } + + // The values we expect to find for the caller's registers. + MDRawContextRISCV64 expected; + + // The validity mask for expected. + int expected_validity; + + // The validity mask to impose on the context frame. + int context_frame_validity; +}; + +class CFI: public CFIFixture, public Test { }; + +TEST_F(CFI, At4000) { + stack_section.start() = expected.sp; + raw_context.pc = 0x0000000040004000L; + raw_context.ra = 0x0000000040005510L; + CheckWalk(); +} + +TEST_F(CFI, At4001) { + Label frame1_sp = expected.sp; + stack_section + .D64(0x5e68b5d5b5d55e68L) // saved s1 + .D64(0x34f3ebd1ebd134f3L) // saved s2 + .D64(0xe11081128112e110L) // saved s0 + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x0000000040004001L; + // distinct callee s1, s2 and s0 + raw_context.s1 = 0xadc9f635a635adc9L; + raw_context.s2 = 0x623135ac35ac6231L; + raw_context.s0 = 0x5fc4be14be145fc4L; + CheckWalk(); +} + +// As above, but unwind from a context that has only the PC and SP. +TEST_F(CFI, At4001LimitedValidity) { + Label frame1_sp = expected.sp; + stack_section + .D64(0x5e68b5d5b5d55e68L) // saved s1 + .D64(0x34f3ebd1ebd134f3L) // saved s2 + .D64(0xe11081128112e110L) // saved s0 + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + context_frame_validity = StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_SP; + raw_context.pc = 0x0000000040004001L; + raw_context.s0 = 0x5fc4be14be145fc4L; + + expected_validity = (StackFrameRISCV64::CONTEXT_VALID_PC | + StackFrameRISCV64::CONTEXT_VALID_SP | + StackFrameRISCV64::CONTEXT_VALID_S0 | + StackFrameRISCV64::CONTEXT_VALID_S1 | + StackFrameRISCV64::CONTEXT_VALID_S2); + CheckWalk(); +} + +TEST_F(CFI, At4002) { + Label frame1_sp = expected.sp; + stack_section + .D64(0xff3dfb81fb81ff3dL) // no longer saved s1 + .D64(0x34f3ebd1ebd134f3L) // no longer saved s2 + .D64(0xe11081128112e110L) // saved s0 + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x0000000040004002L; + raw_context.a1 = 0x5e68b5d5b5d55e68L; // saved s1 + raw_context.a2 = 0x34f3ebd1ebd134f3L; // saved s2 + raw_context.a3 = 0x74bca31ea31e74bcL; // saved s3 + raw_context.a4 = 0x16b32dcb2dcb16b3L; // saved s4 + raw_context.s1 = 0xadc9f635a635adc9L; // distinct callee s1 + raw_context.s2 = 0x623135ac35ac6231L; // distinct callee s2 + raw_context.s3 = 0xac4543564356ac45L; // distinct callee s3 + raw_context.s4 = 0x2561562f562f2561L; // distinct callee s4 + // distinct callee s0 + raw_context.s0 = 0x5fc4be14be145fc4L; + CheckWalk(); +} + +TEST_F(CFI, At4003) { + Label frame1_sp = expected.sp; + stack_section + .D64(0xdd5a48c848c8dd5aL) // saved a2 (even though it's not callee-saves) + .D64(0xff3dfb81fb81ff3dL) // no longer saved s1 + .D64(0x34f3ebd1ebd134f3L) // no longer saved s2 + .D64(0xe11081128112e110L) // saved s0 + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x0000000040004003L; + // distinct callee a2 and fp + raw_context.a2 = 0xfb756319fb756319L; + raw_context.s0 = 0x5fc4be14be145fc4L; + // caller's a2 + expected.a2 = 0xdd5a48c848c8dd5aL; + expected_validity |= StackFrameRISCV64::CONTEXT_VALID_A2; + CheckWalk(); +} + +// We have no new rule at module offset 0x4004, so the results here should +// be the same as those at module offset 0x4003. +TEST_F(CFI, At4004) { + Label frame1_sp = expected.sp; + stack_section + .D64(0xdd5a48c848c8dd5aL) // saved a2 (even though it's not callee-saves) + .D64(0xff3dfb81fb81ff3dL) // no longer saved s1 + .D64(0x34f3ebd1ebd134f3L) // no longer saved s2 + .D64(0xe11081128112e110L) // saved s0 + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x0000000040004004L; + // distinct callee a2 and s0 + raw_context.a2 = 0xfb756319fb756319L; + raw_context.s0 = 0x5fc4be14be145fc4L; + // caller's a2 + expected.a2 = 0xdd5a48c848c8dd5aL; + expected_validity |= StackFrameRISCV64::CONTEXT_VALID_A2; + CheckWalk(); +} + +// Here we move the .cfa, but provide an explicit rule to recover the SP, +// so again there should be no change in the registers recovered. +TEST_F(CFI, At4005) { + Label frame1_sp = expected.sp; + stack_section + .D64(0xdd5a48c848c8dd5aL) // saved a2 (even though it's not callee-saves) + .D64(0xff3dfb81fb81ff3dL) // no longer saved s1 + .D64(0x34f3ebd1ebd134f3L) // no longer saved s2 + .D64(0xe11081128112e110L) // saved s0 + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x0000000040004005L; + raw_context.a2 = 0xfb756319fb756319L; // distinct callee a2 + expected.a2 = 0xdd5a48c848c8dd5aL; // caller's a2 + expected_validity |= StackFrameRISCV64::CONTEXT_VALID_A2; + CheckWalk(); +} + +// Here we provide an explicit rule for the PC, and have the saved .ra be +// bogus. +TEST_F(CFI, At4006) { + Label frame1_sp = expected.sp; + stack_section + .D64(0x0000000040005510L) // saved pc + .D64(0xdd5a48c848c8dd5aL) // saved a2 (even though it's not callee-saves) + .D64(0xff3dfb81fb81ff3dL) // no longer saved s1 + .D64(0x34f3ebd1ebd134f3L) // no longer saved s2 + .D64(0xe11081128112e110L) // saved s0 + .D64(0xf8d157835783f8d1L) // .ra rule recovers this, which is garbage + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x0000000040004006L; + raw_context.a2 = 0xfb756319fb756319L; // distinct callee a2 + expected.a2 = 0xdd5a48c848c8dd5aL; // caller's a2 + expected_validity |= StackFrameRISCV64::CONTEXT_VALID_A2; + CheckWalk(); +} + +// Check that we reject rules that would cause the stack pointer to +// move in the wrong direction. +TEST_F(CFI, RejectBackwards) { + raw_context.pc = 0x0000000040006000L; + raw_context.sp = 0x0000000080000000L; + raw_context.ra = 0x0000000040005510L; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} + +// Check that we reject rules whose expressions' evaluation fails. +TEST_F(CFI, RejectBadExpressions) { + raw_context.pc = 0x0000000040007000L; + raw_context.sp = 0x0000000080000000L; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} diff --git a/src/processor/stackwalker_riscv_unittest.cc b/src/processor/stackwalker_riscv_unittest.cc new file mode 100644 index 00000000..f4a6b79c --- /dev/null +++ b/src/processor/stackwalker_riscv_unittest.cc @@ -0,0 +1,883 @@ +// Copyright 2013 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* stackwalker_riscv_unittest.cc: Unit tests for StackwalkerRISCV class. + * + * Author: Iacopo Colonnelli + */ + +#include <string.h> +#include <string> +#include <vector> + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_riscv.h" +#include "processor/windows_frame_info.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameRISCV; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerRISCV; +using google_breakpad::SystemInfo; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::DoAll; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class StackwalkerRISCVFixture { +public: + StackwalkerRISCVFixture() + : stack_section(kLittleEndian), + // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(0x40000000, 0x10000, "module1", "version1"), + module2(0x50000000, 0x10000, "module2", "version2") { + // Identify the system as an iOS system. + system_info.os = "iOS"; + system_info.os_short = "ios"; + system_info.cpu = "riscv"; + system_info.cpu_info = ""; + + // Put distinctive values in the raw CPU context. + BrandContext(&raw_context); + + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + + // Reset max_frames_scanned since it's static. + Stackwalker::set_max_frames_scanned(1024); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule* module, const string& info) { + size_t buffer_size; + char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + // Populate stack_region with the contents of stack_section. Use + // stack_section.start() as the region's starting address. + void RegionFromSection() { + string contents; + ASSERT_TRUE(stack_section.GetContents(&contents)); + stack_region.Init(stack_section.start().Value(), contents); + } + + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. + void BrandContext(MDRawContextRISCV *raw_context) { + uint8_t x = 173; + for (size_t i = 0; i < sizeof(*raw_context); i++) + reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17); + } + + SystemInfo system_info; + MDRawContextRISCV raw_context; + Section stack_section; + MockMemoryRegion stack_region; + MockCodeModule module1; + MockCodeModule module2; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + CallStack call_stack; + const vector<StackFrame*>* frames; +}; + +class SanityCheck: public StackwalkerRISCVFixture, public Test { }; + +TEST_F(SanityCheck, NoResolver) { + // Since the context's frame pointer is garbage, the stack walk will end after + // the first frame. + StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + // This should succeed even without a resolver or supplier. + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameRISCV *frame = static_cast<StackFrameRISCV*>(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetContextFrame: public StackwalkerRISCVFixture, public Test { }; + +// The stackwalker should be able to produce the context frame even +// without stack memory present. +TEST_F(GetContextFrame, NoStackMemory) { + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, NULL, &modules, + &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameRISCV *frame = static_cast<StackFrameRISCV*>(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetCallerFrame: public StackwalkerRISCVFixture, public Test { }; + +TEST_F(GetCallerFrame, ScanWithoutSymbols) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + // Force scanning through three frames to ensure that the + // stack pointer is set properly in scan-recovered frames. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(8, 0) // space + + .D32(0x40090000) // junk that's not + .D32(0x60000000) // a return address + + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(8, 0) // space + + .D32(0xF0000000) // more junk + .D32(0x0000000D) + + .D32(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.pc = 0x40005510; + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.pc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.sp); + + StackFrameRISCV *frame2 = static_cast<StackFrameRISCV*>(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); + ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.pc); + EXPECT_EQ(frame2_sp.Value(), frame2->context.sp); +} + +TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { + // During stack scanning, if a potential return address + // is located within a loaded module that has symbols, + // it is only considered a valid return address if it + // lies within a function's bounds. + stack_section.start() = 0x80000000; + uint64_t return_address = 0x50000200; + Label frame1_sp; + + stack_section + // frame 0 + .Append(8, 0) // space + + .D32(0x40090000) // junk that's not + .D32(0x60000000) // a return address + + .D32(0x40001000) // a couple of plausible addresses + .D32(0x5000F000) // that are not within functions + + .D32(return_address) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.pc = 0x40000200; + raw_context.sp = stack_section.start().Value(); + + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 100 400 10 monotreme\n"); + SetModuleSymbols(&module2, + // The calling frame's function. + "FUNC 100 400 10 marsupial\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + EXPECT_EQ("monotreme", frame0->function_name); + EXPECT_EQ(0x40000100UL, frame0->function_base); + + StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address, frame1->context.pc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.sp); + EXPECT_EQ("marsupial", frame1->function_name); + EXPECT_EQ(0x50000100UL, frame1->function_base); +} + +TEST_F(GetCallerFrame, ScanFirstFrame) { + // If the stackwalker resorts to stack scanning, it will scan much + // farther to find the caller of the context frame. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D32(0x40090000) // junk that's not + .D32(0x60000000) // a return address + + .Append(48, 0) // more space + + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D32(0xF0000000) // more junk + .D32(0x0000000D) + + .Append(168, 0) // more space + + .D32(return_address2) // actual return address + // (won't be found) + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.pc = 0x40005510; + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.pc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.sp); +} + +// Test that set_max_frames_scanned prevents using stack scanning +// to find caller frames. +TEST_F(GetCallerFrame, ScanningNotAllowed) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(8, 0) // space + + .D32(0x40090000) // junk that's not + .D32(0x60000000) // a return address + + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(8, 0) // space + + .D32(0xF0000000) // more junk + .D32(0x0000000D) + + .D32(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.pc = 0x40005510; + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + Stackwalker::set_max_frames_scanned(0); + + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + + StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); +} + +class GetFramesByFramePointer: + public StackwalkerRISCVFixture, + public Test { }; + +TEST_F(GetFramesByFramePointer, OnlyFramePointer) { + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + Label frame1_fp, frame2_fp; + stack_section + // frame 0 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000) // a return address. + + .Mark(&frame1_fp) // Next fp will point to the next value. + .D32(frame2_fp) // Save current frame pointer. + .D32(return_address2) // Save current link register. + .Mark(&frame1_sp) + + // frame 1 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000) // a return address. + + .Mark(&frame2_fp) + .D32(0) + .D32(0) + .Mark(&frame2_sp) + + // frame 2 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000); // a return address. + RegionFromSection(); + + + raw_context.pc = 0x40005510; + raw_context.ra = return_address1; + raw_context.s0 = frame1_fp.Value(); + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, + &stack_region, &modules, &frame_symbolizer); + + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); + ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_RA | + StackFrameRISCV::CONTEXT_VALID_S0 | + StackFrameRISCV::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.pc); + EXPECT_EQ(return_address2, frame1->context.ra); + EXPECT_EQ(frame1_sp.Value(), frame1->context.sp); + EXPECT_EQ(frame2_fp.Value(), frame1->context.s0); + + StackFrameRISCV *frame2 = static_cast<StackFrameRISCV*>(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust); + ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_RA | + StackFrameRISCV::CONTEXT_VALID_S0 | + StackFrameRISCV::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.pc); + EXPECT_EQ(0U, frame2->context.ra); + EXPECT_EQ(frame2_sp.Value(), frame2->context.sp); + EXPECT_EQ(0U, frame2->context.s0); +} + +struct CFIFixture: public StackwalkerRISCVFixture { + CFIFixture() { + // Provide a bunch of STACK CFI records; we'll walk to the caller + // from every point in this series, expecting to find the same set + // of register values. + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 4000 1000 10 enchiridion\n" + // Initially, nothing has been pushed on the stack, + // and the return address is still in the return + // address register (ra). + "STACK CFI INIT 4000 100 .cfa: sp 0 + .ra: ra\n" + // Push s1, s2, the frame pointer (s0) and the + // return address register. + "STACK CFI 4001 .cfa: sp 16 + .ra: .cfa -4 + ^" + " s1: .cfa -16 + ^ s2: .cfa -12 + ^ " + " s0: .cfa -8 + ^\n" + // Save s1..s4 in a1..a4: verify that we populate + // the youngest frame with all the values we have. + "STACK CFI 4002 s1: a1 s2: a2 s3: a3 s4: a4\n" + // Restore s1..s4. Save the non-callee-saves register a2. + "STACK CFI 4003 .cfa: sp 20 + a2: .cfa 20 - ^" + " s1: s1 s2: s2 s3: s3 s4: s4\n" + // Move the .cfa back eight bytes, to point at the return + // address, and restore the sp explicitly. + "STACK CFI 4005 .cfa: sp 16 + a2: .cfa 16 - ^" + " s0: .cfa 4 - ^ .ra: .cfa ^ sp: .cfa 4 +\n" + // Recover the PC explicitly from a new stack slot; + // provide garbage for the .ra. + "STACK CFI 4006 .cfa: sp 20 + pc: .cfa 20 - ^\n" + + // The calling function. + "FUNC 5000 1000 10 epictetus\n" + // Mark it as end of stack. + "STACK CFI INIT 5000 1000 .cfa: 0 .ra: 0\n" + + // A function whose CFI makes the stack pointer + // go backwards. + "FUNC 6000 1000 20 palinal\n" + "STACK CFI INIT 6000 1000 .cfa: sp 4 - .ra: ra\n" + + // A function with CFI expressions that can't be + // evaluated. + "FUNC 7000 1000 20 rhetorical\n" + "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n"); + + // Provide some distinctive values for the caller's registers. + expected.pc = 0x40005510; + expected.sp = 0x80000000; + expected.s1 = 0xb5d55e68; + expected.s2 = 0xebd134f3; + expected.s3 = 0xa31e74bc; + expected.s4 = 0x2dcb16b3; + expected.s5 = 0x2ada2137; + expected.s6 = 0xbbbb557d; + expected.s7 = 0x48bf8ca7; + expected.s8 = 0xab4621f0; + expected.s9 = 0x32b71467; + expected.s10 = 0xa673645f; + expected.s11 = 0xa673645f; + expected.s0 = 0x8112e110; + + // Expect CFI to recover all callee-saves registers. Since CFI is the + // only stack frame construction technique we have, aside from the + // context frame itself, there's no way for us to have a set of valid + // registers smaller than this. + expected_validity = (StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_SP | + StackFrameRISCV::CONTEXT_VALID_S1 | + StackFrameRISCV::CONTEXT_VALID_S2 | + StackFrameRISCV::CONTEXT_VALID_S3 | + StackFrameRISCV::CONTEXT_VALID_S4 | + StackFrameRISCV::CONTEXT_VALID_S5 | + StackFrameRISCV::CONTEXT_VALID_S6 | + StackFrameRISCV::CONTEXT_VALID_S7 | + StackFrameRISCV::CONTEXT_VALID_S8 | + StackFrameRISCV::CONTEXT_VALID_S9 | + StackFrameRISCV::CONTEXT_VALID_S10 | + StackFrameRISCV::CONTEXT_VALID_S11 | + StackFrameRISCV::CONTEXT_VALID_S0); + + // By default, context frames provide all registers, as normal. + context_frame_validity = StackFrameRISCV::CONTEXT_VALID_ALL; + + // By default, registers are unchanged. + raw_context = expected; + } + + // Walk the stack, using stack_section as the contents of the stack + // and raw_context as the current register values. (Set the stack + // pointer to the stack's starting address.) Expect two stack + // frames; in the older frame, expect the callee-saves registers to + // have values matching those in 'expected'. + void CheckWalk() { + RegionFromSection(); + raw_context.sp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + walker.SetContextFrameValidity(context_frame_validity); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(context_frame_validity, frame0->context_validity); + EXPECT_EQ("enchiridion", frame0->function_name); + EXPECT_EQ(0x40004000U, frame0->function_base); + + StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ(expected_validity, frame1->context_validity); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_A2) + EXPECT_EQ(expected.a2, frame1->context.a2); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S1) + EXPECT_EQ(expected.s1, frame1->context.s1); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S2) + EXPECT_EQ(expected.s2, frame1->context.s2); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S3) + EXPECT_EQ(expected.s3, frame1->context.s3); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S4) + EXPECT_EQ(expected.s4, frame1->context.s4); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S5) + EXPECT_EQ(expected.s5, frame1->context.s5); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S6) + EXPECT_EQ(expected.s6, frame1->context.s6); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S7) + EXPECT_EQ(expected.s7, frame1->context.s7); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S8) + EXPECT_EQ(expected.s8, frame1->context.s8); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S9) + EXPECT_EQ(expected.s9, frame1->context.s9); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S10) + EXPECT_EQ(expected.s10, frame1->context.s10); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S11) + EXPECT_EQ(expected.s11, frame1->context.s11); + if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S0) + EXPECT_EQ(expected.s0, frame1->context.s0); + + // We would never have gotten a frame in the first place if the SP + // and PC weren't valid or ->instruction weren't set. + EXPECT_EQ(expected.sp, frame1->context.sp); + EXPECT_EQ(expected.pc, frame1->context.pc); + EXPECT_EQ(expected.pc, frame1->instruction + 4); + EXPECT_EQ("epictetus", frame1->function_name); + } + + // The values we expect to find for the caller's registers. + MDRawContextRISCV expected; + + // The validity mask for expected. + int expected_validity; + + // The validity mask to impose on the context frame. + int context_frame_validity; +}; + +class CFI: public CFIFixture, public Test { }; + +TEST_F(CFI, At4000) { + stack_section.start() = expected.sp; + raw_context.pc = 0x40004000; + raw_context.ra = 0x40005510; + CheckWalk(); +} + +TEST_F(CFI, At4001) { + Label frame1_sp = expected.sp; + stack_section + .D32(0xb5d55e68) // saved s1 + .D32(0xebd134f3) // saved s2 + .D32(0x8112e110) // saved s0 + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x40004001; + // distinct callee s1, s2 and s0 + raw_context.s1 = 0xa635adc9; + raw_context.s2 = 0x35ac6231; + raw_context.s0 = 0xbe145fc4; + CheckWalk(); +} + +// As above, but unwind from a context that has only the PC and SP. +TEST_F(CFI, At4001LimitedValidity) { + Label frame1_sp = expected.sp; + stack_section + .D32(0xb5d55e68) // saved s1 + .D32(0xebd134f3) // saved s2 + .D32(0x8112e110) // saved s0 + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + context_frame_validity = StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_SP; + raw_context.pc = 0x40004001; + raw_context.s0 = 0xbe145fc4; + + expected_validity = (StackFrameRISCV::CONTEXT_VALID_PC | + StackFrameRISCV::CONTEXT_VALID_SP | + StackFrameRISCV::CONTEXT_VALID_S0 | + StackFrameRISCV::CONTEXT_VALID_S1 | + StackFrameRISCV::CONTEXT_VALID_S2); + CheckWalk(); +} + +TEST_F(CFI, At4002) { + Label frame1_sp = expected.sp; + stack_section + .D32(0xfb81ff3d) // no longer saved s1 + .D32(0xebd134f3) // no longer saved s2 + .D32(0x8112e110) // saved s0 + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x40004002; + raw_context.a1 = 0xb5d55e68; // saved a1 + raw_context.a2 = 0xebd134f3; // saved a2 + raw_context.a3 = 0xa31e74bc; // saved a3 + raw_context.a4 = 0x2dcb16b3; // saved a4 + raw_context.s1 = 0xa635adc9; // distinct callee s1 + raw_context.s2 = 0x35ac6231; // distinct callee s2 + raw_context.s3 = 0x4356ac45; // distinct callee s3 + raw_context.s4 = 0x562f2561; // distinct callee s4 + // distinct callee s0 + raw_context.s0 = 0xbe145fc4; + CheckWalk(); +} + +TEST_F(CFI, At4003) { + Label frame1_sp = expected.sp; + stack_section + .D32(0x48c8dd5a) // saved a2 (even though it's not callee-saves) + .D32(0xfb81ff3d) // no longer saved s1 + .D32(0xebd134f3) // no longer saved s2 + .D32(0x8112e110) // saved s0 + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x40004003; + // distinct callee a2 and fp + raw_context.a2 = 0xfb756319; + raw_context.s0 = 0xbe145fc4; + // caller's a2 + expected.a2 = 0x48c8dd5a; + expected_validity |= StackFrameRISCV::CONTEXT_VALID_A2; + CheckWalk(); +} + +// We have no new rule at module offset 0x4004, so the results here should +// be the same as those at module offset 0x4003. +TEST_F(CFI, At4004) { + Label frame1_sp = expected.sp; + stack_section + .D32(0x48c8dd5a) // saved a2 (even though it's not callee-saves) + .D32(0xfb81ff3d) // no longer saved s1 + .D32(0xebd134f3) // no longer saved s2 + .D32(0x8112e110) // saved s0 + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x40004004; + // distinct callee a2 and s0 + raw_context.a2 = 0xfb756319; + raw_context.s0 = 0xbe145fc4; + // caller's a2 + expected.a2 = 0x48c8dd5a; + expected_validity |= StackFrameRISCV::CONTEXT_VALID_A2; + CheckWalk(); +} + +// Here we move the .cfa, but provide an explicit rule to recover the SP, +// so again there should be no change in the registers recovered. +TEST_F(CFI, At4005) { + Label frame1_sp = expected.sp; + stack_section + .D32(0x48c8dd5a) // saved a2 (even though it's not callee-saves) + .D32(0xfb81ff3d) // no longer saved s1 + .D32(0xebd134f3) // no longer saved s2 + .D32(0x8112e110) // saved s0 + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x40004005; + raw_context.a2 = 0xfb756319; // distinct callee a2 + expected.a2 = 0x48c8dd5a; // caller's a2 + expected_validity |= StackFrameRISCV::CONTEXT_VALID_A2; + CheckWalk(); +} + +// Here we provide an explicit rule for the PC, and have the saved .ra be +// bogus. +TEST_F(CFI, At4006) { + Label frame1_sp = expected.sp; + stack_section + .D32(0x40005510) // saved pc + .D32(0x48c8dd5a) // saved a2 (even though it's not callee-saves) + .D32(0xfb81ff3d) // no longer saved s1 + .D32(0xebd134f3) // no longer saved s2 + .D32(0x8112e110) // saved s0 + .D32(0x5783f8d1) // .ra rule recovers this, which is garbage + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.pc = 0x40004006; + raw_context.a2 = 0xfb756319; // distinct callee a2 + expected.a2 = 0x48c8dd5a; // caller's a2 + expected_validity |= StackFrameRISCV::CONTEXT_VALID_A2; + CheckWalk(); +} + +// Check that we reject rules that would cause the stack pointer to +// move in the wrong direction. +TEST_F(CFI, RejectBackwards) { + raw_context.pc = 0x40006000; + raw_context.sp = 0x80000000; + raw_context.ra = 0x40005510; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} + +// Check that we reject rules whose expressions' evaluation fails. +TEST_F(CFI, RejectBadExpressions) { + raw_context.pc = 0x40007000; + raw_context.sp = 0x80000000; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerRISCV walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} diff --git a/src/processor/stackwalker_selftest.cc b/src/processor/stackwalker_selftest.cc index f692d4c4..2737f64d 100644 --- a/src/processor/stackwalker_selftest.cc +++ b/src/processor/stackwalker_selftest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -420,7 +419,7 @@ int main(int argc, char** argv) { // Not i386 or ppc or sparc? We can only test stacks we know how to walk. -int main(int argc, char **argv) { +int main(int argc, char** argv) { BPLOG_INIT(&argc, &argv); // "make check" interprets an exit status of 77 to mean that the test is diff --git a/src/processor/stackwalker_selftest_sol.s b/src/processor/stackwalker_selftest_sol.s index 648b0499..11d1698f 100644 --- a/src/processor/stackwalker_selftest_sol.s +++ b/src/processor/stackwalker_selftest_sol.s @@ -1,5 +1,4 @@ -/* Copyright (c) 2007, Google Inc. - * All rights reserved. +/* Copyright 2007 Google LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ * 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 + * * Neither the name of Google LLC nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * diff --git a/src/processor/stackwalker_sparc.cc b/src/processor/stackwalker_sparc.cc index 4de838af..fb76744c 100644 --- a/src/processor/stackwalker_sparc.cc +++ b/src/processor/stackwalker_sparc.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -112,10 +111,9 @@ StackFrame* StackwalkerSPARC::GetCallerFrame(const CallStack* stack, } // Should we terminate the stack walk? (end-of-stack or broken invariant) - if (TerminateWalk(instruction, - stack_pointer, - last_frame->context.g_r[14], - stack->frames()->size() == 1)) { + if (TerminateWalk(instruction, stack_pointer, last_frame->context.g_r[14], + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { return NULL; } diff --git a/src/processor/stackwalker_sparc.h b/src/processor/stackwalker_sparc.h index e8f2a388..b7ba507e 100644 --- a/src/processor/stackwalker_sparc.h +++ b/src/processor/stackwalker_sparc.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/stackwalker_unittest_utils.h b/src/processor/stackwalker_unittest_utils.h index 3a92a5ea..3d651b2c 100644 --- a/src/processor/stackwalker_unittest_utils.h +++ b/src/processor/stackwalker_unittest_utils.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -57,7 +56,7 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion { // Set this region's address and contents. If we have placed an // instance of this class in a test fixture class, individual tests // can use this to provide the region's contents. - void Init(uint64_t base_address, const string &contents) { + void Init(uint64_t base_address, const string& contents) { base_address_ = base_address; contents_ = contents; } @@ -65,16 +64,16 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion { uint64_t GetBase() const { return base_address_; } uint32_t GetSize() const { return contents_.size(); } - bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { return GetMemoryLittleEndian(address, value); } - bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { return GetMemoryLittleEndian(address, value); } - bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { return GetMemoryLittleEndian(address, value); } - bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { return GetMemoryLittleEndian(address, value); } void Print() const { @@ -85,7 +84,7 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion { // Fetch a little-endian value from ADDRESS in contents_ whose size // is BYTES, and store it in *VALUE. Return true on success. template<typename ValueType> - bool GetMemoryLittleEndian(uint64_t address, ValueType *value) const { + bool GetMemoryLittleEndian(uint64_t address, ValueType* value) const { if (address < base_address_ || address - base_address_ + sizeof(ValueType) > contents_.size()) return false; @@ -105,7 +104,7 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion { class MockCodeModule: public google_breakpad::CodeModule { public: MockCodeModule(uint64_t base_address, uint64_t size, - const string &code_file, const string &version) + const string& code_file, const string& version) : base_address_(base_address), size_(size), code_file_(code_file) { } uint64_t base_address() const { return base_address_; } @@ -115,7 +114,7 @@ class MockCodeModule: public google_breakpad::CodeModule { string debug_file() const { return code_file_; } string debug_identifier() const { return code_file_; } string version() const { return version_; } - google_breakpad::CodeModule *Copy() const { + google_breakpad::CodeModule* Copy() const { abort(); // Tests won't use this. } virtual bool is_unloaded() const { return false; } @@ -134,16 +133,16 @@ class MockCodeModules: public google_breakpad::CodeModules { typedef google_breakpad::CodeModule CodeModule; typedef google_breakpad::CodeModules CodeModules; - void Add(const MockCodeModule *module) { + void Add(const MockCodeModule* module) { modules_.push_back(module); } unsigned int module_count() const { return modules_.size(); } - const CodeModule *GetModuleForAddress(uint64_t address) const { + const CodeModule* GetModuleForAddress(uint64_t address) const { for (ModuleVector::const_iterator i = modules_.begin(); i != modules_.end(); i++) { - const MockCodeModule *module = *i; + const MockCodeModule* module = *i; if (module->base_address() <= address && address - module->base_address() < module->size()) return module; @@ -151,17 +150,17 @@ class MockCodeModules: public google_breakpad::CodeModules { return NULL; }; - const CodeModule *GetMainModule() const { return modules_[0]; } + const CodeModule* GetMainModule() const { return modules_[0]; } - const CodeModule *GetModuleAtSequence(unsigned int sequence) const { + const CodeModule* GetModuleAtSequence(unsigned int sequence) const { return modules_.at(sequence); } - const CodeModule *GetModuleAtIndex(unsigned int index) const { + const CodeModule* GetModuleAtIndex(unsigned int index) const { return modules_.at(index); } - CodeModules *Copy() const { abort(); } // Tests won't use this + CodeModules* Copy() const { abort(); } // Tests won't use this virtual std::vector<google_breakpad::linked_ptr<const CodeModule> > GetShrunkRangeModules() const { @@ -169,7 +168,7 @@ class MockCodeModules: public google_breakpad::CodeModules { } private: - typedef std::vector<const MockCodeModule *> ModuleVector; + typedef std::vector<const MockCodeModule*> ModuleVector; ModuleVector modules_; }; @@ -177,26 +176,26 @@ class MockSymbolSupplier: public google_breakpad::SymbolSupplier { public: typedef google_breakpad::CodeModule CodeModule; typedef google_breakpad::SystemInfo SystemInfo; - MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file)); - MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data)); - MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size)); - MOCK_METHOD1(FreeSymbolData, void(const CodeModule *module)); + MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file)); + MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + string* symbol_data)); + MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule* module, + const SystemInfo* system_info, + string* symbol_file, + char** symbol_data, + size_t* symbol_data_size)); + MOCK_METHOD1(FreeSymbolData, void(const CodeModule* module)); // Copies the passed string contents into a newly allocated buffer. // The newly allocated buffer will be freed during destruction. - char* CopySymbolDataAndOwnTheCopy(const string &info, - size_t *symbol_data_size) { + char* CopySymbolDataAndOwnTheCopy(const string& info, + size_t* symbol_data_size) { *symbol_data_size = info.size() + 1; - char *symbol_data = new char[*symbol_data_size]; + char* symbol_data = new char[*symbol_data_size]; memcpy(symbol_data, info.c_str(), info.size()); symbol_data[info.size()] = '\0'; symbol_data_to_free_.push_back(symbol_data); diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc index ed2b383d..b598c5bd 100644 --- a/src/processor/stackwalker_x86.cc +++ b/src/processor/stackwalker_x86.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -136,11 +135,14 @@ StackFrame* StackwalkerX86::GetContextFrame() { } StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( - const vector<StackFrame*> &frames, + const vector<StackFrame*>& frames, WindowsFrameInfo* last_frame_info, bool stack_scan_allowed) { StackFrame::FrameTrust trust = StackFrame::FRAME_TRUST_NONE; + // The last frame can never be inline. A sequence of inline frames always + // finishes with a conventional frame. + assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE); StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back()); // Save the stack walking info we found, in case we need it later to @@ -187,9 +189,15 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( uint32_t last_frame_callee_parameter_size = 0; int frames_already_walked = frames.size(); - if (frames_already_walked >= 2) { + for (int last_frame_callee_id = frames_already_walked - 2; + last_frame_callee_id >= 0; last_frame_callee_id--) { + // Searching for a real callee frame. Skipping inline frames since they + // cannot be downcasted to StackFrameX86. + if (frames[last_frame_callee_id]->trust == StackFrame::FRAME_TRUST_INLINE) { + continue; + } const StackFrameX86* last_frame_callee - = static_cast<StackFrameX86*>(frames[frames_already_walked - 2]); + = static_cast<StackFrameX86*>(frames[last_frame_callee_id]); WindowsFrameInfo* last_frame_callee_info = last_frame_callee->windows_frame_info; if (last_frame_callee_info && @@ -385,9 +393,10 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( // frame pointer. uint32_t location_start = last_frame->context.esp; uint32_t location, eip; - if (!stack_scan_allowed - || !ScanForReturnAddress(location_start, &location, &eip, - frames.size() == 1 /* is_context_frame */)) { + if (!stack_scan_allowed || + !ScanForReturnAddress(location_start, &location, &eip, + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { // if we can't find an instruction pointer even with stack scanning, // give up. return NULL; @@ -429,9 +438,10 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( // looking one 32-bit word above that location. uint32_t location_start = dictionary[".raSearchStart"] + 4; uint32_t location; - if (stack_scan_allowed - && ScanForReturnAddress(location_start, &location, &eip, - frames.size() == 1 /* is_context_frame */)) { + if (stack_scan_allowed && + ScanForReturnAddress(location_start, &location, &eip, + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { // This is a better return address that what program string // evaluation found. Use it, and set %esp to the location above the // one where the return address was found. @@ -514,8 +524,11 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( } StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( - const vector<StackFrame*> &frames, + const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info) { + // The last frame can never be inline. A sequence of inline frames always + // finishes with a conventional frame. + assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE); StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back()); last_frame->cfi_frame_info = cfi_frame_info; @@ -539,9 +552,12 @@ StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( } StackFrameX86* StackwalkerX86::GetCallerByEBPAtBase( - const vector<StackFrame*> &frames, + const vector<StackFrame*>& frames, bool stack_scan_allowed) { StackFrame::FrameTrust trust; + // The last frame can never be inline. A sequence of inline frames always + // finishes with a conventional frame. + assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE); StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back()); uint32_t last_esp = last_frame->context.esp; uint32_t last_ebp = last_frame->context.ebp; @@ -581,9 +597,10 @@ StackFrameX86* StackwalkerX86::GetCallerByEBPAtBase( // return address. This can happen if last_frame is executing code // for a module for which we don't have symbols, and that module // is compiled without a frame pointer. - if (!stack_scan_allowed - || !ScanForReturnAddress(last_esp, &caller_esp, &caller_eip, - frames.size() == 1 /* is_context_frame */)) { + if (!stack_scan_allowed || + !ScanForReturnAddress(last_esp, &caller_esp, &caller_eip, + /*is_context_frame=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { // if we can't find an instruction pointer even with stack scanning, // give up. return NULL; @@ -632,8 +649,11 @@ StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack, return NULL; } - const vector<StackFrame*> &frames = *stack->frames(); + const vector<StackFrame*>& frames = *stack->frames(); StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back()); + // The last frame can never be inline. A sequence of inline frames always + // finishes with a conventional frame. + assert(last_frame->trust != StackFrame::FRAME_TRUST_INLINE); scoped_ptr<StackFrameX86> new_frame; // If the resolver has Windows stack walking information, use that. @@ -660,10 +680,10 @@ StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack, return NULL; // Should we terminate the stack walk? (end-of-stack or broken invariant) - if (TerminateWalk(new_frame->context.eip, - new_frame->context.esp, + if (TerminateWalk(new_frame->context.eip, new_frame->context.esp, last_frame->context.esp, - frames.size() == 1)) { + /*first_unwind=*/last_frame->trust == + StackFrame::FRAME_TRUST_CONTEXT)) { return NULL; } diff --git a/src/processor/stackwalker_x86.h b/src/processor/stackwalker_x86.h index 0659a13b..1867a689 100644 --- a/src/processor/stackwalker_x86.h +++ b/src/processor/stackwalker_x86.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -81,14 +80,14 @@ class StackwalkerX86 : public Stackwalker { // to construct the frame that called frames.back(). The caller // takes ownership of the returned frame. Return NULL on failure. StackFrameX86* GetCallerByWindowsFrameInfo( - const vector<StackFrame*> &frames, + const vector<StackFrame*>& frames, WindowsFrameInfo* windows_frame_info, bool stack_scan_allowed); // Use cfi_frame_info (derived from STACK CFI records) to construct // the frame that called frames.back(). The caller takes ownership // of the returned frame. Return NULL on failure. - StackFrameX86* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames, + StackFrameX86* GetCallerByCFIFrameInfo(const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info); // Assuming a traditional frame layout --- where the caller's %ebp @@ -96,7 +95,7 @@ class StackwalkerX86 : public Stackwalker { // %ebp points to the saved %ebp --- construct the frame that called // frames.back(). The caller takes ownership of the returned frame. // Return NULL on failure. - StackFrameX86* GetCallerByEBPAtBase(const vector<StackFrame*> &frames, + StackFrameX86* GetCallerByEBPAtBase(const vector<StackFrame*>& frames, bool stack_scan_allowed); // Stores the CPU context corresponding to the innermost stack frame to diff --git a/src/processor/stackwalker_x86_unittest.cc b/src/processor/stackwalker_x86_unittest.cc index 359f1c86..3d786b8e 100644 --- a/src/processor/stackwalker_x86_unittest.cc +++ b/src/processor/stackwalker_x86_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -113,7 +112,7 @@ class StackwalkerX86Fixture { // Set the Breakpad symbol information that supplier should return for // MODULE to INFO. - void SetModuleSymbols(MockCodeModule *module, const string &info) { + void SetModuleSymbols(MockCodeModule* module, const string& info) { size_t buffer_size; char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) @@ -134,7 +133,7 @@ class StackwalkerX86Fixture { void BrandContext(MDRawContextX86 *raw_context) { uint8_t x = 173; for (size_t i = 0; i < sizeof(*raw_context); i++) - reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17); + reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17); } SystemInfo system_info; @@ -151,7 +150,7 @@ class StackwalkerX86Fixture { MockSymbolSupplier supplier; BasicSourceLineResolver resolver; CallStack call_stack; - const vector<StackFrame *> *frames; + const vector<StackFrame*>* frames; }; class SanityCheck: public StackwalkerX86Fixture, public Test { }; @@ -175,7 +174,7 @@ TEST_F(SanityCheck, NoResolver) { ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); - StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -201,7 +200,7 @@ TEST_F(GetContextFrame, Simple) { ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); - StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -224,7 +223,7 @@ TEST_F(GetContextFrame, NoStackMemory) { ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); frames = call_stack.frames(); - StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(0)); // Check that the values from the original raw context made it // through to the context in the stack frame. EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); @@ -269,7 +268,7 @@ TEST_F(GetCallerFrame, Traditional) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); EXPECT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x4000c7a5U, frame0->instruction); @@ -279,7 +278,7 @@ TEST_F(GetCallerFrame, Traditional) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -333,7 +332,7 @@ TEST_F(GetCallerFrame, TraditionalScan) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x4000f49dU, frame0->instruction); @@ -344,7 +343,7 @@ TEST_F(GetCallerFrame, TraditionalScan) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -399,7 +398,7 @@ TEST_F(GetCallerFrame, TraditionalScanLongWay) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x4000f49dU, frame0->instruction); @@ -410,7 +409,7 @@ TEST_F(GetCallerFrame, TraditionalScanLongWay) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -465,7 +464,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) { ASSERT_EQ(1U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x4000f49dU, frame0->instruction); @@ -524,7 +523,7 @@ TEST_F(GetCallerFrame, WindowsFrameData) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x4000aa85U, frame0->instruction); @@ -535,7 +534,7 @@ TEST_F(GetCallerFrame, WindowsFrameData) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -605,7 +604,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataAligned) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x4000aa85U, frame0->instruction); @@ -616,7 +615,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataAligned) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -693,7 +692,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) { ASSERT_EQ(3U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x40001004U, frame0->instruction); @@ -714,7 +713,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -737,7 +736,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2)); + StackFrameX86 *frame2 = static_cast<StackFrameX86*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -793,7 +792,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataScan) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x40000c9cU, frame0->instruction); @@ -804,7 +803,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataScan) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the walker // does not actually fetch the EBP after a scan (forcing the next frame @@ -882,7 +881,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x40000700U, frame0->instruction); @@ -893,7 +892,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust); // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the // walker does not actually fetch the EBP after a scan (forcing the @@ -955,7 +954,7 @@ TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x4000e8b8U, frame0->instruction); @@ -976,7 +975,7 @@ TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -1039,7 +1038,7 @@ TEST_F(GetCallerFrame, WindowsFPOUsedEBP) { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x40009ab8U, frame0->instruction); @@ -1060,7 +1059,7 @@ TEST_F(GetCallerFrame, WindowsFPOUsedEBP) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -1170,8 +1169,8 @@ TEST_F(GetCallerFrame, WindowsFPOReferencesEBX) { StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, &frame_symbolizer); - vector<const CodeModule *> modules_without_symbols; - vector<const CodeModule *> modules_with_corrupt_symbols; + vector<const CodeModule*> modules_without_symbols; + vector<const CodeModule*> modules_with_corrupt_symbols; ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, &modules_with_corrupt_symbols)); ASSERT_EQ(0U, modules_without_symbols.size()); @@ -1180,31 +1179,31 @@ TEST_F(GetCallerFrame, WindowsFPOReferencesEBX) { ASSERT_EQ(5U, frames->size()); { - const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(0)); + const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame.trust); EXPECT_EQ(0x77726bf4U, frame.context.eip); EXPECT_EQ("KiFastSystemCallRet", frame.function_name); } { - const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(1)); + const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust); EXPECT_EQ(0x7772655cU, frame.context.eip); EXPECT_EQ("NtWaitForKeyedEvent", frame.function_name); } { - const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(2)); + const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust); EXPECT_EQ(0x776e4a3fU, frame.context.eip); EXPECT_EQ("RtlSleepConditionVariableSRW", frame.function_name); } { - const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(3)); + const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(3)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust); EXPECT_EQ(0x7728219eU, frame.context.eip); EXPECT_EQ("SleepConditionVariableSRW", frame.function_name); } { - const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(4)); + const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(4)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust); EXPECT_EQ(0x5ac0486cU, frame.context.eip); EXPECT_EQ("base::ConditionVariable::TimedWait", frame.function_name); @@ -1318,7 +1317,7 @@ TEST_F(GetCallerFrame, WindowsFPOSystemCall) { ASSERT_EQ(4U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x771ef8c1U, frame0->instruction); @@ -1338,7 +1337,7 @@ TEST_F(GetCallerFrame, WindowsFPOSystemCall) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP @@ -1532,7 +1531,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) { ASSERT_EQ(3U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(0x77c181cdU, frame0->instruction); @@ -1554,7 +1553,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | @@ -1578,7 +1577,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2)); + StackFrameX86 *frame2 = static_cast<StackFrameX86*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | @@ -1610,7 +1609,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { MockCodeModule chrome_dll(0x59630000, 0x19e3000, "chrome.dll", "version1"); SetModuleSymbols(&chrome_dll, // chrome.dll "FUNC 56422 50c 8 base::MessageLoop::RunTask" - "(base::PendingTask const &)\n" + "(base::PendingTask const&)\n" "56422 e 458 4589\n" "STACK WIN 4 56422 50c 11 0 8 c ac 0 1 $T1 .raSearch = $T0 " "$T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + = " @@ -1627,7 +1626,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { "$T1 4 - 64 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + " "= $20 $T0 56 - ^ = $23 $T0 60 - ^ = $24 $T0 64 - ^ =\n" "FUNC 55bf0 49 4 base::MessagePumpWin::Run(base::" - "MessagePump::Delegate *)\n" + "MessagePump::Delegate*)\n" "55bf0 49 48 4724\n" "STACK WIN 4 55bf0 49 c 0 4 0 10 0 1 $T0 $ebp = $eip $T0 4 " "+ ^ = $ebp $T0 ^ = $esp $T0 8 + =\n" @@ -1735,7 +1734,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { ASSERT_EQ(3U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame->context_validity); EXPECT_EQ("base::MessagePumpForIO::DoRunLoop()", frame->function_name); @@ -1756,13 +1755,13 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | StackFrameX86::CONTEXT_VALID_EBP), frame->context_validity); - EXPECT_EQ("base::MessagePumpWin::Run(base::MessagePump::Delegate *)", + EXPECT_EQ("base::MessagePumpWin::Run(base::MessagePump::Delegate*)", frame->function_name); EXPECT_EQ(1500011566U, frame->instruction + 1); EXPECT_EQ(1500011566U, frame->context.eip); @@ -1779,7 +1778,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { } { // To avoid reusing locals by mistake - StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(2)); + StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | @@ -1984,7 +1983,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( ASSERT_EQ(4U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ(raw_context.eip, frame0->context.eip); @@ -1996,7 +1995,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | @@ -2016,7 +2015,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( } { // To avoid reusing locals by mistake - StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2)); + StackFrameX86 *frame2 = static_cast<StackFrameX86*>(frames->at(2)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | @@ -2036,7 +2035,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( } { // To avoid reusing locals by mistake - StackFrameX86 *frame3 = static_cast<StackFrameX86 *>(frames->at(3)); + StackFrameX86 *frame3 = static_cast<StackFrameX86*>(frames->at(3)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame3->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | @@ -2126,7 +2125,7 @@ struct CFIFixture: public StackwalkerX86Fixture { ASSERT_EQ(2U, frames->size()); { // To avoid reusing locals by mistake - StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0)); + StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); EXPECT_EQ("enchiridion", frame0->function_name); @@ -2138,7 +2137,7 @@ struct CFIFixture: public StackwalkerX86Fixture { } { // To avoid reusing locals by mistake - StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1)); + StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | diff --git a/src/processor/static_address_map-inl.h b/src/processor/static_address_map-inl.h index 67e07976..0dd13f84 100644 --- a/src/processor/static_address_map-inl.h +++ b/src/processor/static_address_map-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -44,8 +43,8 @@ namespace google_breakpad { template<typename AddressType, typename EntryType> bool StaticAddressMap<AddressType, EntryType>::Retrieve( - const AddressType &address, - const EntryType *&entry, AddressType *entry_address) const { + const AddressType& address, + const EntryType*& entry, AddressType* entry_address) const { // upper_bound gives the first element whose key is greater than address, // but we want the first element whose key is less than or equal to address. diff --git a/src/processor/static_address_map.h b/src/processor/static_address_map.h index 6bafc667..156ecd63 100644 --- a/src/processor/static_address_map.h +++ b/src/processor/static_address_map.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -52,15 +51,15 @@ template<typename AddressType, typename EntryType> class StaticAddressMap { public: StaticAddressMap(): map_() { } - explicit StaticAddressMap(const char *map_data): map_(map_data) { } + explicit StaticAddressMap(const char* map_data): map_(map_data) { } // Locates the entry stored at the highest address less than or equal to // the address argument. If there is no such range, returns false. The // entry is returned in entry, which is a required argument. If // entry_address is not NULL, it will be set to the address that the entry // was stored at. - bool Retrieve(const AddressType &address, - const EntryType *&entry, AddressType *entry_address) const; + bool Retrieve(const AddressType& address, + const EntryType*& entry, AddressType* entry_address) const; private: friend class ModuleComparer; diff --git a/src/processor/static_address_map_unittest.cc b/src/processor/static_address_map_unittest.cc index 12c735cf..2e206a09 100644 --- a/src/processor/static_address_map_unittest.cc +++ b/src/processor/static_address_map_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -95,7 +94,7 @@ class TestStaticAddressMap : public ::testing::Test { int address_test; string entry; string entry_test; - const char *entry_cstring = NULL; + const char* entry_cstring = NULL; bool found; bool found_test; @@ -143,11 +142,11 @@ class TestStaticAddressMap : public ::testing::Test { // Test data sets: static const int kNumberTestCases = 4; static const int testsize[]; - int *testdata[kNumberTestCases]; + int* testdata[kNumberTestCases]; AddrMap addr_map[kNumberTestCases]; TestMap test_map[kNumberTestCases]; - char *map_data[kNumberTestCases]; + char* map_data[kNumberTestCases]; google_breakpad::AddressMapSerializer<int, string> serializer; }; @@ -229,7 +228,7 @@ TEST_F(TestStaticAddressMap, Test1000RandomElementsMap) { } } -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/src/processor/static_contained_range_map-inl.h b/src/processor/static_contained_range_map-inl.h index 777c7621..60606ddc 100644 --- a/src/processor/static_contained_range_map-inl.h +++ b/src/processor/static_contained_range_map-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,7 +46,7 @@ StaticContainedRangeMap<AddressType, EntryType>::StaticContainedRangeMap( const char *base) : base_(*(reinterpret_cast<const AddressType*>(base))), entry_size_(*(reinterpret_cast<const uint32_t*>(base + sizeof(base_)))), - entry_ptr_(reinterpret_cast<const EntryType *>( + entry_ptr_(reinterpret_cast<const EntryType*>( base + sizeof(base_) + sizeof(entry_size_))), map_(base + sizeof(base_) + sizeof(entry_size_) + entry_size_) { if (entry_size_ == 0) @@ -57,7 +56,7 @@ StaticContainedRangeMap<AddressType, EntryType>::StaticContainedRangeMap( template<typename AddressType, typename EntryType> bool StaticContainedRangeMap<AddressType, EntryType>::RetrieveRange( - const AddressType &address, const EntryType *&entry) const { + const AddressType& address, const EntryType*& entry) const { // Get an iterator to the child range whose high address is equal to or // greater than the supplied address. If the supplied address is higher @@ -87,6 +86,23 @@ bool StaticContainedRangeMap<AddressType, EntryType>::RetrieveRange( return true; } +template <typename AddressType, typename EntryType> +bool StaticContainedRangeMap<AddressType, EntryType>::RetrieveRanges( + const AddressType& address, + std::vector<const EntryType*>& entries) const { + MapConstIterator iterator = map_.lower_bound(address); + if (iterator == map_.end()) + return false; + const char* memory_child = + reinterpret_cast<const char*>(iterator.GetValuePtr()); + StaticContainedRangeMap child_map(memory_child); + if (address < child_map.base_) + return false; + child_map.RetrieveRanges(address, entries); + entries.push_back(child_map.entry_ptr_); + return true; +} + } // namespace google_breakpad #endif // PROCESSOR_STATIC_CONTAINED_RANGE_MAP_INL_H__ diff --git a/src/processor/static_contained_range_map.h b/src/processor/static_contained_range_map.h index 6a9b8b7b..86e54666 100644 --- a/src/processor/static_contained_range_map.h +++ b/src/processor/static_contained_range_map.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,6 +41,7 @@ #ifndef PROCESSOR_STATIC_CONTAINED_RANGE_MAP_H__ #define PROCESSOR_STATIC_CONTAINED_RANGE_MAP_H__ +#include <vector> #include "processor/static_map-inl.h" namespace google_breakpad { @@ -57,7 +57,12 @@ class StaticContainedRangeMap { // child ranges, and not the entry contained by |this|. This is necessary // to support a sparsely-populated root range. If no descendant range // encompasses the address, returns false. - bool RetrieveRange(const AddressType &address, const EntryType *&entry) const; + bool RetrieveRange(const AddressType& address, const EntryType*& entry) const; + + // Retrieves the vector of entries encompassing the specified address from the + // innermost entry to the outermost entry. + bool RetrieveRanges(const AddressType& address, + std::vector<const EntryType*>& entry) const; private: friend class ModuleComparer; diff --git a/src/processor/static_contained_range_map_unittest.cc b/src/processor/static_contained_range_map_unittest.cc index 4ee47578..cdc11c1d 100644 --- a/src/processor/static_contained_range_map_unittest.cc +++ b/src/processor/static_contained_range_map_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -273,6 +272,25 @@ TEST_F(TestStaticCRMMap, TestSingleElementMap) { ASSERT_EQ(*entry_test, entry); } +TEST_F(TestStaticCRMMap, TestRetrieveRangeEntries) { + CRMMap crm_map; + + crm_map.StoreRange(2, 5, 0); + crm_map.StoreRange(2, 6, 1); + crm_map.StoreRange(2, 7, 2); + + unsigned int size; + scoped_array<char> serialized_data; + serialized_data.reset(serializer_.Serialize(&crm_map, &size)); + scoped_ptr<TestMap> test_map(new TestMap(serialized_data.get())); + + std::vector<const int*> entry_tests; + ASSERT_TRUE(test_map->RetrieveRanges(3, entry_tests)); + ASSERT_EQ(*entry_tests[0], 0); + ASSERT_EQ(*entry_tests[1], 1); + ASSERT_EQ(*entry_tests[2], 2); +} + TEST_F(TestStaticCRMMap, RunTestData) { unsigned int test_high = sizeof(test_data) / sizeof(test_data[0]); diff --git a/src/processor/static_map-inl.h b/src/processor/static_map-inl.h index e6aac6ab..f9929efe 100644 --- a/src/processor/static_map-inl.h +++ b/src/processor/static_map-inl.h @@ -1,4 +1,4 @@ -// Copyright 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -59,7 +59,7 @@ StaticMap<Key, Value, Compare>::StaticMap(const char* raw_data) // find(), lower_bound() and upper_bound() implement binary search algorithm. template<typename Key, typename Value, typename Compare> StaticMapIterator<Key, Value, Compare> -StaticMap<Key, Value, Compare>::find(const Key &key) const { +StaticMap<Key, Value, Compare>::find(const Key& key) const { int begin = 0; int end = num_nodes_; int middle; @@ -80,7 +80,7 @@ StaticMap<Key, Value, Compare>::find(const Key &key) const { template<typename Key, typename Value, typename Compare> StaticMapIterator<Key, Value, Compare> -StaticMap<Key, Value, Compare>::lower_bound(const Key &key) const { +StaticMap<Key, Value, Compare>::lower_bound(const Key& key) const { int begin = 0; int end = num_nodes_; int middle; @@ -101,7 +101,7 @@ StaticMap<Key, Value, Compare>::lower_bound(const Key &key) const { template<typename Key, typename Value, typename Compare> StaticMapIterator<Key, Value, Compare> -StaticMap<Key, Value, Compare>::upper_bound(const Key &key) const { +StaticMap<Key, Value, Compare>::upper_bound(const Key& key) const { int begin = 0; int end = num_nodes_; int middle; diff --git a/src/processor/static_map.h b/src/processor/static_map.h index 9723ab2a..a8f49582 100644 --- a/src/processor/static_map.h +++ b/src/processor/static_map.h @@ -1,4 +1,4 @@ -// Copyright 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -72,7 +72,7 @@ namespace google_breakpad { template<typename Key> class DefaultCompare { public: - int operator()(const Key &k1, const Key &k2) const { + int operator()(const Key& k1, const Key& k2) const { if (k1 < k2) return -1; if (k1 == k2) return 0; return 1; @@ -104,15 +104,15 @@ class StaticMap { } // Lookup operations. - iterator find(const Key &k) const; + iterator find(const Key& k) const; // lower_bound(k) searches in a sorted range for the first element that has a // key not less than the argument k. - iterator lower_bound(const Key &k) const; + iterator lower_bound(const Key& k) const; // upper_bound(k) searches in a sorted range for the first element that has a // key greater than the argument k. - iterator upper_bound(const Key &k) const; + iterator upper_bound(const Key& k) const; // Checks if the underlying memory data conforms to the predefined pattern: // first check the number of nodes is non-negative, diff --git a/src/processor/static_map_iterator-inl.h b/src/processor/static_map_iterator-inl.h index 7a7db5ad..01a1b7f7 100644 --- a/src/processor/static_map_iterator-inl.h +++ b/src/processor/static_map_iterator-inl.h @@ -1,4 +1,4 @@ -// Copyright 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -43,7 +43,7 @@ namespace google_breakpad { template<typename Key, typename Value, typename Compare> StaticMapIterator<Key, Value, Compare>::StaticMapIterator(const char* base, - const int &index): + const int& index): index_(index), base_(base) { // See static_map.h for documentation on // bytes format of serialized StaticMap data. diff --git a/src/processor/static_map_iterator.h b/src/processor/static_map_iterator.h index 1af8fff4..6c190e97 100644 --- a/src/processor/static_map_iterator.h +++ b/src/processor/static_map_iterator.h @@ -1,4 +1,4 @@ -// Copyright 2010 Google Inc. All Rights Reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -10,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -87,7 +87,7 @@ class StaticMapIterator { friend class StaticMap<Key, Value, Compare>; // Only StaticMap can call this constructor. - explicit StaticMapIterator(const char* base, const int32_t &index); + explicit StaticMapIterator(const char* base, const int32_t& index); // Index of node that the iterator is pointing to. int32_t index_; diff --git a/src/processor/static_map_unittest.cc b/src/processor/static_map_unittest.cc index 393d43d5..4360e8c6 100644 --- a/src/processor/static_map_unittest.cc +++ b/src/processor/static_map_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -46,7 +45,7 @@ typedef std::map< KeyType, ValueType > StdMap; template<typename Key, typename Value> class SimpleMapSerializer { public: - static char* Serialize(const std::map<Key, Value> &stdmap, + static char* Serialize(const std::map<Key, Value>& stdmap, unsigned int* size = NULL) { unsigned int size_per_node = sizeof(uint32_t) + sizeof(Key) + sizeof(Value); @@ -237,19 +236,19 @@ class TestValidMap : public ::testing::Test { } } - void FindTester(int test_case, const KeyType &key) { + void FindTester(int test_case, const KeyType& key) { iter_test = test_map[test_case].find(key); iter_std = std_map[test_case].find(key); CompareLookupResult(test_case); } - void LowerBoundTester(int test_case, const KeyType &key) { + void LowerBoundTester(int test_case, const KeyType& key) { iter_test = test_map[test_case].lower_bound(key); iter_std = std_map[test_case].lower_bound(key); CompareLookupResult(test_case); } - void UpperBoundTester(int test_case, const KeyType &key) { + void UpperBoundTester(int test_case, const KeyType& key) { iter_test = test_map[test_case].upper_bound(key); iter_std = std_map[test_case].upper_bound(key); CompareLookupResult(test_case); diff --git a/src/processor/static_range_map-inl.h b/src/processor/static_range_map-inl.h index f6cef1a9..b0a32747 100644 --- a/src/processor/static_range_map-inl.h +++ b/src/processor/static_range_map-inl.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -43,8 +42,8 @@ namespace google_breakpad { template<typename AddressType, typename EntryType> bool StaticRangeMap<AddressType, EntryType>::RetrieveRange( - const AddressType &address, const EntryType *&entry, - AddressType *entry_base, AddressType *entry_size) const { + const AddressType& address, const EntryType*& entry, + AddressType* entry_base, AddressType* entry_size) const { MapConstIterator iterator = map_.lower_bound(address); if (iterator == map_.end()) return false; @@ -55,7 +54,7 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveRange( // be below the range's low address, though. When that happens, address // references something not within any range, so return false. - const Range *range = iterator.GetValuePtr(); + const Range* range = iterator.GetValuePtr(); // Make sure AddressType and EntryType are copyable basic types // e.g.: integer types, pointers etc @@ -74,8 +73,8 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveRange( template<typename AddressType, typename EntryType> bool StaticRangeMap<AddressType, EntryType>::RetrieveNearestRange( - const AddressType &address, const EntryType *&entry, - AddressType *entry_base, AddressType *entry_size) const { + const AddressType& address, const EntryType*& entry, + AddressType* entry_base, AddressType* entry_size) const { // If address is within a range, RetrieveRange can handle it. if (RetrieveRange(address, entry, entry_base, entry_size)) return true; @@ -91,7 +90,7 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveNearestRange( return false; --iterator; - const Range *range = iterator.GetValuePtr(); + const Range* range = iterator.GetValuePtr(); entry = range->entryptr(); if (entry_base) *entry_base = range->base(); @@ -103,8 +102,8 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveNearestRange( template<typename AddressType, typename EntryType> bool StaticRangeMap<AddressType, EntryType>::RetrieveRangeAtIndex( - int index, const EntryType *&entry, - AddressType *entry_base, AddressType *entry_size) const { + int index, const EntryType*& entry, + AddressType* entry_base, AddressType* entry_size) const { if (index >= GetCount()) { BPLOG(ERROR) << "Index out of range: " << index << "/" << GetCount(); @@ -113,7 +112,7 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveRangeAtIndex( MapConstIterator iterator = map_.IteratorAtIndex(index); - const Range *range = iterator.GetValuePtr(); + const Range* range = iterator.GetValuePtr(); entry = range->entryptr(); if (entry_base) diff --git a/src/processor/static_range_map.h b/src/processor/static_range_map.h index 91aabb03..319085db 100644 --- a/src/processor/static_range_map.h +++ b/src/processor/static_range_map.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -50,21 +49,21 @@ template<typename AddressType, typename EntryType> class StaticRangeMap { public: StaticRangeMap(): map_() { } - explicit StaticRangeMap(const char *memory): map_(memory) { } + explicit StaticRangeMap(const char* memory): map_(memory) { } // Locates the range encompassing the supplied address. If there is // no such range, returns false. entry_base and entry_size, if non-NULL, // are set to the base and size of the entry's range. - bool RetrieveRange(const AddressType &address, const EntryType *&entry, - AddressType *entry_base, AddressType *entry_size) const; + bool RetrieveRange(const AddressType& address, const EntryType*& entry, + AddressType* entry_base, AddressType* entry_size) const; // Locates the range encompassing the supplied address, if one exists. // If no range encompasses the supplied address, locates the nearest range // to the supplied address that is lower than the address. Returns false // if no range meets these criteria. entry_base and entry_size, if // non-NULL, are set to the base and size of the entry's range. - bool RetrieveNearestRange(const AddressType &address, const EntryType *&entry, - AddressType *entry_base, AddressType *entry_size) + bool RetrieveNearestRange(const AddressType& address, const EntryType*& entry, + AddressType* entry_base, AddressType* entry_size) const; // Treating all ranges as a list ordered by the address spaces that they @@ -74,8 +73,8 @@ class StaticRangeMap { // range. // // RetrieveRangeAtIndex is not optimized for speedy operation. - bool RetrieveRangeAtIndex(int index, const EntryType *&entry, - AddressType *entry_base, AddressType *entry_size) + bool RetrieveRangeAtIndex(int index, const EntryType*& entry, + AddressType* entry_base, AddressType* entry_size) const; // Returns the number of ranges stored in the RangeMap. diff --git a/src/processor/static_range_map_unittest.cc b/src/processor/static_range_map_unittest.cc index 28217362..3903e948 100644 --- a/src/processor/static_range_map_unittest.cc +++ b/src/processor/static_range_map_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -228,10 +227,10 @@ void TestStaticRangeMap::RetrieveTest(TestMap* range_map, } for (AddressType offset = low_offset; offset <= high_offset; ++offset) { - AddressType address = - offset + - (!side ? range_test->address : - range_test->address + range_test->size - 1); + AddressType address = AddIgnoringOverflow( + offset, (!side ? range_test->address + : AddIgnoringOverflow(range_test->address, + range_test->size - 1))); bool expected_result = false; // This is correct for tests not stored. if (range_test->expect_storable) { @@ -414,7 +413,7 @@ TEST_F(TestStaticRangeMap, RunTestCase0Again) { } // namespace google_breakpad -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/src/processor/symbolic_constants_win.cc b/src/processor/symbolic_constants_win.cc index 8cf283f6..0c57b686 100644 --- a/src/processor/symbolic_constants_win.cc +++ b/src/processor/symbolic_constants_win.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2015 Google Inc. -// All rights reserved. +// Copyright 2015 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/symbolic_constants_win.h b/src/processor/symbolic_constants_win.h index 3f4d38eb..bc9ff350 100644 --- a/src/processor/symbolic_constants_win.h +++ b/src/processor/symbolic_constants_win.h @@ -1,5 +1,4 @@ -// Copyright (c) 2015 Google Inc. -// All rights reserved. +// Copyright 2015 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/synth_minidump.cc b/src/processor/synth_minidump.cc index aa86d248..9dacb395 100644 --- a/src/processor/synth_minidump.cc +++ b/src/processor/synth_minidump.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,7 +36,7 @@ namespace google_breakpad { namespace SynthMinidump { -Section::Section(const Dump &dump) +Section::Section(const Dump& dump) : test_assembler::Section(dump.endianness()) { } void Section::CiteLocationIn(test_assembler::Section *section) const { @@ -49,9 +48,9 @@ void Stream::CiteStreamIn(test_assembler::Section *section) const { CiteLocationIn(section); } -SystemInfo::SystemInfo(const Dump &dump, - const MDRawSystemInfo &system_info, - const String &csd_version) +SystemInfo::SystemInfo(const Dump& dump, + const MDRawSystemInfo& system_info, + const String& csd_version) : Stream(dump, MD_SYSTEM_INFO_STREAM) { D16(system_info.processor_architecture); D16(system_info.processor_level); @@ -108,7 +107,7 @@ const MDRawSystemInfo SystemInfo::windows_x86 = { const string SystemInfo::windows_x86_csd_version = "Service Pack 2"; -String::String(const Dump &dump, const string &contents) : Section(dump) { +String::String(const Dump& dump, const string& contents) : Section(dump) { D32(contents.size() * 2); for (string::const_iterator i = contents.begin(); i != contents.end(); i++) D16(*i); @@ -123,7 +122,7 @@ void Memory::CiteMemoryIn(test_assembler::Section *section) const { CiteLocationIn(section); } -Context::Context(const Dump &dump, const MDRawContextX86 &context) +Context::Context(const Dump& dump, const MDRawContextX86& context) : Section(dump) { // The caller should have properly set the CPU type flag. // The high 24 bits identify the CPU. Note that context records with no CPU @@ -173,7 +172,7 @@ Context::Context(const Dump &dump, const MDRawContextX86 &context) assert(Size() == sizeof(MDRawContextX86)); } -Context::Context(const Dump &dump, const MDRawContextARM &context) +Context::Context(const Dump& dump, const MDRawContextARM& context) : Section(dump) { // The caller should have properly set the CPU type flag. assert((context.context_flags & MD_CONTEXT_ARM) || @@ -192,7 +191,7 @@ Context::Context(const Dump &dump, const MDRawContextARM &context) assert(Size() == sizeof(MDRawContextARM)); } -Context::Context(const Dump &dump, const MDRawContextMIPS &context) +Context::Context(const Dump& dump, const MDRawContextMIPS& context) : Section(dump) { // The caller should have properly set the CPU type flag. assert(context.context_flags & MD_CONTEXT_MIPS); @@ -228,8 +227,8 @@ Context::Context(const Dump &dump, const MDRawContextMIPS &context) assert(Size() == sizeof(MDRawContextMIPS)); } -Thread::Thread(const Dump &dump, - uint32_t thread_id, const Memory &stack, const Context &context, +Thread::Thread(const Dump& dump, + uint32_t thread_id, const Memory& stack, const Context& context, uint32_t suspend_count, uint32_t priority_class, uint32_t priority, uint64_t teb) : Section(dump) { D32(thread_id); @@ -242,13 +241,13 @@ Thread::Thread(const Dump &dump, assert(Size() == sizeof(MDRawThread)); } -Module::Module(const Dump &dump, +Module::Module(const Dump& dump, uint64_t base_of_image, uint32_t size_of_image, - const String &name, + const String& name, uint32_t time_date_stamp, uint32_t checksum, - const MDVSFixedFileInfo &version_info, + const MDVSFixedFileInfo& version_info, const Section *cv_record, const Section *misc_record) : Section(dump) { D64(base_of_image); @@ -297,10 +296,10 @@ const MDVSFixedFileInfo Module::stock_version_info = { 0 // file_date_lo }; -UnloadedModule::UnloadedModule(const Dump &dump, +UnloadedModule::UnloadedModule(const Dump& dump, uint64_t base_of_image, uint32_t size_of_image, - const String &name, + const String& name, uint32_t checksum, uint32_t time_date_stamp) : Section(dump) { D64(base_of_image); @@ -310,15 +309,15 @@ UnloadedModule::UnloadedModule(const Dump &dump, name.CiteStringIn(this); } -UnloadedModuleList::UnloadedModuleList(const Dump &dump, uint32_t type) +UnloadedModuleList::UnloadedModuleList(const Dump& dump, uint32_t type) : List<UnloadedModule>(dump, type, false) { D32(sizeof(MDRawUnloadedModuleList)); D32(sizeof(MDRawUnloadedModule)); D32(count_label_); } -Exception::Exception(const Dump &dump, - const Context &context, +Exception::Exception(const Dump& dump, + const Context& context, uint32_t thread_id, uint32_t exception_code, uint32_t exception_flags, @@ -332,7 +331,7 @@ Exception::Exception(const Dump &dump, D64(exception_address); D32(0); // number_parameters D32(0); // __align - for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i) + for (size_t i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i) D64(0); // exception_information context.CiteLocationIn(this); assert(Size() == sizeof(MDRawExceptionStream)); @@ -361,22 +360,22 @@ Dump::Dump(uint64_t flags, assert(Size() == sizeof(MDRawHeader)); } -Dump &Dump::Add(SynthMinidump::Section *section) { +Dump& Dump::Add(SynthMinidump::Section *section) { section->Finish(file_start_ + Size()); Append(*section); return *this; } -Dump &Dump::Add(Stream *stream) { - Add(static_cast<SynthMinidump::Section *>(stream)); +Dump& Dump::Add(Stream *stream) { + Add(static_cast<SynthMinidump::Section*>(stream)); stream->CiteStreamIn(&stream_directory_); stream_count_++; return *this; } -Dump &Dump::Add(Memory *memory) { +Dump& Dump::Add(Memory *memory) { // Add the memory contents themselves to the file. - Add(static_cast<SynthMinidump::Section *>(memory)); + Add(static_cast<SynthMinidump::Section*>(memory)); // The memory list is a list of MDMemoryDescriptors, not of actual // memory elements. Produce a descriptor, and add that to the list. @@ -386,17 +385,17 @@ Dump &Dump::Add(Memory *memory) { return *this; } -Dump &Dump::Add(Thread *thread) { +Dump& Dump::Add(Thread *thread) { thread_list_.Add(thread); return *this; } -Dump &Dump::Add(Module *module) { +Dump& Dump::Add(Module *module) { module_list_.Add(module); return *this; } -Dump &Dump::Add(UnloadedModule *unloaded_module) { +Dump& Dump::Add(UnloadedModule *unloaded_module) { unloaded_module_list_.Add(unloaded_module); return *this; } @@ -413,7 +412,7 @@ void Dump::Finish() { // has the stream count and MDRVA. stream_count_label_ = stream_count_; stream_directory_rva_ = file_start_ + Size(); - Append(static_cast<test_assembler::Section &>(stream_directory_)); + Append(static_cast<test_assembler::Section& >(stream_directory_)); } } // namespace SynthMinidump diff --git a/src/processor/synth_minidump.h b/src/processor/synth_minidump.h index 8f49cfff..a52be03b 100644 --- a/src/processor/synth_minidump.h +++ b/src/processor/synth_minidump.h @@ -1,7 +1,6 @@ // -*- mode: C++ -*- -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -135,7 +134,7 @@ class String; // A test_assembler::Section which will be appended to a minidump. class Section: public test_assembler::Section { public: - explicit Section(const Dump &dump); + explicit Section(const Dump& dump); // Append an MDLocationDescriptor referring to this section to SECTION. // If 'this' is NULL, append a descriptor with a zero length and MDRVA. @@ -145,13 +144,13 @@ class Section: public test_assembler::Section { // bad, if such language exists. Having this function handle NULL // 'this' is convenient, but if it causes trouble, it's not hard to // do differently.) - void CiteLocationIn(test_assembler::Section *section) const; + void CiteLocationIn(test_assembler::Section* section) const; // Note that this section's contents are complete, and that it has // been placed in the minidump file at OFFSET. The 'Add' member // functions call the Finish member function of the object being // added for you; if you are 'Add'ing this section, you needn't Finish it. - virtual void Finish(const Label &offset) { + virtual void Finish(const Label& offset) { file_offset_ = offset; size_ = Size(); } @@ -166,10 +165,10 @@ class Stream: public Section { public: // Create a stream of type TYPE. You can append whatever contents // you like to this stream using the test_assembler::Section methods. - Stream(const Dump &dump, uint32_t type) : Section(dump), type_(type) { } + Stream(const Dump& dump, uint32_t type) : Section(dump), type_(type) { } // Append an MDRawDirectory referring to this stream to SECTION. - void CiteStreamIn(test_assembler::Section *section) const; + void CiteStreamIn(test_assembler::Section* section) const; private: // The type of this stream. @@ -186,9 +185,9 @@ class SystemInfo: public Stream { // // Remember that you are still responsible for 'Add'ing CSD_VERSION // to the dump yourself. - SystemInfo(const Dump &dump, - const MDRawSystemInfo &system_info, - const String &csd_version); + SystemInfo(const Dump& dump, + const MDRawSystemInfo& system_info, + const String& csd_version); // Stock MDRawSystemInfo information and associated strings, for // writing tests. @@ -199,10 +198,10 @@ class SystemInfo: public Stream { // An MDString: a string preceded by a 32-bit length. class String: public Section { public: - String(const Dump &dump, const string &value); + String(const Dump& dump, const string& value); // Append an MDRVA referring to this string to SECTION. - void CiteStringIn(test_assembler::Section *section) const; + void CiteStringIn(test_assembler::Section* section) const; }; // A range of memory contents. 'Add'ing a memory range to a minidump @@ -211,11 +210,11 @@ class String: public Section { // to memory addresses. class Memory: public Section { public: - Memory(const Dump &dump, uint64_t address) + Memory(const Dump& dump, uint64_t address) : Section(dump), address_(address) { start() = address; } // Append an MDMemoryDescriptor referring to this memory range to SECTION. - void CiteMemoryIn(test_assembler::Section *section) const; + void CiteMemoryIn(test_assembler::Section* section) const; private: // The process address from which these memory contents were taken. @@ -226,11 +225,11 @@ class Memory: public Section { class Context: public Section { public: // Create a context belonging to DUMP whose contents are a copy of CONTEXT. - Context(const Dump &dump, const MDRawContextX86 &context); - Context(const Dump &dump, const MDRawContextARM &context); - Context(const Dump &dump, const MDRawContextMIPS &context); + Context(const Dump& dump, const MDRawContextX86& context); + Context(const Dump& dump, const MDRawContextARM& context); + Context(const Dump& dump, const MDRawContextMIPS& context); // Add an empty context to the dump. - Context(const Dump &dump) : Section(dump) {} + Context(const Dump& dump) : Section(dump) {} // Add constructors for other architectures here. Remember to byteswap. }; @@ -238,10 +237,10 @@ class Thread: public Section { public: // Create a thread belonging to DUMP with the given values, citing // STACK and CONTEXT (which you must Add to the dump separately). - Thread(const Dump &dump, + Thread(const Dump& dump, uint32_t thread_id, - const Memory &stack, - const Context &context, + const Memory& stack, + const Context& context, uint32_t suspend_count = 0, uint32_t priority_class = 0, uint32_t priority = 0, @@ -253,15 +252,15 @@ class Module: public Section { // Create a module with the given values. Note that CV_RECORD and // MISC_RECORD can be NULL, in which case the corresponding location // descriptior in the minidump will have a length of zero. - Module(const Dump &dump, + Module(const Dump& dump, uint64_t base_of_image, uint32_t size_of_image, - const String &name, + const String& name, uint32_t time_date_stamp = 1262805309, uint32_t checksum = 0, - const MDVSFixedFileInfo &version_info = Module::stock_version_info, - const Section *cv_record = NULL, - const Section *misc_record = NULL); + const MDVSFixedFileInfo& version_info = Module::stock_version_info, + const Section* cv_record = NULL, + const Section* misc_record = NULL); private: // A standard MDVSFixedFileInfo structure to use as a default for @@ -272,18 +271,18 @@ class Module: public Section { class UnloadedModule: public Section { public: - UnloadedModule(const Dump &dump, + UnloadedModule(const Dump& dump, uint64_t base_of_image, uint32_t size_of_image, - const String &name, + const String& name, uint32_t checksum = 0, uint32_t time_date_stamp = 1262805309); }; class Exception : public Stream { public: - Exception(const Dump &dump, - const Context &context, + Exception(const Dump& dump, + const Context& context, uint32_t thread_id = 0, uint32_t exception_code = 0, uint32_t exception_flags = 0, @@ -295,12 +294,12 @@ public: template<typename Element> class List: public Stream { public: - List(const Dump &dump, uint32_t type) : Stream(dump, type), count_(0) { + List(const Dump& dump, uint32_t type) : Stream(dump, type), count_(0) { D32(count_label_); } // Add ELEMENT to this list. - void Add(Element *element) { + void Add(Element* element) { element->Finish(file_offset_ + Size()); Append(*element); count_++; @@ -311,7 +310,7 @@ class List: public Stream { // Finish up the contents of this section, mark it as having been // placed at OFFSET. - virtual void Finish(const Label &offset) { + virtual void Finish(const Label& offset) { Stream::Finish(offset); count_label_ = count_; } @@ -322,14 +321,14 @@ class List: public Stream { protected: // This constructor allows derived lists to specify their own layout // rather than starting with count as specified in the public constructor. - List(const Dump &dump, uint32_t type, bool) : Stream(dump, type), count_(0) {} + List(const Dump& dump, uint32_t type, bool) : Stream(dump, type), count_(0) {} Label count_label_; }; class UnloadedModuleList : public List<UnloadedModule> { public: - UnloadedModuleList(const Dump &dump, uint32_t type); + UnloadedModuleList(const Dump& dump, uint32_t type); }; class Dump: public test_assembler::Section { @@ -349,12 +348,12 @@ class Dump: public test_assembler::Section { // whatever directory or list is appropriate for its type. The // stream directory, memory list, thread list, and module list are // accumulated this way. - Dump &Add(SynthMinidump::Section *object); // simply append data - Dump &Add(Stream *object); // append, record in stream directory - Dump &Add(Memory *object); // append, record in memory list - Dump &Add(Thread *object); // append, record in thread list - Dump &Add(Module *object); // append, record in module list - Dump &Add(UnloadedModule *object); // append, record in unloaded module list + Dump& Add(SynthMinidump::Section* object); // simply append data + Dump& Add(Stream* object); // append, record in stream directory + Dump& Add(Memory* object); // append, record in memory list + Dump& Add(Thread* object); // append, record in thread list + Dump& Add(Module* object); // append, record in module list + Dump& Add(UnloadedModule* object); // append, record in unloaded module list // Complete the construction of the minidump, given the Add calls // we've seen up to this point. After this call, this Dump's @@ -367,26 +366,26 @@ class Dump: public test_assembler::Section { Label file_start_; // The stream directory. We construct this incrementally from - // Add(Stream *) calls. + // Add(Stream*) calls. SynthMinidump::Section stream_directory_; // The directory's contents. size_t stream_count_; // The number of streams so far. Label stream_count_label_; // Cited in file header. Label stream_directory_rva_; // The directory's file offset. // This minidump's thread list. We construct this incrementally from - // Add(Thread *) calls. + // Add(Thread*) calls. List<Thread> thread_list_; // This minidump's module list. We construct this incrementally from - // Add(Module *) calls. + // Add(Module*) calls. List<Module> module_list_; // This minidump's unloaded module list. We construct this incrementally from - // Add(UnloadedModule *) calls. + // Add(UnloadedModule*) calls. UnloadedModuleList unloaded_module_list_; // This minidump's memory list. We construct this incrementally from - // Add(Memory *) calls. This is actually a list of MDMemoryDescriptors, + // Add(Memory*) calls. This is actually a list of MDMemoryDescriptors, // not memory ranges --- thus the odd type. List<SynthMinidump::Section> memory_list_; }; diff --git a/src/processor/synth_minidump_unittest.cc b/src/processor/synth_minidump_unittest.cc index 8835b449..4bc46747 100644 --- a/src/processor/synth_minidump_unittest.cc +++ b/src/processor/synth_minidump_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/processor/testdata/linux_inline.dmp b/src/processor/testdata/linux_inline.dmp Binary files differnew file mode 100644 index 00000000..5b216f8b --- /dev/null +++ b/src/processor/testdata/linux_inline.dmp diff --git a/src/processor/testdata/linux_test_app.cc b/src/processor/testdata/linux_test_app.cc index 18f0f62f..4ff4f707 100644 --- a/src/processor/testdata/linux_test_app.cc +++ b/src/processor/testdata/linux_test_app.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -51,8 +50,8 @@ namespace { // google_breakpad::MinidumpCallback to invoke after minidump generation. -static bool callback(const char *dump_path, const char *id, - void *context, +static bool callback(const char* dump_path, const char* id, + void* context, bool succeeded) { if (succeeded) { printf("dump guid is %s\n", id); @@ -65,13 +64,13 @@ static bool callback(const char *dump_path, const char *id, } static void CrashFunction() { - int *i = reinterpret_cast<int*>(0x45); + int* i = reinterpret_cast<int*>(0x45); *i = 5; // crash! } } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { google_breakpad::ExceptionHandler eh(".", NULL, callback, NULL, true); if (!eh.WriteMinidump()) { printf("Failed to generate on-demand minidump\n"); diff --git a/src/processor/testdata/minidump2.dump.out b/src/processor/testdata/minidump2.dump.out index 8585c89b..bad1b80f 100644 --- a/src/processor/testdata/minidump2.dump.out +++ b/src/processor/testdata/minidump2.dump.out @@ -670,7 +670,7 @@ MDRawContextX86 extended_registers[512] = 0x7f0200000000220000000000000000000000000000000000801f0000ffff00000000000018b72200000100000000000018b72200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004509917c4e09917c38b622002400020024b42200020000009041917c0070fd7f0510907cccb22200000000009cb3220018ee907c7009917cc0e4977c6f3e917c623e917c08020000dcb62200b4b622001e000000000000000000000000000000000000002eb42200000000000f000000020000001e00200000fcfd7f2f63796764726976652f632f444f43554d457e312f4d4d454e544f7e312f4c4f43414c537e312f54656d7000000000000000000130b422000000004300000000000000001efcfd7f4509917c4e09917c5ad9000008b32200b4b62200 MDRawSystemInfo - processor_architecture = 0x0 + processor_architecture = 0x0 (x86) processor_level = 6 processor_revision = 0xd08 number_of_processors = 1 @@ -678,7 +678,7 @@ MDRawSystemInfo major_version = 5 minor_version = 1 build_number = 2600 - platform_id = 0x2 + platform_id = 0x2 (windows) csd_version_rva = 0x768 suite_mask = 0x100 cpu.x86_cpu_info (valid): diff --git a/src/processor/testdata/minidump_crashpad_annotation.dmp b/src/processor/testdata/minidump_crashpad_annotation.dmp Binary files differnew file mode 100644 index 00000000..00cfc5a3 --- /dev/null +++ b/src/processor/testdata/minidump_crashpad_annotation.dmp diff --git a/src/processor/testdata/module1.out b/src/processor/testdata/module1.out index cd6e18d1..6774e4f1 100644 --- a/src/processor/testdata/module1.out +++ b/src/processor/testdata/module1.out @@ -3,7 +3,7 @@ INFO CODE_ID FFFFFFFF module1.exe FILE 1 file1_1.cc FILE 2 file1_2.cc FILE 3 file1_3.cc -FUNC 1000 c 0 Function1_1 +FUNC m 1000 c 0 Function1_1 1000 4 44 1 1004 4 45 1 1008 4 46 1 @@ -14,7 +14,7 @@ FUNC 1200 100 8 Function1_3 FUNC 1300 100 c Function1_4 FUNC 2000 0 0 Test_Zero_Size_Function_Is_Ignored 2000 4 88 2 -PUBLIC 2800 0 PublicSymbol +PUBLIC m 2800 0 PublicSymbol FUNC 3000 7000 42 LargeFunction 3000 7000 4098359 3 STACK WIN 4 1000 c 1 0 0 0 0 0 1 $eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ = diff --git a/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.new.sym b/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.new.sym new file mode 100644 index 00000000..5cd83209 --- /dev/null +++ b/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.new.sym @@ -0,0 +1,71 @@ +MODULE Linux x86_64 BBA6FA10B8AAB33D00000000000000000 linux_inline +INFO CODE_ID 10FAA6BBAAB83DB3 +FILE 0 linux_inline.cpp +FILE 1 a.cpp +FILE 2 b.cpp +FILE 3 c.cpp +INLINE_ORIGIN 0 bar() +INLINE_ORIGIN 1 foo() +INLINE_ORIGIN 2 func() +FUNC 15b30 6cf 0 main +INLINE 0 42 1 1 15b45 6b1 +INLINE 1 39 2 0 15b72 684 +INLINE 2 32 3 2 15b83 673 +15b30 15 41 0 +15b45 11 36 0 +15b56 a 37 0 +15b60 6 37 0 +15b66 5 38 0 +15b6b 7 0 0 +15b72 11 31 0 +15b83 a 9 0 +15b8d 4 9 0 +15b91 6 9 0 +15b97 7 0 0 +15b9e 11 10 0 +15baf 7 0 0 +15bb6 2e 12 0 +15be4 7 0 0 +15beb 5 12 0 +15bf0 1d 13 0 +15c0d 1d 14 0 +15c2a e 0 0 +15c38 1c 15 0 +15c54 a 16 0 +15c5e 7 0 0 +15c65 2c 16 0 +15c91 15 0 0 +15ca6 a 16 0 +15cb0 87 15 0 +15d37 7 0 0 +15d3e 33 15 0 +15d71 7 0 0 +15d78 24 15 0 +15d9c a 17 0 +15da6 e 0 0 +15db4 a 18 0 +15dbe e 0 0 +15dcc a 19 0 +15dd6 7 0 0 +15ddd a 20 0 +15de7 7 0 0 +15dee 2c 21 0 +15e1a 3c 22 0 +15e56 28 23 0 +15e7e 5a 18 0 +15ed8 d 28 0 +15ee5 11 12 0 +15ef6 67 28 0 +15f5d 2b 15 0 +15f88 7 0 0 +15f8f 8c 15 0 +1601b 7 0 0 +16022 3d 15 0 +1605f 67 28 0 +160c6 54 18 0 +1611a 3c 28 0 +16156 c 12 0 +16162 54 18 0 +161b6 2 27 0 +161b8 3e 28 0 +161f6 9 43 0
\ No newline at end of file diff --git a/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.old.sym b/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.old.sym new file mode 100644 index 00000000..775640f0 --- /dev/null +++ b/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.old.sym @@ -0,0 +1,68 @@ +MODULE Linux x86_64 BBA6FA10B8AAB33D00000000000000000 linux_inline +INFO CODE_ID 10FAA6BBAAB83DB3 +FILE 0 linux_inline.cpp +INLINE_ORIGIN 0 0 bar() +INLINE_ORIGIN 1 0 foo() +INLINE_ORIGIN 2 0 func() +FUNC 15b30 6cf 0 main +INLINE 0 42 1 15b45 6b1 +INLINE 1 39 0 15b72 684 +INLINE 2 32 2 15b83 673 +15b30 15 41 0 +15b45 11 36 0 +15b56 a 37 0 +15b60 6 37 0 +15b66 5 38 0 +15b6b 7 0 0 +15b72 11 31 0 +15b83 a 9 0 +15b8d 4 9 0 +15b91 6 9 0 +15b97 7 0 0 +15b9e 11 10 0 +15baf 7 0 0 +15bb6 2e 12 0 +15be4 7 0 0 +15beb 5 12 0 +15bf0 1d 13 0 +15c0d 1d 14 0 +15c2a e 0 0 +15c38 1c 15 0 +15c54 a 16 0 +15c5e 7 0 0 +15c65 2c 16 0 +15c91 15 0 0 +15ca6 a 16 0 +15cb0 87 15 0 +15d37 7 0 0 +15d3e 33 15 0 +15d71 7 0 0 +15d78 24 15 0 +15d9c a 17 0 +15da6 e 0 0 +15db4 a 18 0 +15dbe e 0 0 +15dcc a 19 0 +15dd6 7 0 0 +15ddd a 20 0 +15de7 7 0 0 +15dee 2c 21 0 +15e1a 3c 22 0 +15e56 28 23 0 +15e7e 5a 18 0 +15ed8 d 28 0 +15ee5 11 12 0 +15ef6 67 28 0 +15f5d 2b 15 0 +15f88 7 0 0 +15f8f 8c 15 0 +1601b 7 0 0 +16022 3d 15 0 +1605f 67 28 0 +160c6 54 18 0 +1611a 3c 28 0 +16156 c 12 0 +16162 54 18 0 +161b6 2 27 0 +161b8 3e 28 0 +161f6 9 43 0 diff --git a/src/processor/testdata/test_app.cc b/src/processor/testdata/test_app.cc index 7882a8bd..79cabef0 100644 --- a/src/processor/testdata/test_app.cc +++ b/src/processor/testdata/test_app.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,9 +37,9 @@ namespace { -static bool callback(const wchar_t *dump_path, const wchar_t *id, - void *context, EXCEPTION_POINTERS *exinfo, - MDRawAssertionInfo *assertion, +static bool callback(const wchar_t* dump_path, const wchar_t* id, + void* context, EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, bool succeeded) { if (succeeded) { printf("dump guid is %ws\n", id); @@ -53,13 +52,13 @@ static bool callback(const wchar_t *dump_path, const wchar_t *id, } static void CrashFunction() { - int *i = reinterpret_cast<int*>(0x45); + int* i = reinterpret_cast<int*>(0x45); *i = 5; // crash! } } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { google_breakpad::ExceptionHandler eh( L".", NULL, callback, NULL, google_breakpad::ExceptionHandler::HANDLER_ALL); diff --git a/src/processor/testdata/thread_name_list.dmp b/src/processor/testdata/thread_name_list.dmp Binary files differnew file mode 100644 index 00000000..fbe84b63 --- /dev/null +++ b/src/processor/testdata/thread_name_list.dmp diff --git a/src/processor/testdata/tiny-exe-fastfail.dmp b/src/processor/testdata/tiny-exe-fastfail.dmp Binary files differnew file mode 100644 index 00000000..f7a0a502 --- /dev/null +++ b/src/processor/testdata/tiny-exe-fastfail.dmp diff --git a/src/processor/testdata/tiny-exe-with-cet-xsave.dmp b/src/processor/testdata/tiny-exe-with-cet-xsave.dmp Binary files differnew file mode 100644 index 00000000..9b641afb --- /dev/null +++ b/src/processor/testdata/tiny-exe-with-cet-xsave.dmp diff --git a/src/processor/testdata/write_av_non_canonical.dmp b/src/processor/testdata/write_av_non_canonical.dmp Binary files differnew file mode 100644 index 00000000..02da25ee --- /dev/null +++ b/src/processor/testdata/write_av_non_canonical.dmp diff --git a/src/processor/tokenize.cc b/src/processor/tokenize.cc index 8fce87a2..4e62f2ea 100644 --- a/src/processor/tokenize.cc +++ b/src/processor/tokenize.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -42,10 +41,10 @@ namespace google_breakpad { using std::vector; -bool Tokenize(char *line, - const char *separators, - int max_tokens, - vector<char*> *tokens) { +bool Tokenize(char* line, + const char* separators, + int max_tokens, + vector<char*>* tokens) { tokens->clear(); tokens->reserve(max_tokens); @@ -53,8 +52,8 @@ bool Tokenize(char *line, // Split tokens on the separator character. // strip them out before exhausting max_tokens. - char *save_ptr; - char *token = strtok_r(line, separators, &save_ptr); + char* save_ptr; + char* token = strtok_r(line, separators, &save_ptr); while (token && --remaining > 0) { tokens->push_back(token); if (remaining > 1) @@ -69,10 +68,9 @@ bool Tokenize(char *line, return tokens->size() == static_cast<unsigned int>(max_tokens); } -void StringToVector(const string &str, vector<char> &vec) { +void StringToVector(const string& str, vector<char>& vec) { vec.resize(str.length() + 1); - std::copy(str.begin(), str.end(), - vec.begin()); + std::copy(str.begin(), str.end(), vec.begin()); vec[str.length()] = '\0'; } diff --git a/src/processor/tokenize.h b/src/processor/tokenize.h index 9ff571d5..b30c7415 100644 --- a/src/processor/tokenize.h +++ b/src/processor/tokenize.h @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -50,13 +49,13 @@ namespace google_breakpad { // Tokenize, but may be treated as a failure if the caller expects an // exact, as opposed to maximum, number of tokens. -bool Tokenize(char *line, - const char *separators, +bool Tokenize(char* line, + const char* separators, int max_tokens, - std::vector<char*> *tokens); + std::vector<char*>* tokens); // For convenience, since you need a char* to pass to Tokenize. // You can call StringToVector on a string, and use &vec[0]. -void StringToVector(const string &str, std::vector<char> &vec); +void StringToVector(const string& str, std::vector<char>& vec); } // namespace google_breakpad diff --git a/src/processor/windows_frame_info.h b/src/processor/windows_frame_info.h index f96e0a43..4014a1a9 100644 --- a/src/processor/windows_frame_info.h +++ b/src/processor/windows_frame_info.h @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -113,9 +112,9 @@ struct WindowsFrameInfo { // otherwise. type, rva and code_size are present in the STACK line, // but not the StackFrameInfo structure, so return them as outparams. static WindowsFrameInfo *ParseFromString(const string string, - int &type, - uint64_t &rva, - uint64_t &code_size) { + int& type, + uint64_t& rva, + uint64_t& code_size) { // The format of a STACK WIN record is documented at: // // https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md @@ -160,7 +159,7 @@ struct WindowsFrameInfo { } // CopyFrom makes "this" WindowsFrameInfo object identical to "that". - void CopyFrom(const WindowsFrameInfo &that) { + void CopyFrom(const WindowsFrameInfo& that) { type_ = that.type_; valid = that.valid; prolog_size = that.prolog_size; diff --git a/src/third_party/curl/curlbuild.h b/src/third_party/curl/curlbuild.h index 595df4e4..2fb1d020 100644 --- a/src/third_party/curl/curlbuild.h +++ b/src/third_party/curl/curlbuild.h @@ -156,7 +156,8 @@ /* The size of `long', as computed by sizeof. */ #if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) || \ defined(__aarch64__) || (defined(__mips__) && _MIPS_SIM == _ABI64) || \ - defined(__powerpc64__) || defined(__s390x__) || defined(__LP64__) + defined(__powerpc64__) || defined(__s390x__) || defined(__LP64__) || \ + (defined(__riscv) && __riscv_xlen == 64) #define CURL_SIZEOF_LONG 8 #else #define CURL_SIZEOF_LONG 4 diff --git a/src/third_party/libdisasm/libdisasm.gyp b/src/third_party/libdisasm/libdisasm.gyp deleted file mode 100644 index 5c8dc458..00000000 --- a/src/third_party/libdisasm/libdisasm.gyp +++ /dev/null @@ -1,67 +0,0 @@ -# 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': [ - '../../build/common.gypi', - ], - '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', - ], - }, - ], -} diff --git a/src/third_party/linux/include/gflags/gflags_completions.h b/src/third_party/linux/include/gflags/gflags_completions.h index 9d9ce7a5..fe06b47a 100644 --- a/src/third_party/linux/include/gflags/gflags_completions.h +++ b/src/third_party/linux/include/gflags/gflags_completions.h @@ -1,5 +1,4 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. +// Copyright 2008 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/third_party/lss/linux_syscall_support.h b/src/third_party/lss/linux_syscall_support.h index a0879033..99a4b444 100644 --- a/src/third_party/lss/linux_syscall_support.h +++ b/src/third_party/lss/linux_syscall_support.h @@ -88,7 +88,8 @@ */ #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \ - defined(__aarch64__) || defined(__s390__)) \ + defined(__aarch64__) || defined(__s390__) || defined(__e2k__) || \ + (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch_lp64)) \ && (defined(__linux) || defined(__ANDROID__)) #ifndef SYS_CPLUSPLUS @@ -266,6 +267,12 @@ struct kernel_timeval { long tv_usec; }; +/* include/linux/time.h */ +struct kernel_itimerval { + struct kernel_timeval it_interval; + struct kernel_timeval it_value; +}; + /* include/linux/resource.h */ struct kernel_rusage { struct kernel_timeval ru_utime; @@ -287,7 +294,8 @@ struct kernel_rusage { }; #if defined(__i386__) || defined(__ARM_EABI__) || defined(__ARM_ARCH_3__) \ - || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) + || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) \ + || defined(__e2k__) /* include/asm-{arm,i386,mips,ppc}/signal.h */ struct kernel_old_sigaction { @@ -301,8 +309,8 @@ struct kernel_old_sigaction { } __attribute__((packed,aligned(4))); #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) #define kernel_old_sigaction kernel_sigaction -#elif defined(__aarch64__) - // No kernel_old_sigaction defined for arm64. +#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) + // No kernel_old_sigaction defined for arm64 riscv and loongarch64. #endif /* Some kernel functions (e.g. sigaction() in 2.6.23) require that the @@ -341,7 +349,9 @@ struct kernel_sigaction { void (*sa_sigaction_)(int, siginfo_t *, void *); }; unsigned long sa_flags; +#if !defined(__riscv) && !defined(__loongarch_lp64) void (*sa_restorer)(void); +#endif struct kernel_sigset_t sa_mask; #endif }; @@ -355,6 +365,16 @@ struct kernel_sockaddr { /* include/asm-{arm,aarch64,i386,mips,ppc,s390}/stat.h */ #ifdef __mips__ #if _MIPS_SIM == _MIPS_SIM_ABI64 +typedef unsigned long long kernel_blkcnt_t; +typedef unsigned kernel_blksize_t; +typedef unsigned kernel_dev_t; +typedef unsigned kernel_gid_t; +typedef unsigned long long kernel_ino_t; +typedef unsigned kernel_mode_t; +typedef unsigned kernel_nlink_t; +typedef long long kernel_off_t; +typedef unsigned kernel_time_t; +typedef unsigned kernel_uid_t; struct kernel_stat { #else struct kernel_stat64 { @@ -401,6 +421,28 @@ struct kernel_stat64 { unsigned long __unused4; unsigned long __unused5; }; +#elif defined(__e2k__) +struct kernel_stat64 { + unsigned long long st_dev; + unsigned long long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long long st_rdev; + long long st_size; + int st_blksize; + int __pad2; + unsigned long long st_blocks; + int st_atime_; + unsigned int st_atime_nsec_; + int st_mtime_; + unsigned int st_mtime_nsec_; + int st_ctime_; + unsigned int st_ctime_nsec_; + unsigned int __unused4; + unsigned int __unused5; +}; #else struct kernel_stat64 { unsigned long long st_dev; @@ -427,165 +469,264 @@ struct kernel_stat64 { /* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/stat.h */ #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) +typedef unsigned kernel_blkcnt_t; +typedef unsigned kernel_blksize_t; +typedef unsigned short kernel_dev_t; +typedef unsigned short kernel_gid_t; +typedef unsigned kernel_ino_t; +typedef unsigned short kernel_mode_t; +typedef unsigned short kernel_nlink_t; +typedef unsigned kernel_off_t; +typedef unsigned kernel_time_t; +typedef unsigned short kernel_uid_t; struct kernel_stat { /* The kernel headers suggest that st_dev and st_rdev should be 32bit * quantities encoding 12bit major and 20bit minor numbers in an interleaved * format. In reality, we do not see useful data in the top bits. So, * we'll leave the padding in here, until we find a better solution. */ - unsigned short st_dev; + kernel_dev_t st_dev; short pad1; - unsigned st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - unsigned short st_rdev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; short pad2; - unsigned st_size; - unsigned st_blksize; - unsigned st_blocks; - unsigned st_atime_; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; unsigned st_atime_nsec_; - unsigned st_mtime_; + kernel_time_t st_mtime_; unsigned st_mtime_nsec_; - unsigned st_ctime_; + kernel_time_t st_ctime_; unsigned st_ctime_nsec_; unsigned __unused4; unsigned __unused5; }; #elif defined(__x86_64__) +typedef int64_t kernel_blkcnt_t; +typedef int64_t kernel_blksize_t; +typedef uint64_t kernel_dev_t; +typedef unsigned kernel_gid_t; +typedef uint64_t kernel_ino_t; +typedef unsigned kernel_mode_t; +typedef uint64_t kernel_nlink_t; +typedef int64_t kernel_off_t; +typedef uint64_t kernel_time_t; +typedef unsigned kernel_uid_t; struct kernel_stat { - uint64_t st_dev; - uint64_t st_ino; - uint64_t st_nlink; - unsigned st_mode; - unsigned st_uid; - unsigned st_gid; + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_nlink_t st_nlink; + kernel_mode_t st_mode; + kernel_uid_t st_uid; + kernel_gid_t st_gid; unsigned __pad0; - uint64_t st_rdev; - int64_t st_size; - int64_t st_blksize; - int64_t st_blocks; - uint64_t st_atime_; + kernel_dev_t st_rdev; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; uint64_t st_atime_nsec_; - uint64_t st_mtime_; + kernel_time_t st_mtime_; uint64_t st_mtime_nsec_; - uint64_t st_ctime_; + kernel_time_t st_ctime_; uint64_t st_ctime_nsec_; int64_t __unused4[3]; }; #elif defined(__PPC__) +typedef unsigned long kernel_blkcnt_t; +typedef unsigned long kernel_blksize_t; +typedef unsigned kernel_dev_t; +typedef unsigned kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned long kernel_mode_t; +typedef unsigned short kernel_nlink_t; +typedef long kernel_off_t; +typedef unsigned long kernel_time_t; +typedef unsigned kernel_uid_t; struct kernel_stat { - unsigned st_dev; - unsigned long st_ino; // ino_t - unsigned long st_mode; // mode_t - unsigned short st_nlink; // nlink_t - unsigned st_uid; // uid_t - unsigned st_gid; // gid_t - unsigned st_rdev; - long st_size; // off_t - unsigned long st_blksize; - unsigned long st_blocks; - unsigned long st_atime_; + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_gid_t st_uid; + kernel_uid_t st_gid; + kernel_dev_t st_rdev; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; unsigned long st_atime_nsec_; - unsigned long st_mtime_; + kernel_time_t st_mtime_; unsigned long st_mtime_nsec_; - unsigned long st_ctime_; + kernel_time_t st_ctime_; unsigned long st_ctime_nsec_; unsigned long __unused4; unsigned long __unused5; }; #elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) +typedef int kernel_blkcnt_t; +typedef int kernel_blksize_t; +typedef unsigned kernel_dev_t; +typedef unsigned kernel_gid_t; +typedef unsigned kernel_ino_t; +typedef unsigned kernel_mode_t; +typedef unsigned kernel_nlink_t; +typedef long kernel_off_t; +typedef long kernel_time_t; +typedef unsigned kernel_uid_t; struct kernel_stat { - unsigned st_dev; + kernel_dev_t st_dev; int st_pad1[3]; - unsigned st_ino; - unsigned st_mode; - unsigned st_nlink; - unsigned st_uid; - unsigned st_gid; - unsigned st_rdev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; int st_pad2[2]; - long st_size; + kernel_off_t st_size; int st_pad3; - long st_atime_; + kernel_time_t st_atime_; long st_atime_nsec_; - long st_mtime_; + kernel_time_t st_mtime_; long st_mtime_nsec_; - long st_ctime_; + kernel_time_t st_ctime_; long st_ctime_nsec_; - int st_blksize; - int st_blocks; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; int st_pad4[14]; }; -#elif defined(__aarch64__) +#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) +typedef long kernel_blkcnt_t; +typedef int kernel_blksize_t; +typedef unsigned long kernel_dev_t; +typedef unsigned int kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned int kernel_mode_t; +typedef unsigned int kernel_nlink_t; +typedef long kernel_off_t; +typedef long kernel_time_t; +typedef unsigned int kernel_uid_t; struct kernel_stat { - unsigned long st_dev; - unsigned long st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - unsigned long st_rdev; + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; unsigned long __pad1; - long st_size; - int st_blksize; + kernel_off_t st_size; + kernel_blksize_t st_blksize; int __pad2; - long st_blocks; - long st_atime_; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; unsigned long st_atime_nsec_; - long st_mtime_; + kernel_time_t st_mtime_; unsigned long st_mtime_nsec_; - long st_ctime_; + kernel_time_t st_ctime_; unsigned long st_ctime_nsec_; unsigned int __unused4; unsigned int __unused5; }; #elif defined(__s390x__) +typedef long kernel_blkcnt_t; +typedef unsigned long kernel_blksize_t; +typedef unsigned long kernel_dev_t; +typedef unsigned int kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned int kernel_mode_t; +typedef unsigned long kernel_nlink_t; +typedef unsigned long kernel_off_t; +typedef unsigned long kernel_time_t; +typedef unsigned int kernel_uid_t; struct kernel_stat { - unsigned long st_dev; - unsigned long st_ino; - unsigned long st_nlink; - unsigned int st_mode; - unsigned int st_uid; - unsigned int st_gid; + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_nlink_t st_nlink; + kernel_mode_t st_mode; + kernel_uid_t st_uid; + kernel_gid_t st_gid; unsigned int __pad1; - unsigned long st_rdev; - unsigned long st_size; - unsigned long st_atime_; + kernel_dev_t st_rdev; + kernel_off_t st_size; + kernel_time_t st_atime_; unsigned long st_atime_nsec_; - unsigned long st_mtime_; + kernel_time_t st_mtime_; unsigned long st_mtime_nsec_; - unsigned long st_ctime_; + kernel_time_t st_ctime_; unsigned long st_ctime_nsec_; - unsigned long st_blksize; - long st_blocks; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; unsigned long __unused[3]; }; #elif defined(__s390__) +typedef unsigned long kernel_blkcnt_t; +typedef unsigned long kernel_blksize_t; +typedef unsigned short kernel_dev_t; +typedef unsigned short kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned short kernel_mode_t; +typedef unsigned short kernel_nlink_t; +typedef unsigned long kernel_off_t; +typedef unsigned long kernel_time_t; +typedef unsigned short kernel_uid_t; struct kernel_stat { - unsigned short st_dev; + kernel_dev_t st_dev; unsigned short __pad1; - unsigned long st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - unsigned short st_rdev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; unsigned short __pad2; - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - unsigned long st_atime_; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; unsigned long st_atime_nsec_; - unsigned long st_mtime_; + kernel_time_t st_mtime_; unsigned long st_mtime_nsec_; - unsigned long st_ctime_; + kernel_time_t st_ctime_; unsigned long st_ctime_nsec_; unsigned long __unused4; unsigned long __unused5; }; +#elif defined(__e2k__) +typedef unsigned long kernel_blkcnt_t; +typedef unsigned long kernel_blksize_t; +typedef unsigned long kernel_dev_t; +typedef unsigned int kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned int kernel_mode_t; +typedef unsigned long kernel_nlink_t; +typedef unsigned long kernel_off_t; +typedef unsigned long kernel_time_t; +typedef unsigned int kernel_uid_t; +struct kernel_stat { + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; + unsigned long st_atime_nsec_; + kernel_time_t st_mtime_; + unsigned long st_mtime_nsec_; + kernel_time_t st_ctime_; + unsigned long st_ctime_nsec_; +}; #endif /* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/statfs.h */ @@ -701,6 +842,37 @@ struct kernel_statfs { }; #endif +struct kernel_statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t __reserved; +}; + +struct kernel_statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t __spare0[1]; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct kernel_statx_timestamp stx_atime; + struct kernel_statx_timestamp stx_btime; + struct kernel_statx_timestamp stx_ctime; + struct kernel_statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t stx_mnt_id; + uint64_t __spare2; + uint64_t __spare3[12]; +}; /* Definitions missing from the standard header files */ #ifndef O_DIRECTORY @@ -737,6 +909,18 @@ struct kernel_statfs { #ifndef AT_REMOVEDIR #define AT_REMOVEDIR 0x200 #endif +#ifndef AT_NO_AUTOMOUNT +#define AT_NO_AUTOMOUNT 0x800 +#endif +#ifndef AT_EMPTY_PATH +#define AT_EMPTY_PATH 0x1000 +#endif +#ifndef STATX_BASIC_STATS +#define STATX_BASIC_STATS 0x000007ffU +#endif +#ifndef AT_STATX_SYNC_AS_STAT +#define AT_STATX_SYNC_AS_STAT 0x0000 +#endif #ifndef MREMAP_FIXED #define MREMAP_FIXED 2 #endif @@ -954,6 +1138,9 @@ struct kernel_statfs { #ifndef __NR_fallocate #define __NR_fallocate 324 #endif +#ifndef __NR_getrandom +#define __NR_getrandom 355 +#endif /* End of i386 definitions */ #elif defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) #ifndef __NR_setresuid @@ -1052,14 +1239,20 @@ struct kernel_statfs { #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_SYSCALL_BASE + 315) #endif +#ifndef __NR_fstatat64 +#define __NR_fstatat64 (__NR_SYSCALL_BASE + 327) +#endif #ifndef __NR_move_pages #define __NR_move_pages (__NR_SYSCALL_BASE + 344) #endif #ifndef __NR_getcpu #define __NR_getcpu (__NR_SYSCALL_BASE + 345) #endif +#ifndef __NR_getrandom +#define __NR_getrandom (__NR_SYSCALL_BASE + 384) +#endif /* End of ARM 3/EABI definitions */ -#elif defined(__aarch64__) +#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) #ifndef __NR_setxattr #define __NR_setxattr 5 #endif @@ -1115,9 +1308,11 @@ struct kernel_statfs { #ifndef __NR_readlinkat #define __NR_readlinkat 78 #endif +#if !defined(__loongarch_lp64) #ifndef __NR_newfstatat #define __NR_newfstatat 79 #endif +#endif #ifndef __NR_set_tid_address #define __NR_set_tid_address 96 #endif @@ -1155,7 +1350,12 @@ struct kernel_statfs { #ifndef __NR_move_pages #define __NR_move_pages 239 #endif -/* End of aarch64 definitions */ +#ifndef __NR_getrandom +#define __NR_getrandom 278 +#endif +#ifndef __NR_statx +#define __NR_statx 291 +#endif #elif defined(__x86_64__) #ifndef __NR_pread64 #define __NR_pread64 17 @@ -1246,6 +1446,9 @@ struct kernel_statfs { #ifndef __NR_fallocate #define __NR_fallocate 285 #endif +#ifndef __NR_getrandom +#define __NR_getrandom 318 +#endif /* End of x86-64 definitions */ #elif defined(__mips__) #if _MIPS_SIM == _MIPS_SIM_ABI32 @@ -1347,6 +1550,9 @@ struct kernel_statfs { #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_Linux + 315) #endif +#ifndef __NR_getrandom +#define __NR_getrandom (__NR_Linux + 353) +#endif /* End of MIPS (old 32bit API) definitions */ #elif _MIPS_SIM == _MIPS_SIM_ABI64 #ifndef __NR_pread64 @@ -1425,6 +1631,9 @@ struct kernel_statfs { #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_Linux + 274) #endif +#ifndef __NR_getrandom +#define __NR_getrandom (__NR_Linux + 313) +#endif /* End of MIPS (64bit API) definitions */ #else #ifndef __NR_setresuid @@ -1861,15 +2070,16 @@ struct kernel_statfs { #endif #undef LSS_RETURN - #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ - || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__)) + #if defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ + || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__) \ + || defined(__e2k__) || defined(__riscv) || defined(__loongarch_lp64) /* Failing system calls return a negative result in the range of * -1..-4095. These are "errno" values with the sign inverted. */ #define LSS_RETURN(type, res) \ do { \ if ((unsigned long)(res) >= (unsigned long)(-4095)) { \ - LSS_ERRNO = -(res); \ + LSS_ERRNO = (int)(-(res)); \ res = -1; \ } \ return (type) (res); \ @@ -2223,7 +2433,7 @@ struct kernel_statfs { #define _LSS_RETURN(type, res, cast) \ do { \ if ((uint64_t)(res) >= (uint64_t)(-4095)) { \ - LSS_ERRNO = -(res); \ + LSS_ERRNO = (int)(-(res)); \ res = -1; \ } \ return (type)(cast)(res); \ @@ -2772,7 +2982,7 @@ struct kernel_statfs { void *newtls, int *child_tidptr) { int64_t __res; { - register uint64_t __flags __asm__("x0") = flags; + register uint64_t __flags __asm__("x0") = (uint64_t)flags; register void *__stack __asm__("x1") = child_stack; register void *__ptid __asm__("x2") = parent_tidptr; register void *__tls __asm__("x3") = newtls; @@ -3355,6 +3565,503 @@ struct kernel_statfs { } LSS_RETURN(int, __ret); } + #elif defined(__riscv) && __riscv_xlen == 64 + #undef LSS_REG + #define LSS_REG(r,a) register int64_t __r##r __asm__("a"#r) = (int64_t)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register int64_t __res_a0 __asm__("a0"); \ + register int64_t __a7 __asm__("a7") = __NR_##name; \ + int64_t __res; \ + __asm__ __volatile__ ("scall\n" \ + : "=r"(__res_a0) \ + : "r"(__a7) , ## args \ + : "memory"); \ + __res = __res_a0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + int64_t __res; + { + register int64_t __res_a0 __asm__("a0"); + register uint64_t __flags __asm__("a0") = flags; + register void *__stack __asm__("a1") = child_stack; + register void *__ptid __asm__("a2") = parent_tidptr; + register void *__tls __asm__("a3") = newtls; + register int *__ctid __asm__("a4") = child_tidptr; + __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "addi %2,%2,-16\n" + "sd %1, 0(%2)\n" + "sd %4, 8(%2)\n" + + /* %a0 = syscall(%a0 = flags, + * %a1 = child_stack, + * %a2 = parent_tidptr, + * %a3 = newtls, + * %a4 = child_tidptr) + */ + "li a7, %8\n" + "scall\n" + + /* if (%a0 != 0) + * return %a0; + */ + "bnez %0, 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ld a1, 0(sp)\n" + "ld a0, 8(sp)\n" + "jalr a1\n" + + /* Call _exit(%a0). + */ + "li a7, %9\n" + "scall\n" + "1:\n" + : "=r" (__res_a0) + : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "cc", "memory"); + __res = __res_a0; + } + LSS_RETURN(int, __res); + } + #elif defined(__e2k__) + + #undef _LSS_BODY + #define _LSS_BODY(nr, type, name, ...) \ + register unsigned long long __res; \ + __asm__ __volatile__ \ + ( \ + "{\n\t" \ + " sdisp %%ctpr1, 0x3\n\t" \ + " addd, s 0x0, %[sys_num], %%b[0]\n\t" \ + LSS_BODY_ASM##nr \ + "}\n\t" \ + "{\n\t" \ + " call %%ctpr1, wbs = %#\n\t" \ + "}\n\t" \ + "{\n\t" \ + " addd, s 0x0, %%b[0], %[res]\n\t" \ + "}\n\t" \ + : [res] "=r" (__res) \ + : \ + LSS_BODY_ARG##nr(__VA_ARGS__) \ + [sys_num] "ri" (__NR_##name) \ + : "ctpr1", "ctpr2", "ctpr3", \ + "b[0]", "b[1]", "b[2]", "b[3]", \ + "b[4]", "b[5]", "b[6]", "b[7]" \ + ); \ + LSS_RETURN(type, __res); + + #undef LSS_BODY + #define LSS_BODY(nr, type, name, args...) \ + _LSS_BODY(nr, type, name, ## args) + + #undef LSS_BODY_ASM0 + #undef LSS_BODY_ASM1 + #undef LSS_BODY_ASM2 + #undef LSS_BODY_ASM3 + #undef LSS_BODY_ASM4 + #undef LSS_BODY_ASM5 + #undef LSS_BODY_ASM6 + + #define LSS_BODY_ASM0 + #define LSS_BODY_ASM1 LSS_BODY_ASM0 \ + " addd, s 0x0, %[arg1], %%b[1]\n\t" + #define LSS_BODY_ASM2 LSS_BODY_ASM1 \ + " addd, s 0x0, %[arg2], %%b[2]\n\t" + #define LSS_BODY_ASM3 LSS_BODY_ASM2 \ + " addd, s 0x0, %[arg3], %%b[3]\n\t" + #define LSS_BODY_ASM4 LSS_BODY_ASM3 \ + " addd, s 0x0, %[arg4], %%b[4]\n\t" + #define LSS_BODY_ASM5 LSS_BODY_ASM4 \ + " addd, s 0x0, %[arg5], %%b[5]\n\t" + #define LSS_BODY_ASM6 LSS_BODY_ASM5 \ + "}\n\t" \ + "{\n\t" \ + " addd, s 0x0, %[arg6], %%b[6]\n\t" + + #undef LSS_SYSCALL_ARG + #define LSS_SYSCALL_ARG(a) ((unsigned long long)(uintptr_t)(a)) + + #undef LSS_BODY_ARG0 + #undef LSS_BODY_ARG1 + #undef LSS_BODY_ARG2 + #undef LSS_BODY_ARG3 + #undef LSS_BODY_ARG4 + #undef LSS_BODY_ARG5 + #undef LSS_BODY_ARG6 + + #define LSS_BODY_ARG0() + #define LSS_BODY_ARG1(_arg1) \ + [arg1] "ri" LSS_SYSCALL_ARG(_arg1), + #define LSS_BODY_ARG2(_arg1, _arg2) \ + LSS_BODY_ARG1(_arg1) \ + [arg2] "ri" LSS_SYSCALL_ARG(_arg2), + #define LSS_BODY_ARG3(_arg1, _arg2, _arg3) \ + LSS_BODY_ARG2(_arg1, _arg2) \ + [arg3] "ri" LSS_SYSCALL_ARG(_arg3), + #define LSS_BODY_ARG4(_arg1, _arg2, _arg3, _arg4) \ + LSS_BODY_ARG3(_arg1, _arg2, _arg3) \ + [arg4] "ri" LSS_SYSCALL_ARG(_arg4), + #define LSS_BODY_ARG5(_arg1, _arg2, _arg3, _arg4, _arg5) \ + LSS_BODY_ARG4(_arg1, _arg2, _arg3, _arg4) \ + [arg5] "ri" LSS_SYSCALL_ARG(_arg5), + #define LSS_BODY_ARG6(_arg1, _arg2, _arg3, _arg4, _arg5, _arg6) \ + LSS_BODY_ARG5(_arg1, _arg2, _arg3, _arg4, _arg5) \ + [arg6] "ri" LSS_SYSCALL_ARG(_arg6), + + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(0, type, name); \ + } + + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_BODY(1, type, name, arg1) \ + } + + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_BODY(2, type, name, arg1, arg2) \ + } + + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_BODY(3, type, name, arg1, arg2, arg3) \ + } + + #undef _syscall4 + #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_BODY(4, type, name, arg1, arg2, arg3, arg4) \ + } + + #undef _syscall5 + #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5) \ + } + + #undef _syscall6 + #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5, type6, arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6) \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + unsigned long long __res; + + __asm__ __volatile__ ( + "{\n\t" + " addd,s 0x0, %[nr_clone], %%b[0]\n\t" + " addd,s 0x0, %[flags], %%db[1]\n\t" + " addd,s 0x0, %[child_stack], %%db[2]\n\t" + " addd,s 0x0, %[parent_tidptr], %%db[3]\n\t" + " addd,s 0x0, %[child_tidptr], %%db[4]\n\t" + " addd,s 0x0, %[newtls], %%db[5]\n\t" + "}\n\t" + /* if (fn == NULL) + * return -EINVAL; + */ + + "{\n\t" + " disp %%ctpr1, .L1\n\t" + "}\n\t" + "{\n\t" + " cmpesb,s 0x0, %[fn], %%pred0\n\t" + "}\n\t" + "{\n\t" + " ct %%ctpr1 ? %%pred0\n\t" + "}\n\t" + + /* if (child_stack == NULL) + * return -EINVAL; + */ + "{\n\t" + " cmpesb,s 0x0, %%db[2], %%pred0\n\t" + "}\n\t" + "{\n\t" + " ct %%ctpr1 ? %%pred0\n\t" + "}\n\t" + + /* b[0] = syscall(%b[0] = __NR_clone, + * %db[1] = flags, + * %db[2] = child_stack, + * %db[3] = parent_tidptr, + * %db[4] = child_tidptr, + * %db[5] = newtls) + */ + "{\n\t" + " sdisp %%ctpr1, 0x3\n\t" + "}\n\t" + "{\n\t" + " call %%ctpr1, wbs = %#\n\t" + "}\n\t" + + /* if (%[b0] != 0) + * return %b[0]; + */ + "{\n\t" + " disp %%ctpr1, .L2\n\t" + " cmpesb,s 0x0, %%b[0], %%pred0\n\t" + "}\n\t" + "{\n\t" + " ct %%ctpr1 ? ~%%pred0\n\t" + "}\n\t" + /* In the child, now. Call "fn(arg)". + */ + + "{\n\t" + " movtd,s %[fn], %%ctpr1\n\t" + "}\n\t" + "{\n\t" + " addd,s 0x0, %[arg], %%db[0]\n\t" + "}\n\t" + "{\n\t" + " call %%ctpr1, wbs = %#\n\t" + "}\n\t" + /* Call _exit(%b[0]). + */ + + "{\n\t" + " sdisp %%ctpr1, 0x3\n\t" + " addd,s 0x0, %%b[0], %%b[1]\n\t" + "}\n\t" + "{\n\t" + " addd,s 0x0, %[nr_exit], %%b[0]\n\t" + "}\n\t" + "{\n\t" + " call %%ctpr1, wbs = %#\n\t" + "}\n\t" + "{\n\t" + " disp %%ctpr1, .L2\n\t" + " adds,s 0x0, 0x0, %%b[0]\n\t" + "}\n\t" + "{\n\t" + " ct %%ctpr1\n\t" + "}\n\t" + ".L1:\n\t" + "{\n\t" + " addd,s 0x0, %[einval], %%b[0]\n\t" + "}\n\t" + ".L2:\n\t" + "{\n\t" + " addd,s 0x0, %%b[0], %[res]\n\t" + "}\n\t" + : [res] "=r" LSS_SYSCALL_ARG(__res) + : [nr_clone] "ri" LSS_SYSCALL_ARG(__NR_clone) + [arg] "ri" LSS_SYSCALL_ARG(arg) + [nr_exit] "ri" LSS_SYSCALL_ARG(__NR_exit) + [flags] "ri" LSS_SYSCALL_ARG(flags) + [child_stack] "ri" LSS_SYSCALL_ARG(child_stack) + [parent_tidptr] "ri" + LSS_SYSCALL_ARG(parent_tidptr) + [newtls] "ri" LSS_SYSCALL_ARG(newtls) + [child_tidptr] "ri" + LSS_SYSCALL_ARG(child_tidptr) + [fn] "ri" LSS_SYSCALL_ARG(fn) + [einval] "ri" LSS_SYSCALL_ARG(-EINVAL) + : "ctpr1", "b[0]", "b[1]", "b[2]", "b[3]", + "b[4]", "b[5]", "pred0"); + LSS_RETURN(int, __res); + } + #elif defined(__loongarch_lp64) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(ar,a) register int64_t __r##ar __asm__("a"#ar) = (int64_t)a + /* syscall is like subroutine calls, all caller-saved registers may be + * clobbered, we should add them to the |Clobbers| list. + * a0 is not included because it's in the output list. + */ + #define LSS_SYSCALL_CLOBBERS "t0", "t1", "t2", "t3", "t4", "t5", "t6", \ + "t7", "t8", "memory" + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register int64_t __res_a0 __asm__("a0"); \ + int64_t __res; \ + __asm__ __volatile__ ("li.d $a7, %1\n" \ + "syscall 0x0\n" \ + : "=r"(__res_a0) \ + : "i"(__NR_##name) , ## args \ + : LSS_SYSCALL_CLOBBERS); \ + __res = __res_a0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + int64_t __res; + { + register int64_t __res_a0 __asm__("a0"); + register uint64_t __flags __asm__("a0") = flags; + register void *__stack __asm__("a1") = child_stack; + register void *__ptid __asm__("a2") = parent_tidptr; + register void *__tls __asm__("a3") = newtls; + register int *__ctid __asm__("a4") = child_tidptr; + __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "addi.d %2, %2, -16\n" + "st.d %1, %2, 8\n" + "st.d %4, %2, 0\n" + + /* %a0 = syscall(%a0 = flags, + * %a1 = child_stack, + * %a2 = parent_tidptr, + * %a3 = newtls, + * %a4 = child_tidptr) + */ + "li.d $a7, %8\n" + "syscall 0x0\n" + + /* if (%a0 != 0) + * return %a0; + */ + "bnez $a0, 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ld.d $a0, $sp, 0\n" + "ld.d $a1, $sp, 8\n" + "addi.d $sp, $sp, 16\n" + "jirl $ra, $a1, 0\n" + + /* Call _exit(%a0). + */ + "li.d $a7, %9\n" + "syscall 0x0\n" + "1:\n" + : "=r" (__res_a0) + : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : LSS_SYSCALL_CLOBBERS); + __res = __res_a0; + } + LSS_RETURN(int, __res); + } + #endif #define __NR__exit __NR_exit #define __NR__gettid __NR_gettid @@ -3385,8 +4092,10 @@ struct kernel_statfs { // fork is polyfilled below when not available. LSS_INLINE _syscall0(pid_t, fork) #endif + #if defined(__NR_fstat) LSS_INLINE _syscall2(int, fstat, int, f, struct kernel_stat*, b) + #endif LSS_INLINE _syscall2(int, fstatfs, int, f, struct kernel_statfs*, b) #if defined(__x86_64__) @@ -3408,6 +4117,8 @@ struct kernel_statfs { struct kernel_dirent64*, d, int, c) LSS_INLINE _syscall0(gid_t, getegid) LSS_INLINE _syscall0(uid_t, geteuid) + LSS_INLINE _syscall2(int, getitimer, int, w, + struct kernel_itimerval*, c) #if defined(__NR_getpgrp) LSS_INLINE _syscall0(pid_t, getpgrp) #endif @@ -3419,10 +4130,10 @@ struct kernel_statfs { gid_t *, e, gid_t *, s) LSS_INLINE _syscall3(int, getresuid, uid_t *, r, uid_t *, e, uid_t *, s) -#if !defined(__ARM_EABI__) + #if defined(__NR_getrlimit) LSS_INLINE _syscall2(int, getrlimit, int, r, struct kernel_rlimit*, l) -#endif + #endif LSS_INLINE _syscall1(pid_t, getsid, pid_t, p) LSS_INLINE _syscall0(pid_t, _gettid) LSS_INLINE _syscall2(pid_t, gettimeofday, struct kernel_timeval*, t, @@ -3529,6 +4240,9 @@ struct kernel_statfs { LSS_INLINE _syscall1(int, setfsuid, uid_t, u) LSS_INLINE _syscall1(int, setuid, uid_t, u) LSS_INLINE _syscall1(int, setgid, gid_t, g) + LSS_INLINE _syscall3(int, setitimer, int, w, + const struct kernel_itimerval*, n, + struct kernel_itimerval*, o) LSS_INLINE _syscall2(int, setpgid, pid_t, p, pid_t, g) LSS_INLINE _syscall3(int, setpriority, int, a, @@ -3537,8 +4251,10 @@ struct kernel_statfs { gid_t, e, gid_t, s) LSS_INLINE _syscall3(int, setresuid, uid_t, r, uid_t, e, uid_t, s) + #if defined(__NR_setrlimit) LSS_INLINE _syscall2(int, setrlimit, int, r, const struct kernel_rlimit*, l) + #endif LSS_INLINE _syscall0(pid_t, setsid) LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s, const stack_t*, o) @@ -3546,10 +4262,14 @@ struct kernel_statfs { LSS_INLINE _syscall1(int, sigreturn, unsigned long, u) #endif #if defined(__NR_stat) - // stat is polyfilled below when not available. + // stat and lstat are polyfilled below when not available. LSS_INLINE _syscall2(int, stat, const char*, f, struct kernel_stat*, b) #endif + #if defined(__NR_lstat) + LSS_INLINE _syscall2(int, lstat, const char*, f, + struct kernel_stat*, b) + #endif LSS_INLINE _syscall2(int, statfs, const char*, f, struct kernel_statfs*, b) LSS_INLINE _syscall3(int, tgkill, pid_t, p, @@ -3568,23 +4288,6 @@ struct kernel_statfs { LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu, unsigned *, node, void *, unused) #endif - #if defined(__x86_64__) || \ - (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) - LSS_INLINE _syscall3(int, recvmsg, int, s, - struct kernel_msghdr*, m, int, f) - LSS_INLINE _syscall3(int, sendmsg, int, s, - const struct kernel_msghdr*, m, int, f) - LSS_INLINE _syscall6(int, sendto, int, s, - const void*, m, size_t, l, - int, f, - const struct kernel_sockaddr*, a, int, t) - LSS_INLINE _syscall2(int, shutdown, int, s, - int, h) - LSS_INLINE _syscall3(int, socket, int, d, - int, t, int, p) - LSS_INLINE _syscall4(int, socketpair, int, d, - int, t, int, p, int*, s) - #endif #if defined(__NR_fadvise64) #if defined(__x86_64__) /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ @@ -3658,11 +4361,21 @@ struct kernel_statfs { int, f, int, mode, loff_t, offset, loff_t, len) #endif #endif + #if defined(__NR_getrandom) + LSS_INLINE _syscall3(ssize_t, getrandom, void*, buffer, size_t, length, + unsigned int, flags) + #endif #if defined(__NR_newfstatat) LSS_INLINE _syscall4(int, newfstatat, int, d, const char *, p, struct kernel_stat*, b, int, f) #endif + #if defined(__NR_statx) + LSS_INLINE _syscall5(int, statx, int, d, + const char *, p, + int, f, int, m, + struct kernel_statx*, b) + #endif #if defined(__x86_64__) || defined(__s390x__) LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, gid_t *egid, @@ -3869,43 +4582,43 @@ struct kernel_statfs { LSS_INLINE int LSS_NAME(sigaddset)(struct kernel_sigset_t *set, int signum) { - if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { - set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] - |= 1UL << ((signum - 1) % (8*sizeof(set->sig[0]))); + set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] + |= 1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0]))); return 0; } } LSS_INLINE int LSS_NAME(sigdelset)(struct kernel_sigset_t *set, int signum) { - if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { - set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] - &= ~(1UL << ((signum - 1) % (8*sizeof(set->sig[0])))); + set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] + &= ~(1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0])))); return 0; } } LSS_INLINE int LSS_NAME(sigismember)(struct kernel_sigset_t *set, int signum) { - if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { - return !!(set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] & - (1UL << ((signum - 1) % (8*sizeof(set->sig[0]))))); + return !!(set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] & + (1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0]))))); } } #if defined(__i386__) || \ defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ defined(__PPC__) || \ - (defined(__s390__) && !defined(__s390x__)) + (defined(__s390__) && !defined(__s390x__)) || defined(__e2k__) #define __NR__sigaction __NR_sigaction #define __NR__sigpending __NR_sigpending #define __NR__sigsuspend __NR_sigsuspend @@ -4159,23 +4872,31 @@ struct kernel_statfs { LSS_SC_BODY(4, int, 8, d, type, protocol, sv); } #endif - #if defined(__ARM_EABI__) || defined (__aarch64__) + #if defined(__NR_recvmsg) LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg, int, flags) + #endif + #if defined(__NR_sendmsg) LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*, msg, int, flags) + #endif + #if defined(__NR_sendto) LSS_INLINE _syscall6(ssize_t, sendto, int, s, const void*, buf, size_t,len, int, flags, const struct kernel_sockaddr*, to, unsigned int, tolen) + #endif + #if defined(__NR_shutdown) LSS_INLINE _syscall2(int, shutdown, int, s, int, how) + #endif + #if defined(__NR_socket) LSS_INLINE _syscall3(int, socket, int, domain, int, type, int, protocol) + #endif + #if defined(__NR_socketpair) LSS_INLINE _syscall4(int, socketpair, int, d, int, type, int, protocol, int*, sv) #endif - #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ - (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ - defined(__s390__) - #define __NR__socketcall __NR_socketcall + + #if defined(__NR_socketcall) LSS_INLINE _syscall2(int, _socketcall, int, c, va_list, a) LSS_INLINE int LSS_NAME(socketcall)(int op, ...) { @@ -4187,36 +4908,43 @@ struct kernel_statfs { return rc; } + # if !defined(__NR_recvmsg) LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, int flags){ return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags); } - + # endif + # if !defined(__NR_sendmsg) LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, const struct kernel_msghdr *msg, int flags) { return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags); } - + # endif + # if !defined(__NR_sendto) LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, int flags, const struct kernel_sockaddr *to, unsigned int tolen) { return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen); } - + # endif + # if !defined(__NR_shutdown) LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { return LSS_NAME(socketcall)(13, s, how); } - + # endif + # if !defined(__NR_socket) LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { return LSS_NAME(socketcall)(1, domain, type, protocol); } - + # endif + # if !defined(__NR_socketpair) LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, int sv[2]) { return LSS_NAME(socketcall)(8, d, type, protocol, sv); } + # endif #endif #if defined(__NR_fstatat64) LSS_INLINE _syscall4(int, fstatat64, int, d, @@ -4298,12 +5026,12 @@ struct kernel_statfs { va_start(ap, flags); new_address = va_arg(ap, void *); rc = LSS_NAME(_mremap)(old_address, old_size, new_size, - flags, new_address); + (unsigned long)flags, new_address); va_end(ap); return rc; } - LSS_INLINE int LSS_NAME(ptrace_detach)(pid_t pid) { + LSS_INLINE long LSS_NAME(ptrace_detach)(pid_t pid) { /* PTRACE_DETACH can sometimes forget to wake up the tracee and it * then sends job control signals to the real parent, rather than to * the tracer. We reduce the risk of this happening by starting a @@ -4314,7 +5042,8 @@ struct kernel_statfs { * detached. Large multi threaded apps can take a long time in the kernel * processing SIGCONT. */ - int rc, err; + long rc; + int err; LSS_NAME(sched_yield)(); rc = LSS_NAME(ptrace)(PTRACE_DETACH, pid, (void *)0, (void *)0); err = LSS_ERRNO; @@ -4347,7 +5076,7 @@ struct kernel_statfs { LSS_SYSCALL_ARG(c), (uint64_t)(o)); } - LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, unsigned c) { + LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, size_t c) { LSS_BODY(3, int, readahead, LSS_SYSCALL_ARG(f), (uint64_t)(o), LSS_SYSCALL_ARG(c)); } @@ -4386,7 +5115,7 @@ struct kernel_statfs { unsigned, o2) LSS_INLINE _syscall5(ssize_t, _pwrite64, int, f, const void *, b, size_t, c, unsigned, o1, - long, o2) + unsigned, o2) LSS_INLINE _syscall4(int, _readahead, int, f, unsigned, o1, unsigned, o2, size_t, c) #endif @@ -4407,9 +5136,9 @@ struct kernel_statfs { return LSS_NAME(_pwrite64)(fd, buf, count, LSS_LLARG_PAD o.arg[0], o.arg[1]); } - LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, int len) { + LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, size_t count) { union { loff_t off; unsigned arg[2]; } o = { off }; - return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], len); + return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], count); } #endif #endif @@ -4464,10 +5193,79 @@ struct kernel_statfs { } #endif +#if defined(__NR_statx) + /* copy the contents of kernel_statx to the kernel_stat structure. */ + LSS_INLINE void LSS_NAME(cp_stat_statx)(struct kernel_stat *to, + struct kernel_statx *from) { + memset(to, 0, sizeof(struct kernel_stat)); + to->st_dev = (kernel_dev_t)((from->stx_dev_minor & 0xff) | + ((from->stx_dev_major & 0xfff) << 8) | + ((from->stx_dev_minor & ~0xffu) << 12)); + to->st_rdev = (kernel_dev_t)((from->stx_rdev_minor & 0xff) | + ((from->stx_rdev_major & 0xfff) << 8) | + ((from->stx_rdev_minor & ~0xffu) << 12)); + to->st_ino = (kernel_ino_t)from->stx_ino; + to->st_mode = (kernel_mode_t)from->stx_mode; + to->st_nlink = (kernel_nlink_t)from->stx_nlink; + to->st_uid = (kernel_uid_t)from->stx_uid; + to->st_gid = (kernel_gid_t)from->stx_gid; + to->st_atime_ = (kernel_time_t)(from->stx_atime.tv_sec); + to->st_atime_nsec_ = from->stx_atime.tv_nsec; + to->st_mtime_ = (kernel_time_t)(from->stx_mtime.tv_sec); + to->st_mtime_nsec_ = from->stx_mtime.tv_nsec; + to->st_ctime_ = (kernel_time_t)(from->stx_ctime.tv_sec); + to->st_ctime_nsec_ = from->stx_ctime.tv_nsec; + to->st_size = (kernel_off_t)(from->stx_size); + to->st_blocks = (kernel_blkcnt_t)(from->stx_blocks); + to->st_blksize = (kernel_blksize_t)from->stx_blksize; + } +#endif + +#if !defined(__NR_fstat) + LSS_INLINE int LSS_NAME(fstat)(int fd, + struct kernel_stat *buf) { + #if defined(__NR_newfstatat) + return LSS_NAME(newfstatat)(fd, "", buf, AT_EMPTY_PATH); + #elif defined(__NR_statx) + struct kernel_statx stx; + int flags = AT_NO_AUTOMOUNT | AT_EMPTY_PATH; + int mask = STATX_BASIC_STATS; + int res = LSS_NAME(statx)(fd, "", flags, mask, &stx); + LSS_NAME(cp_stat_statx)(buf, &stx); + return res; + #endif + } +#endif + #if !defined(__NR_stat) LSS_INLINE int LSS_NAME(stat)(const char *pathname, struct kernel_stat *buf) { - return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0); + #if defined(__NR_newfstatat) + return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0); + #elif defined(__NR_statx) + struct kernel_statx stx; + int flags = AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT; + int mask = STATX_BASIC_STATS; + int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx); + LSS_NAME(cp_stat_statx)(buf, &stx); + return res; + #endif + } +#endif + +#if !defined(__NR_lstat) + LSS_INLINE int LSS_NAME(lstat)(const char *pathname, + struct kernel_stat *buf) { + #if defined(__NR_newfstatat) + return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, AT_SYMLINK_NOFOLLOW); + #elif defined(__NR_statx) + struct kernel_statx stx; + int flags = AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; + int mask = STATX_BASIC_STATS; + int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx); + LSS_NAME(cp_stat_statx)(buf, &stx); + return res; + #endif } #endif @@ -4481,7 +5279,7 @@ struct kernel_statfs { // TODO: define this in an arch-independant way instead of inlining the clone // syscall body. -# if defined(__aarch64__) +# if defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) LSS_INLINE pid_t LSS_NAME(fork)(void) { // No fork syscall on aarch64 - implement by means of the clone syscall. // Note that this does not reset glibc's cached view of the PID/TID, so diff --git a/src/tools/linux/core2md/core2md.cc b/src/tools/linux/core2md/core2md.cc index c3a9da39..3f34294f 100644 --- a/src/tools/linux/core2md/core2md.cc +++ b/src/tools/linux/core2md/core2md.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -33,13 +32,15 @@ #include "client/linux/minidump_writer/minidump_writer.h" #include "client/linux/minidump_writer/linux_core_dumper.h" +#include "common/path_helper.h" using google_breakpad::AppMemoryList; using google_breakpad::MappingList; using google_breakpad::LinuxCoreDumper; static int ShowUsage(const char* argv0) { - fprintf(stderr, "Usage: %s <core file> <procfs dir> <output>\n", argv0); + fprintf(stderr, "Usage: %s <core file> <procfs dir> <output>\n", + google_breakpad::BaseName(argv0).c_str()); return 1; } diff --git a/src/tools/linux/core_handler/core_handler.cc b/src/tools/linux/core_handler/core_handler.cc new file mode 100644 index 00000000..224073d3 --- /dev/null +++ b/src/tools/linux/core_handler/core_handler.cc @@ -0,0 +1,147 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// core_handler.cc: A tool to handle coredumps on Linux + +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <syslog.h> +#include <unistd.h> +#include <sstream> + +#include "client/linux/minidump_writer/linux_core_dumper.h" +#include "client/linux/minidump_writer/minidump_writer.h" +#include "common/path_helper.h" +#include "common/scoped_ptr.h" + +namespace { + +using google_breakpad::AppMemoryList; +using google_breakpad::LinuxCoreDumper; +using google_breakpad::MappingList; +using google_breakpad::scoped_array; + +// Size of the core dump to read in order to access all the threads +// descriptions. +// +// The first section is the note0 section which contains the thread states. On +// x86-64 a typical thread description take about 1432B. Reading 1 MB allows +// several hundreds of threads. +const int core_read_size = 1024 * 1024; + +void ShowUsage(const char* argv0) { + fprintf(stderr, "Usage: %s <process id> <minidump file>\n\n", + google_breakpad::BaseName(argv0).c_str()); + fprintf(stderr, + "A tool which serves as a core dump handler and produces " + "minidump files.\n"); + fprintf(stderr, "Please refer to the online documentation:\n"); + fprintf(stderr, + "https://chromium.googlesource.com/breakpad/breakpad/+/HEAD" + "/docs/linux_core_handler.md\n"); +} + +bool WriteMinidumpFromCore(const char* filename, + const char* core_path, + const char* procfs_override) { + MappingList mappings; + AppMemoryList memory_list; + LinuxCoreDumper dumper(0, core_path, procfs_override); + return google_breakpad::WriteMinidump(filename, mappings, memory_list, + &dumper); +} + +bool HandleCrash(pid_t pid, const char* procfs_dir, const char* md_filename) { + int r = 0; + scoped_array<char> buf(new char[core_read_size]); + while (r != core_read_size) { + int ret = read(STDIN_FILENO, &buf[r], core_read_size - r); + if (ret == 0) { + break; + } else if (ret == -1) { + return false; + } + r += ret; + } + + int fd = memfd_create("core_file", MFD_CLOEXEC); + if (fd == -1) { + return false; + } + + int w = write(fd, &buf[0], r); + if (w != r) { + close(fd); + return false; + } + + std::stringstream core_file_ss; + core_file_ss << "/proc/self/fd/" << fd; + std::string core_file(core_file_ss.str()); + + if (!WriteMinidumpFromCore(md_filename, core_file.c_str(), procfs_dir)) { + close(fd); + return false; + } + close(fd); + + return true; +} + +} // namespace + +int main(int argc, char* argv[]) { + int ret = EXIT_FAILURE; + + if (argc != 3) { + ShowUsage(argv[0]); + return ret; + } + + const char* pid_str = argv[1]; + const char* md_filename = argv[2]; + pid_t pid = atoi(pid_str); + + std::stringstream proc_dir_ss; + proc_dir_ss << "/proc/" << pid_str; + std::string proc_dir(proc_dir_ss.str()); + + openlog("core_handler", 0, 0); + if (HandleCrash(pid, proc_dir.c_str(), md_filename)) { + syslog(LOG_NOTICE, "Minidump generated at %s\n", md_filename); + ret = EXIT_SUCCESS; + } else { + syslog(LOG_ERR, "Cannot generate minidump %s\n", md_filename); + } + closelog(); + + return ret; +} diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc index ebdf2314..8998b3b3 100644 --- a/src/tools/linux/dump_syms/dump_syms.cc +++ b/src/tools/linux/dump_syms/dump_syms.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,32 +36,41 @@ #include <vector> #include "common/linux/dump_symbols.h" +#include "common/path_helper.h" using google_breakpad::WriteSymbolFile; using google_breakpad::WriteSymbolFileHeader; int usage(const char* self) { - fprintf(stderr, "Usage: %s [OPTION] <binary-with-debugging-info> " - "[directories-for-debug-file]\n\n", self); + fprintf(stderr, + "Usage: %s [OPTION] <binary-with-debugging-info> " + "[directories-for-debug-file]\n\n", + google_breakpad::BaseName(self).c_str()); fprintf(stderr, "Options:\n"); fprintf(stderr, " -i: Output module header information only.\n"); fprintf(stderr, " -c Do not generate CFI section\n"); + fprintf(stderr, " -d Generate INLINE/INLINE_ORIGIN records\n"); fprintf(stderr, " -r Do not handle inter-compilation " "unit references\n"); fprintf(stderr, " -v Print all warnings to stderr\n"); fprintf(stderr, " -n <name> Use specified name for name of the object\n"); fprintf(stderr, " -o <os> Use specified name for the " "operating system\n"); + fprintf(stderr, " -m Enable writing the optional 'm' field on FUNC" + "and PUBLIC, denoting multiple symbols for " + "the address.\n"); return 1; } -int main(int argc, char **argv) { +int main(int argc, char** argv) { if (argc < 2) return usage(argv[0]); bool header_only = false; bool cfi = true; + bool handle_inlines = false; bool handle_inter_cu_refs = true; bool log_to_stderr = false; + bool enable_multiple_field = false; std::string obj_name; const char* obj_os = "Linux"; int arg_index = 1; @@ -72,6 +80,8 @@ int main(int argc, char **argv) { header_only = true; } else if (strcmp("-c", argv[arg_index]) == 0) { cfi = false; + } else if (strcmp("-d", argv[arg_index]) == 0) { + handle_inlines = true; } else if (strcmp("-r", argv[arg_index]) == 0) { handle_inter_cu_refs = false; } else if (strcmp("-v", argv[arg_index]) == 0) { @@ -90,6 +100,8 @@ int main(int argc, char **argv) { } obj_os = argv[arg_index + 1]; ++arg_index; + } else if (strcmp("-m", argv[arg_index]) == 0) { + enable_multiple_field = true; } else { printf("2.4 %s\n", argv[arg_index]); return usage(argv[0]); @@ -124,8 +136,10 @@ int main(int argc, char **argv) { return 1; } } else { - SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI; - google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs); + SymbolData symbol_data = (handle_inlines ? INLINES : NO_DATA) | + (cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES; + google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs, + enable_multiple_field); if (!WriteSymbolFile(binary, obj_name, obj_os, debug_dirs, options, std::cout)) { fprintf(saved_stderr, "Failed to write symbol file.\n"); diff --git a/src/tools/linux/md2core/minidump-2-core.cc b/src/tools/linux/md2core/minidump-2-core.cc index a60be323..a4ddbe8e 100644 --- a/src/tools/linux/md2core/minidump-2-core.cc +++ b/src/tools/linux/md2core/minidump-2-core.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. +// Copyright 2009 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -77,6 +76,8 @@ #define ELF_ARCH EM_MIPS #elif defined(__aarch64__) #define ELF_ARCH EM_AARCH64 +#elif defined(__riscv) + #define ELF_ARCH EM_RISCV #endif #if defined(__arm__) @@ -84,7 +85,7 @@ // containing core registers, while they use 'user_regs_struct' on other // architectures. This file-local typedef simplifies the source code. typedef user_regs user_regs_struct; -#elif defined (__mips__) +#elif defined (__mips__) || defined(__riscv) // This file-local typedef simplifies the source code. typedef gregset_t user_regs_struct; #endif @@ -149,16 +150,14 @@ SetupOptions(int argc, const char* argv[], Options* options) { options->use_filename = false; options->inc_guid = false; - while ((ch = getopt(argc, (char * const *)argv, "fhio:S:v")) != -1) { + while ((ch = getopt(argc, (char * const*)argv, "fhio:S:v")) != -1) { switch (ch) { case 'h': Usage(argc, argv); exit(0); - break; case '?': Usage(argc, argv); exit(1); - break; case 'f': options->use_filename = true; @@ -224,7 +223,7 @@ writea(int fd, const void* idata, size_t length) { */ static inline int sex() { int probe = 1; - return !*(char *)&probe; + return !*(char*)&probe; } typedef struct elf_timeval { /* Time value with microsecond resolution */ @@ -261,7 +260,7 @@ typedef struct prpsinfo { /* Information about process */ unsigned char pr_zomb; /* Zombie */ signed char pr_nice; /* Nice val */ unsigned long pr_flag; /* Flags */ -#if defined(__x86_64__) || defined(__mips__) +#if defined(__x86_64__) || defined(__mips__) || defined(__riscv) uint32_t pr_uid; /* User ID */ uint32_t pr_gid; /* Group ID */ #else @@ -308,7 +307,7 @@ struct CrashedProcess { struct Thread { pid_t tid; -#if defined(__mips__) +#if defined(__mips__) || defined(__riscv) mcontext_t mcontext; #else user_regs_struct regs; @@ -535,6 +534,71 @@ ParseThreadRegisters(CrashedProcess::Thread* thread, thread->mcontext.fpc_eir = rawregs->float_save.fir; #endif } +#elif defined(__riscv) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { +# if __riscv_xlen == 32 + const MDRawContextRISCV* rawregs = range.GetData<MDRawContextRISCV>(0); +# elif __riscv_xlen == 64 + const MDRawContextRISCV64* rawregs = range.GetData<MDRawContextRISCV64>(0); +# else +# error "Unexpected __riscv_xlen" +# endif + + thread->mcontext.__gregs[0] = rawregs->pc; + thread->mcontext.__gregs[1] = rawregs->ra; + thread->mcontext.__gregs[2] = rawregs->sp; + thread->mcontext.__gregs[3] = rawregs->gp; + thread->mcontext.__gregs[4] = rawregs->tp; + thread->mcontext.__gregs[5] = rawregs->t0; + thread->mcontext.__gregs[6] = rawregs->t1; + thread->mcontext.__gregs[7] = rawregs->t2; + thread->mcontext.__gregs[8] = rawregs->s0; + thread->mcontext.__gregs[9] = rawregs->s1; + thread->mcontext.__gregs[10] = rawregs->a0; + thread->mcontext.__gregs[11] = rawregs->a1; + thread->mcontext.__gregs[12] = rawregs->a2; + thread->mcontext.__gregs[13] = rawregs->a3; + thread->mcontext.__gregs[14] = rawregs->a4; + thread->mcontext.__gregs[15] = rawregs->a5; + thread->mcontext.__gregs[16] = rawregs->a6; + thread->mcontext.__gregs[17] = rawregs->a7; + thread->mcontext.__gregs[18] = rawregs->s2; + thread->mcontext.__gregs[19] = rawregs->s3; + thread->mcontext.__gregs[20] = rawregs->s4; + thread->mcontext.__gregs[21] = rawregs->s5; + thread->mcontext.__gregs[22] = rawregs->s6; + thread->mcontext.__gregs[23] = rawregs->s7; + thread->mcontext.__gregs[24] = rawregs->s8; + thread->mcontext.__gregs[25] = rawregs->s9; + thread->mcontext.__gregs[26] = rawregs->s10; + thread->mcontext.__gregs[27] = rawregs->s11; + thread->mcontext.__gregs[28] = rawregs->t3; + thread->mcontext.__gregs[29] = rawregs->t4; + thread->mcontext.__gregs[30] = rawregs->t5; + thread->mcontext.__gregs[31] = rawregs->t6; + +# if __riscv_flen == 32 + for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__f.__f[i] = rawregs->float_save.regs[i]; + } + thread->mcontext.__fpregs.__f.__fcsr = rawregs->float_save.fpcsr; +# elif __riscv_flen == 64 + for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__d.__f[i] = rawregs->float_save.regs[i]; + } + thread->mcontext.__fpregs.__d.__fcsr = rawregs->float_save.fpcsr; +# elif __riscv_flen == 128 + for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) { + thread->mcontext.__fpregs.__q.__f[2*i] = rawregs->float_save.regs[i].high; + thread->mcontext.__fpregs.__q.__f[2*i+1] = rawregs->float_save.regs[i].low; + } + thread->mcontext.__fpregs.__q.__fcsr = rawregs->float_save.fpcsr; +# else +# error "Unexpected __riscv_flen" +# endif +} #else #error "This code has not been ported to your platform yet" #endif @@ -602,7 +666,8 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, exit(1); } #elif defined(__aarch64__) - if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD) { + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD && + sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64) { fprintf(stderr, "This version of minidump-2-core only supports ARM (64bit).\n"); exit(1); @@ -623,11 +688,26 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, # else # error "This mips ABI is currently not supported (n32)" # endif +#elif defined(__riscv) +# if __riscv_xlen == 32 + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_RISCV) { + fprintf(stderr, + "This version of minidump-2-core only supports RISCV.\n"); + exit(1); + } +# elif __riscv_xlen == 64 + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_RISCV64) { + fprintf(stderr, + "This version of minidump-2-core only supports RISCV64.\n"); + exit(1); + } +# else +# error "Unexpected __riscv_xlen" +# endif #else #error "This code has not been ported to your platform yet" #endif - if (!strstr(full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str(), - "Linux") && + if (sysinfo->platform_id != MD_OS_LINUX && sysinfo->platform_id != MD_OS_NACL) { fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n"); exit(1); @@ -651,6 +731,10 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, ? "MIPS" : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS64 ? "MIPS64" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_RISCV + ? "RISCV" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_RISCV64 + ? "RISCV64" : "???", sysinfo->number_of_processors, sysinfo->processor_level, @@ -660,10 +744,10 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64) { fputs("Vendor id: ", stderr); const char *nul = - (const char *)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0, + (const char*)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0, sizeof(sysinfo->cpu.x86_cpu_info.vendor_id)); fwrite(sysinfo->cpu.x86_cpu_info.vendor_id, - nul ? nul - (const char *)&sysinfo->cpu.x86_cpu_info.vendor_id[0] + nul ? nul - (const char*)&sysinfo->cpu.x86_cpu_info.vendor_id[0] : sizeof(sysinfo->cpu.x86_cpu_info.vendor_id), 1, stderr); fputs("\n", stderr); } @@ -759,7 +843,7 @@ ParseEnvironment(const Options& options, CrashedProcess* crashinfo, memcpy(env, range.data(), range.length()); int nul_count = 0; for (char *ptr = env;;) { - ptr = (char *)memchr(ptr, '\000', range.length() - (ptr - env)); + ptr = (char*)memchr(ptr, '\000', range.length() - (ptr - env)); if (!ptr) { break; } @@ -928,6 +1012,8 @@ WriteThread(const Options& options, const CrashedProcess::Thread& thread, pr.pr_pid = thread.tid; #if defined(__mips__) memcpy(&pr.pr_reg, &thread.mcontext.gregs, sizeof(user_regs_struct)); +#elif defined(__riscv) + memcpy(&pr.pr_reg, &thread.mcontext.__gregs, sizeof(user_regs_struct)); #else memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct)); #endif @@ -1076,7 +1162,7 @@ AugmentMappings(const Options& options, CrashedProcess* crashinfo, for (unsigned i = 0; i < crashinfo->threads.size(); ++i) { const CrashedProcess::Thread& thread = crashinfo->threads[i]; AddDataToMapping(crashinfo, - string((char *)thread.stack, thread.stack_length), + string((char*)thread.stack, thread.stack_length), thread.stack_addr); } diff --git a/src/tools/linux/md2core/minidump_memory_range.h b/src/tools/linux/md2core/minidump_memory_range.h index a793e2cf..6cf07470 100644 --- a/src/tools/linux/md2core/minidump_memory_range.h +++ b/src/tools/linux/md2core/minidump_memory_range.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/tools/linux/md2core/minidump_memory_range_unittest.cc b/src/tools/linux/md2core/minidump_memory_range_unittest.cc index fe4ded83..9012101d 100644 --- a/src/tools/linux/md2core/minidump_memory_range_unittest.cc +++ b/src/tools/linux/md2core/minidump_memory_range_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // diff --git a/src/tools/linux/pid2md/pid2md.cc b/src/tools/linux/pid2md/pid2md.cc new file mode 100644 index 00000000..ca1cb637 --- /dev/null +++ b/src/tools/linux/pid2md/pid2md.cc @@ -0,0 +1,58 @@ +// Copyright 2020 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// pid2md.cc: An utility to generate a minidump from a running process + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "client/linux/minidump_writer/minidump_writer.h" +#include "common/path_helper.h" + +int main(int argc, char* argv[]) { + if (argc != 3) { + fprintf(stderr, "Usage: %s <process id> <minidump file>\n\n", + google_breakpad::BaseName(argv[0]).c_str()); + fprintf(stderr, + "A tool to generate a minidump from a running process. The process " + "resumes its\nactivity once the operation is completed. Permission " + "to trace the process is\nrequired.\n"); + return EXIT_FAILURE; + } + + pid_t process_id = atoi(argv[1]); + const char* minidump_file = argv[2]; + + if (!google_breakpad::WriteMinidump(minidump_file, process_id, process_id)) { + fprintf(stderr, "Unable to generate minidump.\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/tools/linux/symupload/minidump_upload.cc b/src/tools/linux/symupload/minidump_upload.cc index 19f17450..6adead03 100644 --- a/src/tools/linux/symupload/minidump_upload.cc +++ b/src/tools/linux/symupload/minidump_upload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -41,6 +40,7 @@ #include <string> #include "common/linux/http_upload.h" +#include "common/path_helper.h" #include "common/using_std_string.h" using google_breakpad::HTTPUpload; @@ -91,8 +91,10 @@ static void Start(Options *options) { static void Usage(int argc, const char *argv[]) { fprintf(stderr, "Submit minidump information.\n"); - fprintf(stderr, "Usage: %s [options...] -p <product> -v <version> <minidump> " - "<upload-URL>\n", argv[0]); + fprintf(stderr, + "Usage: %s [options...] -p <product> -v <version> <minidump> " + "<upload-URL>\n", + google_breakpad::BaseName(argv[0]).c_str()); fprintf(stderr, "Options:\n"); fprintf(stderr, "<minidump> should be a minidump.\n"); fprintf(stderr, "<upload-URL> is the destination for the upload\n"); @@ -111,7 +113,7 @@ SetupOptions(int argc, const char *argv[], Options *options) { extern int optind; int ch; - while ((ch = getopt(argc, (char * const *)argv, "p:u:v:x:h?")) != -1) { + while ((ch = getopt(argc, (char * const*)argv, "p:u:v:x:h?")) != -1) { switch (ch) { case 'p': options->product = optarg; diff --git a/src/tools/linux/symupload/sym_upload.cc b/src/tools/linux/symupload/sym_upload.cc index f155eb95..8f5e8a50 100644 --- a/src/tools/linux/symupload/sym_upload.cc +++ b/src/tools/linux/symupload/sym_upload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -47,6 +46,7 @@ #include <locale> #include "common/linux/symbol_upload.h" +#include "common/path_helper.h" using google_breakpad::sym_upload::UploadProtocol; using google_breakpad::sym_upload::Options; @@ -66,10 +66,11 @@ static void Usage(int argc, const char *argv[]) { fprintf(stderr, "Submit symbol information.\n"); fprintf(stderr, "Usage: %s [options...] <symbol-file> <upload-URL>\n", - argv[0]); + google_breakpad::BaseName(argv[0]).c_str()); fprintf(stderr, "Options:\n"); - fprintf(stderr, "<symbol-file> should be created by using the dump_syms" - "tool.\n"); + fprintf(stderr, + "<symbol-file> should be created by using the dump_syms " + "tool.\n"); fprintf(stderr, "<upload-URL> is the destination for the upload\n"); fprintf(stderr, "-p:\t <protocol> One of ['sym-upload-v1'," " 'sym-upload-v2'], defaults to 'sym-upload-v1'.\n"); @@ -111,17 +112,20 @@ Usage(int argc, const char *argv[]) { //============================================================================= static void SetupOptions(int argc, const char *argv[], Options *options) { - extern int optind; + extern int optind, optopt; int ch; constexpr char flag_pattern[] = "u:v:x:p:k:t:c:i:hf?"; - while ((ch = getopt(argc, (char * const *)argv, flag_pattern)) != -1) { + while ((ch = getopt(argc, (char * const*)argv, flag_pattern)) != -1) { switch (ch) { case 'h': case '?': Usage(argc, argv); - exit(0); - break; + // ch might be '?' because getopt found an error while parsing args (as + // opposed to finding "-?" as an arg), in which case optopt is set to + // the bad arg value, so return an error code if optopt is set, + // otherwise exit cleanly. + exit(optopt == 0 ? 0 : 1); case 'u': options->proxy_user_pwd = optarg; break; @@ -166,7 +170,6 @@ SetupOptions(int argc, const char *argv[], Options *options) { fprintf(stderr, "Invalid option '%c'\n", ch); Usage(argc, argv); exit(1); - break; } } diff --git a/src/tools/linux/tools_linux.gypi b/src/tools/linux/tools_linux.gypi deleted file mode 100644 index 020e4c1c..00000000 --- a/src/tools/linux/tools_linux.gypi +++ /dev/null @@ -1,83 +0,0 @@ -# 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.cc', - ], - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - { - 'target_name': 'symupload', - 'type': 'executable', - 'sources': [ - 'symupload/sym_upload.cc', - ], - 'link_settings': { - 'libraries': [ - '-ldl', - ], - }, - 'dependencies': [ - '../common/common.gyp:common', - ], - }, - ], -} diff --git a/src/tools/mac/crash_report/crash_report.mm b/src/tools/mac/crash_report/crash_report.mm deleted file mode 100644 index f68200c7..00000000 --- a/src/tools/mac/crash_report/crash_report.mm +++ /dev/null @@ -1,408 +0,0 @@ -// 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. - -// crash_report.mm: Convert the contents of a minidump into a format that -// looks more like Apple's CrashReporter format - -#include <unistd.h> - -#include <mach/machine.h> -#include <mach-o/arch.h> - -#include <string> - -#include <Foundation/Foundation.h> - -#include "common/scoped_ptr.h" -#include "google_breakpad/processor/basic_source_line_resolver.h" -#include "google_breakpad/processor/call_stack.h" -#include "google_breakpad/processor/code_module.h" -#include "google_breakpad/processor/minidump.h" -#include "google_breakpad/processor/minidump_processor.h" -#include "google_breakpad/processor/process_state.h" -#include "google_breakpad/processor/stack_frame_cpu.h" -#include "google_breakpad/processor/system_info.h" -#include "processor/pathname_stripper.h" -#include "processor/simple_symbol_supplier.h" - -#include "on_demand_symbol_supplier.h" - -using std::string; - -using google_breakpad::BasicSourceLineResolver; -using google_breakpad::CallStack; -using google_breakpad::CodeModule; -using google_breakpad::CodeModules; -using google_breakpad::Minidump; -using google_breakpad::MinidumpProcessor; -using google_breakpad::OnDemandSymbolSupplier; -using google_breakpad::PathnameStripper; -using google_breakpad::ProcessState; -using google_breakpad::scoped_ptr; -using google_breakpad::StackFrame; -using google_breakpad::StackFramePPC; -using google_breakpad::StackFrameX86; -using google_breakpad::SystemInfo; - -typedef struct { - NSString *minidumpPath; - NSString *searchDir; - NSString *symbolSearchDir; - BOOL printThreadMemory; -} Options; - -//============================================================================= -static int PrintRegister(const char *name, u_int32_t value, int sequence) { - if (sequence % 4 == 0) { - printf("\n"); - } - printf("%6s = 0x%08x ", name, value); - return ++sequence; -} - -//============================================================================= -static void PrintStack(const CallStack *stack, const string &cpu) { - size_t frame_count = stack->frames()->size(); - char buffer[1024]; - for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) { - const StackFrame *frame = stack->frames()->at(frame_index); - const CodeModule *module = frame->module; - printf("%2zu ", frame_index); - - if (module) { - // Module name (20 chars max) - strcpy(buffer, PathnameStripper::File(module->code_file()).c_str()); - int maxStr = 20; - buffer[maxStr] = 0; - printf("%-*s", maxStr, buffer); - - strcpy(buffer, module->version().c_str()); - buffer[maxStr] = 0; - - printf("%-*s",maxStr, buffer); - - u_int64_t instruction = frame->instruction; - - // PPC only: Adjust the instruction to match that of Crash reporter. The - // instruction listed is actually the return address. See the detailed - // comments in stackwalker_ppc.cc for more information. - if (cpu == "ppc" && frame_index) - instruction += 4; - - printf(" 0x%08llx ", instruction); - - // Function name - if (!frame->function_name.empty()) { - printf("%s", frame->function_name.c_str()); - if (!frame->source_file_name.empty()) { - string source_file = PathnameStripper::File(frame->source_file_name); - printf(" + 0x%llx (%s:%d)", - instruction - frame->source_line_base, - source_file.c_str(), frame->source_line); - } else { - printf(" + 0x%llx", instruction - frame->function_base); - } - } - } - printf("\n"); - } -} - -//============================================================================= -static void PrintRegisters(const CallStack *stack, const string &cpu) { - int sequence = 0; - const StackFrame *frame = stack->frames()->at(0); - if (cpu == "x86") { - const StackFrameX86 *frame_x86 = - reinterpret_cast<const StackFrameX86*>(frame); - - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP) - sequence = PrintRegister("eip", frame_x86->context.eip, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) - sequence = PrintRegister("esp", frame_x86->context.esp, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP) - sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX) - sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI) - sequence = PrintRegister("esi", frame_x86->context.esi, sequence); - if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI) - sequence = PrintRegister("edi", frame_x86->context.edi, sequence); - if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) { - sequence = PrintRegister("eax", frame_x86->context.eax, sequence); - sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence); - sequence = PrintRegister("edx", frame_x86->context.edx, sequence); - sequence = PrintRegister("efl", frame_x86->context.eflags, sequence); - } - } else if (cpu == "ppc") { - const StackFramePPC *frame_ppc = - reinterpret_cast<const StackFramePPC*>(frame); - - if ((frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_ALL) == - StackFramePPC::CONTEXT_VALID_ALL) { - sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); - sequence = PrintRegister("srr1", frame_ppc->context.srr1, sequence); - sequence = PrintRegister("cr", frame_ppc->context.cr, sequence); - sequence = PrintRegister("xer", frame_ppc->context.xer, sequence); - sequence = PrintRegister("lr", frame_ppc->context.lr, sequence); - sequence = PrintRegister("ctr", frame_ppc->context.ctr, sequence); - sequence = PrintRegister("mq", frame_ppc->context.mq, sequence); - sequence = PrintRegister("vrsave", frame_ppc->context.vrsave, sequence); - - sequence = 0; - char buffer[5]; - for (int i = 0; i < MD_CONTEXT_PPC_GPR_COUNT; ++i) { - sprintf(buffer, "r%d", i); - sequence = PrintRegister(buffer, frame_ppc->context.gpr[i], sequence); - } - } else { - if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0) - sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); - if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1) - sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence); - } - } - - printf("\n"); -} - -static void PrintModules(const CodeModules *modules) { - if (!modules) - return; - - printf("\n"); - printf("Loaded modules:\n"); - - u_int64_t main_address = 0; - const CodeModule *main_module = modules->GetMainModule(); - if (main_module) { - main_address = main_module->base_address(); - } - - unsigned int module_count = modules->module_count(); - for (unsigned int module_sequence = 0; - module_sequence < module_count; - ++module_sequence) { - const CodeModule *module = modules->GetModuleAtSequence(module_sequence); - assert(module); - u_int64_t base_address = module->base_address(); - printf("0x%08llx - 0x%08llx %s %s%s %s\n", - base_address, base_address + module->size() - 1, - PathnameStripper::File(module->code_file()).c_str(), - module->version().empty() ? "???" : module->version().c_str(), - main_module != NULL && base_address == main_address ? - " (main)" : "", - module->code_file().c_str()); - } -} - -static void ProcessSingleReport(Options *options, NSString *file_path) { - string minidump_file([file_path fileSystemRepresentation]); - BasicSourceLineResolver resolver; - string search_dir = options->searchDir ? - [options->searchDir fileSystemRepresentation] : ""; - string symbol_search_dir = options->symbolSearchDir ? - [options->symbolSearchDir fileSystemRepresentation] : ""; - scoped_ptr<OnDemandSymbolSupplier> symbol_supplier( - new OnDemandSymbolSupplier(search_dir, symbol_search_dir)); - scoped_ptr<MinidumpProcessor> - minidump_processor(new MinidumpProcessor(symbol_supplier.get(), &resolver)); - ProcessState process_state; - scoped_ptr<Minidump> dump(new google_breakpad::Minidump(minidump_file)); - - if (!dump->Read()) { - fprintf(stderr, "Minidump %s could not be read\n", dump->path().c_str()); - return; - } - if (minidump_processor->Process(dump.get(), &process_state) != - google_breakpad::PROCESS_OK) { - fprintf(stderr, "MinidumpProcessor::Process failed\n"); - return; - } - - const SystemInfo *system_info = process_state.system_info(); - string cpu = system_info->cpu; - - // Convert the time to a string - u_int32_t time_date_stamp = process_state.time_date_stamp(); - struct tm timestruct; - gmtime_r(reinterpret_cast<time_t*>(&time_date_stamp), ×truct); - char timestr[20]; - strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct); - printf("Date: %s GMT\n", timestr); - - printf("Operating system: %s (%s)\n", system_info->os.c_str(), - system_info->os_version.c_str()); - printf("Architecture: %s\n", cpu.c_str()); - - if (process_state.crashed()) { - printf("Crash reason: %s\n", process_state.crash_reason().c_str()); - printf("Crash address: 0x%llx\n", process_state.crash_address()); - } else { - printf("No crash\n"); - } - - int requesting_thread = process_state.requesting_thread(); - if (requesting_thread != -1) { - printf("\n"); - printf("Thread %d (%s)\n", - requesting_thread, - process_state.crashed() ? "crashed" : - "requested dump, did not crash"); - PrintStack(process_state.threads()->at(requesting_thread), cpu); - } - - // Print all of the threads in the dump. - int thread_count = static_cast<int>(process_state.threads()->size()); - const std::vector<google_breakpad::MemoryRegion*> - *thread_memory_regions = process_state.thread_memory_regions(); - - for (int thread_index = 0; thread_index < thread_count; ++thread_index) { - if (thread_index != requesting_thread) { - // Don't print the crash thread again, it was already printed. - printf("\n"); - printf("Thread %d\n", thread_index); - PrintStack(process_state.threads()->at(thread_index), cpu); - google_breakpad::MemoryRegion *thread_stack_bytes = - thread_memory_regions->at(thread_index); - if (options->printThreadMemory) { - thread_stack_bytes->Print(); - } - } - } - - // Print the crashed registers - if (requesting_thread != -1) { - printf("\nThread %d:", requesting_thread); - PrintRegisters(process_state.threads()->at(requesting_thread), cpu); - } - - // Print information about modules - PrintModules(process_state.modules()); -} - -//============================================================================= -static void Start(Options *options) { - NSFileManager *manager = [NSFileManager defaultManager]; - NSString *minidump_path = options->minidumpPath; - BOOL is_dir = NO; - BOOL file_exists = [manager fileExistsAtPath:minidump_path - isDirectory:&is_dir]; - if (file_exists && is_dir) { - NSDirectoryEnumerator *enumerator = - [manager enumeratorAtPath:minidump_path]; - NSString *current_file = nil; - while ((current_file = [enumerator nextObject])) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - if ([[current_file pathExtension] isEqualTo:@"dmp"]) { - printf("Attempting to process report: %s\n", - [current_file cStringUsingEncoding:NSASCIIStringEncoding]); - NSString *full_path = - [minidump_path stringByAppendingPathComponent:current_file]; - ProcessSingleReport(options, full_path); - } - [pool release]; - } - } else if (file_exists) { - ProcessSingleReport(options, minidump_path); - } -} - -//============================================================================= -static void Usage(int argc, const char *argv[]) { - fprintf(stderr, "Convert a minidump to a crash report. Breakpad symbol " - "files will be used (or created if missing) in /tmp.\n" - "If a symbol-file-search-dir is specified, any symbol " - "files in it will be used instead of being loaded from " - "modules on disk.\n" - "If modules cannot be found at the paths stored in the " - "minidump file, they will be searched for at " - "<module-search-dir>/<path-in-minidump-file>.\n"); - fprintf(stderr, "Usage: %s [-s module-search-dir] [-S symbol-file-search-dir] " - "minidump-file\n", argv[0]); - fprintf(stderr, "\t-s: Specify a search directory to use for missing modules\n" - "\t-S: Specify a search directory to use for symbol files\n" - "\t-t: Print thread stack memory in hex\n" - "\t-h: Usage\n" - "\t-?: Usage\n"); -} - -//============================================================================= -static void SetupOptions(int argc, const char *argv[], Options *options) { - extern int optind; - char ch; - - while ((ch = getopt(argc, (char * const *)argv, "S:s:ht?")) != -1) { - switch (ch) { - case 's': - options->searchDir = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:optarg - length:strlen(optarg)]; - break; - - case 'S': - options->symbolSearchDir = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:optarg - length:strlen(optarg)]; - break; - - case 't': - options->printThreadMemory = YES; - break; - case 'h': - case '?': - Usage(argc, argv); - exit(1); - break; - } - } - - if ((argc - optind) != 1) { - fprintf(stderr, "%s: Missing minidump file\n", argv[0]); - Usage(argc, argv); - exit(1); - } - - options->minidumpPath = [[NSFileManager defaultManager] - stringWithFileSystemRepresentation:argv[optind] - length:strlen(argv[optind])]; -} - -//============================================================================= -int main (int argc, const char * argv[]) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - Options options; - - bzero(&options, sizeof(Options)); - SetupOptions(argc, argv, &options); - Start(&options); - [pool release]; - - return 0; -} diff --git a/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj b/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj deleted file mode 100644 index 33204f7e..00000000 --- a/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj +++ /dev/null @@ -1,618 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 45; - objects = { - -/* Begin PBXBuildFile section */ - 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */; }; - 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */; }; - 4247E6402110D5A500482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4247E63F2110D5A500482558 /* path_helper.cc */; }; - 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */; }; - 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721E126F9ADE00B43EAF /* exploitability.cc */; }; - 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */; }; - 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */; }; - 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */; }; - 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722C126F9B6E00B43EAF /* x86_misc.c */; }; - 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */; }; - 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; - 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7234126F9BC200B43EAF /* ia32_settings.c */; }; - 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */; }; - 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; - 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; - 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; - 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725A126F9C8000B43EAF /* ia32_operand.c */; }; - 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725C126F9C9200B43EAF /* x86_insn.c */; }; - 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */; }; - 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7263126F9CBB00B43EAF /* x86_imm.c */; }; - 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CA5613DFBA84006CABE3 /* md5.cc */; }; - 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */; }; - 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */; }; - 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */; }; - 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */; }; - 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */; }; - 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */; }; - 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */; }; - 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8411F0C6FB00FCF3E4 /* language.cc */; }; - 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8611F0C6FB00FCF3E4 /* module.cc */; }; - 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */; }; - 8B40BDC00C0638E4009535AF /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B40BDBF0C0638E4009535AF /* logging.cc */; }; - 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* crash_report.mm */; settings = {ATTRIBUTES = (); }; }; - 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; - 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */; }; - 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */; }; - 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172A0B1B8B2400F8391B /* call_stack.cc */; }; - 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */; }; - 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF173F0B1B8B9A00F8391B /* minidump.cc */; }; - 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */; }; - 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */; }; - 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17530B1B8BF900F8391B /* stackwalker.cc */; }; - 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF175B0B1B8C1B00F8391B /* process_state.cc */; }; - 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */; }; - 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */; }; - 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */; }; - 9BE650B20B52FE3000611104 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AC0B52FE3000611104 /* file_id.cc */; }; - 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AE0B52FE3000611104 /* macho_id.cc */; }; - 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650B00B52FE3000611104 /* macho_walker.cc */; }; - D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */; }; - D2A5DD631188658B00081F03 /* tokenize.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD621188658B00081F03 /* tokenize.cc */; }; - F407DC48185773C10064622B /* exploitability_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC40185773C10064622B /* exploitability_linux.cc */; }; - F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC41185773C10064622B /* stack_frame_symbolizer.cc */; }; - F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC42185773C10064622B /* stackwalker_arm64.cc */; }; - F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC44185773C10064622B /* stackwalker_mips.cc */; }; - F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC46185773C10064622B /* stackwalker_ppc64.cc */; }; - F44DDD8719C85CD50047280E /* dump_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8419C85CD50047280E /* dump_context.cc */; }; - F44DDD8819C85CD50047280E /* dump_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8519C85CD50047280E /* dump_object.cc */; }; - F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8619C85CD50047280E /* microdump_processor.cc */; }; - F47180561D745DEF0032F208 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180541D745DEF0032F208 /* elf_reader.cc */; }; - F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180571D7467630032F208 /* proc_maps_linux.cc */; }; - F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180591D7468A40032F208 /* symbolic_constants_win.cc */; }; - F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4D43B2E1A38490700C290B2 /* microdump.cc */; }; - F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE20E8ABCA600E953AD /* bytereader.cc */; }; - F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */; }; - F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */; }; - F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */; }; - FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */; }; - FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 08FB7796FE84155DC02AAC07 /* crash_report.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = crash_report.mm; sourceTree = "<group>"; }; - 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; }; - 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; }; - 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_old_arm64_context.cc; path = ../../../processor/convert_old_arm64_context.cc; sourceTree = "<group>"; }; - 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert_old_arm64_context.h; path = ../../../processor/convert_old_arm64_context.h; sourceTree = "<group>"; }; - 4247E63E2110D5A500482558 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; }; - 4247E63F2110D5A500482558 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; }; - 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = source_line_resolver_base.cc; path = ../../../processor/source_line_resolver_base.cc; sourceTree = SOURCE_ROOT; }; - 4D2C721E126F9ADE00B43EAF /* exploitability.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability.cc; path = ../../../processor/exploitability.cc; sourceTree = SOURCE_ROOT; }; - 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_win.cc; path = ../../../processor/exploitability_win.cc; sourceTree = SOURCE_ROOT; }; - 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = disassembler_x86.cc; path = ../../../processor/disassembler_x86.cc; sourceTree = SOURCE_ROOT; }; - 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_disasm.c; path = ../../../third_party/libdisasm/x86_disasm.c; sourceTree = SOURCE_ROOT; }; - 4D2C722C126F9B6E00B43EAF /* x86_misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_misc.c; path = ../../../third_party/libdisasm/x86_misc.c; sourceTree = SOURCE_ROOT; }; - 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_operand_list.c; path = ../../../third_party/libdisasm/x86_operand_list.c; sourceTree = SOURCE_ROOT; }; - 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_invariant.c; path = ../../../third_party/libdisasm/ia32_invariant.c; sourceTree = SOURCE_ROOT; }; - 4D2C7234126F9BC200B43EAF /* ia32_settings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_settings.c; path = ../../../third_party/libdisasm/ia32_settings.c; sourceTree = SOURCE_ROOT; }; - 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_insn.c; path = ../../../third_party/libdisasm/ia32_insn.c; sourceTree = SOURCE_ROOT; }; - 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_opcode_tables.c; path = ../../../third_party/libdisasm/ia32_opcode_tables.c; sourceTree = SOURCE_ROOT; }; - 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_implicit.c; path = ../../../third_party/libdisasm/ia32_implicit.c; sourceTree = SOURCE_ROOT; }; - 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_reg.c; path = ../../../third_party/libdisasm/ia32_reg.c; sourceTree = SOURCE_ROOT; }; - 4D2C725A126F9C8000B43EAF /* ia32_operand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_operand.c; path = ../../../third_party/libdisasm/ia32_operand.c; sourceTree = SOURCE_ROOT; }; - 4D2C725C126F9C9200B43EAF /* x86_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_insn.c; path = ../../../third_party/libdisasm/x86_insn.c; sourceTree = SOURCE_ROOT; }; - 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_modrm.c; path = ../../../third_party/libdisasm/ia32_modrm.c; sourceTree = SOURCE_ROOT; }; - 4D2C7263126F9CBB00B43EAF /* x86_imm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_imm.c; path = ../../../third_party/libdisasm/x86_imm.c; sourceTree = SOURCE_ROOT; }; - 4D72CA5613DFBA84006CABE3 /* md5.cc */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; }; - 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; }; - 5578003F0BE1F28500EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; }; - 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; - 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; - 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; - 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = SOURCE_ROOT; }; - 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = SOURCE_ROOT; }; - 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = SOURCE_ROOT; }; - 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = SOURCE_ROOT; }; - 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = SOURCE_ROOT; }; - 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = SOURCE_ROOT; }; - 8B31FF8411F0C6FB00FCF3E4 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF8511F0C6FB00FCF3E4 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = SOURCE_ROOT; }; - 8B31FF8611F0C6FB00FCF3E4 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = SOURCE_ROOT; }; - 8B31FF8711F0C6FB00FCF3E4 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = SOURCE_ROOT; }; - 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = SOURCE_ROOT; }; - 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = SOURCE_ROOT; }; - 8B40BDBF0C0638E4009535AF /* logging.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cc; path = ../../../processor/logging.cc; sourceTree = SOURCE_ROOT; }; - 8DD76FA10486AA7600D96B5E /* crash_report */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = crash_report; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B35FEE20B2675F9008DE8C7 /* code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_module.h; path = ../../../google_breakpad/processor/code_module.h; sourceTree = SOURCE_ROOT; }; - 9B35FEE30B2675F9008DE8C7 /* code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_modules.h; path = ../../../google_breakpad/processor/code_modules.h; sourceTree = SOURCE_ROOT; }; - 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_module.h; path = ../../../processor/basic_code_module.h; sourceTree = SOURCE_ROOT; }; - 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_code_modules.cc; path = ../../../processor/basic_code_modules.cc; sourceTree = SOURCE_ROOT; }; - 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_modules.h; path = ../../../processor/basic_code_modules.h; sourceTree = SOURCE_ROOT; }; - 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = basic_source_line_resolver.h; sourceTree = "<group>"; }; - 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source_line_resolver_interface.h; sourceTree = "<group>"; }; - 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_source_line_resolver.cc; path = ../../../processor/basic_source_line_resolver.cc; sourceTree = SOURCE_ROOT; }; - 9B44619D0B66C66B00BBB817 /* system_info.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = system_info.h; sourceTree = "<group>"; }; - 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = breakpad_types.h; sourceTree = "<group>"; }; - 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_format.h; sourceTree = "<group>"; }; - 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = call_stack.h; sourceTree = "<group>"; }; - 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memory_region.h; sourceTree = "<group>"; }; - 9BDF16FE0B1B8ACD00F8391B /* minidump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump.h; sourceTree = "<group>"; }; - 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_processor.h; sourceTree = "<group>"; }; - 9BDF17000B1B8ACD00F8391B /* process_state.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = process_state.h; sourceTree = "<group>"; }; - 9BDF17010B1B8ACD00F8391B /* stack_frame.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame.h; sourceTree = "<group>"; }; - 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame_cpu.h; sourceTree = "<group>"; }; - 9BDF17030B1B8ACD00F8391B /* stackwalker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stackwalker.h; sourceTree = "<group>"; }; - 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = symbol_supplier.h; sourceTree = "<group>"; }; - 9BDF172A0B1B8B2400F8391B /* call_stack.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = call_stack.cc; path = ../../../processor/call_stack.cc; sourceTree = SOURCE_ROOT; }; - 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_processor.cc; path = ../../../processor/minidump_processor.cc; sourceTree = SOURCE_ROOT; }; - 9BDF173F0B1B8B9A00F8391B /* minidump.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump.cc; path = ../../../processor/minidump.cc; sourceTree = SOURCE_ROOT; }; - 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc.cc; path = ../../../processor/stackwalker_ppc.cc; sourceTree = SOURCE_ROOT; }; - 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_x86.cc; path = ../../../processor/stackwalker_x86.cc; sourceTree = SOURCE_ROOT; }; - 9BDF17530B1B8BF900F8391B /* stackwalker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker.cc; path = ../../../processor/stackwalker.cc; sourceTree = SOURCE_ROOT; }; - 9BDF175B0B1B8C1B00F8391B /* process_state.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = process_state.cc; path = ../../../processor/process_state.cc; sourceTree = SOURCE_ROOT; }; - 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = on_demand_symbol_supplier.h; sourceTree = "<group>"; }; - 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = on_demand_symbol_supplier.mm; sourceTree = "<group>"; }; - 9BDF192D0B1BC15D00F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; }; - 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = SOURCE_ROOT; }; - 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pathname_stripper.cc; path = ../../../processor/pathname_stripper.cc; sourceTree = SOURCE_ROOT; }; - 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "range_map-inl.h"; path = "../../../processor/range_map-inl.h"; sourceTree = SOURCE_ROOT; }; - 9BDF1A7B0B1BE30100F8391B /* range_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = range_map.h; path = ../../../processor/range_map.h; sourceTree = SOURCE_ROOT; }; - 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "address_map-inl.h"; path = "../../../processor/address_map-inl.h"; sourceTree = SOURCE_ROOT; }; - 9BDF1AFB0B1BEB6300F8391B /* address_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = address_map.h; path = ../../../processor/address_map.h; sourceTree = SOURCE_ROOT; }; - 9BE650AC0B52FE3000611104 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; }; - 9BE650AD0B52FE3000611104 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; }; - 9BE650AE0B52FE3000611104 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; }; - 9BE650AF0B52FE3000611104 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; }; - 9BE650B00B52FE3000611104 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; }; - 9BE650B10B52FE3000611104 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; }; - D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_frame_info.cc; path = ../../../processor/cfi_frame_info.cc; sourceTree = SOURCE_ROOT; }; - D2A5DD621188658B00081F03 /* tokenize.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tokenize.cc; path = ../../../processor/tokenize.cc; sourceTree = SOURCE_ROOT; }; - F407DC40185773C10064622B /* exploitability_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_linux.cc; path = ../../../processor/exploitability_linux.cc; sourceTree = "<group>"; }; - F407DC41185773C10064622B /* stack_frame_symbolizer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stack_frame_symbolizer.cc; path = ../../../processor/stack_frame_symbolizer.cc; sourceTree = "<group>"; }; - F407DC42185773C10064622B /* stackwalker_arm64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm64.cc; path = ../../../processor/stackwalker_arm64.cc; sourceTree = "<group>"; }; - F407DC43185773C10064622B /* stackwalker_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm64.h; path = ../../../processor/stackwalker_arm64.h; sourceTree = "<group>"; }; - F407DC44185773C10064622B /* stackwalker_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_mips.cc; path = ../../../processor/stackwalker_mips.cc; sourceTree = "<group>"; }; - F407DC45185773C10064622B /* stackwalker_mips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_mips.h; path = ../../../processor/stackwalker_mips.h; sourceTree = "<group>"; }; - F407DC46185773C10064622B /* stackwalker_ppc64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc64.cc; path = ../../../processor/stackwalker_ppc64.cc; sourceTree = "<group>"; }; - F407DC47185773C10064622B /* stackwalker_ppc64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_ppc64.h; path = ../../../processor/stackwalker_ppc64.h; sourceTree = "<group>"; }; - F44DDD8419C85CD50047280E /* dump_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_context.cc; path = ../../../processor/dump_context.cc; sourceTree = "<group>"; }; - F44DDD8519C85CD50047280E /* dump_object.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_object.cc; path = ../../../processor/dump_object.cc; sourceTree = "<group>"; }; - F44DDD8619C85CD50047280E /* microdump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump_processor.cc; path = ../../../processor/microdump_processor.cc; sourceTree = "<group>"; }; - F44DDD8A19C85CFB0047280E /* dump_context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_context.h; path = ../../../google_breakpad/processor/dump_context.h; sourceTree = "<group>"; }; - F44DDD8B19C85CFB0047280E /* dump_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_object.h; path = ../../../google_breakpad/processor/dump_object.h; sourceTree = "<group>"; }; - F44DDD8C19C85CFC0047280E /* microdump_processor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump_processor.h; path = ../../../google_breakpad/processor/microdump_processor.h; sourceTree = "<group>"; }; - F44DDD8D19C85CFC0047280E /* process_result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = process_result.h; path = ../../../google_breakpad/processor/process_result.h; sourceTree = "<group>"; }; - F47180541D745DEF0032F208 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; }; - F47180551D745DEF0032F208 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; }; - F47180571D7467630032F208 /* proc_maps_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = proc_maps_linux.cc; path = ../../../processor/proc_maps_linux.cc; sourceTree = "<group>"; }; - F47180591D7468A40032F208 /* symbolic_constants_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = symbolic_constants_win.cc; path = ../../../processor/symbolic_constants_win.cc; sourceTree = "<group>"; }; - F4D43B2E1A38490700C290B2 /* microdump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump.cc; path = ../../../processor/microdump.cc; sourceTree = "<group>"; }; - F4D43B301A38492000C290B2 /* microdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump.h; path = ../../../google_breakpad/processor/microdump.h; sourceTree = "<group>"; }; - F9C7ECE20E8ABCA600E953AD /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; }; - F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; }; - F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; }; - F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm.cc; path = ../../../processor/stackwalker_arm.cc; sourceTree = SOURCE_ROOT; }; - F9F0706610FBC02D0037B88B /* stackwalker_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm.h; path = ../../../processor/stackwalker_arm.h; sourceTree = SOURCE_ROOT; }; - FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_amd64.cc; path = ../../../processor/stackwalker_amd64.cc; sourceTree = SOURCE_ROOT; }; - FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_amd64.h; path = ../../../processor/stackwalker_amd64.h; sourceTree = SOURCE_ROOT; }; - FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_sparc.cc; path = ../../../processor/stackwalker_sparc.cc; sourceTree = SOURCE_ROOT; }; - FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = stackwalker_sparc.h; path = ../../../processor/stackwalker_sparc.h; sourceTree = SOURCE_ROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 08FB7794FE84155DC02AAC07 /* crash_report */ = { - isa = PBXGroup; - children = ( - 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */, - 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */, - 4247E63F2110D5A500482558 /* path_helper.cc */, - 4247E63E2110D5A500482558 /* path_helper.h */, - 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */, - 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */, - 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */, - F9C7ECE10E8ABC7F00E953AD /* DWARF */, - 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */, - 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */, - 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */, - 5578003F0BE1F28500EC23E0 /* macho_utilities.h */, - 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */, - 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */, - 9BDF192D0B1BC15D00F8391B /* dump_syms.h */, - 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */, - 08FB7796FE84155DC02AAC07 /* crash_report.mm */, - F44DDD8D19C85CFC0047280E /* process_result.h */, - 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */, - F44DDD8419C85CD50047280E /* dump_context.cc */, - F44DDD8A19C85CFB0047280E /* dump_context.h */, - F44DDD8519C85CD50047280E /* dump_object.cc */, - F44DDD8B19C85CFB0047280E /* dump_object.h */, - F4D43B2E1A38490700C290B2 /* microdump.cc */, - F4D43B301A38492000C290B2 /* microdump.h */, - F44DDD8619C85CD50047280E /* microdump_processor.cc */, - F44DDD8C19C85CFC0047280E /* microdump_processor.h */, - 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */, - 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */, - 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */, - 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */, - 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */, - 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */, - 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */, - 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */, - 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */, - 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */, - 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */, - 8B31FF8411F0C6FB00FCF3E4 /* language.cc */, - 8B31FF8511F0C6FB00FCF3E4 /* language.h */, - 4D72CA5613DFBA84006CABE3 /* md5.cc */, - 8B31FF8611F0C6FB00FCF3E4 /* module.cc */, - 8B31FF8711F0C6FB00FCF3E4 /* module.h */, - 08FB7795FE84155DC02AAC07 /* breakpad */, - 4D2C726E126F9CE200B43EAF /* libdisasm */, - 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, - 1AB674ADFE9D54B511CA2CBB /* Products */, - ); - name = crash_report; - sourceTree = "<group>"; - }; - 08FB7795FE84155DC02AAC07 /* breakpad */ = { - isa = PBXGroup; - children = ( - 9BE650AB0B52FE1A00611104 /* common */, - 9BDF17280B1B8B0200F8391B /* processor */, - 9BDF16F70B1B8ACD00F8391B /* google_breakpad */, - ); - name = breakpad; - sourceTree = "<group>"; - }; - 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { - isa = PBXGroup; - children = ( - 08FB779EFE84155DC02AAC07 /* Foundation.framework */, - ); - name = "External Frameworks and Libraries"; - sourceTree = "<group>"; - }; - 1AB674ADFE9D54B511CA2CBB /* Products */ = { - isa = PBXGroup; - children = ( - 8DD76FA10486AA7600D96B5E /* crash_report */, - ); - name = Products; - sourceTree = "<group>"; - }; - 4D2C726E126F9CE200B43EAF /* libdisasm */ = { - isa = PBXGroup; - children = ( - 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */, - 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */, - 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */, - 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */, - 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */, - 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */, - 4D2C725A126F9C8000B43EAF /* ia32_operand.c */, - 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */, - 4D2C7234126F9BC200B43EAF /* ia32_settings.c */, - 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */, - 4D2C7263126F9CBB00B43EAF /* x86_imm.c */, - 4D2C725C126F9C9200B43EAF /* x86_insn.c */, - 4D2C722C126F9B6E00B43EAF /* x86_misc.c */, - 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */, - ); - name = libdisasm; - sourceTree = "<group>"; - }; - 9BDF16F70B1B8ACD00F8391B /* google_breakpad */ = { - isa = PBXGroup; - children = ( - 9BDF16F80B1B8ACD00F8391B /* common */, - 9BDF16FB0B1B8ACD00F8391B /* processor */, - ); - name = google_breakpad; - path = ../../../google_breakpad; - sourceTree = SOURCE_ROOT; - }; - 9BDF16F80B1B8ACD00F8391B /* common */ = { - isa = PBXGroup; - children = ( - 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */, - 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */, - ); - path = common; - sourceTree = "<group>"; - }; - 9BDF16FB0B1B8ACD00F8391B /* processor */ = { - isa = PBXGroup; - children = ( - 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */, - 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */, - 9B35FEE20B2675F9008DE8C7 /* code_module.h */, - 9B35FEE30B2675F9008DE8C7 /* code_modules.h */, - 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */, - 9BDF16FE0B1B8ACD00F8391B /* minidump.h */, - 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */, - 9BDF17000B1B8ACD00F8391B /* process_state.h */, - 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */, - 9BDF17010B1B8ACD00F8391B /* stack_frame.h */, - 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */, - 9BDF17030B1B8ACD00F8391B /* stackwalker.h */, - 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */, - 9B44619D0B66C66B00BBB817 /* system_info.h */, - ); - path = processor; - sourceTree = "<group>"; - }; - 9BDF17280B1B8B0200F8391B /* processor */ = { - isa = PBXGroup; - children = ( - 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */, - F407DC40185773C10064622B /* exploitability_linux.cc */, - F407DC41185773C10064622B /* stack_frame_symbolizer.cc */, - F407DC42185773C10064622B /* stackwalker_arm64.cc */, - F407DC43185773C10064622B /* stackwalker_arm64.h */, - F407DC44185773C10064622B /* stackwalker_mips.cc */, - F407DC45185773C10064622B /* stackwalker_mips.h */, - F407DC46185773C10064622B /* stackwalker_ppc64.cc */, - F407DC47185773C10064622B /* stackwalker_ppc64.h */, - 4D2C721E126F9ADE00B43EAF /* exploitability.cc */, - 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */, - D2A5DD621188658B00081F03 /* tokenize.cc */, - D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */, - F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */, - F9F0706610FBC02D0037B88B /* stackwalker_arm.h */, - 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */, - 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */, - 9BDF1AFB0B1BEB6300F8391B /* address_map.h */, - 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */, - 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */, - 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */, - 9BDF172A0B1B8B2400F8391B /* call_stack.cc */, - 8B40BDBF0C0638E4009535AF /* logging.cc */, - 9BDF173F0B1B8B9A00F8391B /* minidump.cc */, - 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */, - 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */, - F47180571D7467630032F208 /* proc_maps_linux.cc */, - 9BDF175B0B1B8C1B00F8391B /* process_state.cc */, - 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */, - 9BDF1A7B0B1BE30100F8391B /* range_map.h */, - 9BDF17530B1B8BF900F8391B /* stackwalker.cc */, - 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */, - 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */, - FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */, - FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */, - FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */, - FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */, - F47180591D7468A40032F208 /* symbolic_constants_win.cc */, - ); - name = processor; - sourceTree = "<group>"; - }; - 9BE650AB0B52FE1A00611104 /* common */ = { - isa = PBXGroup; - children = ( - 9BE650AC0B52FE3000611104 /* file_id.cc */, - 9BE650AD0B52FE3000611104 /* file_id.h */, - 9BE650AE0B52FE3000611104 /* macho_id.cc */, - 9BE650AF0B52FE3000611104 /* macho_id.h */, - 9BE650B00B52FE3000611104 /* macho_walker.cc */, - 9BE650B10B52FE3000611104 /* macho_walker.h */, - ); - name = common; - sourceTree = "<group>"; - }; - F9C7ECE10E8ABC7F00E953AD /* DWARF */ = { - isa = PBXGroup; - children = ( - F9C7ECE20E8ABCA600E953AD /* bytereader.cc */, - F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */, - 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */, - 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */, - F47180541D745DEF0032F208 /* elf_reader.cc */, - F47180551D745DEF0032F208 /* elf_reader.h */, - F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */, - ); - name = DWARF; - sourceTree = "<group>"; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 8DD76F960486AA7600D96B5E /* crash_report */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */; - buildPhases = ( - 8DD76F990486AA7600D96B5E /* Sources */, - 8DD76F9B0486AA7600D96B5E /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = crash_report; - productInstallPath = "$(HOME)/bin"; - productName = crash_report; - productReference = 8DD76FA10486AA7600D96B5E /* crash_report */; - productType = "com.apple.product-type.tool"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 08FB7793FE84155DC02AAC07 /* Project object */ = { - isa = PBXProject; - attributes = { - }; - buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */; - compatibilityVersion = "Xcode 3.1"; - developmentRegion = en; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 08FB7794FE84155DC02AAC07 /* crash_report */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 8DD76F960486AA7600D96B5E /* crash_report */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 8DD76F990486AA7600D96B5E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */, - 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */, - F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */, - 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */, - 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */, - 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */, - F44DDD8719C85CD50047280E /* dump_context.cc in Sources */, - 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */, - 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */, - 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */, - 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */, - F47180561D745DEF0032F208 /* elf_reader.cc in Sources */, - 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */, - 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */, - 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */, - 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */, - 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */, - 9BE650B20B52FE3000611104 /* file_id.cc in Sources */, - 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */, - 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */, - 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */, - 8B40BDC00C0638E4009535AF /* logging.cc in Sources */, - FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */, - FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */, - F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */, - F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */, - F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */, - F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */, - D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */, - D2A5DD631188658B00081F03 /* tokenize.cc in Sources */, - 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */, - F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */, - 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */, - F44DDD8819C85CD50047280E /* dump_object.cc in Sources */, - 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */, - 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */, - 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */, - 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */, - 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */, - 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */, - 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */, - F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */, - F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */, - 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */, - 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */, - 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */, - 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */, - F407DC48185773C10064622B /* exploitability_linux.cc in Sources */, - 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */, - 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */, - 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */, - 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */, - F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */, - 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */, - 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */, - 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */, - 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */, - 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */, - 4247E6402110D5A500482558 /* path_helper.cc in Sources */, - F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */, - 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */, - 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */, - F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */, - 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */, - 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */, - F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */, - 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */, - 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 1DEB927508733DD40010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - HEADER_SEARCH_PATHS = ../../../../src; - PRODUCT_NAME = crash_report; - }; - name = Debug; - }; - 1DEB927608733DD40010E9CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - HEADER_SEARCH_PATHS = ../../../../src; - PRODUCT_NAME = crash_report; - }; - name = Release; - }; - 1DEB927908733DD40010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - }; - name = Debug; - }; - 1DEB927A08733DD40010E9CD /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB927508733DD40010E9CD /* Debug */, - 1DEB927608733DD40010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB927908733DD40010E9CD /* Debug */, - 1DEB927A08733DD40010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; -} diff --git a/src/tools/mac/crash_report/on_demand_symbol_supplier.h b/src/tools/mac/crash_report/on_demand_symbol_supplier.h deleted file mode 100644 index 3fbe108e..00000000 --- a/src/tools/mac/crash_report/on_demand_symbol_supplier.h +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2006, 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. - -// on_demand_symbol_supplier.h: Provides a Symbol Supplier that will create -// a breakpad symbol file on demand. - -#ifndef TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ -#define TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ - -#include <map> -#include <string> -#include "google_breakpad/processor/symbol_supplier.h" - -namespace google_breakpad { - -using std::map; -using std::string; -class MinidumpModule; - -class OnDemandSymbolSupplier : public SymbolSupplier { - public: - // |search_dir| is the directory to search for alternative symbols with - // the same name as the module in the minidump - OnDemandSymbolSupplier(const string &search_dir, - const string &symbol_search_dir); - virtual ~OnDemandSymbolSupplier() {} - - // Returns the path to the symbol file for the given module. - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file); - - // Returns the path to the symbol file for the given module. - virtual SymbolResult GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data); - // Allocates data buffer on heap, and takes the ownership of - // the data buffer. - virtual SymbolResult GetCStringSymbolData(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size); - - // Delete the data buffer allocated for module in GetCStringSymbolData(). - virtual void FreeSymbolData(const CodeModule *module); - - protected: - // Search directory - string search_dir_; - string symbol_search_dir_; - - // When we create a symbol file for a module, save the name of the module - // and the path to that module's symbol file. - map<string, string> module_file_map_; - - // Map of allocated data buffers, keyed by module->code_file(). - map<string, char *> memory_buffers_; - - // Return the name for |module| This will be the value used as the key - // to the |module_file_map_|. - string GetNameForModule(const CodeModule *module); - - // Find the module on local system. If the module resides in a different - // location than the full path in the minidump, this will be the location - // used. - string GetLocalModulePath(const CodeModule *module); - - // Return the full path for |module|. - string GetModulePath(const CodeModule *module); - - // Return the path to the symbol file for |module|. If an empty string is - // returned, then |module| doesn't have a symbol file. - string GetModuleSymbolFile(const CodeModule *module); - - // Generate the breakpad symbol file for |module|. Return true if successful. - // File is generated in /tmp. - bool GenerateSymbolFile(const CodeModule *module, - const SystemInfo *system_info); -}; - -} // namespace google_breakpad - -#endif // TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ diff --git a/src/tools/mac/crash_report/on_demand_symbol_supplier.mm b/src/tools/mac/crash_report/on_demand_symbol_supplier.mm deleted file mode 100644 index 1955d266..00000000 --- a/src/tools/mac/crash_report/on_demand_symbol_supplier.mm +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (c) 2006, 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 <Foundation/Foundation.h> -#include <sys/stat.h> -#include <map> -#include <string> -#include <iostream> -#include <fstream> -#include <utility> - -#include "google_breakpad/processor/basic_source_line_resolver.h" -#include "google_breakpad/processor/minidump.h" -#include "google_breakpad/processor/system_info.h" -#include "processor/pathname_stripper.h" - -#include "on_demand_symbol_supplier.h" -#include "common/mac/dump_syms.h" - -using std::map; -using std::string; - -using google_breakpad::OnDemandSymbolSupplier; -using google_breakpad::PathnameStripper; -using google_breakpad::SymbolSupplier; -using google_breakpad::SystemInfo; - -OnDemandSymbolSupplier::OnDemandSymbolSupplier(const string &search_dir, - const string &symbol_search_dir) - : search_dir_(search_dir) { - NSFileManager *mgr = [NSFileManager defaultManager]; - size_t length = symbol_search_dir.length(); - if (length) { - // Load all sym files in symbol_search_dir into our module_file_map - // A symbol file always starts with a line like this: - // MODULE mac x86 BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon - // or - // MODULE mac ppc BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon - const char *symbolSearchStr = symbol_search_dir.c_str(); - NSString *symbolSearchPath = - [mgr stringWithFileSystemRepresentation:symbolSearchStr - length:strlen(symbolSearchStr)]; - NSDirectoryEnumerator *dirEnum = [mgr enumeratorAtPath:symbolSearchPath]; - NSString *fileName; - NSCharacterSet *hexSet = - [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"]; - NSCharacterSet *newlineSet = - [NSCharacterSet characterSetWithCharactersInString:@"\r\n"]; - while ((fileName = [dirEnum nextObject])) { - // Check to see what type of file we have - NSDictionary *attrib = [dirEnum fileAttributes]; - NSString *fileType = [attrib objectForKey:NSFileType]; - if ([fileType isEqualToString:NSFileTypeDirectory]) { - // Skip subdirectories - [dirEnum skipDescendents]; - } else { - NSString *filePath = [symbolSearchPath stringByAppendingPathComponent:fileName]; - NSString *dataStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL]; - if (dataStr) { - // Check file to see if it is of appropriate type, and grab module - // name. - NSScanner *scanner = [NSScanner scannerWithString:dataStr]; - BOOL goodScan = [scanner scanString:@"MODULE mac " intoString:nil]; - if (goodScan) { - goodScan = ([scanner scanString:@"x86 " intoString:nil] || - [scanner scanString:@"x86_64 " intoString:nil] || - [scanner scanString:@"ppc " intoString:nil]); - if (goodScan) { - NSString *moduleID; - goodScan = [scanner scanCharactersFromSet:hexSet - intoString:&moduleID]; - if (goodScan) { - // Module IDs are always 33 chars long - goodScan = [moduleID length] == 33; - if (goodScan) { - NSString *moduleName; - goodScan = [scanner scanUpToCharactersFromSet:newlineSet - intoString:&moduleName]; - if (goodScan) { - goodScan = [moduleName length] > 0; - if (goodScan) { - const char *moduleNameStr = [moduleName UTF8String]; - const char *filePathStr = [filePath fileSystemRepresentation]; - // Map our file - module_file_map_[moduleNameStr] = filePathStr; - } - } - } - } - } - } - } - } - } - } -} - -SymbolSupplier::SymbolResult -OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file) { - string path(GetModuleSymbolFile(module)); - - if (path.empty()) { - if (!GenerateSymbolFile(module, system_info)) - return NOT_FOUND; - - path = GetModuleSymbolFile(module); - } - - if (path.empty()) - return NOT_FOUND; - - *symbol_file = path; - return FOUND; -} - -SymbolSupplier::SymbolResult -OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - string *symbol_data) { - SymbolSupplier::SymbolResult s = GetSymbolFile(module, - system_info, - symbol_file); - - - if (s == FOUND) { - std::ifstream in(symbol_file->c_str()); - getline(in, *symbol_data, std::string::traits_type::to_char_type( - std::string::traits_type::eof())); - in.close(); - } - - return s; -} - -SymbolSupplier::SymbolResult -OnDemandSymbolSupplier::GetCStringSymbolData(const CodeModule *module, - const SystemInfo *system_info, - string *symbol_file, - char **symbol_data, - size_t *symbol_data_size) { - std::string symbol_data_string; - SymbolSupplier::SymbolResult result = GetSymbolFile(module, - system_info, - symbol_file, - &symbol_data_string); - if (result == FOUND) { - *symbol_data_size = symbol_data_string.size() + 1; - *symbol_data = new char[*symbol_data_size]; - if (*symbol_data == NULL) { - // Should return INTERRUPT on memory allocation failure. - return INTERRUPT; - } - memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); - (*symbol_data)[symbol_data_string.size()] = '\0'; - memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); - } - return result; -} - -void OnDemandSymbolSupplier::FreeSymbolData(const CodeModule *module) { - map<string, char *>::iterator it = memory_buffers_.find(module->code_file()); - if (it != memory_buffers_.end()) { - delete [] it->second; - memory_buffers_.erase(it); - } -} - -string OnDemandSymbolSupplier::GetLocalModulePath(const CodeModule *module) { - NSFileManager *mgr = [NSFileManager defaultManager]; - const char *moduleStr = module->code_file().c_str(); - NSString *modulePath = - [mgr stringWithFileSystemRepresentation:moduleStr length:strlen(moduleStr)]; - const char *searchStr = search_dir_.c_str(); - NSString *searchDir = - [mgr stringWithFileSystemRepresentation:searchStr length:strlen(searchStr)]; - - if ([mgr fileExistsAtPath:modulePath]) - return module->code_file(); - - // If the module is not found, try to start appending the components to the - // search string and stop if a file (not dir) is found or all components - // have been appended - NSArray *pathComponents = [modulePath componentsSeparatedByString:@"/"]; - size_t count = [pathComponents count]; - NSMutableString *path = [NSMutableString string]; - - for (size_t i = 0; i < count; ++i) { - [path setString:searchDir]; - - for (size_t j = 0; j < i + 1; ++j) { - size_t idx = count - 1 - i + j; - [path appendFormat:@"/%@", [pathComponents objectAtIndex:idx]]; - } - - BOOL isDir; - if ([mgr fileExistsAtPath:path isDirectory:&isDir] && (!isDir)) { - return [path fileSystemRepresentation]; - } - } - - return ""; -} - -string OnDemandSymbolSupplier::GetModulePath(const CodeModule *module) { - return module->code_file(); -} - -string OnDemandSymbolSupplier::GetNameForModule(const CodeModule *module) { - return PathnameStripper::File(module->code_file()); -} - -string OnDemandSymbolSupplier::GetModuleSymbolFile(const CodeModule *module) { - string name(GetNameForModule(module)); - map<string, string>::iterator result = module_file_map_.find(name); - - return (result == module_file_map_.end()) ? "" : (*result).second; -} - -static float GetFileModificationTime(const char *path) { - float result = 0; - struct stat file_stat; - if (stat(path, &file_stat) == 0) - result = (float)file_stat.st_mtimespec.tv_sec + - (float)file_stat.st_mtimespec.tv_nsec / 1.0e9f; - - return result; -} - -bool OnDemandSymbolSupplier::GenerateSymbolFile(const CodeModule *module, - const SystemInfo *system_info) { - bool result = true; - string name = GetNameForModule(module); - string module_path = GetLocalModulePath(module); - NSString *symbol_path = [NSString stringWithFormat:@"/tmp/%s.%s.sym", - name.c_str(), system_info->cpu.c_str()]; - - if (module_path.empty()) - return false; - - // Check if there's already a symbol file cached. Ensure that the file is - // newer than the module. Otherwise, generate a new one. - BOOL generate_file = YES; - if ([[NSFileManager defaultManager] fileExistsAtPath:symbol_path]) { - // Check if the module file is newer than the saved symbols - float cache_time = - GetFileModificationTime([symbol_path fileSystemRepresentation]); - float module_time = - GetFileModificationTime(module_path.c_str()); - - if (cache_time > module_time) - generate_file = NO; - } - - if (generate_file) { - DumpSymbols dump(ALL_SYMBOL_DATA, false); - if (dump.Read(module_path)) { - // What Breakpad calls "x86" should be given to the system as "i386". - std::string architecture; - if (system_info->cpu.compare("x86") == 0) { - architecture = "i386"; - } else { - architecture = system_info->cpu; - } - - if (dump.SetArchitecture(architecture)) { - std::fstream file([symbol_path fileSystemRepresentation], - std::ios_base::out | std::ios_base::trunc); - dump.WriteSymbolFile(file); - } else { - printf("Architecture %s not available for %s\n", - system_info->cpu.c_str(), name.c_str()); - result = false; - } - } else { - printf("Unable to open %s\n", module_path.c_str()); - result = false; - } - } - - // Add the mapping - if (result) - module_file_map_[name] = [symbol_path fileSystemRepresentation]; - - return result; -} diff --git a/src/tools/mac/dump_syms/dump_syms_tool.cc b/src/tools/mac/dump_syms/dump_syms_tool.cc index 6f68457b..2e05cbf3 100644 --- a/src/tools/mac/dump_syms/dump_syms_tool.cc +++ b/src/tools/mac/dump_syms/dump_syms_tool.cc @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2011, Google Inc. -// All rights reserved. +// Copyright 2011 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -37,6 +36,8 @@ #include <algorithm> #include <iostream> +#include <memory> +#include <utility> #include <vector> #include "common/mac/dump_syms.h" @@ -51,8 +52,14 @@ using std::vector; struct Options { Options() - : srcPath(), dsymPath(), arch(), header_only(false), - cfi(true), handle_inter_cu_refs(true) {} + : srcPath(), + dsymPath(), + arch(), + header_only(false), + cfi(true), + handle_inter_cu_refs(true), + handle_inlines(false), + enable_multiple(false) {} string srcPath; string dsymPath; @@ -60,6 +67,8 @@ struct Options { bool header_only; bool cfi; bool handle_inter_cu_refs; + bool handle_inlines; + bool enable_multiple; }; static bool StackFrameEntryComparator(const Module::StackFrameEntry* a, @@ -101,14 +110,47 @@ static void CopyCFIDataBetweenModules(Module* to_module, // 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)); + to_module->AddStackFrameEntry( + std::make_unique<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); +static bool SetArchitecture(DumpSymbols& dump_symbols, + const NXArchInfo* arch, + const std::string& filename) { + if (!dump_symbols.SetArchitecture(arch->cputype, arch->cpusubtype)) { + fprintf(stderr, "%s: no architecture '%s' is present in file.\n", + filename.c_str(), arch->name); + size_t available_size; + const SuperFatArch* available = + dump_symbols.AvailableArchitectures(&available_size); + if (available_size == 1) + fprintf(stderr, "the file's architecture is: "); + else + fprintf(stderr, "architectures present in the file are:\n"); + for (size_t i = 0; i < available_size; i++) { + const SuperFatArch* arch = &available[i]; + const NXArchInfo* arch_info = + google_breakpad::BreakpadGetArchInfoFromCpuType(arch->cputype, + arch->cpusubtype); + if (arch_info) + fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description); + else + fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n", + arch->cputype, arch->cpusubtype); + } + return false; + } + return true; +} + +static bool Start(const Options& options) { + SymbolData symbol_data = + (options.handle_inlines ? INLINES : NO_DATA) | + (options.cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES; + DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs, + options.enable_multiple); // 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 @@ -126,31 +168,9 @@ static bool Start(const Options &options) { 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", - primary_file.c_str(), options.arch->name); - size_t available_size; - const SuperFatArch *available = - dump_symbols.AvailableArchitectures(&available_size); - if (available_size == 1) - fprintf(stderr, "the file's architecture is: "); - else - fprintf(stderr, "architectures present in the file are:\n"); - for (size_t i = 0; i < available_size; i++) { - const SuperFatArch *arch = &available[i]; - const NXArchInfo *arch_info = - google_breakpad::BreakpadGetArchInfoFromCpuType( - arch->cputype, arch->cpusubtype); - if (arch_info) - fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description); - else - fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n", - arch->cputype, arch->cpusubtype); - } - return false; - } + if (options.arch && + !SetArchitecture(dump_symbols, options.arch, primary_file)) { + return false; } if (options.header_only) @@ -168,6 +188,10 @@ static bool Start(const Options &options) { if (!dump_symbols.Read(options.srcPath)) return false; + if (options.arch && + !SetArchitecture(dump_symbols, options.arch, options.srcPath)) { + return false; + } Module* cfi_module = NULL; if (!dump_symbols.ReadSymbolData(&cfi_module)) return false; @@ -201,6 +225,10 @@ static void Usage(int argc, const char *argv[]) { "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-d: Generate INLINE and INLINE_ORIGIN records\n"); + fprintf(stderr, + "\t-m: Enable writing the optional 'm' field on FUNC " + "and PUBLIC, denoting multiple symbols for the address.\n"); fprintf(stderr, "\t-h: Usage\n"); fprintf(stderr, "\t-?: Usage\n"); } @@ -210,7 +238,7 @@ static void SetupOptions(int argc, const char *argv[], Options *options) { extern int optind; signed char ch; - while ((ch = getopt(argc, (char * const *)argv, "ia:g:chr?")) != -1) { + while ((ch = getopt(argc, (char* const*)argv, "ia:g:crdm?h")) != -1) { switch (ch) { case 'i': options->header_only = true; @@ -235,6 +263,12 @@ static void SetupOptions(int argc, const char *argv[], Options *options) { case 'r': options->handle_inter_cu_refs = false; break; + case 'd': + options->handle_inlines = true; + break; + case 'm': + options->enable_multiple = true; + break; case '?': case 'h': Usage(argc, argv); diff --git a/src/tools/mac/dump_syms/macho_dump.cc b/src/tools/mac/dump_syms/macho_dump.cc index 6e784ca7..b724cc74 100644 --- a/src/tools/mac/dump_syms/macho_dump.cc +++ b/src/tools/mac/dump_syms/macho_dump.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2010, Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -60,7 +59,7 @@ namespace mach_o = google_breakpad::mach_o; string program_name; -int check_syscall(int result, const char *operation, const char *filename) { +int check_syscall(int result, const char* operation, const char* filename) { if (result < 0) { fprintf(stderr, "%s: %s '%s': %s\n", program_name.c_str(), operation, @@ -73,7 +72,7 @@ int check_syscall(int result, const char *operation, const char *filename) { class DumpSection: public mach_o::Reader::SectionHandler { public: DumpSection() : index_(0) { } - bool HandleSection(const mach_o::Section §ion) { + bool HandleSection(const mach_o::Section& section) { printf(" section %d '%s' in segment '%s'\n" " address: 0x%llx\n" " alignment: 1 << %d B\n" @@ -92,13 +91,13 @@ class DumpSection: public mach_o::Reader::SectionHandler { class DumpCommand: public mach_o::Reader::LoadCommandHandler { public: - DumpCommand(mach_o::Reader *reader) : reader_(reader), index_(0) { } + DumpCommand(mach_o::Reader* reader) : reader_(reader), index_(0) { } bool UnknownCommand(mach_o::LoadCommandType type, - const ByteBuffer &contents) { + const ByteBuffer& contents) { printf(" load command %d: %d", index_++, type); return true; } - bool SegmentCommand(const mach_o::Segment &segment) { + bool SegmentCommand(const mach_o::Segment& segment) { printf(" load command %d: %s-bit segment '%s'\n" " address: 0x%llx\n" " memory size: 0x%llx\n" @@ -115,24 +114,24 @@ class DumpCommand: public mach_o::Reader::LoadCommandHandler { return reader_->WalkSegmentSections(segment, &dump_section); } private: - mach_o::Reader *reader_; + mach_o::Reader* reader_; int index_; }; -void DumpFile(const char *filename) { +void DumpFile(const char* filename) { int fd = check_syscall(open(filename, O_RDONLY), "opening", filename); struct stat attributes; check_syscall(fstat(fd, &attributes), "getting file attributes for", filename); - void *mapping = mmap(NULL, attributes.st_size, PROT_READ, + void* mapping = mmap(NULL, attributes.st_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - check_syscall(mapping == (void *)-1 ? -1 : 0, + check_syscall(mapping == (void*)-1 ? -1 : 0, "mapping contents of", filename); mach_o::FatReader::Reporter fat_reporter(filename); mach_o::FatReader fat_reader(&fat_reporter); - if (!fat_reader.Read(reinterpret_cast<uint8_t *>(mapping), + if (!fat_reader.Read(reinterpret_cast<uint8_t*>(mapping), attributes.st_size)) { exit(1); } @@ -140,14 +139,14 @@ void DumpFile(const char *filename) { size_t object_files_size; const SuperFatArch* super_fat_object_files = fat_reader.object_files(&object_files_size); - struct fat_arch *object_files; + struct fat_arch* object_files; if (!super_fat_object_files->ConvertToFatArch(object_files)) { exit(1); } printf(" object file count: %ld\n", object_files_size); for (size_t i = 0; i < object_files_size; i++) { - const struct fat_arch &file = object_files[i]; - const NXArchInfo *fat_arch_info = + const struct fat_arch& file = object_files[i]; + const NXArchInfo* fat_arch_info = google_breakpad::BreakpadGetArchInfoFromCpuType( file.cputype, file.cpusubtype); printf("\n object file %ld:\n" @@ -162,7 +161,7 @@ void DumpFile(const char *filename) { name << filename; if (object_files_size > 1) name << ", object file #" << i; - ByteBuffer file_contents(reinterpret_cast<uint8_t *>(mapping) + ByteBuffer file_contents(reinterpret_cast<uint8_t*>(mapping) + file.offset, file.size); mach_o::Reader::Reporter reporter(name.str()); mach_o::Reader reader(&reporter); @@ -170,7 +169,7 @@ void DumpFile(const char *filename) { exit(1); } - const NXArchInfo *macho_arch_info = + const NXArchInfo* macho_arch_info = NXGetArchInfoFromCpuType(reader.cpu_type(), reader.cpu_subtype()); printf(" Mach-O header:\n" @@ -190,7 +189,7 @@ void DumpFile(const char *filename) { } // namespace -int main(int argc, char **argv) { +int main(int argc, char** argv) { program_name = google_breakpad::BaseName(argv[0]); if (argc == 1) { fprintf(stderr, "Usage: %s FILE ...\n" diff --git a/src/tools/mac/symupload/symupload.m b/src/tools/mac/symupload/symupload.m deleted file mode 100644 index a7cce7b0..00000000 --- a/src/tools/mac/symupload/symupload.m +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) 2006, 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. - -// symupload.m: Upload a symbol file to a HTTP server. The upload is sent as -// a multipart/form-data POST request with the following parameters: -// code_file: the basename of the module, e.g. "app" -// debug_file: the basename of the debugging file, e.g. "app" -// debug_identifier: the debug file's identifier, usually consisting of -// the guid and age embedded in the pdb, e.g. -// "11111111BBBB3333DDDD555555555555F" -// os: the operating system that the module was built for -// cpu: the CPU that the module was built for (x86 or ppc) -// symbol_file: the contents of the breakpad-format symbol file - -#include <fcntl.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <Foundation/Foundation.h> -#include "HTTPMultipartUpload.h" - -typedef struct { - NSString *symbolsPath; - NSString *uploadURLStr; - BOOL success; -} Options; - -//============================================================================= -static NSArray *ModuleDataForSymbolFile(NSString *file) { - NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:file]; - NSData *data = [fh readDataOfLength:1024]; - NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSScanner *scanner = [NSScanner scannerWithString:str]; - NSString *line; - NSMutableArray *parts = nil; - const int MODULE_ID_INDEX = 3; - - if ([scanner scanUpToString:@"\n" intoString:&line]) { - parts = [[NSMutableArray alloc] init]; - NSScanner *moduleInfoScanner = [NSScanner scannerWithString:line]; - NSString *moduleInfo; - // Get everything BEFORE the module name. None of these properties - // can have spaces. - for (int i = 0; i <= MODULE_ID_INDEX; i++) { - [moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo]; - [parts addObject:moduleInfo]; - } - - // Now get the module name. This can have a space so we scan to - // the end of the line. - [moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo]; - [parts addObject:moduleInfo]; - } - - [str release]; - - return parts; -} - -//============================================================================= -static void Start(Options *options) { - NSURL *url = [NSURL URLWithString:options->uploadURLStr]; - HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; - NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; - NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath); - NSMutableString *compactedID = - [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; - [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0 - range:NSMakeRange(0, [compactedID length])]; - - // Add parameters - [parameters setObject:compactedID forKey:@"debug_identifier"]; - - // MODULE <os> <cpu> <uuid> <module-name> - // 0 1 2 3 4 - [parameters setObject:[moduleParts objectAtIndex:1] forKey:@"os"]; - [parameters setObject:[moduleParts objectAtIndex:2] forKey:@"cpu"]; - [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"debug_file"]; - [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"code_file"]; - [ul setParameters:parameters]; - - NSArray *keys = [parameters allKeys]; - int count = [keys count]; - for (int i = 0; i < count; ++i) { - NSString *key = [keys objectAtIndex:i]; - NSString *value = [parameters objectForKey:key]; - fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], - [value UTF8String]); - } - - // Add file - [ul addFileAtPath:options->symbolsPath name:@"symbol_file"]; - - // Send it - NSError *error = nil; - NSData *data = [ul send:&error]; - NSString *result = [[NSString alloc] initWithData:data - encoding:NSUTF8StringEncoding]; - int status = [[ul response] statusCode]; - - fprintf(stdout, "Send: %s\n", error ? [[error description] UTF8String] : - "No Error"); - fprintf(stdout, "Response: %d\n", status); - fprintf(stdout, "Result: %lu bytes\n%s\n", - (unsigned long)[data length], [result UTF8String]); - - [result release]; - [ul release]; - options->success = !error && status==200; -} - -//============================================================================= -static void -Usage(int argc, const char *argv[]) { - fprintf(stderr, "Submit symbol information.\n"); - fprintf(stderr, "Usage: %s <symbols> <upload-URL>\n", argv[0]); - fprintf(stderr, "<symbols> should be created by using the dump_syms tool.\n"); - fprintf(stderr, "<upload-URL> is the destination for the upload\n"); - fprintf(stderr, "\t-h: Usage\n"); - fprintf(stderr, "\t-?: Usage\n"); -} - -//============================================================================= -static void -SetupOptions(int argc, const char *argv[], Options *options) { - extern int optind; - char ch; - - while ((ch = getopt(argc, (char * const *)argv, "h?")) != -1) { - switch (ch) { - default: - Usage(argc, argv); - exit(0); - break; - } - } - - if ((argc - optind) != 2) { - fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); - Usage(argc, argv); - exit(1); - } - - int fd = open(argv[optind], O_RDONLY); - if (fd < 0) { - fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); - exit(1); - } - - struct stat statbuf; - if (fstat(fd, &statbuf) < 0) { - fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); - close(fd); - exit(1); - } - close(fd); - - if (!S_ISREG(statbuf.st_mode)) { - fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]); - exit(1); - } - - options->symbolsPath = [NSString stringWithUTF8String:argv[optind]]; - options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]]; -} - -//============================================================================= -int main (int argc, const char * argv[]) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - Options options; - - bzero(&options, sizeof(Options)); - SetupOptions(argc, argv, &options); - Start(&options); - - [pool release]; - return options.success ? 0 : 1; -} diff --git a/src/tools/mac/symupload/symupload.mm b/src/tools/mac/symupload/symupload.mm new file mode 100644 index 00000000..521b811f --- /dev/null +++ b/src/tools/mac/symupload/symupload.mm @@ -0,0 +1,474 @@ +// Copyright 2006 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// symupload.mm: Upload a symbol file to a HTTP server. The upload is sent as +// a multipart/form-data POST request with the following parameters: +// code_file: the basename of the module, e.g. "app" +// debug_file: the basename of the debugging file, e.g. "app" +// debug_identifier: the debug file's identifier, usually consisting of +// the guid and age embedded in the pdb, e.g. +// "11111111BBBB3333DDDD555555555555F" +// os: the operating system that the module was built for +// cpu: the CPU that the module was built for (x86 or ppc) +// symbol_file: the contents of the breakpad-format symbol file + +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <Foundation/Foundation.h> + +#include "HTTPMultipartUpload.h" +#include "HTTPPutRequest.h" +#include "SymbolCollectorClient.h" +#include "common/mac/dump_syms.h" + +using google_breakpad::DumpSymbols; + +NSString* const kBreakpadSymbolType = @"BREAKPAD"; +NSString* const kMachOSymbolType = @"MACHO"; +NSString* const kDSYMSymbolType = @"DSYM"; + +typedef enum { kSymUploadProtocolV1, kSymUploadProtocolV2 } SymUploadProtocol; + +typedef enum { + kResultSuccess = 0, + kResultFailure = 1, + kResultAlreadyExists = 2 +} Result; + +typedef struct { + NSString* symbolsPath; + NSString* uploadURLStr; + SymUploadProtocol symUploadProtocol; + NSString* apiKey; + BOOL force; + Result result; + NSString* type; + NSString* codeFile; + NSString* debugID; + NSString* productName; +} Options; + +//============================================================================= +static NSArray* ModuleDataForSymbolFile(NSString* file) { + NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:file]; + NSData* data = [fh readDataOfLength:1024]; + NSString* str = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + NSScanner* scanner = [NSScanner scannerWithString:str]; + NSString* line; + NSMutableArray* parts = nil; + const int MODULE_ID_INDEX = 3; + + if ([scanner scanUpToString:@"\n" intoString:&line]) { + parts = [[NSMutableArray alloc] init]; + NSScanner* moduleInfoScanner = [NSScanner scannerWithString:line]; + NSString* moduleInfo; + // Get everything BEFORE the module name. None of these properties + // can have spaces. + for (int i = 0; i <= MODULE_ID_INDEX; i++) { + [moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo]; + [parts addObject:moduleInfo]; + } + + // Now get the module name. This can have a space so we scan to + // the end of the line. + [moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo]; + [parts addObject:moduleInfo]; + } + + [str release]; + + return parts; +} + +//============================================================================= +static void StartSymUploadProtocolV1(Options* options, + NSString* OS, + NSString* CPU, + NSString* debugID, + NSString* debugFile) { + NSURL* url = [NSURL URLWithString:options->uploadURLStr]; + HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url]; + NSMutableDictionary* parameters = [NSMutableDictionary dictionary]; + + // Add parameters + [parameters setObject:debugID forKey:@"debug_identifier"]; + [parameters setObject:OS forKey:@"os"]; + [parameters setObject:CPU forKey:@"cpu"]; + [parameters setObject:debugFile forKey:@"debug_file"]; + [parameters setObject:debugFile forKey:@"code_file"]; + [ul setParameters:parameters]; + + NSArray* keys = [parameters allKeys]; + int count = [keys count]; + for (int i = 0; i < count; ++i) { + NSString* key = [keys objectAtIndex:i]; + NSString* value = [parameters objectForKey:key]; + fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], [value UTF8String]); + } + + // Add file + [ul addFileAtPath:options->symbolsPath name:@"symbol_file"]; + + // Send it + NSError* error = nil; + NSData* data = [ul send:&error]; + NSString* result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + int status = [[ul response] statusCode]; + + fprintf(stdout, "Send: %s\n", + error ? [[error description] UTF8String] : "No Error"); + fprintf(stdout, "Response: %d\n", status); + fprintf(stdout, "Result: %lu bytes\n%s\n", (unsigned long)[data length], + [result UTF8String]); + + [result release]; + [ul release]; + options->result = (!error && status == 200) ? kResultSuccess : kResultFailure; +} + +//============================================================================= +static void StartSymUploadProtocolV2(Options* options, + NSString* debugID, + NSString* debugFile) { + options->result = kResultFailure; + + // Only check status of BREAKPAD symbols, because the v2 protocol doesn't + // (yet) have a way to check status of other symbol types. + if (!options->force && [options->type isEqualToString:kBreakpadSymbolType]) { + SymbolStatus symbolStatus = + [SymbolCollectorClient checkSymbolStatusOnServer:options->uploadURLStr + withAPIKey:options->apiKey + withDebugFile:debugFile + withDebugID:debugID]; + if (symbolStatus == SymbolStatusFound) { + fprintf(stdout, "Symbol file already exists, upload aborted." + " Use \"-f\" to overwrite.\n"); + options->result = kResultAlreadyExists; + return; + } else if (symbolStatus == SymbolStatusUnknown) { + fprintf(stdout, "Failed to get check for existing symbol.\n"); + return; + } + } + + UploadURLResponse* URLResponse = + [SymbolCollectorClient createUploadURLOnServer:options->uploadURLStr + withAPIKey:options->apiKey]; + if (URLResponse == nil) { + return; + } + + NSURL* uploadURL = [NSURL URLWithString:[URLResponse uploadURL]]; + HTTPPutRequest* putRequest = [[HTTPPutRequest alloc] initWithURL:uploadURL]; + [putRequest setFile:options->symbolsPath]; + + NSError* error = nil; + NSData* data = [putRequest send:&error]; + NSString* result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + int responseCode = [[putRequest response] statusCode]; + [putRequest release]; + + if (error || responseCode != 200) { + fprintf(stdout, "Failed to upload symbol file.\n"); + fprintf(stdout, "Response code: %d\n", responseCode); + fprintf(stdout, "Response:\n"); + fprintf(stdout, "%s\n", [result UTF8String]); + return; + } + + CompleteUploadResult completeUploadResult = + [SymbolCollectorClient completeUploadOnServer:options->uploadURLStr + withAPIKey:options->apiKey + withUploadKey:[URLResponse uploadKey] + withDebugFile:debugFile + withDebugID:debugID + withType:options->type + withProductName:options->productName]; + [URLResponse release]; + if (completeUploadResult == CompleteUploadResultError) { + fprintf(stdout, "Failed to complete upload.\n"); + return; + } else if (completeUploadResult == CompleteUploadResultDuplicateData) { + fprintf(stdout, "Uploaded file checksum matched existing file checksum," + " no change necessary.\n"); + } else { + fprintf(stdout, "Successfully sent the symbol file.\n"); + } + options->result = kResultSuccess; +} + +//============================================================================= +static void Start(Options* options) { + // If non-BREAKPAD upload special-case. + if (![options->type isEqualToString:kBreakpadSymbolType]) { + StartSymUploadProtocolV2(options, options->debugID, options->codeFile); + return; + } + + NSArray* moduleParts = ModuleDataForSymbolFile(options->symbolsPath); + // MODULE <os> <cpu> <uuid> <module-name> + // 0 1 2 3 4 + NSString* OS = [moduleParts objectAtIndex:1]; + NSString* CPU = [moduleParts objectAtIndex:2]; + NSMutableString* debugID = + [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; + [debugID replaceOccurrencesOfString:@"-" + withString:@"" + options:0 + range:NSMakeRange(0, [debugID length])]; + NSString* debugFile = [moduleParts objectAtIndex:4]; + + if (options->symUploadProtocol == kSymUploadProtocolV1) { + StartSymUploadProtocolV1(options, OS, CPU, debugID, debugFile); + } else if (options->symUploadProtocol == kSymUploadProtocolV2) { + StartSymUploadProtocolV2(options, debugID, debugFile); + } +} + +//============================================================================= +static void Usage(int argc, const char* argv[]) { + fprintf(stderr, "Submit symbol information.\n"); + fprintf(stderr, "Usage: %s [options] <symbol-file> <upload-URL>\n", argv[0]); + fprintf(stderr, "<symbol-file> should be created by using the dump_syms " + "tool.\n"); + fprintf(stderr, "<upload-URL> is the destination for the upload.\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "\t-p <protocol>: protocol to use for upload, accepts " + "[\"sym-upload-v1\", \"sym-upload-v2\"]. Default is " + "\"sym-upload-v1\".\n"); + fprintf(stderr, "\t-k <api-key>: secret for authentication with upload " + "server. [Only in sym-upload-v2 protocol mode]\n"); + fprintf(stderr, "\t-f: Overwrite symbol file on server if already present. " + "[Only in sym-upload-v2 protocol mode]\n"); + fprintf( + stderr, + "\t-t: <symbol-type> Explicitly set symbol upload type (" + "default is 'breakpad').\n" + "\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', " + "'dsym', 'pdb'].\n" + "\t Note: When this flag is set to anything other than 'breakpad', then " + "the '-c' and '-i' flags must also be set.\n"); + fprintf(stderr, "\t-c: <code-file> Explicitly set 'code_file' for symbol " + "upload (basename of executable).\n"); + fprintf(stderr, "\t-i: <debug-id> Explicitly set 'debug_id' for symbol " + "upload (typically build ID of executable). The debug-id for " + "symbol-types 'dsym' and 'macho' will be determined " + "automatically. \n"); + fprintf(stderr, "\t-n: <product-name> Optionally set 'product_name' for " + "symbol upload\n"); + fprintf(stderr, "\t-h: Usage\n"); + fprintf(stderr, "\t-?: Usage\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Exit codes:\n"); + fprintf(stderr, "\t%d: Success\n", kResultSuccess); + fprintf(stderr, "\t%d: Failure\n", kResultFailure); + fprintf(stderr, + "\t%d: Symbol file already exists on server (and -f was not " + "specified).\n", + kResultAlreadyExists); + fprintf(stderr, + "\t [This exit code will only be returned by the sym-upload-v2 " + "protocol.\n"); + fprintf(stderr, + "\t The sym-upload-v1 protocol can return either Success or " + "Failure\n"); + fprintf(stderr, "\t in this case, and the action taken by the server is " + "unspecified.]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Examples:\n"); + fprintf(stderr, " With 'sym-upload-v1':\n"); + fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n", + argv[0]); + fprintf(stderr, " With 'sym-upload-v2':\n"); + fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n"); + fprintf(stderr, + " %s -p sym-upload-v2 -k mysecret123! " + "path/to/symbol_file http://myuploadserver\n", + argv[0]); + fprintf(stderr, " [Explicitly set symbol type to 'macho']\n"); + fprintf(stderr, + " %s -p sym-upload-v2 -k mysecret123! -t macho " + "-c app -i 11111111BBBB3333DDDD555555555555F " + "path/to/symbol_file http://myuploadserver\n", + argv[0]); +} + +//============================================================================= +static void SetupOptions(int argc, const char* argv[], Options* options) { + // Set default options values. + options->symUploadProtocol = kSymUploadProtocolV1; + options->apiKey = nil; + options->type = kBreakpadSymbolType; + options->codeFile = nil; + options->debugID = nil; + options->force = NO; + options->productName = nil; + + extern int optind; + int ch; + + while ((ch = getopt(argc, (char* const*)argv, "p:k:t:c:i:n:hf?")) != -1) { + switch (ch) { + case 'p': + if (strcmp(optarg, "sym-upload-v2") == 0) { + options->symUploadProtocol = kSymUploadProtocolV2; + break; + } else if (strcmp(optarg, "sym-upload-v1") == 0) { + // This is already the default but leave in case that changes. + options->symUploadProtocol = kSymUploadProtocolV1; + break; + } + Usage(argc, argv); + exit(0); + break; + case 'k': + options->apiKey = [NSString stringWithCString:optarg + encoding:NSASCIIStringEncoding]; + break; + case 't': { + // This is really an enum, so treat as upper-case for consistency with + // enum naming convention on server-side. + options->type = [[NSString stringWithCString:optarg + encoding:NSASCIIStringEncoding] + uppercaseString]; + break; + } + case 'c': + options->codeFile = [NSString stringWithCString:optarg + encoding:NSASCIIStringEncoding]; + break; + case 'i': + options->debugID = [NSString stringWithCString:optarg + encoding:NSASCIIStringEncoding]; + break; + case 'n': + options->productName = + [NSString stringWithCString:optarg + encoding:NSASCIIStringEncoding]; + break; + case 'f': + options->force = YES; + break; + default: + Usage(argc, argv); + exit(0); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + int fd = open(argv[optind], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + exit(1); + } + + struct stat statbuf; + if (fstat(fd, &statbuf) < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + close(fd); + exit(1); + } + close(fd); + + if (!S_ISREG(statbuf.st_mode)) { + fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]); + exit(1); + } + + bool isBreakpadUpload = [options->type isEqualToString:kBreakpadSymbolType]; + bool hasCodeFile = options->codeFile != nil; + bool hasDebugID = options->debugID != nil; + if (isBreakpadUpload && (hasCodeFile || hasDebugID)) { + fprintf(stderr, "\n"); + fprintf(stderr, + "%s: -c and -i should only be specified for non-breakpad " + "symbol upload types.\n", + argv[0]); + fprintf(stderr, "\n"); + Usage(argc, argv); + exit(1); + } + + if (!isBreakpadUpload && hasCodeFile && !hasDebugID && + ([options->type isEqualToString:kMachOSymbolType] || + [options->type isEqualToString:kDSYMSymbolType])) { + DumpSymbols dump_symbols(SYMBOLS_AND_FILES | INLINES, false); + if (dump_symbols.Read(argv[optind])) { + std::string identifier = dump_symbols.Identifier(); + if (identifier.empty()) { + fprintf(stderr, "\n"); + fprintf(stderr, + "%s: Unable to determine debug-id. Please specify with '-i'.\n", + argv[0]); + fprintf(stderr, "\n"); + Usage(argc, argv); + exit(1); + } + options->debugID = [NSString stringWithUTF8String:identifier.c_str()]; + hasDebugID = true; + } + } + + if (!isBreakpadUpload && (!hasCodeFile || !hasDebugID)) { + fprintf(stderr, "\n"); + fprintf(stderr, + "%s: -c and -i must be specified for non-breakpad " + "symbol upload types.\n", + argv[0]); + fprintf(stderr, "\n"); + Usage(argc, argv); + exit(1); + } + + options->symbolsPath = [NSString stringWithUTF8String:argv[optind]]; + options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]]; +} + +//============================================================================= +int main(int argc, const char* argv[]) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + Options options; + + bzero(&options, sizeof(Options)); + SetupOptions(argc, argv, &options); + Start(&options); + + [pool release]; + return options.result; +} diff --git a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj index a6a78dc5..903c66f1 100644 --- a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj +++ b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj @@ -7,9 +7,38 @@ objects = { /* Begin PBXBuildFile section */ + 5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */; }; + 5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */; }; + 5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */; }; + 5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */; }; + 5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */; }; + 5B97447524D0AA5F000C71F5 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B97447424D0AA5F000C71F5 /* encoding_util.m */; }; 8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; - 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.m */; settings = {ATTRIBUTES = (); }; }; + 8DD76F9A0486AA7600D96B5E /* symupload.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.mm */; settings = {ATTRIBUTES = (); }; }; 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 930DA19225ED543A008558E3 /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA19025ED543A008558E3 /* dump_syms.cc */; }; + 930DA22C25ED55A9008558E3 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA21F25ED55A8008558E3 /* module.cc */; }; + 930DA22D25ED55A9008558E3 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */; }; + 930DA22E25ED55A9008558E3 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22525ED55A8008558E3 /* stabs_to_module.cc */; }; + 930DA22F25ED55A9008558E3 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22625ED55A9008558E3 /* language.cc */; }; + 930DA23125ED55A9008558E3 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */; }; + 930DA23225ED55A9008558E3 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */; }; + 930DA23725ED55B6008558E3 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23625ED55B6008558E3 /* stabs_reader.cc */; }; + 930DA24225ED55BF008558E3 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23A25ED55BF008558E3 /* macho_id.cc */; }; + 930DA24325ED55BF008558E3 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23C25ED55BF008558E3 /* macho_utilities.cc */; }; + 930DA24425ED55BF008558E3 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23F25ED55BF008558E3 /* macho_reader.cc */; }; + 930DA24525ED55BF008558E3 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24125ED55BF008558E3 /* macho_walker.cc */; }; + 930DA25C25ED56DB008558E3 /* dwarf_range_list_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */; }; + 930DA25D25ED56DB008558E3 /* cfi_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */; }; + 930DA25E25ED56DB008558E3 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25225ED56DB008558E3 /* elf_reader.cc */; }; + 930DA25F25ED56DB008558E3 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */; }; + 930DA26025ED56DB008558E3 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25625ED56DB008558E3 /* dwarf2reader.cc */; }; + 930DA26125ED56DB008558E3 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25925ED56DB008558E3 /* bytereader.cc */; }; + 930DA26925ED56FF008558E3 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA26825ED56FF008558E3 /* test_assembler.cc */; }; + 930DA26E25ED571F008558E3 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA26D25ED571F008558E3 /* arch_utilities.cc */; }; + 930DA27825ED572D008558E3 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27125ED572C008558E3 /* path_helper.cc */; }; + 930DA27925ED572D008558E3 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27525ED572C008558E3 /* file_id.cc */; }; + 930DA27A25ED572D008558E3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27725ED572D008558E3 /* md5.cc */; }; 9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD836000B0544BA0055103E /* minidump_upload.m */; }; 9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */; }; 9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; }; @@ -30,16 +59,78 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = "<group>"; }; + 08FB7796FE84155DC02AAC07 /* symupload.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.objcpp; path = symupload.mm; sourceTree = "<group>"; tabWidth = 2; }; 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 5B6060BB222716FC0015F0A0 /* HTTPRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPRequest.h; path = ../../../common/mac/HTTPRequest.h; sourceTree = "<group>"; tabWidth = 2; }; + 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPRequest.m; path = ../../../common/mac/HTTPRequest.m; sourceTree = "<group>"; tabWidth = 2; }; + 5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HTTPPutRequest.h; path = ../../../common/mac/HTTPPutRequest.h; sourceTree = "<group>"; }; + 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPPutRequest.m; path = ../../../common/mac/HTTPPutRequest.m; sourceTree = "<group>"; tabWidth = 2; }; + 5B6060C22227303A0015F0A0 /* encoding_util.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = encoding_util.h; path = ../../../common/mac/encoding_util.h; sourceTree = "<group>"; tabWidth = 2; }; + 5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HTTPGetRequest.h; path = ../../../common/mac/HTTPGetRequest.h; sourceTree = "<group>"; }; + 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = HTTPGetRequest.m; path = ../../../common/mac/HTTPGetRequest.m; sourceTree = "<group>"; }; + 5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPSimplePostRequest.h; path = ../../../common/mac/HTTPSimplePostRequest.h; sourceTree = "<group>"; tabWidth = 2; }; + 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPSimplePostRequest.m; path = ../../../common/mac/HTTPSimplePostRequest.m; sourceTree = "<group>"; tabWidth = 2; }; + 5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SymbolCollectorClient.h; path = ../../../common/mac/SymbolCollectorClient.h; sourceTree = "<group>"; tabWidth = 2; }; + 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = SymbolCollectorClient.m; path = ../../../common/mac/SymbolCollectorClient.m; sourceTree = "<group>"; tabWidth = 2; }; + 5B97447424D0AA5F000C71F5 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = encoding_util.m; path = ../../../common/mac/encoding_util.m; sourceTree = "<group>"; }; 8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; 8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; }; - 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; }; - 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; }; + 930DA19025ED543A008558E3 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = "<group>"; }; + 930DA19125ED543A008558E3 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = "<group>"; }; + 930DA21F25ED55A8008558E3 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = "<group>"; }; + 930DA22025ED55A8008558E3 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = "<group>"; }; + 930DA22125ED55A8008558E3 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = "<group>"; }; + 930DA22225ED55A8008558E3 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = "<group>"; }; + 930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = "<group>"; }; + 930DA22425ED55A8008558E3 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = "<group>"; }; + 930DA22525ED55A8008558E3 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = "<group>"; }; + 930DA22625ED55A9008558E3 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = "<group>"; }; + 930DA22725ED55A9008558E3 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = "<group>"; }; + 930DA22825ED55A9008558E3 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = "<group>"; }; + 930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = "<group>"; }; + 930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = "<group>"; }; + 930DA23525ED55B6008558E3 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = "<group>"; }; + 930DA23625ED55B6008558E3 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = "<group>"; }; + 930DA23A25ED55BF008558E3 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = "<group>"; }; + 930DA23B25ED55BF008558E3 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = "<group>"; }; + 930DA23C25ED55BF008558E3 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = "<group>"; }; + 930DA23D25ED55BF008558E3 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = "<group>"; }; + 930DA23E25ED55BF008558E3 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = "<group>"; }; + 930DA23F25ED55BF008558E3 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = "<group>"; }; + 930DA24025ED55BF008558E3 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = "<group>"; }; + 930DA24125ED55BF008558E3 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = "<group>"; }; + 930DA24C25ED56DB008558E3 /* line_state_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = line_state_machine.h; path = ../../../common/dwarf/line_state_machine.h; sourceTree = "<group>"; }; + 930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_range_list_handler.cc; path = ../../../common/dwarf_range_list_handler.cc; sourceTree = "<group>"; }; + 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_assembler.cc; path = ../../../common/dwarf/cfi_assembler.cc; sourceTree = "<group>"; }; + 930DA24F25ED56DB008558E3 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = "<group>"; }; + 930DA25025ED56DB008558E3 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = "<group>"; }; + 930DA25125ED56DB008558E3 /* dwarf_range_list_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_range_list_handler.h; path = ../../../common/dwarf_range_list_handler.h; sourceTree = "<group>"; }; + 930DA25225ED56DB008558E3 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; }; + 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = "<group>"; }; + 930DA25425ED56DB008558E3 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; }; + 930DA25525ED56DB008558E3 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = "<group>"; }; + 930DA25625ED56DB008558E3 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = "<group>"; }; + 930DA25725ED56DB008558E3 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = "<group>"; }; + 930DA25825ED56DB008558E3 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = "<group>"; }; + 930DA25925ED56DB008558E3 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = "<group>"; }; + 930DA25A25ED56DB008558E3 /* cfi_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cfi_assembler.h; path = ../../../common/dwarf/cfi_assembler.h; sourceTree = "<group>"; }; + 930DA26725ED56FF008558E3 /* test_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_assembler.h; path = ../../../common/test_assembler.h; sourceTree = "<group>"; }; + 930DA26825ED56FF008558E3 /* test_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler.cc; path = ../../../common/test_assembler.cc; sourceTree = "<group>"; }; + 930DA26C25ED571F008558E3 /* arch_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; }; + 930DA26D25ED571F008558E3 /* arch_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; }; + 930DA27125ED572C008558E3 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; }; + 930DA27225ED572C008558E3 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = "<group>"; }; + 930DA27325ED572C008558E3 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; }; + 930DA27425ED572C008558E3 /* byte_cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byte_cursor.h; path = ../../../common/byte_cursor.h; sourceTree = "<group>"; }; + 930DA27525ED572C008558E3 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = "<group>"; }; + 930DA27625ED572C008558E3 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = "<group>"; }; + 930DA27725ED572D008558E3 /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = md5.cc; path = ../../../common/md5.cc; sourceTree = "<group>"; }; + 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; tabWidth = 2; }; + 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; tabWidth = 2; }; 9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; }; - 9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = minidump_upload.m; sourceTree = "<group>"; }; + 9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = minidump_upload.m; path = ../../../common/mac/minidump_upload.m; sourceTree = "<group>"; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -65,10 +156,23 @@ 08FB7794FE84155DC02AAC07 /* symupload */ = { isa = PBXGroup; children = ( + 930DA21E25ED5586008558E3 /* dump_syms */, + 5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */, + 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */, + 5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */, + 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */, + 5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */, + 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */, + 5B6060C22227303A0015F0A0 /* encoding_util.h */, + 5B97447424D0AA5F000C71F5 /* encoding_util.m */, + 5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */, + 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */, + 5B6060BB222716FC0015F0A0 /* HTTPRequest.h */, + 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */, 8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */, 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */, 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */, - 08FB7796FE84155DC02AAC07 /* symupload.m */, + 08FB7796FE84155DC02AAC07 /* symupload.mm */, 9BD836000B0544BA0055103E /* minidump_upload.m */, 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */, 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */, @@ -95,6 +199,63 @@ name = Products; sourceTree = "<group>"; }; + 930DA21E25ED5586008558E3 /* dump_syms */ = { + isa = PBXGroup; + children = ( + 930DA23A25ED55BF008558E3 /* macho_id.cc */, + 930DA23B25ED55BF008558E3 /* macho_id.h */, + 930DA23F25ED55BF008558E3 /* macho_reader.cc */, + 930DA23E25ED55BF008558E3 /* macho_reader.h */, + 930DA23C25ED55BF008558E3 /* macho_utilities.cc */, + 930DA24025ED55BF008558E3 /* macho_utilities.h */, + 930DA24125ED55BF008558E3 /* macho_walker.cc */, + 930DA23D25ED55BF008558E3 /* macho_walker.h */, + 930DA19025ED543A008558E3 /* dump_syms.cc */, + 930DA19125ED543A008558E3 /* dump_syms.h */, + 930DA23625ED55B6008558E3 /* stabs_reader.cc */, + 930DA23525ED55B6008558E3 /* stabs_reader.h */, + 930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */, + 930DA22125ED55A8008558E3 /* dwarf_cfi_to_module.h */, + 930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */, + 930DA22225ED55A8008558E3 /* dwarf_cu_to_module.h */, + 930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */, + 930DA22725ED55A9008558E3 /* dwarf_line_to_module.h */, + 930DA22625ED55A9008558E3 /* language.cc */, + 930DA22425ED55A8008558E3 /* language.h */, + 930DA21F25ED55A8008558E3 /* module.cc */, + 930DA22025ED55A8008558E3 /* module.h */, + 930DA22525ED55A8008558E3 /* stabs_to_module.cc */, + 930DA22825ED55A9008558E3 /* stabs_to_module.h */, + 930DA25025ED56DB008558E3 /* bytereader-inl.h */, + 930DA25925ED56DB008558E3 /* bytereader.cc */, + 930DA25525ED56DB008558E3 /* bytereader.h */, + 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */, + 930DA25A25ED56DB008558E3 /* cfi_assembler.h */, + 930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */, + 930DA25125ED56DB008558E3 /* dwarf_range_list_handler.h */, + 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */, + 930DA25825ED56DB008558E3 /* dwarf2diehandler.h */, + 930DA24F25ED56DB008558E3 /* dwarf2enums.h */, + 930DA25625ED56DB008558E3 /* dwarf2reader.cc */, + 930DA25725ED56DB008558E3 /* dwarf2reader.h */, + 930DA25225ED56DB008558E3 /* elf_reader.cc */, + 930DA25425ED56DB008558E3 /* elf_reader.h */, + 930DA24C25ED56DB008558E3 /* line_state_machine.h */, + 930DA26825ED56FF008558E3 /* test_assembler.cc */, + 930DA26725ED56FF008558E3 /* test_assembler.h */, + 930DA26D25ED571F008558E3 /* arch_utilities.cc */, + 930DA26C25ED571F008558E3 /* arch_utilities.h */, + 930DA27425ED572C008558E3 /* byte_cursor.h */, + 930DA27225ED572C008558E3 /* byteswap.h */, + 930DA27525ED572C008558E3 /* file_id.cc */, + 930DA27625ED572C008558E3 /* file_id.h */, + 930DA27725ED572D008558E3 /* md5.cc */, + 930DA27125ED572C008558E3 /* path_helper.cc */, + 930DA27325ED572C008558E3 /* path_helper.h */, + ); + name = dump_syms; + sourceTree = "<group>"; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -137,9 +298,15 @@ /* Begin PBXProject section */ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; + attributes = { + }; buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */; compatibilityVersion = "Xcode 3.1"; + developmentRegion = en; hasScannedForEncodings = 1; + knownRegions = ( + en, + ); mainGroup = 08FB7794FE84155DC02AAC07 /* symupload */; projectDirPath = ""; projectRoot = ""; @@ -155,8 +322,37 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */, + 8DD76F9A0486AA7600D96B5E /* symupload.mm in Sources */, + 930DA19225ED543A008558E3 /* dump_syms.cc in Sources */, + 930DA24525ED55BF008558E3 /* macho_walker.cc in Sources */, + 930DA22E25ED55A9008558E3 /* stabs_to_module.cc in Sources */, + 5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */, + 930DA25F25ED56DB008558E3 /* dwarf2diehandler.cc in Sources */, + 930DA27825ED572D008558E3 /* path_helper.cc in Sources */, + 930DA27A25ED572D008558E3 /* md5.cc in Sources */, + 930DA22D25ED55A9008558E3 /* dwarf_cfi_to_module.cc in Sources */, + 930DA24425ED55BF008558E3 /* macho_reader.cc in Sources */, + 930DA24325ED55BF008558E3 /* macho_utilities.cc in Sources */, + 5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */, + 5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */, + 930DA27925ED572D008558E3 /* file_id.cc in Sources */, + 930DA26925ED56FF008558E3 /* test_assembler.cc in Sources */, + 930DA22F25ED55A9008558E3 /* language.cc in Sources */, + 930DA25E25ED56DB008558E3 /* elf_reader.cc in Sources */, + 930DA26E25ED571F008558E3 /* arch_utilities.cc in Sources */, + 930DA24225ED55BF008558E3 /* macho_id.cc in Sources */, + 5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */, + 930DA25C25ED56DB008558E3 /* dwarf_range_list_handler.cc in Sources */, + 5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */, + 930DA25D25ED56DB008558E3 /* cfi_assembler.cc in Sources */, + 930DA23225ED55A9008558E3 /* dwarf_cu_to_module.cc in Sources */, + 930DA23125ED55A9008558E3 /* dwarf_line_to_module.cc in Sources */, + 930DA26125ED56DB008558E3 /* bytereader.cc in Sources */, + 930DA22C25ED55A9008558E3 /* module.cc in Sources */, + 5B97447524D0AA5F000C71F5 /* encoding_util.m in Sources */, + 930DA23725ED55B6008558E3 /* stabs_reader.cc in Sources */, 9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */, + 930DA26025ED56DB008558E3 /* dwarf2reader.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -175,7 +371,13 @@ 1DEB927508733DD40010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ../../..; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include, + ../../../third_party/musl/include/, + ); PRODUCT_NAME = symupload; }; name = Debug; @@ -183,7 +385,17 @@ 1DEB927608733DD40010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - HEADER_SEARCH_PATHS = ../../..; + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + NDEBUG, + HAVE_MACH_O_NLIST_H, + ); + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include, + ../../../third_party/musl/include/, + ); PRODUCT_NAME = symupload; }; name = Release; diff --git a/src/tools/mac/tools_mac.gypi b/src/tools/mac/tools_mac.gypi deleted file mode 100644 index 7457573b..00000000 --- a/src/tools/mac/tools_mac.gypi +++ /dev/null @@ -1,116 +0,0 @@ -# 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.cc', - ], - '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', - ], - }, - ], -} diff --git a/src/tools/mac/upload_system_symbols/arch_constants.h b/src/tools/mac/upload_system_symbols/arch_constants.h index e12e53e2..b6dbc89a 100644 --- a/src/tools/mac/upload_system_symbols/arch_constants.h +++ b/src/tools/mac/upload_system_symbols/arch_constants.h @@ -1,5 +1,4 @@ -/* Copyright 2014, Google Inc. -All rights reserved. +/* Copyright 2014 Google LLC Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer. 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 + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/tools/mac/upload_system_symbols/arch_reader.go b/src/tools/mac/upload_system_symbols/arch_reader.go index ed98fa60..03a76421 100644 --- a/src/tools/mac/upload_system_symbols/arch_reader.go +++ b/src/tools/mac/upload_system_symbols/arch_reader.go @@ -1,5 +1,4 @@ -/* Copyright 2014, Google Inc. -All rights reserved. +/* Copyright 2014 Google LLC Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer. 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 + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/tools/mac/upload_system_symbols/go.mod b/src/tools/mac/upload_system_symbols/go.mod new file mode 100644 index 00000000..ff21bba9 --- /dev/null +++ b/src/tools/mac/upload_system_symbols/go.mod @@ -0,0 +1,3 @@ +module upload_system_symbols + +go 1.17 diff --git a/src/tools/mac/upload_system_symbols/upload_system_symbols.go b/src/tools/mac/upload_system_symbols/upload_system_symbols.go index 05a7764a..ba067276 100644 --- a/src/tools/mac/upload_system_symbols/upload_system_symbols.go +++ b/src/tools/mac/upload_system_symbols/upload_system_symbols.go @@ -1,5 +1,4 @@ -/* Copyright 2014, Google Inc. -All rights reserved. +/* Copyright 2014 Google LLC Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer. 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 + * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -64,12 +63,12 @@ var ( dumpOnlyPath = flag.String("dump-to", "", "Dump the symbols to the specified directory, but do not upload them.") systemRoot = flag.String("system-root", "", "Path to the root of the Mac OS X system whose symbols will be dumped.") dumpArchitecture = flag.String("arch", "", "The CPU architecture for which symbols should be dumped. If not specified, dumps all architectures.") + apiKey = flag.String("api-key", "", "API key to use. If this is present, the `sym-upload-v2` protocol is used.\nSee https://chromium.googlesource.com/breakpad/breakpad/+/HEAD/docs/sym_upload_v2_protocol.md or\n`symupload`'s help for more information.") ) var ( // pathsToScan are the subpaths in the systemRoot that should be scanned for shared libraries. pathsToScan = []string{ - "/System/Library/Components", "/System/Library/Frameworks", "/System/Library/PrivateFrameworks", "/usr/lib", @@ -79,13 +78,26 @@ var ( optionalPathsToScan = []string{ // Gone in 10.15. "/Library/QuickTime", + // Not present in dumped dyld_shared_caches + "/System/Library/Components", } - // uploadServers are the list of servers to which symbols should be uploaded. - uploadServers = []string{ + // uploadServersV1 are the list of servers to which symbols should be + // uploaded when using the V1 protocol. + uploadServersV1 = []string{ "https://clients2.google.com/cr/symbol", "https://clients2.google.com/cr/staging_symbol", } + // uploadServersV2 are the list of servers to which symbols should be + // uploaded when using the V2 protocol. + uploadServersV2 = []string{ + "https://staging-crashsymbolcollector-pa.googleapis.com", + "https://prod-crashsymbolcollector-pa.googleapis.com", + } + + // uploadServers are the list of servers that should be used, accounting + // for whether v1 or v2 protocol is used. + uploadServers = uploadServersV1 // blacklistRegexps match paths that should be excluded from dumping. blacklistRegexps = []*regexp.Regexp{ @@ -102,6 +114,11 @@ func main() { flag.Parse() log.SetFlags(0) + // If `apiKey` is set, we're using the v2 protocol. + if len(*apiKey) > 0 { + uploadServers = uploadServersV2 + } + var uq *UploadQueue if *uploadOnlyPath != "" { @@ -195,17 +212,29 @@ func (uq *UploadQueue) Done() { close(uq.queue) } -func (uq *UploadQueue) worker() { +func (uq *UploadQueue) runSymUpload(symfile, server string) *exec.Cmd { symUpload := path.Join(*breakpadTools, "symupload") + args := []string{symfile, server} + if len(*apiKey) > 0 { + args = append([]string{"-p", "sym-upload-v2", "-k", *apiKey}, args...) + } + return exec.Command(symUpload, args...) +} +func (uq *UploadQueue) worker() { for symfile := range uq.queue { for _, server := range uploadServers { for i := 0; i < 3; i++ { // Give each upload 3 attempts to succeed. - cmd := exec.Command(symUpload, symfile, server) + cmd := uq.runSymUpload(symfile, server) if output, err := cmd.Output(); err == nil { // Success. No retry needed. fmt.Printf("Uploaded %s to %s\n", symfile, server) break + } else if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == 2 && *apiKey != "" { + // Exit code 2 in protocol v2 means the file already exists on the server. + // No point retrying. + fmt.Printf("File %s already exists on %s\n", symfile, server) + break } else { log.Printf("Error running symupload(%s, %s), attempt %d: %v: %s\n", symfile, server, i, err, output) time.Sleep(1 * time.Second) diff --git a/src/tools/python/deps-to-manifest.py b/src/tools/python/deps-to-manifest.py index b4562854..2fcaf771 100755 --- a/src/tools/python/deps-to-manifest.py +++ b/src/tools/python/deps-to-manifest.py @@ -1,6 +1,5 @@ #!/usr/bin/python -# Copyright 2016 Google Inc. -# All rights reserved. +# Copyright 2016 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -12,7 +11,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # @@ -49,7 +48,7 @@ MANIFEST_HEAD = """<?xml version='1.0' encoding='UTF-8'?> <!-- AUTOGENERATED BY %(prog)s; DO NOT EDIT --> <manifest> - <default revision='refs/heads/master' + <default revision='refs/heads/main' remote='chromium' sync-c='true' sync-j='8' /> @@ -100,7 +99,7 @@ def ConvertDepsToManifest(deps, manifest): data = { 'path': 'src', 'name': 'breakpad/breakpad', - 'revision': 'refs/heads/master', + 'revision': 'refs/heads/main', 'remote': 'chromium', } new_contents += MANIFEST_PROJECT % data diff --git a/src/tools/python/filter_syms.py b/src/tools/python/filter_syms.py index abddf789..caf3693a 100644 --- a/src/tools/python/filter_syms.py +++ b/src/tools/python/filter_syms.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 Google Inc. -# All rights reserved. +# Copyright 2012 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -12,7 +11,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/tools/python/tests/filter_syms_unittest.py b/src/tools/python/tests/filter_syms_unittest.py index b111f349..1081fc73 100644 --- a/src/tools/python/tests/filter_syms_unittest.py +++ b/src/tools/python/tests/filter_syms_unittest.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2012 Google Inc. -# All rights reserved. +# Copyright 2012 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -12,7 +11,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/tools/solaris/dump_syms/Makefile b/src/tools/solaris/dump_syms/Makefile index ff77105c..c5f48240 100644 --- a/src/tools/solaris/dump_syms/Makefile +++ b/src/tools/solaris/dump_syms/Makefile @@ -1,5 +1,4 @@ -# Copyright (c) 2007, Google Inc. -# All rights reserved. +# Copyright 2007 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/tools/solaris/dump_syms/dump_syms.cc b/src/tools/solaris/dump_syms/dump_syms.cc index 54cea57e..fc331c21 100644 --- a/src/tools/solaris/dump_syms/dump_syms.cc +++ b/src/tools/solaris/dump_syms/dump_syms.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -36,13 +35,13 @@ using namespace google_breakpad; -int main(int argc, char **argv) { +int main(int argc, char** argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <binary-with-stab-symbol>\n", argv[0]); return 1; } - const char *binary = argv[1]; + const char* binary = argv[1]; DumpSymbols dumper; if (!dumper.WriteSymbolFile(binary, fileno(stdout))) { diff --git a/src/tools/solaris/dump_syms/run_regtest.sh b/src/tools/solaris/dump_syms/run_regtest.sh index ffb34330..27710d9a 100644 --- a/src/tools/solaris/dump_syms/run_regtest.sh +++ b/src/tools/solaris/dump_syms/run_regtest.sh @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2007, Google Inc. -# All rights reserved. +# Copyright 2007 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc b/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc index e617a23b..b4d191bd 100644 --- a/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc +++ b/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -41,7 +40,7 @@ class C { void f() { member_ = g(); } virtual int g() { return 2; } - static char* h(const C &that) { return 0; } + static char* h(const C& that) { return 0; } private: int member_; @@ -53,12 +52,12 @@ static int i() { } // namespace google_breakpad -int main(int argc, char **argv) { +int main(int argc, char** argv) { google_breakpad::C object; object.set_member(google_breakpad::i()); object.f(); int value = object.g(); - char *nothing = object.h(object); + char* nothing = object.h(object); return 0; } diff --git a/src/tools/tools.gyp b/src/tools/tools.gyp deleted file mode 100644 index e6a4210f..00000000 --- a/src/tools/tools.gyp +++ /dev/null @@ -1,38 +0,0 @@ -# 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'], - }], - ], -} diff --git a/src/tools/windows/converter/ms_symbol_server_converter.cc b/src/tools/windows/converter/ms_symbol_server_converter.cc index 2b40faee..bfe46925 100644 --- a/src/tools/windows/converter/ms_symbol_server_converter.cc +++ b/src/tools/windows/converter/ms_symbol_server_converter.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -92,7 +91,7 @@ namespace google_breakpad { #endif // _MSC_VER >= 1400 bool GUIDOrSignatureIdentifier::InitializeFromString( - const string &identifier) { + const string& identifier) { type_ = TYPE_NONE; size_t length = identifier.length(); @@ -128,11 +127,15 @@ bool GUIDOrSignatureIdentifier::InitializeFromString( #undef SSCANF MSSymbolServerConverter::MSSymbolServerConverter( - const string &local_cache, const vector<string> &symbol_servers) + const string& local_cache, + const vector<string>& symbol_servers, + bool trace_symsrv) : symbol_path_(), fail_dns_(false), fail_timeout_(false), - fail_not_found_(false) { + fail_http_https_redir_(false), + fail_not_found_(false), + trace_symsrv_(trace_symsrv) { // Setting local_cache can be done without verifying that it exists because // SymSrv will create it if it is missing - any creation failures will occur // at that time, so there's nothing to check here, making it safe to @@ -184,7 +187,7 @@ class AutoSymSrv { } } - bool Initialize(HANDLE process, char *path, bool invade_process) { + bool Initialize(HANDLE process, char* path, bool invade_process) { process_ = process; // TODO(nbilling): Figure out why dbghelp.dll is being loaded from @@ -240,7 +243,7 @@ class AutoSymSrv { // are supported by calling Delete(). class AutoDeleter { public: - explicit AutoDeleter(const string &path) : path_(path) {} + explicit AutoDeleter(const string& path) : path_(path) {} ~AutoDeleter() { int error; @@ -270,10 +273,10 @@ class AutoDeleter { }; MSSymbolServerConverter::LocateResult -MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, - const string &debug_or_code_id, - const string &version, - string *file_name) { +MSSymbolServerConverter::LocateFile(const string& debug_or_code_file, + const string& debug_or_code_id, + const string& version, + string* file_name) { assert(file_name); file_name->clear(); @@ -290,7 +293,7 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, HANDLE process = GetCurrentProcess(); // CloseHandle is not needed. AutoSymSrv symsrv; if (!symsrv.Initialize(process, - const_cast<char *>(symbol_path_.c_str()), + const_cast<char*>(symbol_path_.c_str()), false)) { fprintf(stderr, "LocateFile: SymInitialize: error %lu for %s %s %s\n", GetLastError(), @@ -326,8 +329,8 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, char path[MAX_PATH]; if (!SymFindFileInPath( process, NULL, - const_cast<char *>(debug_or_code_file.c_str()), - const_cast<void *>(identifier.guid_or_signature_pointer()), + const_cast<char*>(debug_or_code_file.c_str()), + const_cast<void*>(identifier.guid_or_signature_pointer()), identifier.age(), 0, identifier.type() == GUIDOrSignatureIdentifier::TYPE_GUID ? SSRVOPT_GUIDPTR : SSRVOPT_DWORDPTR, @@ -342,6 +345,10 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, return LOCATE_RETRY; } + if (fail_http_https_redir_) { + return LOCATE_HTTP_HTTPS_REDIR; + } + // This is an authoritiative file-not-found message. if (fail_not_found_) { fprintf(stderr, @@ -393,15 +400,15 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, MSSymbolServerConverter::LocateResult -MSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo &missing, - string *pe_file) { +MSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo& missing, + string* pe_file) { return LocateFile(missing.code_file, missing.code_identifier, missing.version, pe_file); } MSSymbolServerConverter::LocateResult -MSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo &missing, - string *symbol_file) { +MSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo& missing, + string* symbol_file) { return LocateFile(missing.debug_file, missing.debug_identifier, missing.version, symbol_file); } @@ -412,51 +419,58 @@ BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process, ULONG action, ULONG64 data, ULONG64 context) { - MSSymbolServerConverter *self = - reinterpret_cast<MSSymbolServerConverter *>(context); + MSSymbolServerConverter* self = + reinterpret_cast<MSSymbolServerConverter*>(context); switch (action) { case CBA_EVENT: { - IMAGEHLP_CBA_EVENT *cba_event = - reinterpret_cast<IMAGEHLP_CBA_EVENT *>(data); + IMAGEHLP_CBA_EVENT* cba_event = + reinterpret_cast<IMAGEHLP_CBA_EVENT*>(data); // Put the string into a string object to be able to use string::find // for substring matching. This is important because the not-found // message does not use the entire string but is appended to the URL // that SymSrv attempted to retrieve. string desc(cba_event->desc); + if (self->trace_symsrv_) { + fprintf(stderr, "LocateFile: SymCallback: action desc '%s'\n", + desc.c_str()); + } // desc_action maps strings (in desc) to boolean pointers that are to // be set to true if the string matches. struct desc_action { - const char *desc; // The substring to match. - bool *action; // On match, this pointer will be set to true. + const char* desc; // The substring to match. + bool* action; // On match, this pointer will be set to true. }; static const desc_action desc_actions[] = { - // When a DNS error occurs, it could be indiciative of network - // problems. - { "SYMSRV: The server name or address could not be resolved\n", - &self->fail_dns_ }, - - // This message is produced if no connection is opened. - { "SYMSRV: A connection with the server could not be established\n", - &self->fail_timeout_ }, - - // This message is produced if a connection is established but the - // server fails to respond to the HTTP request. - { "SYMSRV: The operation timed out\n", - &self->fail_timeout_ }, - - // This message is produced when the requested file is not found, - // even if one or more of the above messages are also produced. - // It's trapped to distinguish between not-found and unknown-failure - // conditions. Note that this message will not be produced if a - // connection is established and the server begins to respond to the - // HTTP request but does not finish transmitting the file. - { " not found\n", - &self->fail_not_found_ } - }; + // When a DNS error occurs, it could be indiciative of network + // problems. + {"SYMSRV: The server name or address could not be resolved\n", + &self->fail_dns_}, + + // This message is produced if no connection is opened. + {"SYMSRV: A connection with the server could not be established\n", + &self->fail_timeout_}, + + // This message is produced if a connection is established but the + // server fails to respond to the HTTP request. + {"SYMSRV: The operation timed out\n", &self->fail_timeout_}, + + // This message is produced if the server is redirecting us from http + // to https. When this happens SymSrv will fail and we need to use + // the https URL in our call-- we've made a mistake. + {"ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR\n", + &self->fail_http_https_redir_}, + + // This message is produced when the requested file is not found, + // even if one or more of the above messages are also produced. + // It's trapped to distinguish between not-found and unknown-failure + // conditions. Note that this message will not be produced if a + // connection is established and the server begins to respond to the + // HTTP request but does not finish transmitting the file. + {" not found\n", &self->fail_not_found_}}; for (int desc_action_index = 0; desc_action_index < @@ -478,7 +492,7 @@ BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process, // static BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback( - const char *filename, void *context) { + const char* filename, void* context) { // FALSE ends the search, indicating that the located symbol file is // satisfactory. return FALSE; @@ -486,12 +500,12 @@ BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback( MSSymbolServerConverter::LocateResult MSSymbolServerConverter::LocateAndConvertSymbolFile( - const MissingSymbolInfo &missing, + const MissingSymbolInfo& missing, bool keep_symbol_file, bool keep_pe_file, - string *converted_symbol_file, - string *symbol_file, - string *out_pe_file) { + string* converted_symbol_file, + string* symbol_file, + string* out_pe_file) { assert(converted_symbol_file); converted_symbol_file->clear(); if (symbol_file) { @@ -580,7 +594,7 @@ MSSymbolServerConverter::LocateAndConvertSymbolFile( *converted_symbol_file = pdb_file.substr(0, pdb_file.length() - 4) + ".sym"; - FILE *converted_output = NULL; + FILE* converted_output = NULL; #if _MSC_VER >= 1400 // MSVC 2005/8 errno_t err; if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w")) @@ -634,10 +648,10 @@ MSSymbolServerConverter::LocateAndConvertSymbolFile( MSSymbolServerConverter::LocateResult MSSymbolServerConverter::LocateAndConvertPEFile( - const MissingSymbolInfo &missing, + const MissingSymbolInfo& missing, bool keep_pe_file, - string *converted_symbol_file, - string *out_pe_file) { + string* converted_symbol_file, + string* out_pe_file) { assert(converted_symbol_file); converted_symbol_file->clear(); @@ -676,7 +690,7 @@ MSSymbolServerConverter::LocateAndConvertPEFile( *converted_symbol_file = pe_file.substr(0, pe_file.length() - 4) + ".sym"; - FILE *converted_output = NULL; + FILE* converted_output = NULL; #if _MSC_VER >= 1400 // MSVC 2005/8 errno_t err; if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w")) diff --git a/src/tools/windows/converter/ms_symbol_server_converter.gyp b/src/tools/windows/converter/ms_symbol_server_converter.gyp deleted file mode 100644 index 57ec7906..00000000 --- a/src/tools/windows/converter/ms_symbol_server_converter.gyp +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 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': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'ms_symbol_server_converter', - 'type': 'static_library', - 'msvs_guid': '1463C4CD-23FC-4DE9-BFDE-283338200157', - 'sources': [ - 'ms_symbol_server_converter.cc', - ], - 'dependencies': [ - '../../../common/windows/common_windows.gyp:common_windows_lib', - ], - }, - ], -} diff --git a/src/tools/windows/converter/ms_symbol_server_converter.h b/src/tools/windows/converter/ms_symbol_server_converter.h index 401f7c34..ffdea7c0 100644 --- a/src/tools/windows/converter/ms_symbol_server_converter.h +++ b/src/tools/windows/converter/ms_symbol_server_converter.h @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -101,13 +100,13 @@ class GUIDOrSignatureIdentifier { // component fields: either a GUID and age, or signature and age. If // successful, sets the relevant fields in the object, including the type // field, and returns true. On error, returns false. - bool InitializeFromString(const string &identifier); + bool InitializeFromString(const string& identifier); GUIDOrSignatureType type() const { return type_; } GUID guid() const { return guid_; } DWORD signature() const { return signature_; } int age() const { return age_; } - const void *guid_or_signature_pointer() const { return &guid_; } + const void* guid_or_signature_pointer() const { return &guid_; } private: GUIDOrSignatureType type_; @@ -127,9 +126,10 @@ class MSSymbolServerConverter { public: enum LocateResult { LOCATE_FAILURE = 0, - LOCATE_NOT_FOUND, // Authoritative: the file is not present. - LOCATE_RETRY, // Transient (network?) error, try again later. - LOCATE_SUCCESS + LOCATE_NOT_FOUND, // Authoritative: the file is not present. + LOCATE_RETRY, // Transient (network?) error, try again later. + LOCATE_SUCCESS, + LOCATE_HTTP_HTTPS_REDIR }; // Create a new object. local_cache is the location (pathname) of a local @@ -141,23 +141,26 @@ class MSSymbolServerConverter { // store to try. The vector must contain at least one string. None of the // strings passed to this constructor may contain asterisk ('*') or semicolon // (';') characters, as the symbol engine uses these characters as separators. - MSSymbolServerConverter(const string &local_cache, - const vector<string> &symbol_servers); + // If |trace_symsrv| is set then callbacks from SymSrv will be logged to + // stderr. + MSSymbolServerConverter(const string& local_cache, + const vector<string>& symbol_servers, + bool trace_symsrv); // Locates the PE file (DLL or EXE) specified by the identifying information // in |missing|, by checking the symbol stores identified when the object // was created. When returning LOCATE_SUCCESS, pe_file is set to // the pathname of the decompressed PE file as it is stored in the // local cache. - LocateResult LocatePEFile(const MissingSymbolInfo &missing, string *pe_file); + LocateResult LocatePEFile(const MissingSymbolInfo& missing, string* pe_file); // Locates the symbol file specified by the identifying information in // |missing|, by checking the symbol stores identified when the object // was created. When returning LOCATE_SUCCESS, symbol_file is set to // the pathname of the decompressed symbol file as it is stored in the // local cache. - LocateResult LocateSymbolFile(const MissingSymbolInfo &missing, - string *symbol_file); + LocateResult LocateSymbolFile(const MissingSymbolInfo& missing, + string* symbol_file); // Calls LocateSymbolFile and converts the returned symbol file to the // dumped-symbol format, storing it adjacent to the symbol file. The @@ -170,12 +173,12 @@ class MSSymbolServerConverter { // is desired, set |keep_symbol_file| and |keep_pe_file| to false to indicate // that the original symbol file (pdb) and executable file (exe, dll) should // be deleted after conversion. - LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo &missing, + LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo& missing, bool keep_symbol_file, bool keep_pe_file, - string *converted_symbol_file, - string *symbol_file, - string *pe_file); + string* converted_symbol_file, + string* symbol_file, + string* pe_file); // Calls LocatePEFile and converts the returned PE file to the // dumped-symbol format, storing it adjacent to the PE file. The @@ -188,10 +191,10 @@ class MSSymbolServerConverter { // to false to indicate that the executable file (exe, dll) should be deleted // after conversion. // NOTE: Currrently only supports x64 PEs. - LocateResult LocateAndConvertPEFile(const MissingSymbolInfo &missing, - bool keep_pe_file, - string *converted_symbol_file, - string *pe_file); + LocateResult LocateAndConvertPEFile(const MissingSymbolInfo& missing, + bool keep_pe_file, + string* converted_symbol_file, + string* pe_file); private: // Locates the PDB or PE file (DLL or EXE) specified by the identifying @@ -199,9 +202,9 @@ class MSSymbolServerConverter { // the symbol stores identified when the object was created. When // returning LOCATE_SUCCESS, file_name is set to the pathname of the // decompressed PDB or PE file file as it is stored in the local cache. - LocateResult LocateFile(const string &debug_or_code_file, - const string &debug_or_code_id, - const string &version, string *file_name); + LocateResult LocateFile(const string& debug_or_code_file, + const string& debug_or_code_id, + const string& version, string* file_name); // Called by various SymSrv functions to report status as progress is made // and to allow the callback to influence processing. Messages sent to this @@ -215,8 +218,8 @@ class MSSymbolServerConverter { // SymFindFileInPath actually seems to accept NULL for a callback function // and behave properly for our needs in that case, but the documentation // doesn't mention it, so this little callback is provided. - static BOOL CALLBACK SymFindFileInPathCallback(const char *filename, - void *context); + static BOOL CALLBACK SymFindFileInPathCallback(const char* filename, + void* context); // The search path used by SymSrv, built based on the arguments to the // constructor. @@ -226,8 +229,12 @@ class MSSymbolServerConverter { // SymFindFileInPath fails for an expected reason. bool fail_dns_; // DNS failures (fail_not_found_ will also be set). bool fail_timeout_; // Timeouts (fail_not_found_ will also be set). + bool fail_http_https_redir_; // Bad URL-- we should be using HTTPS. bool fail_not_found_; // The file could not be found. If this is the only // fail_* member set, then it is authoritative. + + // If set then callbacks from SymSrv will be logged to stderr. + bool trace_symsrv_; }; } // namespace google_breakpad diff --git a/src/tools/windows/converter_exe/converter.cc b/src/tools/windows/converter_exe/converter.cc index 5b70903a..75ec55b0 100644 --- a/src/tools/windows/converter_exe/converter.cc +++ b/src/tools/windows/converter_exe/converter.cc @@ -1,807 +1,904 @@ -// Copyright 2019 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.
-
-#pragma comment(lib, "winhttp.lib")
-#pragma comment(lib, "wininet.lib")
-#pragma comment(lib, "diaguids.lib")
-#pragma comment(lib, "imagehlp.lib")
-
-#include <cassert>
-#include <cstdio>
-#include <ctime>
-#include <map>
-#include <regex>
-#include <string>
-#include <vector>
-
-#include "tools/windows/converter_exe/escaping.h"
-#include "tools/windows/converter_exe/http_download.h"
-#include "tools/windows/converter_exe/tokenizer.h"
-#include "common/windows/http_upload.h"
-#include "common/windows/string_utils-inl.h"
-#include "tools/windows/converter/ms_symbol_server_converter.h"
-
-using strings::WebSafeBase64Unescape;
-using strings::WebSafeBase64Escape;
-
-namespace {
-
-using std::map;
-using std::string;
-using std::vector;
-using std::wstring;
-using crash::HTTPDownload;
-using crash::Tokenizer;
-using google_breakpad::HTTPUpload;
-using google_breakpad::MissingSymbolInfo;
-using google_breakpad::MSSymbolServerConverter;
-using google_breakpad::WindowsStringUtils;
-
-const char *kMissingStringDelimiters = "|";
-const char *kLocalCachePath = "c:\\symbols";
-const char *kNoExeMSSSServer = "http://msdl.microsoft.com/download/symbols/";
-
-// Windows stdio doesn't do line buffering. Use this function to flush after
-// writing to stdout and stderr so that a log will be available if the
-// converter crashes.
-static int FprintfFlush(FILE *file, const char *format, ...) {
- va_list arguments;
- va_start(arguments, format);
- int retval = vfprintf(file, format, arguments);
- va_end(arguments);
- fflush(file);
- return retval;
-}
-
-static string CurrentDateAndTime() {
- const string kUnknownDateAndTime = R"(????-??-?? ??:??:??)";
-
- time_t current_time;
- time(¤t_time);
-
- // localtime_s is safer but is only available in MSVC8. Use localtime
- // in earlier environments.
- struct tm *time_pointer;
-#if _MSC_VER >= 1400 // MSVC 2005/8
- struct tm time_struct;
- time_pointer = &time_struct;
- if (localtime_s(time_pointer, ¤t_time) != 0) {
- return kUnknownDateAndTime;
- }
-#else // _MSC_VER >= 1400
- time_pointer = localtime(¤t_time);
- if (!time_pointer) {
- return kUnknownDateAndTime;
- }
-#endif // _MSC_VER >= 1400
-
- char buffer[256];
- if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_pointer)) {
- return kUnknownDateAndTime;
- }
-
- return string(buffer);
-}
-
-// ParseMissingString turns |missing_string| into a MissingSymbolInfo
-// structure. It returns true on success, and false if no such conversion
-// is possible.
-static bool ParseMissingString(const string &missing_string,
- MissingSymbolInfo *missing_info) {
- assert(missing_info);
-
- vector<string> tokens;
- Tokenizer::Tokenize(kMissingStringDelimiters, missing_string, &tokens);
- if (tokens.size() != 5) {
- return false;
- }
-
- missing_info->debug_file = tokens[0];
- missing_info->debug_identifier = tokens[1];
- missing_info->version = tokens[2];
- missing_info->code_file = tokens[3];
- missing_info->code_identifier = tokens[4];
-
- return true;
-}
-
-// StringMapToWStringMap takes each element in a map that associates
-// (narrow) strings to strings and converts the keys and values to wstrings.
-// Returns true on success and false on failure, printing an error message.
-static bool StringMapToWStringMap(const map<string, string> &smap,
- map<wstring, wstring> *wsmap) {
- assert(wsmap);
- wsmap->clear();
-
- for (map<string, string>::const_iterator iterator = smap.begin();
- iterator != smap.end();
- ++iterator) {
- wstring key;
- if (!WindowsStringUtils::safe_mbstowcs(iterator->first, &key)) {
- FprintfFlush(stderr,
- "StringMapToWStringMap: safe_mbstowcs failed for key %s\n",
- iterator->first.c_str());
- return false;
- }
-
- wstring value;
- if (!WindowsStringUtils::safe_mbstowcs(iterator->second, &value)) {
- FprintfFlush(stderr, "StringMapToWStringMap: safe_mbstowcs failed "
- "for value %s\n",
- iterator->second.c_str());
- return false;
- }
-
- wsmap->insert(make_pair(key, value));
- }
-
- return true;
-}
-
-// MissingSymbolInfoToParameters turns a MissingSymbolInfo structure into a
-// map of parameters suitable for passing to HTTPDownload or HTTPUpload.
-// Returns true on success and false on failure, printing an error message.
-static bool MissingSymbolInfoToParameters(const MissingSymbolInfo &missing_info,
- map<wstring, wstring> *wparameters) {
- assert(wparameters);
-
- map<string, string> parameters;
- string encoded_param;
- // Indicate the params are encoded.
- parameters["encoded"] = "true"; // The string value here does not matter.
-
- WebSafeBase64Escape(missing_info.code_file, &encoded_param);
- parameters["code_file"] = encoded_param;
-
- WebSafeBase64Escape(missing_info.code_identifier, &encoded_param);
- parameters["code_identifier"] = encoded_param;
-
- WebSafeBase64Escape(missing_info.debug_file, &encoded_param);
- parameters["debug_file"] = encoded_param;
-
- WebSafeBase64Escape(missing_info.debug_identifier, &encoded_param);
- parameters["debug_identifier"] = encoded_param;
-
- if (!missing_info.version.empty()) {
- // The version is optional.
- WebSafeBase64Escape(missing_info.version, &encoded_param);
- parameters["version"] = encoded_param;
- }
-
- WebSafeBase64Escape("WinSymConv", &encoded_param);
- parameters["product"] = encoded_param;
-
- if (!StringMapToWStringMap(parameters, wparameters)) {
- // StringMapToWStringMap will have printed an error.
- return false;
- }
-
- return true;
-}
-
-// UploadSymbolFile sends |converted_file| as identified by |missing_info|
-// to the symbol server rooted at |upload_symbol_url|. Returns true on
-// success and false on failure, printing an error message.
-static bool UploadSymbolFile(const wstring &upload_symbol_url,
- const MissingSymbolInfo &missing_info,
- const string &converted_file) {
- map<wstring, wstring> parameters;
- if (!MissingSymbolInfoToParameters(missing_info, ¶meters)) {
- // MissingSymbolInfoToParameters or a callee will have printed an error.
- return false;
- }
-
- wstring converted_file_w;
-
- if (!WindowsStringUtils::safe_mbstowcs(converted_file, &converted_file_w)) {
- FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
- converted_file.c_str());
- return false;
- }
- map<wstring, wstring> files;
- files[L"symbol_file"] = converted_file_w;
-
- FprintfFlush(stderr, "Uploading %s\n", converted_file.c_str());
- if (!HTTPUpload::SendMultipartPostRequest(
- upload_symbol_url, parameters,
- files, NULL, NULL, NULL)) {
- FprintfFlush(stderr, "UploadSymbolFile: HTTPUpload::SendRequest failed "
- "for %s %s %s\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str(),
- missing_info.version.c_str());
- return false;
- }
-
- return true;
-}
-
-// SendFetchFailedPing informs the symbol server based at
-// |fetch_symbol_failure_url| that the symbol file identified by
-// |missing_info| could authoritatively not be located. Returns
-// true on success and false on failure.
-static bool SendFetchFailedPing(const wstring &fetch_symbol_failure_url,
- const MissingSymbolInfo &missing_info) {
- map<wstring, wstring> parameters;
- if (!MissingSymbolInfoToParameters(missing_info, ¶meters)) {
- // MissingSymbolInfoToParameters or a callee will have printed an error.
- return false;
- }
-
- string content;
- if (!HTTPDownload::Download(fetch_symbol_failure_url,
- ¶meters,
- &content,
- NULL)) {
- FprintfFlush(stderr, "SendFetchFailedPing: HTTPDownload::Download failed "
- "for %s %s %s\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str(),
- missing_info.version.c_str());
- return false;
- }
-
- return true;
-}
-
-// Returns true if it's safe to make an external request for the symbol
-// file described in missing_info. It's considered safe to make an
-// external request unless the symbol file's debug_file string matches
-// the given blacklist regular expression.
-// The debug_file name is used from the MissingSymbolInfo struct,
-// matched against the blacklist_regex.
-static bool SafeToMakeExternalRequest(const MissingSymbolInfo &missing_info,
- std::regex blacklist_regex) {
- string file_name = missing_info.debug_file;
- // Use regex_search because we want to match substrings.
- if (std::regex_search(file_name, blacklist_regex)) {
- FprintfFlush(stderr, "Not safe to make external request for file %s\n",
- file_name.c_str());
- return false;
- }
-
- return true;
-}
-
-// Converter options derived from command line parameters.
-struct ConverterOptions {
- ConverterOptions()
- : report_fetch_failures(true) {
- }
-
- ~ConverterOptions() {
- }
-
- // Names of MS Symbol Supplier Servers that are internal to Google, and may
- // have symbols for any request.
- vector<string> full_internal_msss_servers;
-
- // Names of MS Symbol Supplier Servers that are internal to Google, and
- // shouldn't be checked for symbols for any .exe files.
- vector<string> full_external_msss_servers;
-
- // Names of MS Symbol Supplier Servers that are external to Google, and may
- // have symbols for any request.
- vector<string> no_exe_internal_msss_servers;
-
- // Names of MS Symbol Supplier Servers that are external to Google, and
- // shouldn't be checked for symbols for any .exe files.
- vector<string> no_exe_external_msss_servers;
-
- // Temporary local storage for symbols.
- string local_cache_path;
-
- // URL for uploading symbols.
- wstring upload_symbols_url;
-
- // URL to fetch list of missing symbols.
- wstring missing_symbols_url;
-
- // URL to report symbol fetch failure.
- wstring fetch_symbol_failure_url;
-
- // Are symbol fetch failures reported.
- bool report_fetch_failures;
-
- // File containing the list of missing symbols. Fetch failures are not
- // reported if such file is provided.
- string missing_symbols_file;
-
- // Regex used to blacklist files to prevent external symbol requests.
- // Owned and cleaned up by this struct.
- std::regex blacklist_regex;
-
- private:
- // DISABLE_COPY_AND_ASSIGN
- ConverterOptions(const ConverterOptions&);
- ConverterOptions& operator=(const ConverterOptions&);
-};
-
-// ConverMissingSymbolFile takes a single MissingSymbolInfo structure and
-// attempts to locate it from the symbol servers provided in the
-// |options.*_msss_servers| arguments. "Full" servers are those that will be
-// queried for all symbol files; "No-EXE" servers will only be queried for
-// modules whose missing symbol data indicates are not main program executables.
-// Results will be sent to the |options.upload_symbols_url| on success or
-// |options.fetch_symbol_failure_url| on failure, and the local cache will be
-// stored at |options.local_cache_path|. Because nothing can be done even in
-// the event of a failure, this function returns no value, although it
-// may result in error messages being printed.
-static void ConvertMissingSymbolFile(const MissingSymbolInfo &missing_info,
- const ConverterOptions &options) {
- string time_string = CurrentDateAndTime();
- FprintfFlush(stdout, "converter: %s: attempting %s %s %s\n",
- time_string.c_str(),
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str(),
- missing_info.version.c_str());
-
- // The first lookup is always to internal symbol servers.
- // Always ask the symbol servers identified as "full."
- vector<string> msss_servers = options.full_internal_msss_servers;
-
- // If the file is not an .exe file, also ask an additional set of symbol
- // servers, such as Microsoft's public symbol server.
- bool is_exe = false;
-
- if (missing_info.code_file.length() >= 4) {
- string code_extension =
- missing_info.code_file.substr(missing_info.code_file.size() - 4);
-
- // Firefox is a special case: .dll-only servers should be consulted for
- // its symbols. This enables us to get its symbols from Mozilla's
- // symbol server when crashes occur in Google extension code hosted by a
- // Firefox process.
- if (_stricmp(code_extension.c_str(), ".exe") == 0 &&
- _stricmp(missing_info.code_file.c_str(), "firefox.exe") != 0) {
- is_exe = true;
- }
- }
-
- if (!is_exe) {
- msss_servers.insert(msss_servers.end(),
- options.no_exe_internal_msss_servers.begin(),
- options.no_exe_internal_msss_servers.end());
- }
-
- // If there are any suitable internal symbol servers, make a request.
- MSSymbolServerConverter::LocateResult located =
- MSSymbolServerConverter::LOCATE_FAILURE;
- string converted_file;
- if (msss_servers.size() > 0) {
- // Attempt to fetch the symbol file and convert it.
- FprintfFlush(stderr, "Making internal request for %s (%s)\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str());
- MSSymbolServerConverter converter(options.local_cache_path, msss_servers);
- located = converter.LocateAndConvertSymbolFile(missing_info,
- false, // keep_symbol_file
- false, // keep_pe_file
- &converted_file,
- NULL, // symbol_file
- NULL); // pe_file
- switch (located) {
- case MSSymbolServerConverter::LOCATE_SUCCESS:
- FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
- // Upload it. Don't bother checking the return value. If this
- // succeeds, it should disappear from the missing symbol list.
- // If it fails, something will print an error message indicating
- // the cause of the failure, and the item will remain on the
- // missing symbol list.
- UploadSymbolFile(options.upload_symbols_url, missing_info,
- converted_file);
- remove(converted_file.c_str());
-
- // Note: this does leave some directories behind that could be
- // cleaned up. The directories inside options.local_cache_path for
- // debug_file/debug_identifier can be removed at this point.
- break;
-
- case MSSymbolServerConverter::LOCATE_NOT_FOUND:
- FprintfFlush(stderr, "LocateResult = LOCATE_NOT_FOUND\n");
- // The symbol file definitively did not exist. Fall through,
- // so we can attempt an external query if it's safe to do so.
- break;
-
- case MSSymbolServerConverter::LOCATE_RETRY:
- FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
- // Fall through in case we should make an external request.
- // If not, or if an external request fails in the same way,
- // we'll leave the entry in the symbol file list and
- // try again on a future pass. Print a message so that there's
- // a record.
- break;
-
- case MSSymbolServerConverter::LOCATE_FAILURE:
- FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
- // LocateAndConvertSymbolFile printed an error message.
- break;
-
- default:
- FprintfFlush(
- stderr,
- "FATAL: Unexpected return value '%d' from "
- "LocateAndConvertSymbolFile()\n",
- located);
- assert(0);
- break;
- }
- } else {
- // No suitable internal symbol servers. This is fine because the converter
- // is mainly used for downloading and converting of external symbols.
- }
-
- // Make a request to an external server if the internal request didn't
- // succeed, and it's safe to do so.
- if (located != MSSymbolServerConverter::LOCATE_SUCCESS &&
- SafeToMakeExternalRequest(missing_info, options.blacklist_regex)) {
- msss_servers = options.full_external_msss_servers;
- if (!is_exe) {
- msss_servers.insert(msss_servers.end(),
- options.no_exe_external_msss_servers.begin(),
- options.no_exe_external_msss_servers.end());
- }
- if (msss_servers.size() > 0) {
- FprintfFlush(stderr, "Making external request for %s (%s)\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str());
- MSSymbolServerConverter external_converter(options.local_cache_path,
- msss_servers);
- located = external_converter.LocateAndConvertSymbolFile(
- missing_info,
- false, // keep_symbol_file
- false, // keep_pe_file
- &converted_file,
- NULL, // symbol_file
- NULL); // pe_file
- } else {
- FprintfFlush(stderr, "ERROR: No suitable external symbol servers.\n");
- }
- }
-
- // Final handling for this symbol file is based on the result from the
- // external request (if performed above), or on the result from the
- // previous internal lookup.
- switch (located) {
- case MSSymbolServerConverter::LOCATE_SUCCESS:
- FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
- // Upload it. Don't bother checking the return value. If this
- // succeeds, it should disappear from the missing symbol list.
- // If it fails, something will print an error message indicating
- // the cause of the failure, and the item will remain on the
- // missing symbol list.
- UploadSymbolFile(options.upload_symbols_url, missing_info,
- converted_file);
- remove(converted_file.c_str());
-
- // Note: this does leave some directories behind that could be
- // cleaned up. The directories inside options.local_cache_path for
- // debug_file/debug_identifier can be removed at this point.
- break;
-
- case MSSymbolServerConverter::LOCATE_NOT_FOUND:
- // The symbol file definitively didn't exist. Inform the server.
- // If this fails, something will print an error message indicating
- // the cause of the failure, but there's really nothing more to
- // do. If this succeeds, the entry should be removed from the
- // missing symbols list.
- if (!options.report_fetch_failures) {
- FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
- } else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
- missing_info)) {
- FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
- } else {
- FprintfFlush(stderr, "SendFetchFailedPing failed\n");
- }
- break;
-
- case MSSymbolServerConverter::LOCATE_RETRY:
- FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
- // Nothing to do but leave the entry in the symbol file list and
- // try again on a future pass. Print a message so that there's
- // a record.
- FprintfFlush(stderr, "ConvertMissingSymbolFile: deferring retry "
- "for %s %s %s\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str(),
- missing_info.version.c_str());
- break;
-
- case MSSymbolServerConverter::LOCATE_FAILURE:
- FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
- // LocateAndConvertSymbolFile printed an error message.
-
- // This is due to a bad debug file name, so fetch failed.
- if (!options.report_fetch_failures) {
- FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
- } else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
- missing_info)) {
- FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
- } else {
- FprintfFlush(stderr, "SendFetchFailedPing failed\n");
- }
- break;
-
- default:
- FprintfFlush(
- stderr,
- "FATAL: Unexpected return value '%d' from "
- "LocateAndConvertSymbolFile()\n",
- located);
- assert(0);
- break;
- }
-}
-
-
-// Reads the contents of file |file_name| and populates |contents|.
-// Returns true on success.
-static bool ReadFile(string file_name, string *contents) {
- char buffer[1024 * 8];
- FILE *fp = fopen(file_name.c_str(), "rt");
- if (!fp) {
- return false;
- }
- contents->clear();
- while (fgets(buffer, sizeof(buffer), fp) != NULL) {
- contents->append(buffer);
- }
- fclose(fp);
- return true;
-}
-
-// ConvertMissingSymbolsList obtains a missing symbol list from
-// |options.missing_symbols_url| or |options.missing_symbols_file| and calls
-// ConvertMissingSymbolFile for each missing symbol file in the list.
-static bool ConvertMissingSymbolsList(const ConverterOptions &options) {
- // Set param to indicate requesting for encoded response.
- map<wstring, wstring> parameters;
- parameters[L"product"] = L"WinSymConv";
- parameters[L"encoded"] = L"true";
- // Get the missing symbol list.
- string missing_symbol_list;
- if (!options.missing_symbols_file.empty()) {
- if (!ReadFile(options.missing_symbols_file, &missing_symbol_list)) {
- return false;
- }
- } else if (!HTTPDownload::Download(options.missing_symbols_url, ¶meters,
- &missing_symbol_list, NULL)) {
- return false;
- }
-
- // Tokenize the content into a vector.
- vector<string> missing_symbol_lines;
- Tokenizer::Tokenize("\n", missing_symbol_list, &missing_symbol_lines);
-
- FprintfFlush(stderr, "Found %d missing symbol files in list.\n",
- missing_symbol_lines.size() - 1); // last line is empty.
- int convert_attempts = 0;
- for (vector<string>::const_iterator iterator = missing_symbol_lines.begin();
- iterator != missing_symbol_lines.end();
- ++iterator) {
- // Decode symbol line.
- const string &encoded_line = *iterator;
- // Skip lines that are blank.
- if (encoded_line.empty()) {
- continue;
- }
-
- string line;
- if (!WebSafeBase64Unescape(encoded_line, &line)) {
- // If decoding fails, assume the line is not encoded.
- // This is helpful when the program connects to a debug server without
- // encoding.
- line = encoded_line;
- }
-
- FprintfFlush(stderr, "\nLine: %s\n", line.c_str());
-
- // Turn each element into a MissingSymbolInfo structure.
- MissingSymbolInfo missing_info;
- if (!ParseMissingString(line, &missing_info)) {
- FprintfFlush(stderr, "ConvertMissingSymbols: ParseMissingString failed "
- "for %s from %ws\n",
- line.c_str(), options.missing_symbols_url.c_str());
- continue;
- }
-
- ++convert_attempts;
- ConvertMissingSymbolFile(missing_info, options);
- }
-
- // Say something reassuring, since ConvertMissingSymbolFile was never called
- // and therefore never reported any progress.
- if (convert_attempts == 0) {
- string current_time = CurrentDateAndTime();
- FprintfFlush(stdout, "converter: %s: nothing to convert\n",
- current_time.c_str());
- }
-
- return true;
-}
-
-// usage prints the usage message. It returns 1 as a convenience, to be used
-// as a return value from main.
-static int usage(const char *program_name) {
- FprintfFlush(stderr,
- "usage: %s [options]\n"
- " -f <full_msss_server> MS servers to ask for all symbols\n"
- " -n <no_exe_msss_server> same, but prevent asking for EXEs\n"
- " -l <local_cache_path> Temporary local storage for symbols\n"
- " -s <upload_url> URL for uploading symbols\n"
- " -m <missing_symbols_url> URL to fetch list of missing symbols\n"
- " -mf <missing_symbols_file> File containing the list of missing\n"
- " symbols. Fetch failures are not\n"
- " reported if such file is provided.\n"
- " -t <fetch_failure_url> URL to report symbol fetch failure\n"
- " -b <regex> Regex used to blacklist files to\n"
- " prevent external symbol requests\n"
- " Note that any server specified by -f or -n that starts with \\filer\n"
- " will be treated as internal, and all others as external.\n",
- program_name);
-
- return 1;
-}
-
-// "Internal" servers consist only of those whose names start with
-// the literal string "\\filer\".
-static bool IsInternalServer(const string &server_name) {
- if (server_name.find("\\\\filer\\") == 0) {
- return true;
- }
- return false;
-}
-
-// Adds a server with the given name to the list of internal or external
-// servers, as appropriate.
-static void AddServer(const string &server_name,
- vector<string> *internal_servers,
- vector<string> *external_servers) {
- if (IsInternalServer(server_name)) {
- internal_servers->push_back(server_name);
- } else {
- external_servers->push_back(server_name);
- }
-}
-
-} // namespace
-
-int main(int argc, char **argv) {
- string time_string = CurrentDateAndTime();
- FprintfFlush(stdout, "converter: %s: starting\n", time_string.c_str());
-
- ConverterOptions options;
- options.report_fetch_failures = true;
-
- // All arguments are paired.
- if (argc % 2 != 1) {
- return usage(argv[0]);
- }
-
- string blacklist_regex_str;
- bool have_any_msss_servers = false;
- for (int argi = 1; argi < argc; argi += 2) {
- string option = argv[argi];
- string value = argv[argi + 1];
-
- if (option == "-f") {
- AddServer(value, &options.full_internal_msss_servers,
- &options.full_external_msss_servers);
- have_any_msss_servers = true;
- } else if (option == "-n") {
- AddServer(value, &options.no_exe_internal_msss_servers,
- &options.no_exe_external_msss_servers);
- have_any_msss_servers = true;
- } else if (option == "-l") {
- if (!options.local_cache_path.empty()) {
- return usage(argv[0]);
- }
- options.local_cache_path = value;
- } else if (option == "-s") {
- if (!WindowsStringUtils::safe_mbstowcs(value,
- &options.upload_symbols_url)) {
- FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
- value.c_str());
- return 1;
- }
- } else if (option == "-m") {
- if (!WindowsStringUtils::safe_mbstowcs(value,
- &options.missing_symbols_url)) {
- FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
- value.c_str());
- return 1;
- }
- } else if (option == "-mf") {
- options.missing_symbols_file = value;
- printf("Getting the list of missing symbols from a file. Fetch failures"
- " will not be reported.\n");
- options.report_fetch_failures = false;
- } else if (option == "-t") {
- if (!WindowsStringUtils::safe_mbstowcs(
- value,
- &options.fetch_symbol_failure_url)) {
- FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
- value.c_str());
- return 1;
- }
- } else if (option == "-b") {
- blacklist_regex_str = value;
- } else {
- return usage(argv[0]);
- }
- }
-
- if (blacklist_regex_str.empty()) {
- FprintfFlush(stderr, "No blacklist specified.\n");
- return usage(argv[0]);
- }
-
- // Compile the blacklist regular expression for later use.
- options.blacklist_regex = std::regex(blacklist_regex_str.c_str(),
- std::regex_constants::icase);
-
- // Set the defaults. If the user specified any MSSS servers, don't use
- // any default.
- if (!have_any_msss_servers) {
- AddServer(kNoExeMSSSServer, &options.no_exe_internal_msss_servers,
- &options.no_exe_external_msss_servers);
- }
-
- if (options.local_cache_path.empty()) {
- options.local_cache_path = kLocalCachePath;
- }
-
- if (options.upload_symbols_url.empty()) {
- FprintfFlush(stderr, "No upload symbols URL specified.\n");
- return usage(argv[0]);
- }
- if (options.missing_symbols_url.empty() &&
- options.missing_symbols_file.empty()) {
- FprintfFlush(stderr, "No missing symbols URL or file specified.\n");
- return usage(argv[0]);
- }
- if (options.fetch_symbol_failure_url.empty()) {
- FprintfFlush(stderr, "No fetch symbol failure URL specified.\n");
- return usage(argv[0]);
- }
-
- FprintfFlush(stdout,
- "# of Symbol Servers (int/ext): %d/%d full, %d/%d no_exe\n",
- options.full_internal_msss_servers.size(),
- options.full_external_msss_servers.size(),
- options.no_exe_internal_msss_servers.size(),
- options.no_exe_external_msss_servers.size());
-
- if (!ConvertMissingSymbolsList(options)) {
- return 1;
- }
-
- time_string = CurrentDateAndTime();
- FprintfFlush(stdout, "converter: %s: finished\n", time_string.c_str());
- return 0;
-}
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma comment(lib, "winhttp.lib") +#pragma comment(lib, "wininet.lib") +#pragma comment(lib, "diaguids.lib") +#pragma comment(lib, "imagehlp.lib") + +#include <cassert> +#include <cstdio> +#include <ctime> +#include <map> +#include <regex> +#include <string> +#include <vector> + +#include "common/windows/http_upload.h" +#include "common/windows/string_utils-inl.h" +#include "common/windows/sym_upload_v2_protocol.h" +#include "tools/windows/converter/ms_symbol_server_converter.h" +#include "tools/windows/converter_exe/escaping.h" +#include "tools/windows/converter_exe/http_download.h" +#include "tools/windows/converter_exe/tokenizer.h" + +using strings::WebSafeBase64Unescape; +using strings::WebSafeBase64Escape; + +namespace { + +using std::map; +using std::string; +using std::vector; +using std::wstring; +using crash::HTTPDownload; +using crash::Tokenizer; +using google_breakpad::HTTPUpload; +using google_breakpad::MissingSymbolInfo; +using google_breakpad::MSSymbolServerConverter; +using google_breakpad::WindowsStringUtils; + +const char* kMissingStringDelimiters = "|"; +const char* kLocalCachePath = "c:\\symbols"; +const char* kNoExeMSSSServer = "http://msdl.microsoft.com/download/symbols/"; +const wchar_t* kSymbolUploadTypeBreakpad = L"BREAKPAD"; +const wchar_t* kSymbolUploadTypePE = L"PE"; +const wchar_t* kSymbolUploadTypePDB = L"PDB"; +const wchar_t* kConverterProductName = L"WinSymConv"; + +// Windows stdio doesn't do line buffering. Use this function to flush after +// writing to stdout and stderr so that a log will be available if the +// converter crashes. +static int FprintfFlush(FILE* file, const char* format, ...) { + va_list arguments; + va_start(arguments, format); + int retval = vfprintf(file, format, arguments); + va_end(arguments); + fflush(file); + return retval; +} + +static string CurrentDateAndTime() { + const string kUnknownDateAndTime = R"(????-??-?? ??:??:??)"; + + time_t current_time; + time(¤t_time); + + // localtime_s is safer but is only available in MSVC8. Use localtime + // in earlier environments. + struct tm* time_pointer; +#if _MSC_VER >= 1400 // MSVC 2005/8 + struct tm time_struct; + time_pointer =& time_struct; + if (localtime_s(time_pointer,& current_time) != 0) { + return kUnknownDateAndTime; + } +#else // _MSC_VER >= 1400 + time_pointer = localtime(¤t_time); + if (!time_pointer) { + return kUnknownDateAndTime; + } +#endif // _MSC_VER >= 1400 + + char buffer[256]; + if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_pointer)) { + return kUnknownDateAndTime; + } + + return string(buffer); +} + +// ParseMissingString turns |missing_string| into a MissingSymbolInfo +// structure. It returns true on success, and false if no such conversion +// is possible. +static bool ParseMissingString(const string& missing_string, + MissingSymbolInfo* missing_info) { + assert(missing_info); + + vector<string> tokens; + Tokenizer::Tokenize(kMissingStringDelimiters, missing_string,& tokens); + if (tokens.size() != 5) { + return false; + } + + missing_info->debug_file = tokens[0]; + missing_info->debug_identifier = tokens[1]; + missing_info->version = tokens[2]; + missing_info->code_file = tokens[3]; + missing_info->code_identifier = tokens[4]; + + return true; +} + +// StringMapToWStringMap takes each element in a map that associates +// (narrow) strings to strings and converts the keys and values to wstrings. +// Returns true on success and false on failure, printing an error message. +static bool StringMapToWStringMap(const map<string, string>& smap, + map<wstring, wstring>* wsmap) { + assert(wsmap); + wsmap->clear(); + + for (map<string, string>::const_iterator iterator = smap.begin(); + iterator != smap.end(); + ++iterator) { + wstring key; + if (!WindowsStringUtils::safe_mbstowcs(iterator->first,& key)) { + FprintfFlush(stderr, + "StringMapToWStringMap: safe_mbstowcs failed for key %s\n", + iterator->first.c_str()); + return false; + } + + wstring value; + if (!WindowsStringUtils::safe_mbstowcs(iterator->second,& value)) { + FprintfFlush(stderr, "StringMapToWStringMap: safe_mbstowcs failed " + "for value %s\n", + iterator->second.c_str()); + return false; + } + + wsmap->insert(make_pair(key, value)); + } + + return true; +} + +// MissingSymbolInfoToParameters turns a MissingSymbolInfo structure into a +// map of parameters suitable for passing to HTTPDownload or HTTPUpload. +// Returns true on success and false on failure, printing an error message. +static bool MissingSymbolInfoToParameters(const MissingSymbolInfo& missing_info, + map<wstring, wstring>* wparameters) { + assert(wparameters); + + map<string, string> parameters; + string encoded_param; + // Indicate the params are encoded. + parameters["encoded"] = "true"; // The string value here does not matter. + + WebSafeBase64Escape(missing_info.code_file,& encoded_param); + parameters["code_file"] = encoded_param; + + WebSafeBase64Escape(missing_info.code_identifier,& encoded_param); + parameters["code_identifier"] = encoded_param; + + WebSafeBase64Escape(missing_info.debug_file,& encoded_param); + parameters["debug_file"] = encoded_param; + + WebSafeBase64Escape(missing_info.debug_identifier,& encoded_param); + parameters["debug_identifier"] = encoded_param; + + if (!missing_info.version.empty()) { + // The version is optional. + WebSafeBase64Escape(missing_info.version,& encoded_param); + parameters["version"] = encoded_param; + } + + WebSafeBase64Escape("WinSymConv",& encoded_param); + parameters["product"] = encoded_param; + + if (!StringMapToWStringMap(parameters, wparameters)) { + // StringMapToWStringMap will have printed an error. + return false; + } + + return true; +} + +// UploadSymbolFile sends |converted_file| as identified by |debug_file| and +// |debug_identifier|, to the symbol server rooted at |upload_symbol_url|. +// Returns true on success and false on failure, printing an error message. +static bool UploadSymbolFile(const wstring& upload_symbol_url, + const wstring& api_key, + const string& debug_file, + const string& debug_identifier, + const string& symbol_file, + const wstring& symbol_type) { + wstring debug_file_w; + if (!WindowsStringUtils::safe_mbstowcs(debug_file, &debug_file_w)) { + FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n", + symbol_file.c_str()); + return false; + } + + wstring debug_id_w; + if (!WindowsStringUtils::safe_mbstowcs(debug_identifier, &debug_id_w)) { + FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n", + symbol_file.c_str()); + return false; + } + + wstring symbol_file_w; + if (!WindowsStringUtils::safe_mbstowcs(symbol_file, &symbol_file_w)) { + FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n", + symbol_file.c_str()); + return false; + } + + int timeout_ms = 60 * 1000; + FprintfFlush(stderr, "Uploading %s\n", symbol_file.c_str()); + if (!google_breakpad::SymUploadV2ProtocolSend( + upload_symbol_url.c_str(), api_key.c_str(), &timeout_ms, debug_file_w, + debug_id_w, symbol_file_w, symbol_type, kConverterProductName, + /*force=*/true)) { + FprintfFlush(stderr, + "UploadSymbolFile: HTTPUpload::SendRequest failed " + "for %s %s\n", + debug_file.c_str(), debug_identifier.c_str()); + return false; + } + + return true; +} + +// SendFetchFailedPing informs the symbol server based at +// |fetch_symbol_failure_url| that the symbol file identified by +// |missing_info| could authoritatively not be located. Returns +// true on success and false on failure. +static bool SendFetchFailedPing(const wstring& fetch_symbol_failure_url, + const MissingSymbolInfo& missing_info) { + map<wstring, wstring> parameters; + if (!MissingSymbolInfoToParameters(missing_info,& parameters)) { + // MissingSymbolInfoToParameters or a callee will have printed an error. + return false; + } + + string content; + if (!HTTPDownload::Download(fetch_symbol_failure_url, + & parameters, + & content, + NULL)) { + FprintfFlush(stderr, "SendFetchFailedPing: HTTPDownload::Download failed " + "for %s %s %s\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str(), + missing_info.version.c_str()); + return false; + } + + return true; +} + +// Returns true if it's safe to make an external request for the symbol +// file described in missing_info. It's considered safe to make an +// external request unless the symbol file's debug_file string matches +// the given blacklist regular expression. +// The debug_file name is used from the MissingSymbolInfo struct, +// matched against the blacklist_regex. +static bool SafeToMakeExternalRequest(const MissingSymbolInfo& missing_info, + std::regex blacklist_regex) { + string file_name = missing_info.debug_file; + // Use regex_search because we want to match substrings. + if (std::regex_search(file_name, blacklist_regex)) { + FprintfFlush(stderr, "Not safe to make external request for file %s\n", + file_name.c_str()); + return false; + } + + return true; +} + +// Converter options derived from command line parameters. +struct ConverterOptions { + ConverterOptions() + : report_fetch_failures(true), trace_symsrv(false), keep_files(false) {} + + ~ConverterOptions() { + } + + // Names of MS Symbol Supplier Servers that are internal to Google, and may + // have symbols for any request. + vector<string> full_internal_msss_servers; + + // Names of MS Symbol Supplier Servers that are internal to Google, and + // shouldn't be checked for symbols for any .exe files. + vector<string> full_external_msss_servers; + + // Names of MS Symbol Supplier Servers that are external to Google, and may + // have symbols for any request. + vector<string> no_exe_internal_msss_servers; + + // Names of MS Symbol Supplier Servers that are external to Google, and + // shouldn't be checked for symbols for any .exe files. + vector<string> no_exe_external_msss_servers; + + // Temporary local storage for symbols. + string local_cache_path; + + // URL for uploading symbols. + wstring upload_symbols_url; + + // API key to use when uploading symbols. + wstring api_key; + + // URL to fetch list of missing symbols. + wstring missing_symbols_url; + + // URL to report symbol fetch failure. + wstring fetch_symbol_failure_url; + + // Are symbol fetch failures reported. + bool report_fetch_failures; + + // File containing the list of missing symbols. Fetch failures are not + // reported if such file is provided. + string missing_symbols_file; + + // Regex used to blacklist files to prevent external symbol requests. + // Owned and cleaned up by this struct. + std::regex blacklist_regex; + + // If set then SymSrv callbacks are logged to stderr. + bool trace_symsrv; + + // If set then Breakpad/PE/PDB files won't be deleted after processing. + bool keep_files; + + private: + // DISABLE_COPY_AND_ASSIGN + ConverterOptions(const ConverterOptions&); + ConverterOptions& operator=(const ConverterOptions&); +}; + +// ConverMissingSymbolFile takes a single MissingSymbolInfo structure and +// attempts to locate it from the symbol servers provided in the +// |options.*_msss_servers| arguments. "Full" servers are those that will be +// queried for all symbol files; "No-EXE" servers will only be queried for +// modules whose missing symbol data indicates are not main program executables. +// Results will be sent to the |options.upload_symbols_url| on success or +// |options.fetch_symbol_failure_url| on failure, and the local cache will be +// stored at |options.local_cache_path|. Because nothing can be done even in +// the event of a failure, this function returns no value, although it +// may result in error messages being printed. +static void ConvertMissingSymbolFile(const MissingSymbolInfo& missing_info, + const ConverterOptions& options) { + string time_string = CurrentDateAndTime(); + FprintfFlush(stdout, "converter: %s: attempting %s %s %s\n", + time_string.c_str(), + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str(), + missing_info.version.c_str()); + + // The first lookup is always to internal symbol servers. + // Always ask the symbol servers identified as "full." + vector<string> msss_servers = options.full_internal_msss_servers; + + // If the file is not an .exe file, also ask an additional set of symbol + // servers, such as Microsoft's public symbol server. + bool is_exe = false; + + if (missing_info.code_file.length() >= 4) { + string code_extension = + missing_info.code_file.substr(missing_info.code_file.size() - 4); + + // Firefox is a special case: .dll-only servers should be consulted for + // its symbols. This enables us to get its symbols from Mozilla's + // symbol server when crashes occur in Google extension code hosted by a + // Firefox process. + if (_stricmp(code_extension.c_str(), ".exe") == 0 && + _stricmp(missing_info.code_file.c_str(), "firefox.exe") != 0) { + is_exe = true; + } + } + + if (!is_exe) { + msss_servers.insert(msss_servers.end(), + options.no_exe_internal_msss_servers.begin(), + options.no_exe_internal_msss_servers.end()); + } + + // If there are any suitable internal symbol servers, make a request. + MSSymbolServerConverter::LocateResult located = + MSSymbolServerConverter::LOCATE_FAILURE; + string converted_file; + string symbol_file; + string pe_file; + if (msss_servers.size() > 0) { + // Attempt to fetch the symbol file and convert it. + FprintfFlush(stderr, "Making internal request for %s (%s)\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str()); + MSSymbolServerConverter converter(options.local_cache_path, msss_servers, + options.trace_symsrv); + located = converter.LocateAndConvertSymbolFile( + missing_info, + /*keep_symbol_file=*/true, + /*keep_pe_file=*/true, &converted_file, &symbol_file, &pe_file); + switch (located) { + case MSSymbolServerConverter::LOCATE_SUCCESS: + FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n"); + // Upload it. Don't bother checking the return value. If this + // succeeds, it should disappear from the missing symbol list. + // If it fails, something will print an error message indicating + // the cause of the failure, and the item will remain on the + // missing symbol list. + UploadSymbolFile(options.upload_symbols_url, options.api_key, + missing_info.debug_file, missing_info.debug_identifier, + converted_file, kSymbolUploadTypeBreakpad); + if (!options.keep_files) + remove(converted_file.c_str()); + + // Upload PDB/PE if we have them + if (!symbol_file.empty()) { + UploadSymbolFile(options.upload_symbols_url, options.api_key, + missing_info.debug_file, + missing_info.debug_identifier, symbol_file, + kSymbolUploadTypePDB); + if (!options.keep_files) + remove(symbol_file.c_str()); + } + if (!pe_file.empty()) { + UploadSymbolFile(options.upload_symbols_url, options.api_key, + missing_info.code_file, + missing_info.debug_identifier, pe_file, + kSymbolUploadTypePE); + if (!options.keep_files) + remove(pe_file.c_str()); + } + + // Note: this does leave some directories behind that could be + // cleaned up. The directories inside options.local_cache_path for + // debug_file/debug_identifier can be removed at this point. + break; + + case MSSymbolServerConverter::LOCATE_NOT_FOUND: + FprintfFlush(stderr, "LocateResult = LOCATE_NOT_FOUND\n"); + // The symbol file definitively did not exist. Fall through, + // so we can attempt an external query if it's safe to do so. + break; + + case MSSymbolServerConverter::LOCATE_RETRY: + FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n"); + // Fall through in case we should make an external request. + // If not, or if an external request fails in the same way, + // we'll leave the entry in the symbol file list and + // try again on a future pass. Print a message so that there's + // a record. + break; + + case MSSymbolServerConverter::LOCATE_HTTP_HTTPS_REDIR: + FprintfFlush( + stderr, + "LocateResult = LOCATE_HTTP_HTTPS_REDIR\n" + "One of the specified URLs is using HTTP, which causes a redirect " + "from the server to HTTPS, which causes the SymSrv lookup to " + "fail.\n" + "This URL must be replaced with the correct HTTPS URL.\n"); + break; + + case MSSymbolServerConverter::LOCATE_FAILURE: + FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n"); + // LocateAndConvertSymbolFile printed an error message. + break; + + default: + FprintfFlush( + stderr, + "FATAL: Unexpected return value '%d' from " + "LocateAndConvertSymbolFile()\n", + located); + assert(0); + break; + } + } else { + // No suitable internal symbol servers. This is fine because the converter + // is mainly used for downloading and converting of external symbols. + } + + // Make a request to an external server if the internal request didn't + // succeed, and it's safe to do so. + if (located != MSSymbolServerConverter::LOCATE_SUCCESS && + SafeToMakeExternalRequest(missing_info, options.blacklist_regex)) { + msss_servers = options.full_external_msss_servers; + if (!is_exe) { + msss_servers.insert(msss_servers.end(), + options.no_exe_external_msss_servers.begin(), + options.no_exe_external_msss_servers.end()); + } + if (msss_servers.size() > 0) { + FprintfFlush(stderr, "Making external request for %s (%s)\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str()); + MSSymbolServerConverter external_converter( + options.local_cache_path, msss_servers, options.trace_symsrv); + located = external_converter.LocateAndConvertSymbolFile( + missing_info, + /*keep_symbol_file=*/true, + /*keep_pe_file=*/true, &converted_file, &symbol_file, &pe_file); + } else { + FprintfFlush(stderr, "ERROR: No suitable external symbol servers.\n"); + } + } + + // Final handling for this symbol file is based on the result from the + // external request (if performed above), or on the result from the + // previous internal lookup. + switch (located) { + case MSSymbolServerConverter::LOCATE_SUCCESS: + FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n"); + // Upload it. Don't bother checking the return value. If this + // succeeds, it should disappear from the missing symbol list. + // If it fails, something will print an error message indicating + // the cause of the failure, and the item will remain on the + // missing symbol list. + UploadSymbolFile(options.upload_symbols_url, options.api_key, + missing_info.debug_file, missing_info.debug_identifier, + converted_file, kSymbolUploadTypeBreakpad); + if (!options.keep_files) + remove(converted_file.c_str()); + + // Upload PDB/PE if we have them + if (!symbol_file.empty()) { + UploadSymbolFile(options.upload_symbols_url, options.api_key, + missing_info.debug_file, missing_info.debug_identifier, + symbol_file, kSymbolUploadTypePDB); + if (!options.keep_files) + remove(symbol_file.c_str()); + } + if (!pe_file.empty()) { + UploadSymbolFile(options.upload_symbols_url, options.api_key, + missing_info.code_file, missing_info.debug_identifier, + pe_file, kSymbolUploadTypePE); + if (!options.keep_files) + remove(pe_file.c_str()); + } + + // Note: this does leave some directories behind that could be + // cleaned up. The directories inside options.local_cache_path for + // debug_file/debug_identifier can be removed at this point. + break; + + case MSSymbolServerConverter::LOCATE_NOT_FOUND: + // The symbol file definitively didn't exist. Inform the server. + // If this fails, something will print an error message indicating + // the cause of the failure, but there's really nothing more to + // do. If this succeeds, the entry should be removed from the + // missing symbols list. + if (!options.report_fetch_failures) { + FprintfFlush(stderr, "SendFetchFailedPing skipped\n"); + } else if (SendFetchFailedPing(options.fetch_symbol_failure_url, + missing_info)) { + FprintfFlush(stderr, "SendFetchFailedPing succeeded\n"); + } else { + FprintfFlush(stderr, "SendFetchFailedPing failed\n"); + } + break; + + case MSSymbolServerConverter::LOCATE_RETRY: + FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n"); + // Nothing to do but leave the entry in the symbol file list and + // try again on a future pass. Print a message so that there's + // a record. + FprintfFlush(stderr, "ConvertMissingSymbolFile: deferring retry " + "for %s %s %s\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str(), + missing_info.version.c_str()); + break; + + case MSSymbolServerConverter::LOCATE_HTTP_HTTPS_REDIR: + FprintfFlush( + stderr, + "LocateResult = LOCATE_HTTP_HTTPS_REDIR\n" + "One of the specified URLs is using HTTP, which causes a redirect " + "from the server to HTTPS, which causes the SymSrv lookup to fail.\n" + "This URL must be replaced with the correct HTTPS URL.\n"); + break; + + case MSSymbolServerConverter::LOCATE_FAILURE: + FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n"); + // LocateAndConvertSymbolFile printed an error message. + + // This is due to a bad debug file name, so fetch failed. + if (!options.report_fetch_failures) { + FprintfFlush(stderr, "SendFetchFailedPing skipped\n"); + } else if (SendFetchFailedPing(options.fetch_symbol_failure_url, + missing_info)) { + FprintfFlush(stderr, "SendFetchFailedPing succeeded\n"); + } else { + FprintfFlush(stderr, "SendFetchFailedPing failed\n"); + } + break; + + default: + FprintfFlush( + stderr, + "FATAL: Unexpected return value '%d' from " + "LocateAndConvertSymbolFile()\n", + located); + assert(0); + break; + } +} + + +// Reads the contents of file |file_name| and populates |contents|. +// Returns true on success. +static bool ReadFile(string file_name, string* contents) { + char buffer[1024 * 8]; + FILE* fp = fopen(file_name.c_str(), "rt"); + if (!fp) { + return false; + } + contents->clear(); + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + contents->append(buffer); + } + fclose(fp); + return true; +} + +// ConvertMissingSymbolsList obtains a missing symbol list from +// |options.missing_symbols_url| or |options.missing_symbols_file| and calls +// ConvertMissingSymbolFile for each missing symbol file in the list. +static bool ConvertMissingSymbolsList(const ConverterOptions& options) { + // Set param to indicate requesting for encoded response. + map<wstring, wstring> parameters; + parameters[L"product"] = kConverterProductName; + parameters[L"encoded"] = L"true"; + // Get the missing symbol list. + string missing_symbol_list; + if (!options.missing_symbols_file.empty()) { + if (!ReadFile(options.missing_symbols_file,& missing_symbol_list)) { + return false; + } + } else if (!HTTPDownload::Download(options.missing_symbols_url,& parameters, + & missing_symbol_list, NULL)) { + return false; + } + + // Tokenize the content into a vector. + vector<string> missing_symbol_lines; + Tokenizer::Tokenize("\n", missing_symbol_list,& missing_symbol_lines); + + FprintfFlush(stderr, "Found %d missing symbol files in list.\n", + missing_symbol_lines.size() - 1); // last line is empty. + int convert_attempts = 0; + for (vector<string>::const_iterator iterator = missing_symbol_lines.begin(); + iterator != missing_symbol_lines.end(); + ++iterator) { + // Decode symbol line. + const string& encoded_line = *iterator; + // Skip lines that are blank. + if (encoded_line.empty()) { + continue; + } + + string line; + if (!WebSafeBase64Unescape(encoded_line,& line)) { + // If decoding fails, assume the line is not encoded. + // This is helpful when the program connects to a debug server without + // encoding. + line = encoded_line; + } + + FprintfFlush(stderr, "\nLine: %s\n", line.c_str()); + + // Turn each element into a MissingSymbolInfo structure. + MissingSymbolInfo missing_info; + if (!ParseMissingString(line,& missing_info)) { + FprintfFlush(stderr, "ConvertMissingSymbols: ParseMissingString failed " + "for %s from %ws\n", + line.c_str(), options.missing_symbols_url.c_str()); + continue; + } + + ++convert_attempts; + ConvertMissingSymbolFile(missing_info, options); + } + + // Say something reassuring, since ConvertMissingSymbolFile was never called + // and therefore never reported any progress. + if (convert_attempts == 0) { + string current_time = CurrentDateAndTime(); + FprintfFlush(stdout, "converter: %s: nothing to convert\n", + current_time.c_str()); + } + + return true; +} + +// usage prints the usage message. It returns 1 as a convenience, to be used +// as a return value from main. +static int usage(const char* program_name) { + FprintfFlush( + stderr, + "usage: %s [options]\n" + " -f <full_msss_server> MS servers to ask for all symbols\n" + " -n <no_exe_msss_server> same, but prevent asking for EXEs\n" + " -l <local_cache_path> Temporary local storage for symbols\n" + " -s <upload_url> URL for uploading symbols\n" + " -k <api_key> API key to use when uploading symbols\n" + " -m <missing_symbols_url> URL to fetch list of missing symbols\n" + " -mf <missing_symbols_file> File containing the list of missing\n" + " symbols. Fetch failures are not\n" + " reported if such file is provided.\n" + " -t <fetch_failure_url> URL to report symbol fetch failure\n" + " -b <regex> Regex used to blacklist files to\n" + " prevent external symbol requests\n" + " -tss If set then SymSrv callbacks will be\n" + " traced to stderr.\n" + " -keep-files If set then don't delete Breakpad/PE/\n" + " PDB files after conversion.\n" + " Note that any server specified by -f or -n that starts with \\filer\n" + " will be treated as internal, and all others as external.\n", + program_name); + + return 1; +} + +// "Internal" servers consist only of those whose names start with +// the literal string "\\filer\". +static bool IsInternalServer(const string& server_name) { + if (server_name.find("\\\\filer\\") == 0) { + return true; + } + return false; +} + +// Adds a server with the given name to the list of internal or external +// servers, as appropriate. +static void AddServer(const string& server_name, + vector<string>* internal_servers, + vector<string>* external_servers) { + if (IsInternalServer(server_name)) { + internal_servers->push_back(server_name); + } else { + external_servers->push_back(server_name); + } +} + +} // namespace + +int main(int argc, char** argv) { + string time_string = CurrentDateAndTime(); + FprintfFlush(stdout, "converter: %s: starting\n", time_string.c_str()); + + ConverterOptions options; + options.report_fetch_failures = true; + + string blacklist_regex_str; + bool have_any_msss_servers = false; + for (int argi = 1; argi < argc; argi++) { + string option = argv[argi]; + if (option == "-tss") { + printf("Tracing SymSrv callbacks to stderr.\n"); + options.trace_symsrv = true; + continue; + } else if (option == "-keep-files") { + printf("Keeping Breakpad/PE/PDB files after conversion.\n"); + options.keep_files = true; + continue; + } + + string value = argv[++argi]; + if (option == "-f") { + AddServer(value,& options.full_internal_msss_servers, + & options.full_external_msss_servers); + have_any_msss_servers = true; + } else if (option == "-n") { + AddServer(value,& options.no_exe_internal_msss_servers, + & options.no_exe_external_msss_servers); + have_any_msss_servers = true; + } else if (option == "-l") { + if (!options.local_cache_path.empty()) { + return usage(argv[0]); + } + options.local_cache_path = value; + } else if (option == "-s") { + if (!WindowsStringUtils::safe_mbstowcs(value, + & options.upload_symbols_url)) { + FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n", + value.c_str()); + return 1; + } + } else if (option == "-k") { + if (!WindowsStringUtils::safe_mbstowcs(value, &options.api_key)) { + FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n", + value.c_str()); + return 1; + } + } else if (option == "-m") { + if (!WindowsStringUtils::safe_mbstowcs(value, + & options.missing_symbols_url)) { + FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n", + value.c_str()); + return 1; + } + } else if (option == "-mf") { + options.missing_symbols_file = value; + printf("Getting the list of missing symbols from a file. Fetch failures" + " will not be reported.\n"); + options.report_fetch_failures = false; + } else if (option == "-t") { + if (!WindowsStringUtils::safe_mbstowcs( + value, + & options.fetch_symbol_failure_url)) { + FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n", + value.c_str()); + return 1; + } + } else if (option == "-b") { + blacklist_regex_str = value; + } else { + return usage(argv[0]); + } + } + + if (blacklist_regex_str.empty()) { + FprintfFlush(stderr, "No blacklist specified.\n"); + return usage(argv[0]); + } + + // Compile the blacklist regular expression for later use. + options.blacklist_regex = std::regex(blacklist_regex_str.c_str(), + std::regex_constants::icase); + + // Set the defaults. If the user specified any MSSS servers, don't use + // any default. + if (!have_any_msss_servers) { + AddServer(kNoExeMSSSServer,& options.no_exe_internal_msss_servers, + & options.no_exe_external_msss_servers); + } + + if (options.local_cache_path.empty()) { + options.local_cache_path = kLocalCachePath; + } + + if (options.upload_symbols_url.empty()) { + FprintfFlush(stderr, "No upload symbols URL specified.\n"); + return usage(argv[0]); + } + if (options.api_key.empty()) { + FprintfFlush(stderr, "No API key specified.\n"); + return usage(argv[0]); + } + if (options.missing_symbols_url.empty() && + options.missing_symbols_file.empty()) { + FprintfFlush(stderr, "No missing symbols URL or file specified.\n"); + return usage(argv[0]); + } + if (options.fetch_symbol_failure_url.empty()) { + FprintfFlush(stderr, "No fetch symbol failure URL specified.\n"); + return usage(argv[0]); + } + + FprintfFlush(stdout, + "# of Symbol Servers (int/ext): %d/%d full, %d/%d no_exe\n", + options.full_internal_msss_servers.size(), + options.full_external_msss_servers.size(), + options.no_exe_internal_msss_servers.size(), + options.no_exe_external_msss_servers.size()); + + if (!ConvertMissingSymbolsList(options)) { + return 1; + } + + time_string = CurrentDateAndTime(); + FprintfFlush(stdout, "converter: %s: finished\n", time_string.c_str()); + return 0; +} diff --git a/src/tools/windows/converter_exe/converter.gyp b/src/tools/windows/converter_exe/converter.gyp deleted file mode 100644 index fe443d1b..00000000 --- a/src/tools/windows/converter_exe/converter.gyp +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2013 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': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'converter_exe', - 'type': 'executable', - 'sources': [ - 'converter.cc', - 'escaping.cc', - 'escaping.h', - 'http_client.h', - 'http_download.cc', - 'http_download.h', - 'tokenizer.cc', - 'tokenizer.h', - 'winhttp_client.cc', - 'winhttp_client.h', - 'wininet_client.cc', - 'wininet_client.h', - ], - 'dependencies': [ - '../../../common/windows/common_windows.gyp:common_windows_lib', - '../converter/ms_symbol_server_converter.gyp:ms_symbol_server_converter', - ], - }, - ], -} diff --git a/src/tools/windows/converter_exe/escaping.cc b/src/tools/windows/converter_exe/escaping.cc index 74a7203a..de074298 100644 --- a/src/tools/windows/converter_exe/escaping.cc +++ b/src/tools/windows/converter_exe/escaping.cc @@ -1,757 +1,757 @@ -// Copyright 2019 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 "tools/windows/converter_exe/escaping.h"
-
-#include <assert.h>
-
-#define kApb kAsciiPropertyBits
-
-const unsigned char kAsciiPropertyBits[256] = {
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00
- 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
- 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50
- 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70
- 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
-};
-
-// Use !! to suppress the warning C4800 of forcing 'int' to 'bool'.
-static inline bool ascii_isspace(unsigned char c) { return !!(kApb[c] & 0x08); }
-
-///////////////////////////////////
-// scoped_array
-///////////////////////////////////
-// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
-// with new [] and the destructor deletes objects with delete [].
-//
-// As with scoped_ptr<C>, a scoped_array<C> either points to an object
-// or is NULL. A scoped_array<C> owns the object that it points to.
-// scoped_array<T> is thread-compatible, and once you index into it,
-// the returned objects have only the threadsafety guarantees of T.
-//
-// Size: sizeof(scoped_array<C>) == sizeof(C*)
-template <class C>
-class scoped_array {
- public:
-
- // The element type
- typedef C element_type;
-
- // Constructor. Defaults to intializing with NULL.
- // There is no way to create an uninitialized scoped_array.
- // The input parameter must be allocated with new [].
- explicit scoped_array(C* p = NULL) : array_(p) { }
-
- // Destructor. If there is a C object, delete it.
- // We don't need to test ptr_ == NULL because C++ does that for us.
- ~scoped_array() {
- enum { type_must_be_complete = sizeof(C) };
- delete[] array_;
- }
-
- // Reset. Deletes the current owned object, if any.
- // Then takes ownership of a new object, if given.
- // this->reset(this->get()) works.
- void reset(C* p = NULL) {
- if (p != array_) {
- enum { type_must_be_complete = sizeof(C) };
- delete[] array_;
- array_ = p;
- }
- }
-
- // Get one element of the current object.
- // Will assert() if there is no current object, or index i is negative.
- C& operator[](std::ptrdiff_t i) const {
- assert(i >= 0);
- assert(array_ != NULL);
- return array_[i];
- }
-
- // Get a pointer to the zeroth element of the current object.
- // If there is no current object, return NULL.
- C* get() const {
- return array_;
- }
-
- // Comparison operators.
- // These return whether a scoped_array and a raw pointer refer to
- // the same array, not just to two different but equal arrays.
- bool operator==(const C* p) const { return array_ == p; }
- bool operator!=(const C* p) const { return array_ != p; }
-
- // Swap two scoped arrays.
- void swap(scoped_array& p2) {
- C* tmp = array_;
- array_ = p2.array_;
- p2.array_ = tmp;
- }
-
- // Release an array.
- // The return value is the current pointer held by this object.
- // If this object holds a NULL pointer, the return value is NULL.
- // After this operation, this object will hold a NULL pointer,
- // and will not own the object any more.
- C* release() {
- C* retVal = array_;
- array_ = NULL;
- return retVal;
- }
-
- private:
- C* array_;
-
- // Forbid comparison of different scoped_array types.
- template <class C2> bool operator==(scoped_array<C2> const& p2) const;
- template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
-
- // Disallow evil constructors
- scoped_array(const scoped_array&);
- void operator=(const scoped_array&);
-};
-
-
-///////////////////////////////////
-// Escape methods
-///////////////////////////////////
-
-namespace strings {
-
-// Return a mutable char* pointing to a string's internal buffer,
-// which may not be null-terminated. Writing through this pointer will
-// modify the string.
-//
-// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
-// next call to a string method that invalidates iterators.
-//
-// As of 2006-04, there is no standard-blessed way of getting a
-// mutable reference to a string's internal buffer. However, issue 530
-// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
-// proposes this as the method. According to Matt Austern, this should
-// already work on all current implementations.
-inline char* string_as_array(string* str) {
- // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
- return str->empty() ? NULL : &*str->begin();
-}
-
-int CalculateBase64EscapedLen(int input_len, bool do_padding) {
- // these formulae were copied from comments that used to go with the base64
- // encoding functions
- int intermediate_result = 8 * input_len + 5;
- assert(intermediate_result > 0); // make sure we didn't overflow
- int len = intermediate_result / 6;
- if (do_padding) len = ((len + 3) / 4) * 4;
- return len;
-}
-
-// Base64Escape does padding, so this calculation includes padding.
-int CalculateBase64EscapedLen(int input_len) {
- return CalculateBase64EscapedLen(input_len, true);
-}
-
-// ----------------------------------------------------------------------
-// int Base64Unescape() - base64 decoder
-// int Base64Escape() - base64 encoder
-// int WebSafeBase64Unescape() - Google's variation of base64 decoder
-// int WebSafeBase64Escape() - Google's variation of base64 encoder
-//
-// Check out
-// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal
-// description, but what we care about is that...
-// Take the encoded stuff in groups of 4 characters and turn each
-// character into a code 0 to 63 thus:
-// A-Z map to 0 to 25
-// a-z map to 26 to 51
-// 0-9 map to 52 to 61
-// +(- for WebSafe) maps to 62
-// /(_ for WebSafe) maps to 63
-// There will be four numbers, all less than 64 which can be represented
-// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
-// Arrange the 6 digit binary numbers into three bytes as such:
-// aaaaaabb bbbbcccc ccdddddd
-// Equals signs (one or two) are used at the end of the encoded block to
-// indicate that the text was not an integer multiple of three bytes long.
-// ----------------------------------------------------------------------
-
-int Base64UnescapeInternal(const char *src, int szsrc,
- char *dest, int szdest,
- const signed char* unbase64) {
- static const char kPad64 = '=';
-
- int decode = 0;
- int destidx = 0;
- int state = 0;
- unsigned int ch = 0;
- unsigned int temp = 0;
-
- // The GET_INPUT macro gets the next input character, skipping
- // over any whitespace, and stopping when we reach the end of the
- // string or when we read any non-data character. The arguments are
- // an arbitrary identifier (used as a label for goto) and the number
- // of data bytes that must remain in the input to avoid aborting the
- // loop.
-#define GET_INPUT(label, remain) \
- label: \
- --szsrc; \
- ch = *src++; \
- decode = unbase64[ch]; \
- if (decode < 0) { \
- if (ascii_isspace((char)ch) && szsrc >= remain) \
- goto label; \
- state = 4 - remain; \
- break; \
- }
-
- // if dest is null, we're just checking to see if it's legal input
- // rather than producing output. (I suspect this could just be done
- // with a regexp...). We duplicate the loop so this test can be
- // outside it instead of in every iteration.
-
- if (dest) {
- // This loop consumes 4 input bytes and produces 3 output bytes
- // per iteration. We can't know at the start that there is enough
- // data left in the string for a full iteration, so the loop may
- // break out in the middle; if so 'state' will be set to the
- // number of input bytes read.
-
- while (szsrc >= 4) {
- // We'll start by optimistically assuming that the next four
- // bytes of the string (src[0..3]) are four good data bytes
- // (that is, no nulls, whitespace, padding chars, or illegal
- // chars). We need to test src[0..2] for nulls individually
- // before constructing temp to preserve the property that we
- // never read past a null in the string (no matter how long
- // szsrc claims the string is).
-
- if (!src[0] || !src[1] || !src[2] ||
- (temp = ((unbase64[static_cast<int>(src[0])] << 18) |
- (unbase64[static_cast<int>(src[1])] << 12) |
- (unbase64[static_cast<int>(src[2])] << 6) |
- (unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
- // Iff any of those four characters was bad (null, illegal,
- // whitespace, padding), then temp's high bit will be set
- // (because unbase64[] is -1 for all bad characters).
- //
- // We'll back up and resort to the slower decoder, which knows
- // how to handle those cases.
-
- GET_INPUT(first, 4);
- temp = decode;
- GET_INPUT(second, 3);
- temp = (temp << 6) | decode;
- GET_INPUT(third, 2);
- temp = (temp << 6) | decode;
- GET_INPUT(fourth, 1);
- temp = (temp << 6) | decode;
- } else {
- // We really did have four good data bytes, so advance four
- // characters in the string.
-
- szsrc -= 4;
- src += 4;
- decode = -1;
- ch = '\0';
- }
-
- // temp has 24 bits of input, so write that out as three bytes.
-
- if (destidx+3 > szdest) return -1;
- dest[destidx+2] = (char)temp;
- temp >>= 8;
- dest[destidx+1] = (char)temp;
- temp >>= 8;
- dest[destidx] = (char)temp;
- destidx += 3;
- }
- } else {
- while (szsrc >= 4) {
- if (!src[0] || !src[1] || !src[2] ||
- (temp = ((unbase64[static_cast<int>(src[0])] << 18) |
- (unbase64[static_cast<int>(src[1])] << 12) |
- (unbase64[static_cast<int>(src[2])] << 6) |
- (unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
- GET_INPUT(first_no_dest, 4);
- GET_INPUT(second_no_dest, 3);
- GET_INPUT(third_no_dest, 2);
- GET_INPUT(fourth_no_dest, 1);
- } else {
- szsrc -= 4;
- src += 4;
- decode = -1;
- ch = '\0';
- }
- destidx += 3;
- }
- }
-
-#undef GET_INPUT
-
- // if the loop terminated because we read a bad character, return
- // now.
- if (decode < 0 && ch != '\0' && ch != kPad64 && !ascii_isspace((char)ch))
- return -1;
-
- if (ch == kPad64) {
- // if we stopped by hitting an '=', un-read that character -- we'll
- // look at it again when we count to check for the proper number of
- // equals signs at the end.
- ++szsrc;
- --src;
- } else {
- // This loop consumes 1 input byte per iteration. It's used to
- // clean up the 0-3 input bytes remaining when the first, faster
- // loop finishes. 'temp' contains the data from 'state' input
- // characters read by the first loop.
- while (szsrc > 0) {
- --szsrc;
- ch = *src++;
- decode = unbase64[ch];
- if (decode < 0) {
- if (ascii_isspace((char)ch)) {
- continue;
- } else if (ch == '\0') {
- break;
- } else if (ch == kPad64) {
- // back up one character; we'll read it again when we check
- // for the correct number of equals signs at the end.
- ++szsrc;
- --src;
- break;
- } else {
- return -1;
- }
- }
-
- // Each input character gives us six bits of output.
- temp = (temp << 6) | decode;
- ++state;
- if (state == 4) {
- // If we've accumulated 24 bits of output, write that out as
- // three bytes.
- if (dest) {
- if (destidx+3 > szdest) return -1;
- dest[destidx+2] = (char)temp;
- temp >>= 8;
- dest[destidx+1] = (char)temp;
- temp >>= 8;
- dest[destidx] = (char)temp;
- }
- destidx += 3;
- state = 0;
- temp = 0;
- }
- }
- }
-
- // Process the leftover data contained in 'temp' at the end of the input.
- int expected_equals = 0;
- switch (state) {
- case 0:
- // Nothing left over; output is a multiple of 3 bytes.
- break;
-
- case 1:
- // Bad input; we have 6 bits left over.
- return -1;
-
- case 2:
- // Produce one more output byte from the 12 input bits we have left.
- if (dest) {
- if (destidx+1 > szdest) return -1;
- temp >>= 4;
- dest[destidx] = (char)temp;
- }
- ++destidx;
- expected_equals = 2;
- break;
-
- case 3:
- // Produce two more output bytes from the 18 input bits we have left.
- if (dest) {
- if (destidx+2 > szdest) return -1;
- temp >>= 2;
- dest[destidx+1] = (char)temp;
- temp >>= 8;
- dest[destidx] = (char)temp;
- }
- destidx += 2;
- expected_equals = 1;
- break;
-
- default:
- // state should have no other values at this point.
- fprintf(stdout, "This can't happen; base64 decoder state = %d", state);
- }
-
- // The remainder of the string should be all whitespace, mixed with
- // exactly 0 equals signs, or exactly 'expected_equals' equals
- // signs. (Always accepting 0 equals signs is a google extension
- // not covered in the RFC.)
-
- int equals = 0;
- while (szsrc > 0 && *src) {
- if (*src == kPad64)
- ++equals;
- else if (!ascii_isspace(*src))
- return -1;
- --szsrc;
- ++src;
- }
-
- return (equals == 0 || equals == expected_equals) ? destidx : -1;
-}
-
-int Base64Unescape(const char *src, int szsrc, char *dest, int szdest) {
- static const signed char UnBase64[] = {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
- 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
- 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
- -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
- 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
- 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
- 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
- -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
- 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
- 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
- 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1
- };
- // The above array was generated by the following code
- // #include <sys/time.h>
- // #include <stdlib.h>
- // #include <string.h>
- // main()
- // {
- // static const char Base64[] =
- // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- // char *pos;
- // int idx, i, j;
- // printf(" ");
- // for (i = 0; i < 255; i += 8) {
- // for (j = i; j < i + 8; j++) {
- // pos = strchr(Base64, j);
- // if ((pos == NULL) || (j == 0))
- // idx = -1;
- // else
- // idx = pos - Base64;
- // if (idx == -1)
- // printf(" %2d, ", idx);
- // else
- // printf(" %2d/*%c*/,", idx, j);
- // }
- // printf("\n ");
- // }
- // }
-
- return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
-}
-
-bool Base64Unescape(const char *src, int slen, string* dest) {
- // Determine the size of the output string. Base64 encodes every 3 bytes into
- // 4 characters. any leftover chars are added directly for good measure.
- // This is documented in the base64 RFC: http://www.ietf.org/rfc/rfc3548.txt
- const int dest_len = 3 * (slen / 4) + (slen % 4);
-
- dest->resize(dest_len);
-
- // We are getting the destination buffer by getting the beginning of the
- // string and converting it into a char *.
- const int len = Base64Unescape(src, slen,
- string_as_array(dest), dest->size());
- if (len < 0) {
- return false;
- }
-
- // could be shorter if there was padding
- assert(len <= dest_len);
- dest->resize(len);
-
- return true;
-}
-
-// Base64Escape
-//
-// NOTE: We have to use an unsigned type for src because code built
-// in the the /google tree treats characters as signed unless
-// otherwised specified.
-//
-// TODO(who?): Move this function to use the char* type for "src"
-int Base64EscapeInternal(const unsigned char *src, int szsrc,
- char *dest, int szdest, const char *base64,
- bool do_padding) {
- static const char kPad64 = '=';
-
- if (szsrc <= 0) return 0;
-
- char *cur_dest = dest;
- const unsigned char *cur_src = src;
-
- // Three bytes of data encodes to four characters of cyphertext.
- // So we can pump through three-byte chunks atomically.
- while (szsrc > 2) { /* keep going until we have less than 24 bits */
- if ((szdest -= 4) < 0) return 0;
- cur_dest[0] = base64[cur_src[0] >> 2];
- cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
- cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];
- cur_dest[3] = base64[cur_src[2] & 0x3f];
-
- cur_dest += 4;
- cur_src += 3;
- szsrc -= 3;
- }
-
- /* now deal with the tail (<=2 bytes) */
- switch (szsrc) {
- case 0:
- // Nothing left; nothing more to do.
- break;
- case 1:
- // One byte left: this encodes to two characters, and (optionally)
- // two pad characters to round out the four-character cypherblock.
- if ((szdest -= 2) < 0) return 0;
- cur_dest[0] = base64[cur_src[0] >> 2];
- cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];
- cur_dest += 2;
- if (do_padding) {
- if ((szdest -= 2) < 0) return 0;
- cur_dest[0] = kPad64;
- cur_dest[1] = kPad64;
- cur_dest += 2;
- }
- break;
- case 2:
- // Two bytes left: this encodes to three characters, and (optionally)
- // one pad character to round out the four-character cypherblock.
- if ((szdest -= 3) < 0) return 0;
- cur_dest[0] = base64[cur_src[0] >> 2];
- cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
- cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];
- cur_dest += 3;
- if (do_padding) {
- if ((szdest -= 1) < 0) return 0;
- cur_dest[0] = kPad64;
- cur_dest += 1;
- }
- break;
- default:
- // Should not be reached: blocks of 3 bytes are handled
- // in the while loop before this switch statement.
- fprintf(stderr, "Logic problem? szsrc = %d", szsrc);
- assert(false);
- break;
- }
- return (cur_dest - dest);
-}
-
-static const char kBase64Chars[] =
-"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-static const char kWebSafeBase64Chars[] =
-"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-
-int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) {
- return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
-}
-
-void Base64Escape(const unsigned char *src, int szsrc,
- string* dest, bool do_padding) {
- const int max_escaped_size =
- CalculateBase64EscapedLen(szsrc, do_padding);
- dest->clear();
- dest->resize(max_escaped_size + 1, '\0');
- const int escaped_len = Base64EscapeInternal(src, szsrc,
- &*dest->begin(), dest->size(),
- kBase64Chars,
- do_padding);
- assert(max_escaped_size <= escaped_len);
- dest->resize(escaped_len);
-}
-
-void Base64Escape(const string& src, string* dest) {
- Base64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
- src.size(), dest, true);
-}
-
-////////////////////////////////////////////////////
-// WebSafe methods
-////////////////////////////////////////////////////
-
-int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
- static const signed char UnBase64[] = {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 62/*-*/, -1, -1,
- 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
- 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
- -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
- 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
- 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
- 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/,
- -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
- 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
- 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
- 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1
- };
- // The above array was generated by the following code
- // #include <sys/time.h>
- // #include <stdlib.h>
- // #include <string.h>
- // main()
- // {
- // static const char Base64[] =
- // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
- // char *pos;
- // int idx, i, j;
- // printf(" ");
- // for (i = 0; i < 255; i += 8) {
- // for (j = i; j < i + 8; j++) {
- // pos = strchr(Base64, j);
- // if ((pos == NULL) || (j == 0))
- // idx = -1;
- // else
- // idx = pos - Base64;
- // if (idx == -1)
- // printf(" %2d, ", idx);
- // else
- // printf(" %2d/*%c*/,", idx, j);
- // }
- // printf("\n ");
- // }
- // }
-
- return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
-}
-
-bool WebSafeBase64Unescape(const char *src, int slen, string* dest) {
- int dest_len = 3 * (slen / 4) + (slen % 4);
- dest->clear();
- dest->resize(dest_len);
- int len = WebSafeBase64Unescape(src, slen, &*dest->begin(), dest->size());
- if (len < 0) {
- dest->clear();
- return false;
- }
- // could be shorter if there was padding
- assert(len <= dest_len);
- dest->resize(len);
- return true;
-}
-
-bool WebSafeBase64Unescape(const string& src, string* dest) {
- return WebSafeBase64Unescape(src.data(), src.size(), dest);
-}
-
-int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest,
- int szdest, bool do_padding) {
- return Base64EscapeInternal(src, szsrc, dest, szdest,
- kWebSafeBase64Chars, do_padding);
-}
-
-void WebSafeBase64Escape(const unsigned char *src, int szsrc,
- string *dest, bool do_padding) {
- const int max_escaped_size =
- CalculateBase64EscapedLen(szsrc, do_padding);
- dest->clear();
- dest->resize(max_escaped_size + 1, '\0');
- const int escaped_len = Base64EscapeInternal(src, szsrc,
- &*dest->begin(), dest->size(),
- kWebSafeBase64Chars,
- do_padding);
- assert(max_escaped_size <= escaped_len);
- dest->resize(escaped_len);
-}
-
-void WebSafeBase64EscapeInternal(const string& src,
- string* dest,
- bool do_padding) {
- int encoded_len = CalculateBase64EscapedLen(src.size());
- scoped_array<char> buf(new char[encoded_len]);
- int len = WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
- src.size(), buf.get(),
- encoded_len, do_padding);
- dest->assign(buf.get(), len);
-}
-
-void WebSafeBase64Escape(const string& src, string* dest) {
- WebSafeBase64EscapeInternal(src, dest, false);
-}
-
-void WebSafeBase64EscapeWithPadding(const string& src, string* dest) {
- WebSafeBase64EscapeInternal(src, dest, true);
-}
-
-} // namespace strings
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "tools/windows/converter_exe/escaping.h" + +#include <assert.h> + +#define kApb kAsciiPropertyBits + +const unsigned char kAsciiPropertyBits[256] = { + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00 + 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10 + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20 + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40 + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50 + 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60 + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70 + 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40, +}; + +// Use !! to suppress the warning C4800 of forcing 'int' to 'bool'. +static inline bool ascii_isspace(unsigned char c) { return !!(kApb[c] & 0x08); } + +/////////////////////////////////// +// scoped_array +/////////////////////////////////// +// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate +// with new [] and the destructor deletes objects with delete []. +// +// As with scoped_ptr<C>, a scoped_array<C> either points to an object +// or is NULL. A scoped_array<C> owns the object that it points to. +// scoped_array<T> is thread-compatible, and once you index into it, +// the returned objects have only the threadsafety guarantees of T. +// +// Size: sizeof(scoped_array<C>) == sizeof(C*) +template <class C> +class scoped_array { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_array. + // The input parameter must be allocated with new []. + explicit scoped_array(C* p = NULL) : array_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_array() { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != array_) { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + array_ = p; + } + } + + // Get one element of the current object. + // Will assert() if there is no current object, or index i is negative. + C& operator[](std::ptrdiff_t i) const { + assert(i >= 0); + assert(array_ != NULL); + return array_[i]; + } + + // Get a pointer to the zeroth element of the current object. + // If there is no current object, return NULL. + C* get() const { + return array_; + } + + // Comparison operators. + // These return whether a scoped_array and a raw pointer refer to + // the same array, not just to two different but equal arrays. + bool operator==(const C* p) const { return array_ == p; } + bool operator!=(const C* p) const { return array_ != p; } + + // Swap two scoped arrays. + void swap(scoped_array& p2) { + C* tmp = array_; + array_ = p2.array_; + p2.array_ = tmp; + } + + // Release an array. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = array_; + array_ = NULL; + return retVal; + } + + private: + C* array_; + + // Forbid comparison of different scoped_array types. + template <class C2> bool operator==(scoped_array<C2> const& p2) const; + template <class C2> bool operator!=(scoped_array<C2> const& p2) const; + + // Disallow evil constructors + scoped_array(const scoped_array&); + void operator=(const scoped_array&); +}; + + +/////////////////////////////////// +// Escape methods +/////////////////////////////////// + +namespace strings { + +// Return a mutable char* pointing to a string's internal buffer, +// which may not be null-terminated. Writing through this pointer will +// modify the string. +// +// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the +// next call to a string method that invalidates iterators. +// +// As of 2006-04, there is no standard-blessed way of getting a +// mutable reference to a string's internal buffer. However, issue 530 +// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) +// proposes this as the method. According to Matt Austern, this should +// already work on all current implementations. +inline char* string_as_array(string* str) { + // DO NOT USE const_cast<char*>(str->data())! See the unittest for why. + return str->empty() ? NULL : &*str->begin(); +} + +int CalculateBase64EscapedLen(int input_len, bool do_padding) { + // these formulae were copied from comments that used to go with the base64 + // encoding functions + int intermediate_result = 8 * input_len + 5; + assert(intermediate_result > 0); // make sure we didn't overflow + int len = intermediate_result / 6; + if (do_padding) len = ((len + 3) / 4) * 4; + return len; +} + +// Base64Escape does padding, so this calculation includes padding. +int CalculateBase64EscapedLen(int input_len) { + return CalculateBase64EscapedLen(input_len, true); +} + +// ---------------------------------------------------------------------- +// int Base64Unescape() - base64 decoder +// int Base64Escape() - base64 encoder +// int WebSafeBase64Unescape() - Google's variation of base64 decoder +// int WebSafeBase64Escape() - Google's variation of base64 encoder +// +// Check out +// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal +// description, but what we care about is that... +// Take the encoded stuff in groups of 4 characters and turn each +// character into a code 0 to 63 thus: +// A-Z map to 0 to 25 +// a-z map to 26 to 51 +// 0-9 map to 52 to 61 +// +(- for WebSafe) maps to 62 +// /(_ for WebSafe) maps to 63 +// There will be four numbers, all less than 64 which can be represented +// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively). +// Arrange the 6 digit binary numbers into three bytes as such: +// aaaaaabb bbbbcccc ccdddddd +// Equals signs (one or two) are used at the end of the encoded block to +// indicate that the text was not an integer multiple of three bytes long. +// ---------------------------------------------------------------------- + +int Base64UnescapeInternal(const char *src, int szsrc, + char *dest, int szdest, + const signed char* unbase64) { + static const char kPad64 = '='; + + int decode = 0; + int destidx = 0; + int state = 0; + unsigned int ch = 0; + unsigned int temp = 0; + + // The GET_INPUT macro gets the next input character, skipping + // over any whitespace, and stopping when we reach the end of the + // string or when we read any non-data character. The arguments are + // an arbitrary identifier (used as a label for goto) and the number + // of data bytes that must remain in the input to avoid aborting the + // loop. +#define GET_INPUT(label, remain) \ + label: \ + --szsrc; \ + ch = *src++; \ + decode = unbase64[ch]; \ + if (decode < 0) { \ + if (ascii_isspace((char)ch) && szsrc >= remain) \ + goto label; \ + state = 4 - remain; \ + break; \ + } + + // if dest is null, we're just checking to see if it's legal input + // rather than producing output. (I suspect this could just be done + // with a regexp...). We duplicate the loop so this test can be + // outside it instead of in every iteration. + + if (dest) { + // This loop consumes 4 input bytes and produces 3 output bytes + // per iteration. We can't know at the start that there is enough + // data left in the string for a full iteration, so the loop may + // break out in the middle; if so 'state' will be set to the + // number of input bytes read. + + while (szsrc >= 4) { + // We'll start by optimistically assuming that the next four + // bytes of the string (src[0..3]) are four good data bytes + // (that is, no nulls, whitespace, padding chars, or illegal + // chars). We need to test src[0..2] for nulls individually + // before constructing temp to preserve the property that we + // never read past a null in the string (no matter how long + // szsrc claims the string is). + + if (!src[0] || !src[1] || !src[2] || + (temp = ((unbase64[static_cast<int>(src[0])] << 18) | + (unbase64[static_cast<int>(src[1])] << 12) | + (unbase64[static_cast<int>(src[2])] << 6) | + (unbase64[static_cast<int>(src[3])]))) & 0x80000000) { + // Iff any of those four characters was bad (null, illegal, + // whitespace, padding), then temp's high bit will be set + // (because unbase64[] is -1 for all bad characters). + // + // We'll back up and resort to the slower decoder, which knows + // how to handle those cases. + + GET_INPUT(first, 4); + temp = decode; + GET_INPUT(second, 3); + temp = (temp << 6) | decode; + GET_INPUT(third, 2); + temp = (temp << 6) | decode; + GET_INPUT(fourth, 1); + temp = (temp << 6) | decode; + } else { + // We really did have four good data bytes, so advance four + // characters in the string. + + szsrc -= 4; + src += 4; + decode = -1; + ch = '\0'; + } + + // temp has 24 bits of input, so write that out as three bytes. + + if (destidx+3 > szdest) return -1; + dest[destidx+2] = (char)temp; + temp >>= 8; + dest[destidx+1] = (char)temp; + temp >>= 8; + dest[destidx] = (char)temp; + destidx += 3; + } + } else { + while (szsrc >= 4) { + if (!src[0] || !src[1] || !src[2] || + (temp = ((unbase64[static_cast<int>(src[0])] << 18) | + (unbase64[static_cast<int>(src[1])] << 12) | + (unbase64[static_cast<int>(src[2])] << 6) | + (unbase64[static_cast<int>(src[3])]))) & 0x80000000) { + GET_INPUT(first_no_dest, 4); + GET_INPUT(second_no_dest, 3); + GET_INPUT(third_no_dest, 2); + GET_INPUT(fourth_no_dest, 1); + } else { + szsrc -= 4; + src += 4; + decode = -1; + ch = '\0'; + } + destidx += 3; + } + } + +#undef GET_INPUT + + // if the loop terminated because we read a bad character, return + // now. + if (decode < 0 && ch != '\0' && ch != kPad64 && !ascii_isspace((char)ch)) + return -1; + + if (ch == kPad64) { + // if we stopped by hitting an '=', un-read that character -- we'll + // look at it again when we count to check for the proper number of + // equals signs at the end. + ++szsrc; + --src; + } else { + // This loop consumes 1 input byte per iteration. It's used to + // clean up the 0-3 input bytes remaining when the first, faster + // loop finishes. 'temp' contains the data from 'state' input + // characters read by the first loop. + while (szsrc > 0) { + --szsrc; + ch = *src++; + decode = unbase64[ch]; + if (decode < 0) { + if (ascii_isspace((char)ch)) { + continue; + } else if (ch == '\0') { + break; + } else if (ch == kPad64) { + // back up one character; we'll read it again when we check + // for the correct number of equals signs at the end. + ++szsrc; + --src; + break; + } else { + return -1; + } + } + + // Each input character gives us six bits of output. + temp = (temp << 6) | decode; + ++state; + if (state == 4) { + // If we've accumulated 24 bits of output, write that out as + // three bytes. + if (dest) { + if (destidx+3 > szdest) return -1; + dest[destidx+2] = (char)temp; + temp >>= 8; + dest[destidx+1] = (char)temp; + temp >>= 8; + dest[destidx] = (char)temp; + } + destidx += 3; + state = 0; + temp = 0; + } + } + } + + // Process the leftover data contained in 'temp' at the end of the input. + int expected_equals = 0; + switch (state) { + case 0: + // Nothing left over; output is a multiple of 3 bytes. + break; + + case 1: + // Bad input; we have 6 bits left over. + return -1; + + case 2: + // Produce one more output byte from the 12 input bits we have left. + if (dest) { + if (destidx+1 > szdest) return -1; + temp >>= 4; + dest[destidx] = (char)temp; + } + ++destidx; + expected_equals = 2; + break; + + case 3: + // Produce two more output bytes from the 18 input bits we have left. + if (dest) { + if (destidx+2 > szdest) return -1; + temp >>= 2; + dest[destidx+1] = (char)temp; + temp >>= 8; + dest[destidx] = (char)temp; + } + destidx += 2; + expected_equals = 1; + break; + + default: + // state should have no other values at this point. + fprintf(stdout, "This can't happen; base64 decoder state = %d", state); + } + + // The remainder of the string should be all whitespace, mixed with + // exactly 0 equals signs, or exactly 'expected_equals' equals + // signs. (Always accepting 0 equals signs is a google extension + // not covered in the RFC.) + + int equals = 0; + while (szsrc > 0 && *src) { + if (*src == kPad64) + ++equals; + else if (!ascii_isspace(*src)) + return -1; + --szsrc; + ++src; + } + + return (equals == 0 || equals == expected_equals) ? destidx : -1; +} + +int Base64Unescape(const char *src, int szsrc, char *dest, int szdest) { + static const signed char UnBase64[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, + 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, + 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, + -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, + 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, + 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, + 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, + -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, + 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, + 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, + 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 + }; + // The above array was generated by the following code + // #include <sys/time.h> + // #include <stdlib.h> + // #include <string.h> + // main() + // { + // static const char Base64[] = + // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + // char *pos; + // int idx, i, j; + // printf(" "); + // for (i = 0; i < 255; i += 8) { + // for (j = i; j < i + 8; j++) { + // pos = strchr(Base64, j); + // if ((pos == NULL) || (j == 0)) + // idx = -1; + // else + // idx = pos - Base64; + // if (idx == -1) + // printf(" %2d, ", idx); + // else + // printf(" %2d/*%c*/,", idx, j); + // } + // printf("\n "); + // } + // } + + return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64); +} + +bool Base64Unescape(const char *src, int slen, string* dest) { + // Determine the size of the output string. Base64 encodes every 3 bytes into + // 4 characters. any leftover chars are added directly for good measure. + // This is documented in the base64 RFC: http://www.ietf.org/rfc/rfc3548.txt + const int dest_len = 3 * (slen / 4) + (slen % 4); + + dest->resize(dest_len); + + // We are getting the destination buffer by getting the beginning of the + // string and converting it into a char *. + const int len = Base64Unescape(src, slen, + string_as_array(dest), dest->size()); + if (len < 0) { + return false; + } + + // could be shorter if there was padding + assert(len <= dest_len); + dest->resize(len); + + return true; +} + +// Base64Escape +// +// NOTE: We have to use an unsigned type for src because code built +// in the the /google tree treats characters as signed unless +// otherwised specified. +// +// TODO(who?): Move this function to use the char* type for "src" +int Base64EscapeInternal(const unsigned char *src, int szsrc, + char *dest, int szdest, const char *base64, + bool do_padding) { + static const char kPad64 = '='; + + if (szsrc <= 0) return 0; + + char *cur_dest = dest; + const unsigned char *cur_src = src; + + // Three bytes of data encodes to four characters of cyphertext. + // So we can pump through three-byte chunks atomically. + while (szsrc > 2) { /* keep going until we have less than 24 bits */ + if ((szdest -= 4) < 0) return 0; + cur_dest[0] = base64[cur_src[0] >> 2]; + cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)]; + cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)]; + cur_dest[3] = base64[cur_src[2] & 0x3f]; + + cur_dest += 4; + cur_src += 3; + szsrc -= 3; + } + + /* now deal with the tail (<=2 bytes) */ + switch (szsrc) { + case 0: + // Nothing left; nothing more to do. + break; + case 1: + // One byte left: this encodes to two characters, and (optionally) + // two pad characters to round out the four-character cypherblock. + if ((szdest -= 2) < 0) return 0; + cur_dest[0] = base64[cur_src[0] >> 2]; + cur_dest[1] = base64[(cur_src[0] & 0x03) << 4]; + cur_dest += 2; + if (do_padding) { + if ((szdest -= 2) < 0) return 0; + cur_dest[0] = kPad64; + cur_dest[1] = kPad64; + cur_dest += 2; + } + break; + case 2: + // Two bytes left: this encodes to three characters, and (optionally) + // one pad character to round out the four-character cypherblock. + if ((szdest -= 3) < 0) return 0; + cur_dest[0] = base64[cur_src[0] >> 2]; + cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)]; + cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2]; + cur_dest += 3; + if (do_padding) { + if ((szdest -= 1) < 0) return 0; + cur_dest[0] = kPad64; + cur_dest += 1; + } + break; + default: + // Should not be reached: blocks of 3 bytes are handled + // in the while loop before this switch statement. + fprintf(stderr, "Logic problem? szsrc = %d", szsrc); + assert(false); + break; + } + return (cur_dest - dest); +} + +static const char kBase64Chars[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const char kWebSafeBase64Chars[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) { + return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true); +} + +void Base64Escape(const unsigned char *src, int szsrc, + string* dest, bool do_padding) { + const int max_escaped_size = + CalculateBase64EscapedLen(szsrc, do_padding); + dest->clear(); + dest->resize(max_escaped_size + 1, '\0'); + const int escaped_len = Base64EscapeInternal(src, szsrc, + &*dest->begin(), dest->size(), + kBase64Chars, + do_padding); + assert(max_escaped_size <= escaped_len); + dest->resize(escaped_len); +} + +void Base64Escape(const string& src, string* dest) { + Base64Escape(reinterpret_cast<const unsigned char*>(src.c_str()), + src.size(), dest, true); +} + +//////////////////////////////////////////////////// +// WebSafe methods +//////////////////////////////////////////////////// + +int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) { + static const signed char UnBase64[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 62/*-*/, -1, -1, + 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, + 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, + -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, + 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, + 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, + 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/, + -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, + 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, + 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, + 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 + }; + // The above array was generated by the following code + // #include <sys/time.h> + // #include <stdlib.h> + // #include <string.h> + // main() + // { + // static const char Base64[] = + // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + // char *pos; + // int idx, i, j; + // printf(" "); + // for (i = 0; i < 255; i += 8) { + // for (j = i; j < i + 8; j++) { + // pos = strchr(Base64, j); + // if ((pos == NULL) || (j == 0)) + // idx = -1; + // else + // idx = pos - Base64; + // if (idx == -1) + // printf(" %2d, ", idx); + // else + // printf(" %2d/*%c*/,", idx, j); + // } + // printf("\n "); + // } + // } + + return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64); +} + +bool WebSafeBase64Unescape(const char *src, int slen, string* dest) { + int dest_len = 3 * (slen / 4) + (slen % 4); + dest->clear(); + dest->resize(dest_len); + int len = WebSafeBase64Unescape(src, slen, &*dest->begin(), dest->size()); + if (len < 0) { + dest->clear(); + return false; + } + // could be shorter if there was padding + assert(len <= dest_len); + dest->resize(len); + return true; +} + +bool WebSafeBase64Unescape(const string& src, string* dest) { + return WebSafeBase64Unescape(src.data(), src.size(), dest); +} + +int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest, + int szdest, bool do_padding) { + return Base64EscapeInternal(src, szsrc, dest, szdest, + kWebSafeBase64Chars, do_padding); +} + +void WebSafeBase64Escape(const unsigned char *src, int szsrc, + string *dest, bool do_padding) { + const int max_escaped_size = + CalculateBase64EscapedLen(szsrc, do_padding); + dest->clear(); + dest->resize(max_escaped_size + 1, '\0'); + const int escaped_len = Base64EscapeInternal(src, szsrc, + &*dest->begin(), dest->size(), + kWebSafeBase64Chars, + do_padding); + assert(max_escaped_size <= escaped_len); + dest->resize(escaped_len); +} + +void WebSafeBase64EscapeInternal(const string& src, + string* dest, + bool do_padding) { + int encoded_len = CalculateBase64EscapedLen(src.size()); + scoped_array<char> buf(new char[encoded_len]); + int len = WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.c_str()), + src.size(), buf.get(), + encoded_len, do_padding); + dest->assign(buf.get(), len); +} + +void WebSafeBase64Escape(const string& src, string* dest) { + WebSafeBase64EscapeInternal(src, dest, false); +} + +void WebSafeBase64EscapeWithPadding(const string& src, string* dest) { + WebSafeBase64EscapeInternal(src, dest, true); +} + +} // namespace strings diff --git a/src/tools/windows/converter_exe/escaping.h b/src/tools/windows/converter_exe/escaping.h index c8aa90b7..bc36bf57 100644 --- a/src/tools/windows/converter_exe/escaping.h +++ b/src/tools/windows/converter_exe/escaping.h @@ -1,99 +1,99 @@ -// Copyright 2019 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.
-//
-// Base64 escaping methods to encode/decode strings.
-
-#ifndef TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
-
-#include <string>
-
-namespace strings {
-
-using std::string;
-
-// ----------------------------------------------------------------------
-// Base64Escape()
-// WebSafeBase64Escape()
-// Encode "src" to "dest" using base64 encoding.
-// src is not null terminated, instead specify len.
-// 'dest' should have at least CalculateBase64EscapedLen() length.
-// RETURNS the length of dest.
-// The WebSafe variation use '-' instead of '+' and '_' instead of '/'
-// so that we can place the out in the URL or cookies without having
-// to escape them. It also has an extra parameter "do_padding",
-// which when set to false will prevent padding with "=".
-// ----------------------------------------------------------------------
-void Base64Escape(const string& src, string* dest);
-int Base64Escape(const unsigned char* src, int slen, char* dest, int szdest);
-// Encode src into dest with padding.
-void Base64Escape(const unsigned char* src, int szsrc,
- string* dest, bool do_padding);
-
-int WebSafeBase64Escape(const unsigned char* src, int slen, char* dest,
- int szdest, bool do_padding);
-// Encode src into dest web-safely without padding.
-void WebSafeBase64Escape(const string& src, string* dest);
-// Encode src into dest web-safely with padding.
-void WebSafeBase64EscapeWithPadding(const string& src, string* dest);
-void WebSafeBase64Escape(const unsigned char* src, int szsrc,
- string* dest, bool do_padding);
-
-// ----------------------------------------------------------------------
-// Base64Unescape()
-// WebSafeBase64Unescape()
-// Copies "src" to "dest", where src is in base64 and is written to its
-// ASCII equivalents. src is not null terminated, instead specify len.
-// I recommend that slen<szdest, but we honor szdest anyway.
-// RETURNS the length of dest, or -1 if src contains invalid chars.
-// The WebSafe variation use '-' instead of '+' and '_' instead of '/'.
-// The variations that store into a string clear the string first, and
-// return false (with dest empty) if src contains invalid chars; for
-// these versions src and dest must be different strings.
-// ----------------------------------------------------------------------
-int Base64Unescape(const char* src, int slen, char* dest, int szdest);
-bool Base64Unescape(const char* src, int slen, string* dest);
-inline bool Base64Unescape(const string& src, string* dest) {
- return Base64Unescape(src.data(), src.size(), dest);
-}
-
-
-int WebSafeBase64Unescape(const char* src, int slen, char* dest, int szdest);
-bool WebSafeBase64Unescape(const char* src, int slen, string* dest);
-bool WebSafeBase64Unescape(const string& src, string* dest);
-
-// Return the length to use for the output buffer given to the base64 escape
-// routines. Make sure to use the same value for do_padding in both.
-// This function may return incorrect results if given input_len values that
-// are extremely high, which should happen rarely.
-int CalculateBase64EscapedLen(int input_len, bool do_padding);
-// Use this version when calling Base64Escape without a do_padding arg.
-int CalculateBase64EscapedLen(int input_len);
-} // namespace strings
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Base64 escaping methods to encode/decode strings. + +#ifndef TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_ + +#include <string> + +namespace strings { + +using std::string; + +// ---------------------------------------------------------------------- +// Base64Escape() +// WebSafeBase64Escape() +// Encode "src" to "dest" using base64 encoding. +// src is not null terminated, instead specify len. +// 'dest' should have at least CalculateBase64EscapedLen() length. +// RETURNS the length of dest. +// The WebSafe variation use '-' instead of '+' and '_' instead of '/' +// so that we can place the out in the URL or cookies without having +// to escape them. It also has an extra parameter "do_padding", +// which when set to false will prevent padding with "=". +// ---------------------------------------------------------------------- +void Base64Escape(const string& src, string* dest); +int Base64Escape(const unsigned char* src, int slen, char* dest, int szdest); +// Encode src into dest with padding. +void Base64Escape(const unsigned char* src, int szsrc, + string* dest, bool do_padding); + +int WebSafeBase64Escape(const unsigned char* src, int slen, char* dest, + int szdest, bool do_padding); +// Encode src into dest web-safely without padding. +void WebSafeBase64Escape(const string& src, string* dest); +// Encode src into dest web-safely with padding. +void WebSafeBase64EscapeWithPadding(const string& src, string* dest); +void WebSafeBase64Escape(const unsigned char* src, int szsrc, + string* dest, bool do_padding); + +// ---------------------------------------------------------------------- +// Base64Unescape() +// WebSafeBase64Unescape() +// Copies "src" to "dest", where src is in base64 and is written to its +// ASCII equivalents. src is not null terminated, instead specify len. +// I recommend that slen<szdest, but we honor szdest anyway. +// RETURNS the length of dest, or -1 if src contains invalid chars. +// The WebSafe variation use '-' instead of '+' and '_' instead of '/'. +// The variations that store into a string clear the string first, and +// return false (with dest empty) if src contains invalid chars; for +// these versions src and dest must be different strings. +// ---------------------------------------------------------------------- +int Base64Unescape(const char* src, int slen, char* dest, int szdest); +bool Base64Unescape(const char* src, int slen, string* dest); +inline bool Base64Unescape(const string& src, string* dest) { + return Base64Unescape(src.data(), src.size(), dest); +} + + +int WebSafeBase64Unescape(const char* src, int slen, char* dest, int szdest); +bool WebSafeBase64Unescape(const char* src, int slen, string* dest); +bool WebSafeBase64Unescape(const string& src, string* dest); + +// Return the length to use for the output buffer given to the base64 escape +// routines. Make sure to use the same value for do_padding in both. +// This function may return incorrect results if given input_len values that +// are extremely high, which should happen rarely. +int CalculateBase64EscapedLen(int input_len, bool do_padding); +// Use this version when calling Base64Escape without a do_padding arg. +int CalculateBase64EscapedLen(int input_len); +} // namespace strings + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_ diff --git a/src/tools/windows/converter_exe/http_client.h b/src/tools/windows/converter_exe/http_client.h index 3e7aa8a7..38ebf2e4 100644 --- a/src/tools/windows/converter_exe/http_client.h +++ b/src/tools/windows/converter_exe/http_client.h @@ -1,96 +1,96 @@ -// Copyright 2019 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 TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
-#define TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
-
-#include <tchar.h>
-#include <windows.h>
-#include <vector>
-
-typedef void* HttpHandle;
-
-namespace crash {
-
-// HttpClient provides an abstract layer for HTTP APIs. The actual
-// implementation can be based on either WinHttp or WinInet.
-class HttpClient {
- public:
- enum AccessType {
- ACCESS_TYPE_PRECONFIG,
- ACCESS_TYPE_DIRECT,
- ACCESS_TYPE_PROXY,
- };
-
- virtual ~HttpClient() {}
-
- virtual bool CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const = 0;
- virtual bool Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const = 0;
- virtual bool Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const = 0;
- virtual bool OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const = 0;
- virtual bool SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const = 0;
- virtual bool ReceiveResponse(HttpHandle request_handle) const = 0;
- virtual bool GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const = 0;
- virtual bool GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const = 0;
- virtual bool ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const = 0;
- virtual bool Close(HttpHandle handle) const = 0;
-
- static const DWORD kUnknownContentLength = (DWORD)-1;
-};
-
-} // namespace crash
-
-#endif // TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_ +#define TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_ + +#include <tchar.h> +#include <windows.h> +#include <vector> + +typedef void* HttpHandle; + +namespace crash { + +// HttpClient provides an abstract layer for HTTP APIs. The actual +// implementation can be based on either WinHttp or WinInet. +class HttpClient { + public: + enum AccessType { + ACCESS_TYPE_PRECONFIG, + ACCESS_TYPE_DIRECT, + ACCESS_TYPE_PROXY, + }; + + virtual ~HttpClient() {} + + virtual bool CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const = 0; + virtual bool Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const = 0; + virtual bool Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const = 0; + virtual bool OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const = 0; + virtual bool SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const = 0; + virtual bool ReceiveResponse(HttpHandle request_handle) const = 0; + virtual bool GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const = 0; + virtual bool GetContentLength(HttpHandle request_handle, + DWORD* content_length) const = 0; + virtual bool ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const = 0; + virtual bool Close(HttpHandle handle) const = 0; + + static const DWORD kUnknownContentLength = (DWORD)-1; +}; + +} // namespace crash + +#endif // TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_ diff --git a/src/tools/windows/converter_exe/http_download.cc b/src/tools/windows/converter_exe/http_download.cc index 5afc1ccc..75f674e0 100644 --- a/src/tools/windows/converter_exe/http_download.cc +++ b/src/tools/windows/converter_exe/http_download.cc @@ -1,326 +1,326 @@ -// Copyright 2019 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 <assert.h>
-#include <stdio.h>
-#include <Windows.h>
-#include <WinInet.h>
-
-#include <vector>
-
-#include "tools/windows/converter_exe/http_download.h"
-#include "tools/windows/converter_exe/winhttp_client.h"
-#include "tools/windows/converter_exe/wininet_client.h"
-
-namespace crash {
-static const std::vector<char>::size_type kVectorChunkSize = 4096; // 4 KB
-
-using std::vector;
-
-// Class that atuo closes the contained HttpHandle when the object
-// goes out of scope.
-class AutoHttpHandle {
- public:
- AutoHttpHandle() : handle_(NULL) {}
- explicit AutoHttpHandle(HttpHandle handle) : handle_(handle) {}
- ~AutoHttpHandle() {
- if (handle_) {
- InternetCloseHandle(handle_);
- }
- }
-
- HttpHandle get() { return handle_; }
- HttpHandle* get_handle_addr () { return &handle_; }
-
- private:
- HttpHandle handle_;
-};
-
-// Template class for auto releasing the contained pointer when
-// the object goes out of scope.
-template<typename T>
-class AutoPtr {
- public:
- explicit AutoPtr(T* ptr) : ptr_(ptr) {}
- ~AutoPtr() {
- if (ptr_) {
- delete ptr_;
- }
- }
-
- T* get() { return ptr_; }
- T* operator -> () { return ptr_; }
-
- private:
- T* ptr_;
-};
-
-// CheckParameters ensures that the parameters in |parameters| are safe for
-// use in an HTTP URL. Returns true if they are, false if unsafe characters
-// are present.
-static bool CheckParameters(const map<wstring, wstring> *parameters) {
- for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
- iterator != parameters->end();
- ++iterator) {
- const wstring &key = iterator->first;
- if (key.empty()) {
- // Disallow empty parameter names.
- return false;
- }
- for (unsigned int i = 0; i < key.size(); ++i) {
- wchar_t c = key[i];
- if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
- return false;
- }
- }
-
- const wstring &value = iterator->second;
- for (unsigned int i = 0; i < value.size(); ++i) {
- wchar_t c = value[i];
- if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-HttpClient* HTTPDownload::CreateHttpClient(const wchar_t* url) {
- const TCHAR* kHttpApiPolicyEnvironmentVariable = TEXT("USE_WINHTTP");
- TCHAR buffer[2] = {0};
- HttpClient* http_client = NULL;
-
- if (::GetEnvironmentVariable(kHttpApiPolicyEnvironmentVariable,
- buffer,
- sizeof(buffer)/sizeof(buffer[0])) > 0) {
- fprintf(stdout,
- "Environment variable [%ws] is set, use WinHttp\n",
- kHttpApiPolicyEnvironmentVariable);
- http_client = CreateWinHttpClient(url);
- if (http_client == NULL) {
- fprintf(stderr, "WinHttpClient not created, Is the protocol HTTPS? "
- "Fall back to WinInet API.\n");
- }
- } else {
- fprintf(stderr,
- "Environment variable [%ws] is NOT set, use WinInet API\n",
- kHttpApiPolicyEnvironmentVariable);
- }
-
- if (http_client == NULL) {
- return CreateWinInetClient(url);
- }
-
- return http_client;
-}
-
-// static
-bool HTTPDownload::Download(const wstring &url,
- const map<wstring, wstring> *parameters,
- string *content, int *status_code) {
- assert(content);
- AutoPtr<HttpClient> http_client(CreateHttpClient(url.c_str()));
-
- if (!http_client.get()) {
- fprintf(stderr, "Failed to create any http client.\n");
- return false;
- }
-
- if (status_code) {
- *status_code = 0;
- }
-
- wchar_t scheme[16] = {0};
- wchar_t host[256] = {0};
- wchar_t path[256] = {0};
- int port = 0;
- if (!http_client->CrackUrl(url.c_str(),
- 0,
- scheme,
- sizeof(scheme)/sizeof(scheme[0]),
- host,
- sizeof(host)/sizeof(host[0]),
- path,
- sizeof(path)/sizeof(path[0]),
- &port)) {
- fprintf(stderr,
- "HTTPDownload::Download: InternetCrackUrl: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- bool secure = false;
- if (_wcsicmp(scheme, L"https") == 0) {
- secure = true;
- } else if (wcscmp(scheme, L"http") != 0) {
- fprintf(stderr,
- "HTTPDownload::Download: scheme must be http or https for %ws\n",
- url.c_str());
- return false;
- }
-
- AutoHttpHandle internet;
- if (!http_client->Open(NULL, // user agent
- HttpClient::ACCESS_TYPE_PRECONFIG,
- NULL, // proxy name
- NULL, // proxy bypass
- internet.get_handle_addr())) {
- fprintf(stderr,
- "HTTPDownload::Download: Open: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- AutoHttpHandle connection;
- if (!http_client->Connect(internet.get(),
- host,
- port,
- connection.get_handle_addr())) {
- fprintf(stderr,
- "HTTPDownload::Download: InternetConnect: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- wstring request_string = path;
- if (parameters) {
- // TODO(mmentovai): escape bad characters in parameters instead of
- // forbidding them.
- if (!CheckParameters(parameters)) {
- fprintf(stderr,
- "HTTPDownload::Download: invalid characters in parameters\n");
- return false;
- }
-
- bool added_parameter = false;
- for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
- iterator != parameters->end();
- ++iterator) {
- request_string.append(added_parameter ? L"&" : L"?");
- request_string.append(iterator->first);
- request_string.append(L"=");
- request_string.append(iterator->second);
- added_parameter = true;
- }
- }
-
- AutoHttpHandle request;
- if (!http_client->OpenRequest(connection.get(),
- L"GET",
- request_string.c_str(),
- NULL, // version
- NULL, // referer
- secure,
- request.get_handle_addr())) {
- fprintf(stderr,
- "HttpClient::OpenRequest: error %lu for %ws, request: %ws\n",
- GetLastError(), url.c_str(), request_string.c_str());
- return false;
- }
-
- if (!http_client->SendRequest(request.get(), NULL, 0)) {
- fprintf(stderr,
- "HttpClient::SendRequest: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- if (!http_client->ReceiveResponse(request.get())) {
- fprintf(stderr,
- "HttpClient::ReceiveResponse: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- int http_status = 0;
- if (!http_client->GetHttpStatusCode(request.get(), &http_status)) {
- fprintf(stderr,
- "HttpClient::GetHttpStatusCode: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
- if (http_status != 200) {
- fprintf(stderr,
- "HTTPDownload::Download: HTTP status code %d for %ws\n",
- http_status, url.c_str());
- return false;
- }
-
- DWORD content_length = 0;
- vector<char>::size_type buffer_size = 0;
- http_client->GetContentLength(request.get(), &content_length);
- if (content_length == HttpClient::kUnknownContentLength) {
- buffer_size = kVectorChunkSize;
- } else {
- buffer_size = content_length;
- }
-
- if (content_length != 0) {
- vector<char> response_buffer = vector<char>(buffer_size+1);
- DWORD size_read;
- DWORD total_read = 0;
- bool read_result;
- do {
- if (content_length == HttpClient::kUnknownContentLength
- && buffer_size == total_read) {
- // The content length wasn't specified in the response header, so we
- // have to keep growing the buffer until we're done reading.
- buffer_size += kVectorChunkSize;
- response_buffer.resize(buffer_size);
- }
- read_result = !!http_client->ReadData(
- request.get(),
- &response_buffer[total_read],
- static_cast<DWORD>(buffer_size) - total_read,
- &size_read);
- total_read += size_read;
- } while (read_result && (size_read != 0));
-
- if (!read_result) {
- fprintf(stderr,
- "HttpClient::ReadData: error %lu for %ws\n",
- GetLastError(),
- url.c_str());
- return false;
- } else if (size_read != 0) {
- fprintf(stderr,
- "HttpClient::ReadData: error %lu/%lu for %ws\n",
- total_read,
- content_length,
- url.c_str());
- return false;
- }
- content->assign(&response_buffer[0], total_read);
- } else {
- content->clear();
- }
- return true;
-}
-
-} // namespace crash
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <assert.h> +#include <stdio.h> +#include <Windows.h> +#include <WinInet.h> + +#include <vector> + +#include "tools/windows/converter_exe/http_download.h" +#include "tools/windows/converter_exe/winhttp_client.h" +#include "tools/windows/converter_exe/wininet_client.h" + +namespace crash { +static const std::vector<char>::size_type kVectorChunkSize = 4096; // 4 KB + +using std::vector; + +// Class that atuo closes the contained HttpHandle when the object +// goes out of scope. +class AutoHttpHandle { + public: + AutoHttpHandle() : handle_(NULL) {} + explicit AutoHttpHandle(HttpHandle handle) : handle_(handle) {} + ~AutoHttpHandle() { + if (handle_) { + InternetCloseHandle(handle_); + } + } + + HttpHandle get() { return handle_; } + HttpHandle* get_handle_addr () { return &handle_; } + + private: + HttpHandle handle_; +}; + +// Template class for auto releasing the contained pointer when +// the object goes out of scope. +template<typename T> +class AutoPtr { + public: + explicit AutoPtr(T* ptr) : ptr_(ptr) {} + ~AutoPtr() { + if (ptr_) { + delete ptr_; + } + } + + T* get() { return ptr_; } + T* operator -> () { return ptr_; } + + private: + T* ptr_; +}; + +// CheckParameters ensures that the parameters in |parameters| are safe for +// use in an HTTP URL. Returns true if they are, false if unsafe characters +// are present. +static bool CheckParameters(const map<wstring, wstring>* parameters) { + for (map<wstring, wstring>::const_iterator iterator = parameters->begin(); + iterator != parameters->end(); + ++iterator) { + const wstring& key = iterator->first; + if (key.empty()) { + // Disallow empty parameter names. + return false; + } + for (unsigned int i = 0; i < key.size(); ++i) { + wchar_t c = key[i]; + if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) { + return false; + } + } + + const wstring& value = iterator->second; + for (unsigned int i = 0; i < value.size(); ++i) { + wchar_t c = value[i]; + if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) { + return false; + } + } + } + + return true; +} + +HttpClient* HTTPDownload::CreateHttpClient(const wchar_t* url) { + const TCHAR* kHttpApiPolicyEnvironmentVariable = TEXT("USE_WINHTTP"); + TCHAR buffer[2] = {0}; + HttpClient* http_client = NULL; + + if (::GetEnvironmentVariable(kHttpApiPolicyEnvironmentVariable, + buffer, + sizeof(buffer)/sizeof(buffer[0])) > 0) { + fprintf(stdout, + "Environment variable [%ws] is set, use WinHttp\n", + kHttpApiPolicyEnvironmentVariable); + http_client = CreateWinHttpClient(url); + if (http_client == NULL) { + fprintf(stderr, "WinHttpClient not created, Is the protocol HTTPS? " + "Fall back to WinInet API.\n"); + } + } else { + fprintf(stderr, + "Environment variable [%ws] is NOT set, use WinInet API\n", + kHttpApiPolicyEnvironmentVariable); + } + + if (http_client == NULL) { + return CreateWinInetClient(url); + } + + return http_client; +} + +// static +bool HTTPDownload::Download(const wstring& url, + const map<wstring, wstring>* parameters, + string *content, int *status_code) { + assert(content); + AutoPtr<HttpClient> http_client(CreateHttpClient(url.c_str())); + + if (!http_client.get()) { + fprintf(stderr, "Failed to create any http client.\n"); + return false; + } + + if (status_code) { + *status_code = 0; + } + + wchar_t scheme[16] = {0}; + wchar_t host[256] = {0}; + wchar_t path[256] = {0}; + int port = 0; + if (!http_client->CrackUrl(url.c_str(), + 0, + scheme, + sizeof(scheme)/sizeof(scheme[0]), + host, + sizeof(host)/sizeof(host[0]), + path, + sizeof(path)/sizeof(path[0]), + &port)) { + fprintf(stderr, + "HTTPDownload::Download: InternetCrackUrl: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + bool secure = false; + if (_wcsicmp(scheme, L"https") == 0) { + secure = true; + } else if (wcscmp(scheme, L"http") != 0) { + fprintf(stderr, + "HTTPDownload::Download: scheme must be http or https for %ws\n", + url.c_str()); + return false; + } + + AutoHttpHandle internet; + if (!http_client->Open(NULL, // user agent + HttpClient::ACCESS_TYPE_PRECONFIG, + NULL, // proxy name + NULL, // proxy bypass + internet.get_handle_addr())) { + fprintf(stderr, + "HTTPDownload::Download: Open: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + AutoHttpHandle connection; + if (!http_client->Connect(internet.get(), + host, + port, + connection.get_handle_addr())) { + fprintf(stderr, + "HTTPDownload::Download: InternetConnect: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + wstring request_string = path; + if (parameters) { + // TODO(mmentovai): escape bad characters in parameters instead of + // forbidding them. + if (!CheckParameters(parameters)) { + fprintf(stderr, + "HTTPDownload::Download: invalid characters in parameters\n"); + return false; + } + + bool added_parameter = false; + for (map<wstring, wstring>::const_iterator iterator = parameters->begin(); + iterator != parameters->end(); + ++iterator) { + request_string.append(added_parameter ? L"&" : L"?"); + request_string.append(iterator->first); + request_string.append(L"="); + request_string.append(iterator->second); + added_parameter = true; + } + } + + AutoHttpHandle request; + if (!http_client->OpenRequest(connection.get(), + L"GET", + request_string.c_str(), + NULL, // version + NULL, // referer + secure, + request.get_handle_addr())) { + fprintf(stderr, + "HttpClient::OpenRequest: error %lu for %ws, request: %ws\n", + GetLastError(), url.c_str(), request_string.c_str()); + return false; + } + + if (!http_client->SendRequest(request.get(), NULL, 0)) { + fprintf(stderr, + "HttpClient::SendRequest: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + if (!http_client->ReceiveResponse(request.get())) { + fprintf(stderr, + "HttpClient::ReceiveResponse: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + int http_status = 0; + if (!http_client->GetHttpStatusCode(request.get(), &http_status)) { + fprintf(stderr, + "HttpClient::GetHttpStatusCode: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + if (http_status != 200) { + fprintf(stderr, + "HTTPDownload::Download: HTTP status code %d for %ws\n", + http_status, url.c_str()); + return false; + } + + DWORD content_length = 0; + vector<char>::size_type buffer_size = 0; + http_client->GetContentLength(request.get(), &content_length); + if (content_length == HttpClient::kUnknownContentLength) { + buffer_size = kVectorChunkSize; + } else { + buffer_size = content_length; + } + + if (content_length != 0) { + vector<char> response_buffer = vector<char>(buffer_size+1); + DWORD size_read; + DWORD total_read = 0; + bool read_result; + do { + if (content_length == HttpClient::kUnknownContentLength + && buffer_size == total_read) { + // The content length wasn't specified in the response header, so we + // have to keep growing the buffer until we're done reading. + buffer_size += kVectorChunkSize; + response_buffer.resize(buffer_size); + } + read_result = !!http_client->ReadData( + request.get(), + &response_buffer[total_read], + static_cast<DWORD>(buffer_size) - total_read, + &size_read); + total_read += size_read; + } while (read_result && (size_read != 0)); + + if (!read_result) { + fprintf(stderr, + "HttpClient::ReadData: error %lu for %ws\n", + GetLastError(), + url.c_str()); + return false; + } else if (size_read != 0) { + fprintf(stderr, + "HttpClient::ReadData: error %lu/%lu for %ws\n", + total_read, + content_length, + url.c_str()); + return false; + } + content->assign(&response_buffer[0], total_read); + } else { + content->clear(); + } + return true; +} + +} // namespace crash diff --git a/src/tools/windows/converter_exe/http_download.h b/src/tools/windows/converter_exe/http_download.h index 2d705d5e..f58a3d0f 100644 --- a/src/tools/windows/converter_exe/http_download.h +++ b/src/tools/windows/converter_exe/http_download.h @@ -1,62 +1,62 @@ -// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
-
-#include <map>
-#include <string>
-#include "tools/windows/converter_exe/winhttp_client.h"
-
-namespace crash {
-
-using std::map;
-using std::string;
-using std::wstring;
-
-class HTTPDownload {
- public:
- // Retrieves the resource located at |url|, a http or https URL, via WinInet.
- // The request is fetched with GET request; the optional |parameters| are
- // appended to the URL. Returns true on success, placing the content of the
- // retrieved resource in |content|. Returns false on failure. HTTP status
- // codes other than 200 cause Download to return false. If |status_code| is
- // supplied, it will be set to the value of the HTTP status code, if an HTTP
- // transaction occurs. If Download fails before a transaction can occur,
- // |status_code| will be set to 0. Any failures will result in messages
- // being printed to stderr.
- static bool Download(const wstring &url,
- const map<wstring, wstring> *parameters,
- string *content, int *status_code);
- private:
- static HttpClient* CreateHttpClient(const wchar_t*);
-};
-
-} // namespace crash
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_ + +#include <map> +#include <string> +#include "tools/windows/converter_exe/winhttp_client.h" + +namespace crash { + +using std::map; +using std::string; +using std::wstring; + +class HTTPDownload { + public: + // Retrieves the resource located at |url|, a http or https URL, via WinInet. + // The request is fetched with GET request; the optional |parameters| are + // appended to the URL. Returns true on success, placing the content of the + // retrieved resource in |content|. Returns false on failure. HTTP status + // codes other than 200 cause Download to return false. If |status_code| is + // supplied, it will be set to the value of the HTTP status code, if an HTTP + // transaction occurs. If Download fails before a transaction can occur, + // |status_code| will be set to 0. Any failures will result in messages + // being printed to stderr. + static bool Download(const wstring& url, + const map<wstring, wstring>* parameters, + string *content, int *status_code); + private: + static HttpClient* CreateHttpClient(const wchar_t*); +}; + +} // namespace crash + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_ diff --git a/src/tools/windows/converter_exe/tokenizer.cc b/src/tools/windows/converter_exe/tokenizer.cc index 992694cd..6d627536 100644 --- a/src/tools/windows/converter_exe/tokenizer.cc +++ b/src/tools/windows/converter_exe/tokenizer.cc @@ -1,61 +1,61 @@ -// Copyright 2019 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 <assert.h>
-
-#include "tools/windows/converter_exe/tokenizer.h"
-
-namespace crash {
-
-// static
-void Tokenizer::Tokenize(const string &delimiters, const string &input,
- vector<string> *output) {
- assert(output);
- output->clear();
-
- string::size_type position = 0; // Where to begin looking for a delimiter
- string::size_type new_position; // Position of found delimiter
- string token;
-
- while ((new_position = input.find_first_of(delimiters, position)) !=
- string::npos) {
- token = input.substr(position, new_position - position);
- output->push_back(token);
-
- // Next time, begin looking right after this delimiter.
- position = new_position + 1;
- }
-
- // There are no more delimiters in the string. Take everything from the
- // final delimiter up to the end of the string as a token. This may be
- // an empty string.
- token = input.substr(position);
- output->push_back(token);
-}
-
-} // namespace crash
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <assert.h> + +#include "tools/windows/converter_exe/tokenizer.h" + +namespace crash { + +// static +void Tokenizer::Tokenize(const string& delimiters, const string& input, + vector<string>* output) { + assert(output); + output->clear(); + + string::size_type position = 0; // Where to begin looking for a delimiter + string::size_type new_position; // Position of found delimiter + string token; + + while ((new_position = input.find_first_of(delimiters, position)) != + string::npos) { + token = input.substr(position, new_position - position); + output->push_back(token); + + // Next time, begin looking right after this delimiter. + position = new_position + 1; + } + + // There are no more delimiters in the string. Take everything from the + // final delimiter up to the end of the string as a token. This may be + // an empty string. + token = input.substr(position); + output->push_back(token); +} + +} // namespace crash diff --git a/src/tools/windows/converter_exe/tokenizer.h b/src/tools/windows/converter_exe/tokenizer.h index f4bbcfd0..d9829f60 100644 --- a/src/tools/windows/converter_exe/tokenizer.h +++ b/src/tools/windows/converter_exe/tokenizer.h @@ -1,51 +1,51 @@ -// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
-
-#include <string>
-#include <vector>
-
-namespace crash {
-
-using std::string;
-using std::vector;
-
-class Tokenizer {
- public:
- // Splits |input| into a series of tokens delimited in the input string by
- // any of the characters in |delimiters|. The tokens are passed back in the
- // |output| vector.
- static void Tokenize(const string &delimiters, const string &input,
- vector<string> *output);
-};
-
-} // namespace crash
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_ + +#include <string> +#include <vector> + +namespace crash { + +using std::string; +using std::vector; + +class Tokenizer { + public: + // Splits |input| into a series of tokens delimited in the input string by + // any of the characters in |delimiters|. The tokens are passed back in the + // |output| vector. + static void Tokenize(const string& delimiters, const string& input, + vector<string>* output); +}; + +} // namespace crash + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_ diff --git a/src/tools/windows/converter_exe/winhttp_client.cc b/src/tools/windows/converter_exe/winhttp_client.cc index 8a8ade3b..f8c1492d 100644 --- a/src/tools/windows/converter_exe/winhttp_client.cc +++ b/src/tools/windows/converter_exe/winhttp_client.cc @@ -1,307 +1,307 @@ -// Copyright 2019 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 "tools/windows/converter_exe/winhttp_client.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <windows.h>
-#include <winhttp.h>
-#include <vector>
-
-namespace crash {
-
-namespace internal {
-
-// This class implements HttpClient based on WinInet APIs.
-class WinHttpClient : public HttpClient {
- public:
- virtual ~WinHttpClient() {}
- virtual bool CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const;
- virtual bool Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const;
- virtual bool Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const;
- virtual bool OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const;
- virtual bool SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const;
- virtual bool ReceiveResponse(HttpHandle request_handle) const;
- virtual bool GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const;
- virtual bool GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const;
- virtual bool ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const;
- virtual bool Close(HttpHandle handle) const;
-
- private:
- static DWORD MapAccessType(DWORD access_type);
- static HINTERNET ToHINTERNET(HttpHandle handle);
- static HttpHandle FromHINTERNET(HINTERNET handle);
-};
-
-bool WinHttpClient::CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const {
- assert(url);
- assert(scheme);
- assert(host);
- assert(uri);
- assert(port);
-
- URL_COMPONENTS url_comp = {0};
- url_comp.dwStructSize = sizeof(url_comp);
- url_comp.lpszScheme = scheme;
- url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
- url_comp.lpszHostName = host;
- url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
- url_comp.lpszUrlPath = uri;
- url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
-
- bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp);
- if (result) {
- *port = static_cast<int>(url_comp.nPort);
- }
- return result;
-}
-
-bool WinHttpClient::Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const {
- *session_handle = FromHINTERNET(::WinHttpOpen(user_agent,
- MapAccessType(access_type),
- proxy_name,
- proxy_bypass,
- 0));
-
- return !!(*session_handle);
-}
-
-bool WinHttpClient::Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const {
- assert(server);
-
- // Uses NULL user name and password to connect.
- *connection_handle = FromHINTERNET(::WinHttpConnect(
- ToHINTERNET(session_handle),
- server,
- static_cast<INTERNET_PORT>(port),
- NULL));
- return !!(*connection_handle);
-}
-
-bool WinHttpClient::OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const {
- assert(connection_handle);
- assert(verb);
- assert(uri);
- assert(request_handle);
-
- *request_handle = FromHINTERNET(::WinHttpOpenRequest(
- ToHINTERNET(connection_handle),
- verb,
- uri,
- version,
- referrer,
- WINHTTP_DEFAULT_ACCEPT_TYPES,
- is_secure ? WINHTTP_FLAG_SECURE : 0));
- return !!(*request_handle);
-}
-
-bool WinHttpClient::SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const {
- assert(request_handle);
-
- return !!::WinHttpSendRequest(ToHINTERNET(request_handle),
- headers,
- headers_length,
- NULL,
- 0,
- WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
- NULL);
-}
-
-bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const {
- assert(request_handle);
-
- return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL);
-}
-
-bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const {
- TCHAR http_status_string[4] = {0};
- DWORD http_status_string_size = sizeof(http_status_string);
- if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
- WINHTTP_QUERY_STATUS_CODE,
- WINHTTP_HEADER_NAME_BY_INDEX,
- static_cast<void *>(&http_status_string),
- &http_status_string_size, 0)) {
- return false;
- }
-
- *status_code = static_cast<DWORD>(_tcstol(http_status_string, NULL, 10));
- return true;
-}
-
-bool WinHttpClient::GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const {
- assert(request_handle);
- assert(content_length);
-
- TCHAR content_length_string[11] = {0};
- DWORD content_length_string_size = sizeof(content_length_string);
- if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
- WINHTTP_QUERY_CONTENT_LENGTH,
- WINHTTP_HEADER_NAME_BY_INDEX,
- static_cast<void *>(&content_length_string),
- &content_length_string_size, 0)) {
- *content_length = kUnknownContentLength;
- } else {
- *content_length =
- static_cast<DWORD>(wcstol(content_length_string, NULL, 10));
- }
- return true;
-}
-
-bool WinHttpClient::ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const {
- assert(request_handle);
- assert(buffer);
- assert(bytes_read);
-
- DWORD bytes_read_local = 0;
- if (!::WinHttpReadData(ToHINTERNET(request_handle),
- buffer,
- buffer_length,
- &bytes_read_local)) {
- return false;
- }
- *bytes_read = bytes_read_local;
- return true;
-}
-
-bool WinHttpClient::Close(HttpHandle handle) const {
- assert(handle);
- return !!::WinHttpCloseHandle(ToHINTERNET(handle));
-}
-
-DWORD WinHttpClient::MapAccessType(DWORD access_type) {
- switch (static_cast<AccessType>(access_type)) {
- case ACCESS_TYPE_PRECONFIG:
- default:
- return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
- case ACCESS_TYPE_DIRECT:
- return WINHTTP_ACCESS_TYPE_NO_PROXY;
- case ACCESS_TYPE_PROXY:
- return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
- }
-}
-
-
-HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) {
- return static_cast<HINTERNET>(handle);
-}
-
-HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) {
- return static_cast<HttpHandle>(handle);
-}
-
-} // namespace internal
-
-HttpClient* CreateWinHttpClient(const TCHAR* url) {
- assert(url);
-
- internal::WinHttpClient winhttp;
- wchar_t scheme[16] = {0};
- wchar_t host[256] = {0};
- wchar_t path[256] = {0};
- int port = 0;
-
- if (!winhttp.CrackUrl(url,
- 0,
- scheme,
- sizeof(scheme)/sizeof(scheme[0]),
- host,
- sizeof(host)/sizeof(host[0]),
- path,
- sizeof(path)/sizeof(path[0]),
- &port)) {
- return NULL;
- }
-
- if (_wcsicmp(scheme, L"https") == 0) {
- // Winhttp under WINE doesn't support wildcard certificates, so avoid
- // to use it if the scheme is https. The caller should fall back to
- // use wininet if NULL is returned.
- return NULL;
- }
-
- return new internal::WinHttpClient();
-}
-
-} // namespace crash
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "tools/windows/converter_exe/winhttp_client.h" + +#include <assert.h> +#include <stdlib.h> +#include <windows.h> +#include <winhttp.h> +#include <vector> + +namespace crash { + +namespace internal { + +// This class implements HttpClient based on WinInet APIs. +class WinHttpClient : public HttpClient { + public: + virtual ~WinHttpClient() {} + virtual bool CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const; + virtual bool Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const; + virtual bool Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const; + virtual bool OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const; + virtual bool SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const; + virtual bool ReceiveResponse(HttpHandle request_handle) const; + virtual bool GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const; + virtual bool GetContentLength(HttpHandle request_handle, + DWORD* content_length) const; + virtual bool ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const; + virtual bool Close(HttpHandle handle) const; + + private: + static DWORD MapAccessType(DWORD access_type); + static HINTERNET ToHINTERNET(HttpHandle handle); + static HttpHandle FromHINTERNET(HINTERNET handle); +}; + +bool WinHttpClient::CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const { + assert(url); + assert(scheme); + assert(host); + assert(uri); + assert(port); + + URL_COMPONENTS url_comp = {0}; + url_comp.dwStructSize = sizeof(url_comp); + url_comp.lpszScheme = scheme; + url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length); + url_comp.lpszHostName = host; + url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length); + url_comp.lpszUrlPath = uri; + url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length); + + bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp); + if (result) { + *port = static_cast<int>(url_comp.nPort); + } + return result; +} + +bool WinHttpClient::Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const { + *session_handle = FromHINTERNET(::WinHttpOpen(user_agent, + MapAccessType(access_type), + proxy_name, + proxy_bypass, + 0)); + + return !!(*session_handle); +} + +bool WinHttpClient::Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const { + assert(server); + + // Uses NULL user name and password to connect. + *connection_handle = FromHINTERNET(::WinHttpConnect( + ToHINTERNET(session_handle), + server, + static_cast<INTERNET_PORT>(port), + NULL)); + return !!(*connection_handle); +} + +bool WinHttpClient::OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const { + assert(connection_handle); + assert(verb); + assert(uri); + assert(request_handle); + + *request_handle = FromHINTERNET(::WinHttpOpenRequest( + ToHINTERNET(connection_handle), + verb, + uri, + version, + referrer, + WINHTTP_DEFAULT_ACCEPT_TYPES, + is_secure ? WINHTTP_FLAG_SECURE : 0)); + return !!(*request_handle); +} + +bool WinHttpClient::SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const { + assert(request_handle); + + return !!::WinHttpSendRequest(ToHINTERNET(request_handle), + headers, + headers_length, + NULL, + 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + NULL); +} + +bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const { + assert(request_handle); + + return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL); +} + +bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const { + TCHAR http_status_string[4] = {0}; + DWORD http_status_string_size = sizeof(http_status_string); + if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle), + WINHTTP_QUERY_STATUS_CODE, + WINHTTP_HEADER_NAME_BY_INDEX, + static_cast<void*>(&http_status_string), + &http_status_string_size, 0)) { + return false; + } + + *status_code = static_cast<DWORD>(_tcstol(http_status_string, NULL, 10)); + return true; +} + +bool WinHttpClient::GetContentLength(HttpHandle request_handle, + DWORD* content_length) const { + assert(request_handle); + assert(content_length); + + TCHAR content_length_string[11] = {0}; + DWORD content_length_string_size = sizeof(content_length_string); + if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle), + WINHTTP_QUERY_CONTENT_LENGTH, + WINHTTP_HEADER_NAME_BY_INDEX, + static_cast<void*>(&content_length_string), + &content_length_string_size, 0)) { + *content_length = kUnknownContentLength; + } else { + *content_length = + static_cast<DWORD>(wcstol(content_length_string, NULL, 10)); + } + return true; +} + +bool WinHttpClient::ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const { + assert(request_handle); + assert(buffer); + assert(bytes_read); + + DWORD bytes_read_local = 0; + if (!::WinHttpReadData(ToHINTERNET(request_handle), + buffer, + buffer_length, + &bytes_read_local)) { + return false; + } + *bytes_read = bytes_read_local; + return true; +} + +bool WinHttpClient::Close(HttpHandle handle) const { + assert(handle); + return !!::WinHttpCloseHandle(ToHINTERNET(handle)); +} + +DWORD WinHttpClient::MapAccessType(DWORD access_type) { + switch (static_cast<AccessType>(access_type)) { + case ACCESS_TYPE_PRECONFIG: + default: + return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; + case ACCESS_TYPE_DIRECT: + return WINHTTP_ACCESS_TYPE_NO_PROXY; + case ACCESS_TYPE_PROXY: + return WINHTTP_ACCESS_TYPE_NAMED_PROXY; + } +} + + +HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) { + return static_cast<HINTERNET>(handle); +} + +HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) { + return static_cast<HttpHandle>(handle); +} + +} // namespace internal + +HttpClient* CreateWinHttpClient(const TCHAR* url) { + assert(url); + + internal::WinHttpClient winhttp; + wchar_t scheme[16] = {0}; + wchar_t host[256] = {0}; + wchar_t path[256] = {0}; + int port = 0; + + if (!winhttp.CrackUrl(url, + 0, + scheme, + sizeof(scheme)/sizeof(scheme[0]), + host, + sizeof(host)/sizeof(host[0]), + path, + sizeof(path)/sizeof(path[0]), + &port)) { + return NULL; + } + + if (_wcsicmp(scheme, L"https") == 0) { + // Winhttp under WINE doesn't support wildcard certificates, so avoid + // to use it if the scheme is https. The caller should fall back to + // use wininet if NULL is returned. + return NULL; + } + + return new internal::WinHttpClient(); +} + +} // namespace crash diff --git a/src/tools/windows/converter_exe/winhttp_client.h b/src/tools/windows/converter_exe/winhttp_client.h index 819d610f..4ccac7e0 100644 --- a/src/tools/windows/converter_exe/winhttp_client.h +++ b/src/tools/windows/converter_exe/winhttp_client.h @@ -1,40 +1,40 @@ -// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
-
-#include "tools/windows/converter_exe/http_client.h"
-
-namespace crash {
-
-HttpClient* CreateWinHttpClient(const TCHAR* url);
-
-} // namespace crash
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_ + +#include "tools/windows/converter_exe/http_client.h" + +namespace crash { + +HttpClient* CreateWinHttpClient(const TCHAR* url); + +} // namespace crash + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_ diff --git a/src/tools/windows/converter_exe/wininet_client.cc b/src/tools/windows/converter_exe/wininet_client.cc index 3e542db2..90cf114c 100644 --- a/src/tools/windows/converter_exe/wininet_client.cc +++ b/src/tools/windows/converter_exe/wininet_client.cc @@ -1,278 +1,278 @@ -// Copyright 2019 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 "tools/windows/converter_exe/wininet_client.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <windows.h>
-#include <wininet.h>
-
-namespace crash {
-
-namespace internal {
-
-// This class implements HttpClient based on WinInet APIs.
-class WinInetClient : public HttpClient {
- public:
- virtual ~WinInetClient() {}
- virtual bool CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const;
- virtual bool Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const;
- virtual bool Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const;
- virtual bool OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const;
- virtual bool SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const;
- virtual bool ReceiveResponse(HttpHandle request_handle) const;
- virtual bool GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const;
- virtual bool GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const;
- virtual bool ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const;
- virtual bool Close(HttpHandle handle) const;
-
- private:
- static DWORD MapAccessType(DWORD access_type);
- static HINTERNET ToHINTERNET(HttpHandle handle);
- static HttpHandle FromHINTERNET(HINTERNET handle);
-};
-
-bool WinInetClient::CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const {
- assert(url);
- assert(scheme);
- assert(host);
- assert(uri);
- assert(port);
-
- URL_COMPONENTS url_comp = {0};
- url_comp.dwStructSize = sizeof(url_comp);
- url_comp.lpszScheme = scheme;
- url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
- url_comp.lpszHostName = host;
- url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
- url_comp.lpszUrlPath = uri;
- url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
-
- bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp);
- if (result) {
- *port = static_cast<int>(url_comp.nPort);
- }
- return result;
-}
-
-bool WinInetClient::Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const {
- *session_handle = FromHINTERNET(::InternetOpen(user_agent,
- MapAccessType(access_type),
- proxy_name,
- proxy_bypass,
- 0));
- return !!(*session_handle);
-}
-
-bool WinInetClient::Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const {
- assert(server);
-
- // Uses NULL user name and password to connect. Always uses http service.
- *connection_handle = FromHINTERNET(::InternetConnect(
- ToHINTERNET(session_handle),
- server,
- static_cast<INTERNET_PORT>(port),
- NULL,
- NULL,
- INTERNET_SERVICE_HTTP,
- 0,
- 0));
- return !!(*connection_handle);
-}
-
-bool WinInetClient::OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const {
- assert(connection_handle);
- assert(verb);
- assert(uri);
-
- *request_handle = FromHINTERNET(::HttpOpenRequest(
- ToHINTERNET(connection_handle),
- verb,
- uri,
- version,
- referrer,
- NULL,
- is_secure ? INTERNET_FLAG_SECURE : 0,
- NULL));
- return !!(*request_handle);
-}
-
-bool WinInetClient::SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const {
- assert(request_handle);
-
- return !!::HttpSendRequest(ToHINTERNET(request_handle),
- headers,
- headers_length,
- NULL,
- 0);
-}
-
-bool WinInetClient::ReceiveResponse(HttpHandle) const {
- return true;
-}
-
-bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const {
- assert(request_handle);
-
- TCHAR http_status_string[4] = {0};
- DWORD http_status_string_size = sizeof(http_status_string);
- if (!::HttpQueryInfo(ToHINTERNET(request_handle),
- HTTP_QUERY_STATUS_CODE,
- static_cast<void *>(&http_status_string),
- &http_status_string_size,
- 0)) {
- return false;
- }
-
- *status_code = _tcstol(http_status_string, NULL, 10);
- return true;
-}
-
-bool WinInetClient::GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const {
- assert(request_handle);
- assert(content_length);
-
- TCHAR content_length_string[11];
- DWORD content_length_string_size = sizeof(content_length_string);
- if (!::HttpQueryInfo(ToHINTERNET(request_handle),
- HTTP_QUERY_CONTENT_LENGTH,
- static_cast<void *>(&content_length_string),
- &content_length_string_size,
- 0)) {
- *content_length = kUnknownContentLength;
- } else {
- *content_length = wcstol(content_length_string, NULL, 10);
- }
- return true;
-}
-
-bool WinInetClient::ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const {
- assert(request_handle);
- assert(buffer);
- assert(bytes_read);
-
- DWORD bytes_read_local = 0;
- if (!::InternetReadFile(ToHINTERNET(request_handle),
- buffer,
- buffer_length,
- &bytes_read_local)) {
- return false;
- }
- *bytes_read = bytes_read_local;
- return true;
-}
-
-bool WinInetClient::Close(HttpHandle handle) const {
- assert(handle);
- return !!::InternetCloseHandle(ToHINTERNET(handle));
-}
-
-DWORD WinInetClient::MapAccessType(DWORD access_type) {
- switch (static_cast<AccessType>(access_type)) {
- case ACCESS_TYPE_PRECONFIG:
- default:
- return INTERNET_OPEN_TYPE_PRECONFIG;
- case ACCESS_TYPE_DIRECT:
- return INTERNET_OPEN_TYPE_DIRECT;
- case ACCESS_TYPE_PROXY:
- return INTERNET_OPEN_TYPE_PROXY;
- }
-}
-
-HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) {
- return static_cast<HINTERNET>(handle);
-}
-
-HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) {
- return static_cast<HttpHandle>(handle);
-}
-
-} // namespace internal
-
-HttpClient* CreateWinInetClient(const TCHAR*) {
- return new internal::WinInetClient();
-}
-
-} // namespace crash
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "tools/windows/converter_exe/wininet_client.h" + +#include <assert.h> +#include <stdlib.h> +#include <windows.h> +#include <wininet.h> + +namespace crash { + +namespace internal { + +// This class implements HttpClient based on WinInet APIs. +class WinInetClient : public HttpClient { + public: + virtual ~WinInetClient() {} + virtual bool CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const; + virtual bool Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const; + virtual bool Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const; + virtual bool OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const; + virtual bool SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const; + virtual bool ReceiveResponse(HttpHandle request_handle) const; + virtual bool GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const; + virtual bool GetContentLength(HttpHandle request_handle, + DWORD* content_length) const; + virtual bool ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const; + virtual bool Close(HttpHandle handle) const; + + private: + static DWORD MapAccessType(DWORD access_type); + static HINTERNET ToHINTERNET(HttpHandle handle); + static HttpHandle FromHINTERNET(HINTERNET handle); +}; + +bool WinInetClient::CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const { + assert(url); + assert(scheme); + assert(host); + assert(uri); + assert(port); + + URL_COMPONENTS url_comp = {0}; + url_comp.dwStructSize = sizeof(url_comp); + url_comp.lpszScheme = scheme; + url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length); + url_comp.lpszHostName = host; + url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length); + url_comp.lpszUrlPath = uri; + url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length); + + bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp); + if (result) { + *port = static_cast<int>(url_comp.nPort); + } + return result; +} + +bool WinInetClient::Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const { + *session_handle = FromHINTERNET(::InternetOpen(user_agent, + MapAccessType(access_type), + proxy_name, + proxy_bypass, + 0)); + return !!(*session_handle); +} + +bool WinInetClient::Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const { + assert(server); + + // Uses NULL user name and password to connect. Always uses http service. + *connection_handle = FromHINTERNET(::InternetConnect( + ToHINTERNET(session_handle), + server, + static_cast<INTERNET_PORT>(port), + NULL, + NULL, + INTERNET_SERVICE_HTTP, + 0, + 0)); + return !!(*connection_handle); +} + +bool WinInetClient::OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const { + assert(connection_handle); + assert(verb); + assert(uri); + + *request_handle = FromHINTERNET(::HttpOpenRequest( + ToHINTERNET(connection_handle), + verb, + uri, + version, + referrer, + NULL, + is_secure ? INTERNET_FLAG_SECURE : 0, + NULL)); + return !!(*request_handle); +} + +bool WinInetClient::SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const { + assert(request_handle); + + return !!::HttpSendRequest(ToHINTERNET(request_handle), + headers, + headers_length, + NULL, + 0); +} + +bool WinInetClient::ReceiveResponse(HttpHandle) const { + return true; +} + +bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const { + assert(request_handle); + + TCHAR http_status_string[4] = {0}; + DWORD http_status_string_size = sizeof(http_status_string); + if (!::HttpQueryInfo(ToHINTERNET(request_handle), + HTTP_QUERY_STATUS_CODE, + static_cast<void*>(&http_status_string), + &http_status_string_size, + 0)) { + return false; + } + + *status_code = _tcstol(http_status_string, NULL, 10); + return true; +} + +bool WinInetClient::GetContentLength(HttpHandle request_handle, + DWORD* content_length) const { + assert(request_handle); + assert(content_length); + + TCHAR content_length_string[11]; + DWORD content_length_string_size = sizeof(content_length_string); + if (!::HttpQueryInfo(ToHINTERNET(request_handle), + HTTP_QUERY_CONTENT_LENGTH, + static_cast<void*>(&content_length_string), + &content_length_string_size, + 0)) { + *content_length = kUnknownContentLength; + } else { + *content_length = wcstol(content_length_string, NULL, 10); + } + return true; +} + +bool WinInetClient::ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const { + assert(request_handle); + assert(buffer); + assert(bytes_read); + + DWORD bytes_read_local = 0; + if (!::InternetReadFile(ToHINTERNET(request_handle), + buffer, + buffer_length, + &bytes_read_local)) { + return false; + } + *bytes_read = bytes_read_local; + return true; +} + +bool WinInetClient::Close(HttpHandle handle) const { + assert(handle); + return !!::InternetCloseHandle(ToHINTERNET(handle)); +} + +DWORD WinInetClient::MapAccessType(DWORD access_type) { + switch (static_cast<AccessType>(access_type)) { + case ACCESS_TYPE_PRECONFIG: + default: + return INTERNET_OPEN_TYPE_PRECONFIG; + case ACCESS_TYPE_DIRECT: + return INTERNET_OPEN_TYPE_DIRECT; + case ACCESS_TYPE_PROXY: + return INTERNET_OPEN_TYPE_PROXY; + } +} + +HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) { + return static_cast<HINTERNET>(handle); +} + +HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) { + return static_cast<HttpHandle>(handle); +} + +} // namespace internal + +HttpClient* CreateWinInetClient(const TCHAR*) { + return new internal::WinInetClient(); +} + +} // namespace crash diff --git a/src/tools/windows/converter_exe/wininet_client.h b/src/tools/windows/converter_exe/wininet_client.h index bd04b605..8b4c61b5 100644 --- a/src/tools/windows/converter_exe/wininet_client.h +++ b/src/tools/windows/converter_exe/wininet_client.h @@ -1,40 +1,40 @@ -// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
-
-#include "tools/windows/converter_exe/http_client.h"
-
-namespace crash {
-
-HttpClient* CreateWinInetClient(const TCHAR* url);
-
-} // namespace crash
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
+// Copyright 2019 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_ + +#include "tools/windows/converter_exe/http_client.h" + +namespace crash { + +HttpClient* CreateWinInetClient(const TCHAR* url); + +} // namespace crash + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_ diff --git a/src/tools/windows/dump_syms/dump_syms.cc b/src/tools/windows/dump_syms/dump_syms.cc index 5b7d1777..26c226a2 100644 --- a/src/tools/windows/dump_syms/dump_syms.cc +++ b/src/tools/windows/dump_syms/dump_syms.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -33,35 +32,61 @@ #include <stdio.h> #include <wchar.h> +#include <memory> #include <string> #include "common/windows/pdb_source_line_writer.h" #include "common/windows/pe_source_line_writer.h" -using std::wstring; using google_breakpad::PDBSourceLineWriter; using google_breakpad::PESourceLineWriter; using std::unique_ptr; +using std::wstring; + +int usage(const wchar_t* self) { + fprintf(stderr, "Usage: %ws [--pe] [--i] <file.[pdb|exe|dll]>\n", self); + fprintf(stderr, "Options:\n"); + fprintf(stderr, + "--pe:\tRead debugging information from PE file and do " + "not attempt to locate matching PDB file.\n" + "\tThis is only supported for PE32+ (64 bit) PE files.\n"); + fprintf(stderr, + "--i:\tOutput INLINE/INLINE_ORIGIN record\n" + "\tThis cannot be used with [--pe].\n"); + return 1; +} -int wmain(int argc, wchar_t **argv) { - bool success; - if (argc == 2) { - PDBSourceLineWriter pdb_writer; - if (!pdb_writer.Open(wstring(argv[1]), PDBSourceLineWriter::ANY_FILE)) { +int wmain(int argc, wchar_t** argv) { + bool success = false; + bool pe = false; + bool handle_inline = false; + int arg_index = 1; + while (arg_index < argc && wcslen(argv[arg_index]) > 0 && + wcsncmp(L"--", argv[arg_index], 2) == 0) { + if (wcscmp(L"--pe", argv[arg_index]) == 0) { + pe = true; + } else if (wcscmp(L"--i", argv[arg_index]) == 0) { + handle_inline = true; + } + ++arg_index; + } + + if ((pe && handle_inline) || arg_index == argc) { + usage(argv[0]); + return 1; + } + + wchar_t* file_path = argv[arg_index]; + if (pe) { + PESourceLineWriter pe_writer(file_path); + success = pe_writer.WriteSymbols(stdout); + } else { + PDBSourceLineWriter pdb_writer(handle_inline); + if (!pdb_writer.Open(wstring(file_path), PDBSourceLineWriter::ANY_FILE)) { fprintf(stderr, "Open failed.\n"); return 1; } success = pdb_writer.WriteSymbols(stdout); - } else if (argc == 3 && wcscmp(argv[1], L"--pe") == 0) { - PESourceLineWriter pe_writer(argv[2]); - success = pe_writer.WriteSymbols(stdout); - } else { - fprintf(stderr, "Usage: %ws [--pe] <file.[pdb|exe|dll]>\n", argv[0]); - fprintf(stderr, "Options:\n"); - fprintf(stderr, "--pe:\tRead debugging information from PE file and do " - "not attempt to locate matching PDB file.\n" - "\tThis is only supported for PE32+ (64 bit) PE files.\n"); - return 1; } if (!success) { diff --git a/src/tools/windows/dump_syms/dump_syms.gyp b/src/tools/windows/dump_syms/dump_syms.gyp deleted file mode 100644 index b815574b..00000000 --- a/src/tools/windows/dump_syms/dump_syms.gyp +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2013 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': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'dump_syms', - 'type': 'executable', - 'sources': [ - 'dump_syms.cc', - ], - 'dependencies': [ - '../../../common/windows/common_windows.gyp:common_windows_lib', - ], - }, - { - 'target_name': 'dump_syms_unittest', - 'type': 'executable', - 'sources': [ - 'dump_syms_unittest.cc', - ], - 'dependencies': [ - '<(DEPTH)/client/windows/unittests/testing.gyp:gmock', - '<(DEPTH)/client/windows/unittests/testing.gyp:gtest', - 'dump_syms', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalDependencies': [ - 'shell32.lib', - ], - }, - }, - }, - ], -} diff --git a/src/tools/windows/dump_syms/dump_syms_unittest.cc b/src/tools/windows/dump_syms/dump_syms_unittest.cc index 766e5c09..97dc5c9b 100644 --- a/src/tools/windows/dump_syms/dump_syms_unittest.cc +++ b/src/tools/windows/dump_syms/dump_syms_unittest.cc @@ -1,244 +1,244 @@ -// Copyright 2003 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 <Windows.h>
-#include <shellapi.h>
-
-#include <string>
-#include <utility>
-
-#include "breakpad_googletest_includes.h"
-
-namespace tools {
-namespace windows {
-namespace dump_syms {
-
-namespace {
-
-// Root names of PDB and dumped symbol files to be regression tested. These are
-// specified in complexity of the resulting dumped symbol files.
-const wchar_t* kRootNames[] = {
- // A PDB file with no OMAP data.
- L"dump_syms_regtest",
- // A PDB file with OMAP data for an image that has been function-level
- // reordered.
- L"omap_reorder_funcs",
- // A PDB file with OMAP data for an image that had new content injected, all
- // of it with source data.
- L"omap_stretched_filled",
- // A PDB file with OMAP data for an image that had new content injected, but
- // without source data.
- L"omap_stretched",
- // A PDB file with OMAP data for an image that has been basic block reordered.
- L"omap_reorder_bbs",
- // A 64bit PDB file with no OMAP data.
- L"dump_syms_regtest64",
-};
-
-const wchar_t* kPEOnlyRootNames[] = {
- L"pe_only_symbol_test",
-};
-
-void TrimLastComponent(const std::wstring& path,
- std::wstring* trimmed,
- std::wstring* component) {
- size_t len = path.size();
- while (len > 0 && path[len - 1] != '\\')
- --len;
-
- if (component != NULL)
- component->assign(path.c_str() + len, path.c_str() + path.size());
-
- while (len > 0 && path[len - 1] == '\\')
- --len;
-
- if (trimmed != NULL)
- trimmed->assign(path.c_str(), len);
-}
-
-// Get the directory of the current executable.
-bool GetSelfDirectory(std::wstring* self_dir) {
- std::wstring command_line = GetCommandLineW();
-
- int num_args = 0;
- wchar_t** args = NULL;
- args = ::CommandLineToArgvW(command_line.c_str(), &num_args);
- if (args == NULL)
- return false;
-
- *self_dir = args[0];
- TrimLastComponent(*self_dir, self_dir, NULL);
-
- return true;
-}
-
-void RunCommand(const std::wstring& command_line,
- std::string* stdout_string) {
- // Create a PIPE for the child process stdout.
- HANDLE child_stdout_read = 0;
- HANDLE child_stdout_write = 0;
- SECURITY_ATTRIBUTES sec_attr_stdout = {};
- sec_attr_stdout.nLength = sizeof(sec_attr_stdout);
- sec_attr_stdout.bInheritHandle = TRUE;
- ASSERT_TRUE(::CreatePipe(&child_stdout_read, &child_stdout_write,
- &sec_attr_stdout, 0));
- ASSERT_TRUE(::SetHandleInformation(child_stdout_read, HANDLE_FLAG_INHERIT,
- 0));
-
- // Create a PIPE for the child process stdin.
- HANDLE child_stdin_read = 0;
- HANDLE child_stdin_write = 0;
- SECURITY_ATTRIBUTES sec_attr_stdin = {};
- sec_attr_stdin.nLength = sizeof(sec_attr_stdin);
- sec_attr_stdin.bInheritHandle = TRUE;
- ASSERT_TRUE(::CreatePipe(&child_stdin_read, &child_stdin_write,
- &sec_attr_stdin, 0));
- ASSERT_TRUE(::SetHandleInformation(child_stdin_write, HANDLE_FLAG_INHERIT,
- 0));
-
- // Startup the child.
- STARTUPINFO startup_info = {};
- PROCESS_INFORMATION process_info = {};
- startup_info.cb = sizeof(STARTUPINFO);
- startup_info.hStdError = NULL;
- startup_info.hStdInput = child_stdin_read;
- startup_info.hStdOutput = child_stdout_write;
- startup_info.dwFlags = STARTF_USESTDHANDLES;
- ASSERT_TRUE(::CreateProcessW(NULL, (LPWSTR)command_line.c_str(), NULL, NULL,
- TRUE, 0, NULL, NULL,
- &startup_info, &process_info));
-
- // Collect the output.
- ASSERT_TRUE(::CloseHandle(child_stdout_write));
- char buffer[4096] = {};
- DWORD bytes_read = 0;
- while (::ReadFile(child_stdout_read, buffer, sizeof(buffer), &bytes_read,
- NULL) && bytes_read > 0) {
- stdout_string->append(buffer, bytes_read);
- }
-
- // Wait for the process to finish.
- ::WaitForSingleObject(process_info.hProcess, INFINITE);
-
- // Shut down all of our handles.
- ASSERT_TRUE(::CloseHandle(process_info.hThread));
- ASSERT_TRUE(::CloseHandle(process_info.hProcess));
- ASSERT_TRUE(::CloseHandle(child_stdin_write));
- ASSERT_TRUE(::CloseHandle(child_stdin_read));
- ASSERT_TRUE(::CloseHandle(child_stdout_read));
-}
-
-void GetFileContents(const std::wstring& path, std::string* content) {
- FILE* f = ::_wfopen(path.c_str(), L"rb");
- ASSERT_TRUE(f != NULL);
-
- char buffer[4096] = {};
- while (true) {
- size_t bytes_read = ::fread(buffer, 1, sizeof(buffer), f);
- if (bytes_read == 0)
- break;
- content->append(buffer, bytes_read);
- }
-}
-
-class DumpSymsRegressionTest : public testing::TestWithParam<const wchar_t *> {
- public:
- virtual void SetUp() {
- std::wstring self_dir;
- ASSERT_TRUE(GetSelfDirectory(&self_dir));
- dump_syms_exe = self_dir + L"\\dump_syms.exe";
-
- TrimLastComponent(self_dir, &testdata_dir, NULL);
- testdata_dir += L"\\testdata";
- }
-
- std::wstring dump_syms_exe;
- std::wstring testdata_dir;
-};
-
-class DumpSymsPEOnlyRegressionTest : public testing::TestWithParam<const wchar_t *> {
-public:
- virtual void SetUp() {
- std::wstring self_dir;
- ASSERT_TRUE(GetSelfDirectory(&self_dir));
- dump_syms_exe = self_dir + L"\\dump_syms.exe";
-
- TrimLastComponent(self_dir, &testdata_dir, NULL);
- testdata_dir += L"\\testdata";
- }
-
- std::wstring dump_syms_exe;
- std::wstring testdata_dir;
-};
-
-} //namespace
-
-TEST_P(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) {
- const wchar_t* root_name = GetParam();
- std::wstring root_path = testdata_dir + L"\\" + root_name;
-
- std::wstring sym_path = root_path + L".sym";
- std::string expected_symbols;
- ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
-
- std::wstring pdb_path = root_path + L".pdb";
- std::wstring command_line = L"\"" + dump_syms_exe + L"\" \"" +
- pdb_path + L"\"";
- std::string symbols;
- ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
-
- EXPECT_EQ(expected_symbols, symbols);
-}
-
-INSTANTIATE_TEST_CASE_P(DumpSyms, DumpSymsRegressionTest,
- testing::ValuesIn(kRootNames));
-
-TEST_P(DumpSymsPEOnlyRegressionTest, EnsurePEOnlyDumpedSymbolsMatch) {
- const wchar_t* root_name = GetParam();
- std::wstring root_path = testdata_dir + L"\\" + root_name;
-
- std::wstring sym_path = root_path + L".sym";
- std::string expected_symbols;
- ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
-
- std::wstring dll_path = root_path + L".dll";
- std::wstring command_line = L"\"" + dump_syms_exe + L"\" --pe \"" +
- dll_path + L"\"";
- std::string symbols;
- ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
-
- EXPECT_EQ(expected_symbols, symbols);
-}
-
-INSTANTIATE_TEST_CASE_P(PEOnlyDumpSyms, DumpSymsPEOnlyRegressionTest,
- testing::ValuesIn(kPEOnlyRootNames));
-
-
-} // namespace dump_syms
-} // namespace windows
-} // namespace tools
+// Copyright 2003 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <Windows.h> +#include <shellapi.h> + +#include <string> +#include <utility> + +#include "breakpad_googletest_includes.h" + +namespace tools { +namespace windows { +namespace dump_syms { + +namespace { + +// Root names of PDB and dumped symbol files to be regression tested. These are +// specified in complexity of the resulting dumped symbol files. +const wchar_t* kRootNames[] = { + // A PDB file with no OMAP data. + L"dump_syms_regtest", + // A PDB file with OMAP data for an image that has been function-level + // reordered. + L"omap_reorder_funcs", + // A PDB file with OMAP data for an image that had new content injected, all + // of it with source data. + L"omap_stretched_filled", + // A PDB file with OMAP data for an image that had new content injected, but + // without source data. + L"omap_stretched", + // A PDB file with OMAP data for an image that has been basic block reordered. + L"omap_reorder_bbs", + // A 64bit PDB file with no OMAP data. + L"dump_syms_regtest64", +}; + +const wchar_t* kPEOnlyRootNames[] = { + L"pe_only_symbol_test", +}; + +void TrimLastComponent(const std::wstring& path, + std::wstring* trimmed, + std::wstring* component) { + size_t len = path.size(); + while (len > 0 && path[len - 1] != '\\') + --len; + + if (component != NULL) + component->assign(path.c_str() + len, path.c_str() + path.size()); + + while (len > 0 && path[len - 1] == '\\') + --len; + + if (trimmed != NULL) + trimmed->assign(path.c_str(), len); +} + +// Get the directory of the current executable. +bool GetSelfDirectory(std::wstring* self_dir) { + std::wstring command_line = GetCommandLineW(); + + int num_args = 0; + wchar_t** args = NULL; + args = ::CommandLineToArgvW(command_line.c_str(), &num_args); + if (args == NULL) + return false; + + *self_dir = args[0]; + TrimLastComponent(*self_dir, self_dir, NULL); + + return true; +} + +void RunCommand(const std::wstring& command_line, + std::string* stdout_string) { + // Create a PIPE for the child process stdout. + HANDLE child_stdout_read = 0; + HANDLE child_stdout_write = 0; + SECURITY_ATTRIBUTES sec_attr_stdout = {}; + sec_attr_stdout.nLength = sizeof(sec_attr_stdout); + sec_attr_stdout.bInheritHandle = TRUE; + ASSERT_TRUE(::CreatePipe(&child_stdout_read, &child_stdout_write, + &sec_attr_stdout, 0)); + ASSERT_TRUE(::SetHandleInformation(child_stdout_read, HANDLE_FLAG_INHERIT, + 0)); + + // Create a PIPE for the child process stdin. + HANDLE child_stdin_read = 0; + HANDLE child_stdin_write = 0; + SECURITY_ATTRIBUTES sec_attr_stdin = {}; + sec_attr_stdin.nLength = sizeof(sec_attr_stdin); + sec_attr_stdin.bInheritHandle = TRUE; + ASSERT_TRUE(::CreatePipe(&child_stdin_read, &child_stdin_write, + &sec_attr_stdin, 0)); + ASSERT_TRUE(::SetHandleInformation(child_stdin_write, HANDLE_FLAG_INHERIT, + 0)); + + // Startup the child. + STARTUPINFO startup_info = {}; + PROCESS_INFORMATION process_info = {}; + startup_info.cb = sizeof(STARTUPINFO); + startup_info.hStdError = NULL; + startup_info.hStdInput = child_stdin_read; + startup_info.hStdOutput = child_stdout_write; + startup_info.dwFlags = STARTF_USESTDHANDLES; + ASSERT_TRUE(::CreateProcessW(NULL, (LPWSTR)command_line.c_str(), NULL, NULL, + TRUE, 0, NULL, NULL, + &startup_info, &process_info)); + + // Collect the output. + ASSERT_TRUE(::CloseHandle(child_stdout_write)); + char buffer[4096] = {}; + DWORD bytes_read = 0; + while (::ReadFile(child_stdout_read, buffer, sizeof(buffer), &bytes_read, + NULL) && bytes_read > 0) { + stdout_string->append(buffer, bytes_read); + } + + // Wait for the process to finish. + ::WaitForSingleObject(process_info.hProcess, INFINITE); + + // Shut down all of our handles. + ASSERT_TRUE(::CloseHandle(process_info.hThread)); + ASSERT_TRUE(::CloseHandle(process_info.hProcess)); + ASSERT_TRUE(::CloseHandle(child_stdin_write)); + ASSERT_TRUE(::CloseHandle(child_stdin_read)); + ASSERT_TRUE(::CloseHandle(child_stdout_read)); +} + +void GetFileContents(const std::wstring& path, std::string* content) { + FILE* f = ::_wfopen(path.c_str(), L"rb"); + ASSERT_TRUE(f != NULL); + + char buffer[4096] = {}; + while (true) { + size_t bytes_read = ::fread(buffer, 1, sizeof(buffer), f); + if (bytes_read == 0) + break; + content->append(buffer, bytes_read); + } +} + +class DumpSymsRegressionTest : public testing::TestWithParam<const wchar_t*> { + public: + virtual void SetUp() { + std::wstring self_dir; + ASSERT_TRUE(GetSelfDirectory(&self_dir)); + dump_syms_exe = self_dir + L"\\dump_syms.exe"; + + TrimLastComponent(self_dir, &testdata_dir, NULL); + testdata_dir += L"\\testdata"; + } + + std::wstring dump_syms_exe; + std::wstring testdata_dir; +}; + +class DumpSymsPEOnlyRegressionTest : public testing::TestWithParam<const wchar_t*> { +public: + virtual void SetUp() { + std::wstring self_dir; + ASSERT_TRUE(GetSelfDirectory(&self_dir)); + dump_syms_exe = self_dir + L"\\dump_syms.exe"; + + TrimLastComponent(self_dir, &testdata_dir, NULL); + testdata_dir += L"\\testdata"; + } + + std::wstring dump_syms_exe; + std::wstring testdata_dir; +}; + +} //namespace + +TEST_P(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) { + const wchar_t* root_name = GetParam(); + std::wstring root_path = testdata_dir + L"\\" + root_name; + + std::wstring sym_path = root_path + L".sym"; + std::string expected_symbols; + ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols)); + + std::wstring pdb_path = root_path + L".pdb"; + std::wstring command_line = L"\"" + dump_syms_exe + L"\" \"" + + pdb_path + L"\""; + std::string symbols; + ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols)); + + EXPECT_EQ(expected_symbols, symbols); +} + +INSTANTIATE_TEST_SUITE_P(DumpSyms, DumpSymsRegressionTest, + testing::ValuesIn(kRootNames)); + +TEST_P(DumpSymsPEOnlyRegressionTest, EnsurePEOnlyDumpedSymbolsMatch) { + const wchar_t* root_name = GetParam(); + std::wstring root_path = testdata_dir + L"\\" + root_name; + + std::wstring sym_path = root_path + L".sym"; + std::string expected_symbols; + ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols)); + + std::wstring dll_path = root_path + L".dll"; + std::wstring command_line = L"\"" + dump_syms_exe + L"\" --pe \"" + + dll_path + L"\""; + std::string symbols; + ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols)); + + EXPECT_EQ(expected_symbols, symbols); +} + +INSTANTIATE_TEST_SUITE_P(PEOnlyDumpSyms, DumpSymsPEOnlyRegressionTest, + testing::ValuesIn(kPEOnlyRootNames)); + + +} // namespace dump_syms +} // namespace windows +} // namespace tools diff --git a/src/tools/windows/dump_syms/run_regtest.sh b/src/tools/windows/dump_syms/run_regtest.sh index 1f20f64f..2401edd1 100755 --- a/src/tools/windows/dump_syms/run_regtest.sh +++ b/src/tools/windows/dump_syms/run_regtest.sh @@ -1,7 +1,6 @@ #!/bin/sh -# Copyright (c) 2006, Google Inc. -# All rights reserved. +# Copyright 2006 Google LLC # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ # 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 +# * Neither the name of Google LLC nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # diff --git a/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc b/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc index e8efbeb8..442676ba 100644 --- a/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc +++ b/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. +// Copyright 2007 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -48,7 +47,7 @@ class C { void f() { member_ = g(); } virtual int g() { return 2; } - static char* h(const C &that) { return 0; } + static char* h(const C& that) { return 0; } private: int member_; @@ -60,12 +59,12 @@ static int i() { } // namespace google_breakpad -int main(int argc, char **argv) { +int main(int argc, char** argv) { google_breakpad::C object; object.set_member(google_breakpad::i()); object.f(); int value = object.g(); - char *nothing = object.h(object); + char* nothing = object.h(object); return 0; } diff --git a/src/tools/windows/symupload/symupload.cc b/src/tools/windows/symupload/symupload.cc index 7e302932..65123a28 100644 --- a/src/tools/windows/symupload/symupload.cc +++ b/src/tools/windows/symupload/symupload.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. +// Copyright 2006 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -56,24 +55,23 @@ #include "common/windows/http_upload.h" #include "common/windows/pdb_source_line_writer.h" +#include "common/windows/sym_upload_v2_protocol.h" #include "common/windows/symbol_collector_client.h" -using std::string; -using std::wstring; -using std::vector; -using std::map; using google_breakpad::HTTPUpload; -using google_breakpad::SymbolCollectorClient; -using google_breakpad::SymbolStatus; -using google_breakpad::UploadUrlResponse; -using google_breakpad::CompleteUploadResult; using google_breakpad::PDBModuleInfo; using google_breakpad::PDBSourceLineWriter; using google_breakpad::WindowsStringUtils; +using std::map; +using std::string; +using std::vector; +using std::wstring; + +const wchar_t* kSymbolUploadTypeBreakpad = L"BREAKPAD"; // Extracts the file version information for the given filename, // as a string, for example, "1.2.3.4". Returns true on success. -static bool GetFileVersionString(const wchar_t *filename, wstring *version) { +static bool GetFileVersionString(const wchar_t* filename, wstring* version) { DWORD handle; DWORD version_size = GetFileVersionInfoSize(filename, &handle); if (version_size < sizeof(VS_FIXEDFILEINFO)) { @@ -85,7 +83,7 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) { return false; } - void *file_info_buffer = NULL; + void* file_info_buffer = NULL; unsigned int file_info_length; if (!VerQueryValue(&version_info[0], L"\\", &file_info_buffer, &file_info_length)) { @@ -95,7 +93,7 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) { // The maximum value of each version component is 65535 (0xffff), // so the max length is 24, including the terminating null. wchar_t ver_string[24]; - VS_FIXEDFILEINFO *file_info = + VS_FIXEDFILEINFO* file_info = reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer); swprintf(ver_string, sizeof(ver_string) / sizeof(ver_string[0]), L"%d.%d.%d.%d", @@ -114,10 +112,11 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) { // Creates a new temporary file and writes the symbol data from the given // exe/dll file to it. Returns the path to the temp file in temp_file_path // and information about the pdb in pdb_info. -static bool DumpSymbolsToTempFile(const wchar_t *file, - wstring *temp_file_path, - PDBModuleInfo *pdb_info) { - google_breakpad::PDBSourceLineWriter writer; +static bool DumpSymbolsToTempFile(const wchar_t* file, + wstring* temp_file_path, + PDBModuleInfo* pdb_info, + bool handle_inline) { + google_breakpad::PDBSourceLineWriter writer(handle_inline); // Use EXE_FILE to get information out of the exe/dll in addition to the // pdb. The name and version number of the exe/dll are of value, and // there's no way to locate an exe/dll given a pdb. @@ -135,7 +134,7 @@ static bool DumpSymbolsToTempFile(const wchar_t *file, return false; } - FILE *temp_file = NULL; + FILE* temp_file = NULL; #if _MSC_VER >= 1400 // MSVC 2005/8 if (_wfopen_s(&temp_file, temp_filename, L"w") != 0) #else // _MSC_VER >= 1400 @@ -159,97 +158,12 @@ static bool DumpSymbolsToTempFile(const wchar_t *file, return writer.GetModuleInfo(pdb_info); } -static bool DoSymUploadV2( - const wchar_t* api_url, - const wchar_t* api_key, - const wstring& debug_file, - const wstring& debug_id, - const wstring& symbol_file, - bool force) { - wstring url(api_url); - wstring key(api_key); - - if (!force) { - SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus( - url, - key, - debug_file, - debug_id); - if (symbolStatus == SymbolStatus::Found) { - wprintf(L"Symbol file already exists, upload aborted." - L" Use \"-f\" to overwrite.\n"); - return true; - } - else if (symbolStatus == SymbolStatus::Unknown) { - wprintf(L"Failed to get check for existing symbol.\n"); - return false; - } - } - - UploadUrlResponse uploadUrlResponse; - if (!SymbolCollectorClient::CreateUploadUrl( - url, - key, - &uploadUrlResponse)) { - wprintf(L"Failed to create upload URL.\n"); - return false; - } - - wstring signed_url = uploadUrlResponse.upload_url; - wstring upload_key = uploadUrlResponse.upload_key; - wstring response; - int response_code; - bool success = HTTPUpload::SendPutRequest( - signed_url, - symbol_file, - /* timeout = */ NULL, - &response, - &response_code); - if (!success) { - wprintf(L"Failed to send symbol file.\n"); - wprintf(L"Response code: %ld\n", response_code); - wprintf(L"Response:\n"); - wprintf(L"%s\n", response.c_str()); - return false; - } - else if (response_code == 0) { - wprintf(L"Failed to send symbol file: No response code\n"); - return false; - } - else if (response_code != 200) { - wprintf(L"Failed to send symbol file: Response code %ld\n", response_code); - wprintf(L"Response:\n"); - wprintf(L"%s\n", response.c_str()); - return false; - } - - CompleteUploadResult completeUploadResult = - SymbolCollectorClient::CompleteUpload( - url, - key, - upload_key, - debug_file, - debug_id); - if (completeUploadResult == CompleteUploadResult::Error) { - wprintf(L"Failed to complete upload.\n"); - return false; - } - else if (completeUploadResult == CompleteUploadResult::DuplicateData) { - wprintf(L"Uploaded file checksum matched existing file checksum," - L" no change necessary.\n"); - } - else { - wprintf(L"Successfully sent the symbol file.\n"); - } - - return true; -} - __declspec(noreturn) void printUsageAndExit() { wprintf(L"Usage:\n\n" - L" symupload [--timeout NN] [--product product_name] ^\n" + L" symupload [--i] [--timeout NN] [--product product_name] ^\n" L" <file.exe|file.dll> <symbol upload URL> ^\n" L" [...<symbol upload URLs>]\n\n"); + wprintf(L" - i: Extract inline information from pdb.\n"); wprintf(L" - Timeout is in milliseconds, or can be 0 to be unlimited.\n"); wprintf(L" - product_name is an HTTP-friendly product name. It must only\n" L" contain an ascii subset: alphanumeric and punctuation.\n" @@ -270,9 +184,10 @@ __declspec(noreturn) void printUsageAndExit() { exit(0); } -int wmain(int argc, wchar_t *argv[]) { - const wchar_t *module; - const wchar_t *product = nullptr; +int wmain(int argc, wchar_t* argv[]) { + const wchar_t* module; + const wchar_t* product = nullptr; + bool handle_inline = false; int timeout = -1; int currentarg = 1; bool use_sym_upload_v2 = false; @@ -280,6 +195,11 @@ int wmain(int argc, wchar_t *argv[]) { const wchar_t* api_url = nullptr; const wchar_t* api_key = nullptr; while (argc > currentarg + 1) { + if (!wcscmp(L"--i", argv[currentarg])) { + handle_inline = true; + ++currentarg; + continue; + } if (!wcscmp(L"--timeout", argv[currentarg])) { timeout = _wtoi(argv[currentarg + 1]); currentarg += 2; @@ -310,7 +230,7 @@ int wmain(int argc, wchar_t *argv[]) { wstring symbol_file; PDBModuleInfo pdb_info; - if (!DumpSymbolsToTempFile(module, &symbol_file, &pdb_info)) { + if (!DumpSymbolsToTempFile(module, &symbol_file, &pdb_info, handle_inline)) { fwprintf(stderr, L"Could not get symbol data from %s\n", module); return 1; } @@ -329,14 +249,12 @@ int wmain(int argc, wchar_t *argv[]) { if (argc >= currentarg + 2) { api_url = argv[currentarg++]; api_key = argv[currentarg++]; + wstring product_name = product ? wstring(product) : L""; - success = DoSymUploadV2( - api_url, - api_key, - pdb_info.debug_file, - pdb_info.debug_identifier, - symbol_file, - force); + success = google_breakpad::SymUploadV2ProtocolSend( + api_url, api_key, timeout == -1 ? nullptr : &timeout, + pdb_info.debug_file, pdb_info.debug_identifier, symbol_file, + kSymbolUploadTypeBreakpad, product_name, force); } else { printUsageAndExit(); } diff --git a/src/tools/windows/symupload/symupload.gyp b/src/tools/windows/symupload/symupload.gyp deleted file mode 100644 index 4567a4bd..00000000 --- a/src/tools/windows/symupload/symupload.gyp +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2013 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': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'symupload', - 'type': 'executable', - 'sources': [ - 'symupload.cc', - ], - 'dependencies': [ - '../../../common/windows/common_windows.gyp:common_windows_lib', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'LargeAddressAware': '2', - }, - }, - }, - ], -} diff --git a/src/tools/windows/tools_windows.gyp b/src/tools/windows/tools_windows.gyp deleted file mode 100644 index 17b88b4a..00000000 --- a/src/tools/windows/tools_windows.gyp +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2017 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': [ - '../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'build_all', - 'type': 'none', - 'dependencies': [ - './converter/ms_symbol_server_converter.gyp:*', - './converter_exe/converter.gyp:*', - './dump_syms/dump_syms.gyp:*', - './symupload/symupload.gyp:*', - ], - }, - ], -} |